Add support the WowWee 11-Bit RoboRaptor-X protocol. (#1939)

* Basic `sendWowwee()` & decodeWowwee()` routines.
* Unit test coverage including decoding of two different captured messages from a real remote.
* Add reference for available/known RoboRaptor-X codes.

Fixes #1938
This commit is contained in:
David Conran
2022-12-31 18:45:32 +10:00
committed by GitHub
parent 3a81664c24
commit fa77d78076
9 changed files with 231 additions and 1 deletions

View File

@@ -1169,6 +1169,10 @@ bool IRrecv::decode(decode_results *results, irparams_t *save,
DPRINTLN("Attempting GORENJE decode");
if (decodeGorenje(results, offset)) return true;
#endif // DECODE_GORENJE
#if DECODE_WOWWEE
DPRINTLN("Attempting WOWWEE decode");
if (decodeWowwee(results, offset)) return true;
#endif // DECODE_WOWWEE
// Typically new protocols are added above this line.
}
#if DECODE_HASH

View File

@@ -865,6 +865,12 @@ class IRrecv {
const uint16_t nbits = kBosch144Bits,
const bool strict = true);
#endif // DECODE_BOSCH144
#if DECODE_WOWWEE
bool decodeWowwee(decode_results *results,
uint16_t offset = kStartOffset,
const uint16_t nbits = kWowweeBits,
const bool strict = true);
#endif // DECODE_WOWWEE
};
#endif // IRRECV_H_

View File

@@ -931,6 +931,13 @@
#define SEND_GORENJE _IR_ENABLE_DEFAULT_
#endif // SEND_GORENJE
#ifndef DECODE_WOWWEE
#define DECODE_WOWWEE _IR_ENABLE_DEFAULT_
#endif // DECODE_WOWWEE
#ifndef SEND_WOWWEE
#define SEND_WOWWEE _IR_ENABLE_DEFAULT_
#endif // SEND_WOWWEE
#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 || \
@@ -1112,8 +1119,9 @@ enum decode_type_t {
SANYO_AC152,
DAIKIN312,
GORENJE,
WOWWEE,
// Add new entries before this one, and update it to point to the last entry.
kLastDecodeType = GORENJE,
kLastDecodeType = WOWWEE,
};
// Message lengths & required repeat values
@@ -1387,6 +1395,8 @@ const uint16_t kWhirlpoolAcStateLength = 21;
const uint16_t kWhirlpoolAcBits = kWhirlpoolAcStateLength * 8;
const uint16_t kWhirlpoolAcDefaultRepeat = kNoRepeat;
const uint16_t kWhynterBits = 32;
const uint16_t kWowweeBits = 11;
const uint16_t kWowweeDefaultRepeat = kNoRepeat;
const uint8_t kVestelAcBits = 56;
const uint16_t kXmpBits = 64;
const uint16_t kZepealBits = 16;

View File

@@ -605,6 +605,8 @@ uint16_t IRsend::defaultBits(const decode_type_t protocol) {
case MULTIBRACKETS:
case GORENJE:
return 8;
case WOWWEE:
return 11;
case RC5:
case SYMPHONY:
return 12;
@@ -1120,6 +1122,11 @@ bool IRsend::send(const decode_type_t type, const uint64_t data,
sendWhynter(data, nbits, min_repeat);
break;
#endif
#if SEND_WOWWEE
case WOWWEE:
sendWowwee(data, nbits, min_repeat);
break;
#endif // SEND_WOWWEE
#if SEND_XMP
case XMP:
sendXmp(data, nbits, min_repeat);

View File

@@ -870,6 +870,10 @@ class IRsend {
const uint16_t nbytes = kBosch144StateLength,
const uint16_t repeat = kNoRepeat);
#endif // SEND_BOSCH144
#if SEND_WOWWEE
void sendWowwee(const uint64_t data, const uint16_t nbits = kWowweeBits,
const uint16_t repeat = kWowweeDefaultRepeat);
#endif // SEND_WOWWEE
protected:
#ifdef UNIT_TEST

View File

@@ -549,6 +549,8 @@ IRTEXT_CONST_BLOB_DECL(kAllProtocolNamesStr) {
D_STR_DAIKIN312, D_STR_UNSUPPORTED) "\x0"
COND(DECODE_GORENJE || SEND_GORENJE,
D_STR_GORENJE, D_STR_UNSUPPORTED) "\x0"
COND(DECODE_WOWWEE || SEND_WOWWEE,
D_STR_WOWWEE, D_STR_UNSUPPORTED) "\x0"
///< New protocol (macro) strings should be added just above this line.
"\x0" ///< This string requires double null termination.
};

91
src/ir_Wowwee.cpp Normal file
View File

@@ -0,0 +1,91 @@
// Copyright 2022 David Conran
/// @file
/// @brief Support for WowWee RoboRapter protocol
/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues1938
// Supports:
// Brand: WowWee, Model: RoboRapter-X
// WowWee RoboRapter-X messages
// Ref: https://github.com/crankyoldgit/IRremoteESP8266/issues/1938#issuecomment-1367968228
//
// Button Code
// ====== =====
// Left 0x180
// Forward 0x186
// Backward 0x187
// Right 0x188
// Stop 0x18E
// Head Counterclockwise 0x191
// Tail Left 0x192
// Tail Right 0x193
// Head Clockwise 0x194
// Guard Mode 0x1B0
// Roam 0x1B1
// Cautious Mood 0x1B2
// Playful Mood 0x1B3
// Hunting Mood 0x1B4
// Demo 0x1D0
// Bite 0x1D1
#include <algorithm>
#include "IRrecv.h"
#include "IRsend.h"
#include "IRutils.h"
// Constants
const uint16_t kWowweeHdrMark = 6684;
const uint16_t kWowweeHdrSpace = 723;
const uint16_t kWowweeBitMark = 912;
const uint16_t kWowweeOneSpace = 3259;
const uint16_t kWowweeZeroSpace = kWowweeHdrSpace;
const uint16_t kWowweeFreq = 38000; // Hz. (Just a guess)
#if SEND_WOWWEE
/// Send a WowWee formatted message.
/// Status: STABLE / Confirmed working with real device.
/// @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::sendWowwee(uint64_t data, uint16_t nbits, uint16_t repeat) {
sendGeneric(kWowweeHdrMark, kWowweeHdrSpace,
kWowweeBitMark, kWowweeOneSpace,
kWowweeBitMark, kWowweeZeroSpace,
kWowweeBitMark, kDefaultMessageGap, data,
nbits, kWowweeFreq, true, repeat, 33);
}
#endif // SEND_WOWWEE
#if DECODE_WOWWEE
/// Decode the supplied WowWee message.
/// Status: STABLE / Confirmed working with real device.
/// @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::decodeWowwee(decode_results *results, uint16_t offset,
const uint16_t nbits, const bool strict) {
if (strict && nbits != kWowweeBits)
return false; // We expect Wowwee to be a certain sized message.
uint64_t data = 0;
// Match Header + Data + Footer
if (!matchGeneric(results->rawbuf + offset, &data,
results->rawlen - offset, nbits,
kWowweeHdrMark, kWowweeHdrSpace,
kWowweeBitMark, kWowweeOneSpace,
kWowweeBitMark, kWowweeZeroSpace,
kWowweeBitMark, kDefaultMessageGap, true)) return false;
// Success
results->bits = nbits;
results->value = data;
results->decode_type = WOWWEE;
results->command = 0;
results->address = 0;
return true;
}
#endif // DECODE_WOWWEE

View File

@@ -1105,6 +1105,9 @@ D_STR_INDIRECT " " D_STR_MODE
#ifndef D_STR_WHYNTER
#define D_STR_WHYNTER "WHYNTER"
#endif // D_STR_WHYNTER
#ifndef D_STR_WOWWEE
#define D_STR_WOWWEE "WOWWEE"
#endif // D_STR_WOWWEE
#ifndef D_STR_XMP
#define D_STR_XMP "XMP"
#endif // D_STR_XMP

103
test/ir_Wowwee_test.cpp Normal file
View File

@@ -0,0 +1,103 @@
// Copyright 2022 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("WOWWEE", typeToString(decode_type_t::WOWWEE));
ASSERT_EQ(decode_type_t::WOWWEE, strToDecodeType("WOWWEE"));
ASSERT_FALSE(hasACState(decode_type_t::WOWWEE));
ASSERT_FALSE(IRac::isProtocolSupported(decode_type_t::WOWWEE));
ASSERT_EQ(kWowweeBits, IRsend::defaultBits(decode_type_t::WOWWEE));
ASSERT_EQ(kWowweeDefaultRepeat, IRsend::minRepeats(decode_type_t::WOWWEE));
}
// Tests for sendWowwee().
// Test sending typical data only.
TEST(TestSendWowwee, SendDataOnly) {
IRsendTest irsend(kGpioUnused);
irsend.begin();
irsend.reset();
irsend.sendWowwee(0x186); // Nikai TV Power Off.
EXPECT_EQ(
"f38000d33"
"m6684s723"
"m912s723m912s723m912s3259m912s3259m912s723m912s723m912s723m912s723"
"m912s3259m912s3259m912s723m912s100000",
irsend.outputStr());
irsend.reset();
}
// Tests for decodeWowwee().
// Decode normal Wowwee messages.
TEST(TestDecodeWowwee, RealDecode) {
IRsendTest irsend(kGpioUnused);
IRrecv irrecv(kGpioUnused);
irsend.begin();
// Ref: https://github.com/crankyoldgit/IRremoteESP8266/issues/1938#issue-1513240242
const uint16_t rawForward[25] = {
6684, 740, 918, 724, 942, 724, 918, 3250, 870, 3268, 872, 770, 940, 690,
942, 688, 942, 738, 942, 3250, 868, 3268, 872, 732, 918
}; // UNKNOWN 7469BF81
irsend.reset();
irsend.sendRaw(rawForward, 25, 38);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decode(&irsend.capture));
EXPECT_EQ(decode_type_t::WOWWEE, irsend.capture.decode_type);
EXPECT_EQ(kWowweeBits, irsend.capture.bits);
EXPECT_EQ(0x186, irsend.capture.value);
EXPECT_EQ(0x0, irsend.capture.command);
EXPECT_EQ(0x0, irsend.capture.address);
// Ref: https://github.com/crankyoldgit/IRremoteESP8266/issues/1938#issue-1513240242
const uint16_t rawLeft[25] = {
6630, 764, 868, 762, 892, 788, 866, 3324, 792, 3348, 818, 760, 866, 788,
894, 772, 892, 750, 870, 786, 920, 750, 864, 776, 868
}; // UNKNOWN 28A1120F
irsend.reset();
irsend.sendRaw(rawLeft, 25, 38);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decode(&irsend.capture));
EXPECT_EQ(decode_type_t::WOWWEE, irsend.capture.decode_type);
EXPECT_EQ(kWowweeBits, irsend.capture.bits);
EXPECT_EQ(0x180, irsend.capture.value);
EXPECT_EQ(0x0, irsend.capture.command);
EXPECT_EQ(0x0, irsend.capture.address);
}
// Decode normal repeated Wowwee messages.
TEST(TestDecodeWowwee, SyntheticDecode) {
IRsendTest irsend(kGpioUnused);
IRrecv irrecv(kGpioUnused);
irsend.begin();
// Normal Wowwee 11-bit message.
irsend.reset();
irsend.sendWowwee(0x186);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decode(&irsend.capture));
EXPECT_EQ(decode_type_t::WOWWEE, irsend.capture.decode_type);
EXPECT_EQ(kWowweeBits, irsend.capture.bits);
EXPECT_EQ(0x186, irsend.capture.value);
EXPECT_EQ(0x0, irsend.capture.command);
EXPECT_EQ(0x0, irsend.capture.address);
// Normal Wowwee 11-bit message.
irsend.reset();
irsend.sendWowwee(0x180);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decode(&irsend.capture));
EXPECT_EQ(decode_type_t::WOWWEE, irsend.capture.decode_type);
EXPECT_EQ(kWowweeBits, irsend.capture.bits);
EXPECT_EQ(0x180, irsend.capture.value);
EXPECT_EQ(0x0, irsend.capture.command);
EXPECT_EQ(0x0, irsend.capture.address);
}