mirror of
https://github.com/crankyoldgit/IRremoteESP8266.git
synced 2026-01-12 00:05:10 +08:00
Add support for Multibrackets protocol. (#1106)
* Basic send/decode support only. It's a very simple protocol. * Unit tests etc. Fixes #1103
This commit is contained in:
@@ -50,6 +50,7 @@
|
||||
| [Mitsubishi](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Mitsubishi.cpp) | **[Mitsubishi](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Mitsubishi.h)** | HC3000 Projector<BR>KM14A 0179213 remote<BR>MS-GK24VA A/C<BR>TV | | Yes |
|
||||
| [Mitsubishi](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Mitsubishi.cpp) | **[Mitsubishi Electric](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Mitsubishi.h)** | 001CP T7WE10714 remote<BR>KPOA remote<BR>MSH-A24WV / MUH-A24WV A/C<BR>PEAD-RP71JAA Ducted A/C | | Yes |
|
||||
| [MitsubishiHeavy](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_MitsubishiHeavy.cpp) | **[Mitsubishi Heavy Industries](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_MitsubishiHeavy.h)** | RKX502A001C remote<BR>RLA502A700B remote<BR>SRKxxZJ-S A/C<BR>SRKxxZM-S A/C<BR>SRKxxZMXA-S A/C | | Yes |
|
||||
| [Multibrackets](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Multibrackets.cpp) | **Multibrackets** | Motorized Swing mount large - 4500 | | - |
|
||||
| [NEC](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_NEC.cpp) | **[Aloka](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_NEC.h)** | SleepyLights LED Lamp | | - |
|
||||
| [NEC](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_NEC.cpp) | **[Toshiba](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_NEC.h)** | 42TL838 LCD TV | | - |
|
||||
| [NEC](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_NEC.cpp) | **[Yamaha](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_NEC.h)** | RAV561 remote<BR>RXV585B A/V Receiver | | - |
|
||||
@@ -134,6 +135,7 @@
|
||||
- MITSUBISHI_AC
|
||||
- MITSUBISHI_HEAVY_152
|
||||
- MITSUBISHI_HEAVY_88
|
||||
- MULTIBRACKETS
|
||||
- MWM
|
||||
- NEC
|
||||
- NEC_LIKE
|
||||
|
||||
@@ -797,6 +797,10 @@ bool IRrecv::decode(decode_results *results, irparams_t *save,
|
||||
DPRINTLN("Attempting Doshisha decode");
|
||||
if (decodeDoshisha(results, offset)) return true;
|
||||
#endif // DECODE_DOSHISHA
|
||||
#if DECODE_MULTIBRACKETS
|
||||
DPRINTLN("Attempting Multibrackets decode");
|
||||
if (decodeMultibrackets(results, offset)) return true;
|
||||
#endif // DECODE_MULTIBRACKETS
|
||||
// Typically new protocols are added above this line.
|
||||
}
|
||||
#if DECODE_HASH
|
||||
|
||||
12
src/IRrecv.h
12
src/IRrecv.h
@@ -599,10 +599,16 @@ class IRrecv {
|
||||
const bool strict = true);
|
||||
#endif // DECODE_DELONGHI_AC
|
||||
#if DECODE_DOSHISHA
|
||||
bool decodeDoshisha(decode_results *results, uint16_t offset = kStartOffset,
|
||||
const uint16_t nbits = kDoshishaBits,
|
||||
const bool strict = true);
|
||||
bool decodeDoshisha(decode_results *results, uint16_t offset = kStartOffset,
|
||||
const uint16_t nbits = kDoshishaBits,
|
||||
const bool strict = true);
|
||||
#endif // DECODE_DOSHISHA
|
||||
#if DECODE_MULTIBRACKETS
|
||||
bool decodeMultibrackets(decode_results *results,
|
||||
uint16_t offset = kStartOffset,
|
||||
const uint16_t nbits = kMultibracketsBits,
|
||||
const bool strict = true);
|
||||
#endif // DECODE_MULTIBRACKETS
|
||||
};
|
||||
|
||||
#endif // IRRECV_H_
|
||||
|
||||
@@ -614,6 +614,12 @@
|
||||
#define SEND_DOSHISHA _IR_ENABLE_DEFAULT_
|
||||
#endif // SEND_DOSHISHA
|
||||
|
||||
#ifndef DECODE_MULTIBRACKETS
|
||||
#define DECODE_MULTIBRACKETS _IR_ENABLE_DEFAULT_
|
||||
#endif // DECODE_MULTIBRACKETS
|
||||
#ifndef SEND_MULTIBRACKETS
|
||||
#define SEND_MULTIBRACKETS _IR_ENABLE_DEFAULT_
|
||||
#endif // SEND_MULTIBRACKETS
|
||||
#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 || \
|
||||
@@ -743,8 +749,9 @@ enum decode_type_t {
|
||||
AIRWELL,
|
||||
DELONGHI_AC, // 80
|
||||
DOSHISHA,
|
||||
MULTIBRACKETS,
|
||||
// Add new entries before this one, and update it to point to the last entry.
|
||||
kLastDecodeType = DOSHISHA,
|
||||
kLastDecodeType = MULTIBRACKETS,
|
||||
};
|
||||
|
||||
// Message lengths & required repeat values
|
||||
@@ -871,6 +878,8 @@ const uint16_t kMitsubishiHeavy88MinRepeat = kNoRepeat;
|
||||
const uint16_t kMitsubishiHeavy152StateLength = 19;
|
||||
const uint16_t kMitsubishiHeavy152Bits = kMitsubishiHeavy152StateLength * 8;
|
||||
const uint16_t kMitsubishiHeavy152MinRepeat = kNoRepeat;
|
||||
const uint16_t kMultibracketsBits = 8;
|
||||
const uint16_t kMultibracketsDefaultRepeat = kSingleRepeat;
|
||||
const uint16_t kNikaiBits = 24;
|
||||
const uint16_t kNECBits = 32;
|
||||
const uint16_t kNeoclimaStateLength = 12;
|
||||
|
||||
@@ -607,6 +607,7 @@ uint16_t IRsend::minRepeats(const decode_type_t protocol) {
|
||||
case MITSUBISHI:
|
||||
case MITSUBISHI2:
|
||||
case MITSUBISHI_AC:
|
||||
case MULTIBRACKETS:
|
||||
case SHERWOOD:
|
||||
case SYMPHONY:
|
||||
case TOSHIBA_AC:
|
||||
@@ -634,6 +635,8 @@ uint16_t IRsend::minRepeats(const decode_type_t protocol) {
|
||||
// int16_t: The number of bits.
|
||||
uint16_t IRsend::defaultBits(const decode_type_t protocol) {
|
||||
switch (protocol) {
|
||||
case MULTIBRACKETS:
|
||||
return 8;
|
||||
case SYMPHONY:
|
||||
return 11;
|
||||
case RC5:
|
||||
@@ -896,6 +899,11 @@ bool IRsend::send(const decode_type_t type, const uint64_t data,
|
||||
sendMitsubishi2(data, nbits, min_repeat);
|
||||
break;
|
||||
#endif
|
||||
#if SEND_MULTIBRACKETS
|
||||
case MULTIBRACKETS:
|
||||
sendMultibrackets(data, nbits, min_repeat);
|
||||
break;
|
||||
#endif
|
||||
#if SEND_NIKAI
|
||||
case NIKAI:
|
||||
sendNikai(data, nbits, min_repeat);
|
||||
|
||||
@@ -582,6 +582,11 @@ class IRsend {
|
||||
const uint16_t repeat = kNoRepeat);
|
||||
uint64_t encodeDoshisha(const uint8_t command, const uint8_t channel = 0);
|
||||
#endif // SEND_DOSHISHA
|
||||
#if SEND_MULTIBRACKETS
|
||||
void sendMultibrackets(const uint64_t data,
|
||||
const uint16_t nbits = kMultibracketsBits,
|
||||
const uint16_t repeat = kMultibracketsDefaultRepeat);
|
||||
#endif
|
||||
|
||||
protected:
|
||||
#ifdef UNIT_TEST
|
||||
|
||||
@@ -249,5 +249,6 @@ const PROGMEM char *kAllProtocolNamesStr =
|
||||
D_STR_AIRWELL "\x0"
|
||||
D_STR_DELONGHI_AC "\x0"
|
||||
D_STR_DOSHISHA "\x0"
|
||||
D_STR_MULTIBRACKETS "\x0"
|
||||
// New protocol strings should be added just above this line.
|
||||
"\x0"; // This string requires double null termination.
|
||||
|
||||
128
src/ir_Multibrackets.cpp
Normal file
128
src/ir_Multibrackets.cpp
Normal file
@@ -0,0 +1,128 @@
|
||||
// Copyright 2020 David Conran
|
||||
|
||||
#include "IRrecv.h"
|
||||
#include "IRsend.h"
|
||||
|
||||
// Multibrackets protocol.
|
||||
//
|
||||
// Supports:
|
||||
// Brand: Multibrackets, Model: Motorized Swing mount large - 4500
|
||||
|
||||
const uint16_t kMultibracketsTick = 5000; // uSeconds
|
||||
const uint16_t kMultibracketsHdrMark = 3 * kMultibracketsTick; // uSeconds
|
||||
const uint16_t kMultibracketsFooterSpace = 6 * kMultibracketsTick; // uSeconds
|
||||
const uint8_t kMultibracketsTolerance = 5; // Percent
|
||||
const uint16_t kMultibracketsFreq = 38000; // Hertz
|
||||
|
||||
#if SEND_MULTIBRACKETS
|
||||
// Send a Miltibrackets formatted message.
|
||||
//
|
||||
// Args:
|
||||
// data: The message to be sent.
|
||||
// nbits: The number of bits of the message to be sent.
|
||||
// Typically kMultibracketsBits.
|
||||
// repeat: The number of times the command is to be repeated.
|
||||
//
|
||||
// Status: BETA / Appears to be working.
|
||||
//
|
||||
// Ref:
|
||||
// https://github.com/crankyoldgit/IRremoteESP8266/issues/1103
|
||||
// http://info.multibrackets.com/data/common/manuals/4500_code.pdf
|
||||
void IRsend::sendMultibrackets(uint64_t data, uint16_t nbits, uint16_t repeat) {
|
||||
enableIROut(kMultibracketsFreq);
|
||||
for (uint16_t r = 0; r <= repeat; r++) {
|
||||
uint16_t bits = nbits;
|
||||
// Header
|
||||
mark(kMultibracketsHdrMark);
|
||||
// Data
|
||||
// Send 0's until we get down to a bit size we can actually manage.
|
||||
while (bits > sizeof(data) * 8) {
|
||||
space(kMultibracketsTick);
|
||||
bits--;
|
||||
}
|
||||
// Send the supplied data.
|
||||
for (uint64_t mask = 1ULL << (bits - 1); mask; mask >>= 1)
|
||||
if (data & mask) // Send a 1
|
||||
mark(kMultibracketsTick);
|
||||
else // Send a 0
|
||||
space(kMultibracketsTick);
|
||||
// Footer
|
||||
space(kMultibracketsFooterSpace);
|
||||
}
|
||||
}
|
||||
#endif // SEND_MULTIBRACKETS
|
||||
|
||||
#if DECODE_MULTIBRACKETS
|
||||
// Decode the Multibrackets message.
|
||||
//
|
||||
// Args:
|
||||
// results: Ptr to the data to decode and where to store the decode result.
|
||||
// offset: The starting index to use when attempting to decode the raw data.
|
||||
// Typically/Defaults to kStartOffset.
|
||||
// nbits: The number of data bits to expect. Typically kMultibracketsBits.
|
||||
// strict: Flag indicating if we should perform strict matching.
|
||||
// Returns:
|
||||
// boolean: True if it can decode it, false if it can't.
|
||||
//
|
||||
// Status: BETA / Appears to be working.
|
||||
//
|
||||
// Ref:
|
||||
// https://github.com/crankyoldgit/IRremoteESP8266/issues/1103
|
||||
// http://info.multibrackets.com/data/common/manuals/4500_code.pdf
|
||||
bool IRrecv::decodeMultibrackets(decode_results *results, uint16_t offset,
|
||||
const uint16_t nbits, const bool strict) {
|
||||
// Compliance
|
||||
if (strict && nbits != kMultibracketsBits)
|
||||
return false; // Doesn't match our protocol defn.
|
||||
|
||||
// Check there is enough unprocessed buffer left.
|
||||
if (results->rawlen < offset) return false;
|
||||
|
||||
// Header
|
||||
int32_t remaining = *(results->rawbuf + offset);
|
||||
if (!matchAtLeast(remaining, kMultibracketsHdrMark, kMultibracketsTolerance))
|
||||
return false;
|
||||
remaining -= (kMultibracketsHdrMark / kRawTick); // Remove the header.
|
||||
|
||||
// We are done with the header. Onto the data.
|
||||
bool bit = true;
|
||||
uint16_t bitsSoFar = 0;
|
||||
uint64_t data = 0;
|
||||
// Keep going till we run out of message or expected bits.
|
||||
while (offset <= results->rawlen && bitsSoFar < nbits) {
|
||||
// Have we finished processing this rawbuf value yet?
|
||||
if (remaining <= 0) { // No more possible "bits" left in this value.
|
||||
// Invert the bit for next time, and move along the rawbuf.
|
||||
bit = !bit;
|
||||
offset++;
|
||||
// Load the next data point if there is one.
|
||||
if (offset <= results->rawlen) remaining = *(results->rawbuf + offset);
|
||||
} else { // Look for more bits in this entry.
|
||||
if (matchAtLeast(remaining, kMultibracketsTick,
|
||||
kMultibracketsTolerance)) { // There is!
|
||||
data <<= 1;
|
||||
data += bit;
|
||||
bitsSoFar++;
|
||||
}
|
||||
remaining -= (kMultibracketsTick / kRawTick); // Remove the "bit".
|
||||
}
|
||||
}
|
||||
|
||||
// Compliance
|
||||
if (bitsSoFar != nbits) return false;
|
||||
|
||||
// Footer
|
||||
if (results->rawlen <= offset && !matchAtLeast(*(results->rawbuf + offset),
|
||||
kMultibracketsFooterSpace,
|
||||
kMultibracketsTolerance))
|
||||
return false;
|
||||
|
||||
// Success
|
||||
results->decode_type = decode_type_t::MULTIBRACKETS;
|
||||
results->value = data;
|
||||
results->bits = nbits;
|
||||
results->address = 0;
|
||||
results->command = 0;
|
||||
return true;
|
||||
}
|
||||
#endif // DECODE_MULTIBRACKETS
|
||||
@@ -598,6 +598,9 @@
|
||||
#ifndef D_STR_MITSUBISHI_HEAVY_88
|
||||
#define D_STR_MITSUBISHI_HEAVY_88 "MITSUBISHI_HEAVY_88"
|
||||
#endif // D_STR_MITSUBISHI_HEAVY_88
|
||||
#ifndef D_STR_MULTIBRACKETS
|
||||
#define D_STR_MULTIBRACKETS "MULTIBRACKETS"
|
||||
#endif // D_STR_MULTIBRACKETS
|
||||
#ifndef D_STR_MWM
|
||||
#define D_STR_MWM "MWM"
|
||||
#endif // D_STR_MWM
|
||||
|
||||
98
test/ir_Multibrackets_test.cpp
Normal file
98
test/ir_Multibrackets_test.cpp
Normal file
@@ -0,0 +1,98 @@
|
||||
// Copyright 2020 David Conran
|
||||
|
||||
#include "IRac.h"
|
||||
#include "IRrecv.h"
|
||||
#include "IRrecv_test.h"
|
||||
#include "IRsend.h"
|
||||
#include "IRsend_test.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
// Tests for decodeMultibrackets().
|
||||
|
||||
// Ref: https://github.com/crankyoldgit/IRremoteESP8266/issues/1103
|
||||
|
||||
TEST(TestDecodeMultibrackets, RealExample) {
|
||||
IRsendTest irsend(kGpioUnused);
|
||||
IRrecv irrecv(kGpioUnused);
|
||||
// The 1 + ok keypress:
|
||||
uint16_t rawData_1[7] = {20100, 20472, 15092, 30704, 20102, 20472, 15086};
|
||||
irsend.begin();
|
||||
irsend.reset();
|
||||
irsend.sendRaw(rawData_1, 7, 38);
|
||||
irsend.makeDecodeResult();
|
||||
|
||||
ASSERT_TRUE(irrecv.decode(&irsend.capture));
|
||||
ASSERT_EQ(decode_type_t::MULTIBRACKETS, irsend.capture.decode_type);
|
||||
ASSERT_EQ(kMultibracketsBits, irsend.capture.bits);
|
||||
EXPECT_EQ(0x87, irsend.capture.value);
|
||||
EXPECT_EQ(0x0, irsend.capture.address);
|
||||
EXPECT_EQ(0x0, irsend.capture.command);
|
||||
|
||||
// ok keypress.
|
||||
const uint16_t rawData_2[11] = {
|
||||
25124, 5108, 5038, 5110, 5034, 40940, 25132, 5108, 5036, 5110, 5036};
|
||||
|
||||
irsend.begin();
|
||||
irsend.reset();
|
||||
irsend.sendRaw(rawData_2, 11, 38);
|
||||
irsend.makeDecodeResult();
|
||||
|
||||
ASSERT_TRUE(irrecv.decode(&irsend.capture));
|
||||
ASSERT_EQ(decode_type_t::MULTIBRACKETS, irsend.capture.decode_type);
|
||||
ASSERT_EQ(kMultibracketsBits, irsend.capture.bits);
|
||||
EXPECT_EQ(0xD4, irsend.capture.value);
|
||||
EXPECT_EQ(0x0, irsend.capture.address);
|
||||
EXPECT_EQ(0x0, irsend.capture.command);
|
||||
}
|
||||
|
||||
TEST(TestDecodeMultibrackets, SyntheticExample) {
|
||||
IRsendTest irsend(kGpioUnused);
|
||||
IRrecv irrecv(kGpioUnused);
|
||||
irsend.begin();
|
||||
irsend.reset();
|
||||
irsend.sendMultibrackets(0x87);
|
||||
irsend.makeDecodeResult();
|
||||
|
||||
ASSERT_TRUE(irrecv.decode(&irsend.capture));
|
||||
EXPECT_EQ(decode_type_t::MULTIBRACKETS, irsend.capture.decode_type);
|
||||
EXPECT_EQ(kMultibracketsBits, irsend.capture.bits);
|
||||
EXPECT_EQ(0x87, irsend.capture.value);
|
||||
EXPECT_EQ(0x0, irsend.capture.address);
|
||||
EXPECT_EQ(0x0, irsend.capture.command);
|
||||
|
||||
// Real data is:
|
||||
// uint16_t rawData[7] = {20100, 20472, 15092, 30704, 20102, 20472, 15086};
|
||||
|
||||
EXPECT_EQ(
|
||||
"f38000d50m20000s20000m15000s30000m20000s20000m15000s30000",
|
||||
irsend.outputStr());
|
||||
}
|
||||
|
||||
TEST(TestUtils, Housekeeping) {
|
||||
ASSERT_EQ("MULTIBRACKETS", typeToString(decode_type_t::MULTIBRACKETS));
|
||||
ASSERT_EQ(decode_type_t::MULTIBRACKETS, strToDecodeType("MULTIBRACKETS"));
|
||||
ASSERT_FALSE(hasACState(decode_type_t::MULTIBRACKETS));
|
||||
ASSERT_FALSE(IRac::isProtocolSupported(decode_type_t::MULTIBRACKETS));
|
||||
ASSERT_EQ(kMultibracketsBits,
|
||||
IRsend::defaultBits(decode_type_t::MULTIBRACKETS));
|
||||
ASSERT_EQ(kMultibracketsDefaultRepeat,
|
||||
IRsend::minRepeats(decode_type_t::MULTIBRACKETS));
|
||||
}
|
||||
|
||||
TEST(TestDecodeMultibrackets, ShortNoRepeatExample) {
|
||||
IRsendTest irsend(kGpioUnused);
|
||||
IRrecv irrecv(kGpioUnused);
|
||||
// The 1 + ok keypress: (edited to be bare minimum)
|
||||
uint16_t rawData[3] = {20100, 20472, 15092};
|
||||
irsend.begin();
|
||||
irsend.reset();
|
||||
irsend.sendRaw(rawData, 3, 38);
|
||||
irsend.makeDecodeResult();
|
||||
|
||||
ASSERT_TRUE(irrecv.decode(&irsend.capture));
|
||||
ASSERT_EQ(decode_type_t::MULTIBRACKETS, irsend.capture.decode_type);
|
||||
ASSERT_EQ(kMultibracketsBits, irsend.capture.bits);
|
||||
EXPECT_EQ(0x87, irsend.capture.value);
|
||||
EXPECT_EQ(0x0, irsend.capture.address);
|
||||
EXPECT_EQ(0x0, irsend.capture.command);
|
||||
}
|
||||
Reference in New Issue
Block a user