Skip to content

Commit

Permalink
Basic support for Voltas A/C protocol (#1243)
Browse files Browse the repository at this point in the history
* Basic send/decode for the Voltas A/C protocol.
* Unit test coverage for above.


These are all the changes I made on my end so far, to make the library capable of sending and recognizing the various states (as bytes) of the Voltas protocol. 
User-friendly functions for sending and decoding are yet to be implemented.


Ref #1238 

Co-authored-by: David <[email protected]>
  • Loading branch information
manj9501 and crankyoldgit authored Aug 16, 2020
1 parent a6cd2ac commit d64f07b
Show file tree
Hide file tree
Showing 10 changed files with 176 additions and 2 deletions.
4 changes: 4 additions & 0 deletions src/IRrecv.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -860,6 +860,10 @@ bool IRrecv::decode(decode_results *results, irparams_t *save,
DPRINTLN("Attempting Sanyo AC decode");
if (decodeSanyoAc(results, offset)) return true;
#endif // DECODE_SANYO_AC
#if DECODE_VOLTAS
DPRINTLN("Attempting Voltas decode");
if (decodeVoltas(results)) return true;
#endif // DECODE_VOLTAS
// 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 @@ -262,6 +262,12 @@ class IRrecv {
const bool GEThomas = true);
void crudeNoiseFilter(decode_results *results, const uint16_t floor = 0);
bool decodeHash(decode_results *results);
#if DECODE_VOLTAS
bool decodeVoltas(decode_results *results,
uint16_t offset = kStartOffset,
const uint16_t nbits = kVoltasBits,
const bool strict = true);
#endif // DECODE_VOLTAS
#if (DECODE_NEC || DECODE_SHERWOOD || DECODE_AIWA_RC_T501 || DECODE_SANYO)
bool decodeNEC(decode_results *results, uint16_t offset = kStartOffset,
const uint16_t nbits = kNECBits, const bool strict = true);
Expand Down
15 changes: 13 additions & 2 deletions src/IRremoteESP8266.h
Original file line number Diff line number Diff line change
Expand Up @@ -670,6 +670,13 @@
#define SEND_ZEPEAL _IR_ENABLE_DEFAULT_
#endif // SEND_ZEPEAL

#ifndef DECODE_VOLTAS
#define DECODE_VOLTAS _IR_ENABLE_DEFAULT_
#endif // DECODE_VOLTAS
#ifndef SEND_VOLTAS
#define SEND_VOLTAS _IR_ENABLE_DEFAULT_
#endif // SEND_VOLTAS

#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 All @@ -681,7 +688,8 @@
DECODE_NEOCLIMA || DECODE_DAIKIN176 || DECODE_DAIKIN128 || \
DECODE_AMCOR || DECODE_DAIKIN152 || DECODE_MITSUBISHI136 || \
DECODE_MITSUBISHI112 || DECODE_HITACHI_AC424 || DECODE_HITACHI_AC3 || \
DECODE_HITACHI_AC344 || DECODE_CORONA_AC || DECODE_SANYO_AC)
DECODE_HITACHI_AC344 || DECODE_CORONA_AC || DECODE_SANYO_AC || \
DECODE_VOLTAS)
// Add any DECODE to the above if it uses result->state (see kStateSizeMax)
// you might also want to add the protocol to hasACState function
#define DECODE_AC true // We need some common infrastructure for decoding A/Cs.
Expand Down Expand Up @@ -810,8 +818,9 @@ enum decode_type_t {
MIDEA24,
ZEPEAL,
SANYO_AC,
VOLTAS, // 90
// Add new entries before this one, and update it to point to the last entry.
kLastDecodeType = SANYO_AC,
kLastDecodeType = VOLTAS,
};

// Message lengths & required repeat values
Expand Down Expand Up @@ -1023,6 +1032,8 @@ const uint16_t kWhynterBits = 32;
const uint8_t kVestelAcBits = 56;
const uint16_t kZepealBits = 16;
const uint16_t kZepealMinRepeat = 4;
const uint16_t kVoltasBits = 80;
const uint16_t kVoltasStateLength = 10;


// Legacy defines. (Deprecated)
Expand Down
7 changes: 7 additions & 0 deletions src/IRsend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -731,6 +731,8 @@ uint16_t IRsend::defaultBits(const decode_type_t protocol) {
return kToshibaACBits;
case TROTEC:
return kTrotecBits;
case VOLTAS:
return kVoltasBits;
case WHIRLPOOL_AC:
return kWhirlpoolAcBits;
// No default amount of bits.
Expand Down Expand Up @@ -1001,6 +1003,11 @@ bool IRsend::send(const decode_type_t type, const uint64_t data,
bool IRsend::send(const decode_type_t type, const uint8_t *state,
const uint16_t nbytes) {
switch (type) {
#if SEND_VOLTAS
case VOLTAS:
sendVoltas(state, nbytes);
break;
#endif // SEND_VOLTAS
#if SEND_AMCOR
case AMCOR:
sendAmcor(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 @@ -635,6 +635,11 @@ class IRsend {
const uint16_t nbits = kZepealBits,
const uint16_t repeat = kZepealMinRepeat);
#endif
#if SEND_VOLTAS
void sendVoltas(const unsigned char data[],
const uint16_t nbytes = kVoltasStateLength,
const uint16_t repeat = kNoRepeat);
#endif // SEND_VOLTAS

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 @@ -266,5 +266,6 @@ const PROGMEM char *kAllProtocolNamesStr =
D_STR_MIDEA24 "\x0"
D_STR_ZEPEAL "\x0"
D_STR_SANYO_AC "\x0"
D_STR_VOLTAS "\x0"
///< New protocol strings should be added just above this line.
"\x0"; ///< This string requires double null termination.
1 change: 1 addition & 0 deletions src/IRutils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ bool hasACState(const decode_type_t protocol) {
case TCL112AC:
case TOSHIBA_AC:
case TROTEC:
case VOLTAS:
case WHIRLPOOL_AC:
return true;
default:
Expand Down
69 changes: 69 additions & 0 deletions src/ir_Voltas.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// Copyright 2020 David Conran (crankyoldgit)
// Copyright 2020 manj9501
/// @file
/// @brief Support for Voltas A/C protocol
/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1238

// Supports:
// Brand: Voltas, Model: 122LZF 4011252 Window A/C

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

// Constants
const uint16_t kVoltasBitMark = 1026; ///< uSeconds.
const uint16_t kVoltasOneSpace = 2553; ///< uSeconds.
const uint16_t kVoltasZeroSpace = 554; ///< uSeconds.
const uint16_t kVoltasFreq = 38000; ///< Hz.

#if SEND_VOLTAS
/// Send a Voltas formatted message.
/// Status: ALPHA / Untested.
/// @param[in] data An array of bytes containing the IR command.
/// It is assumed to be in MSB order for this code.
/// e.g.
/// @code
/// uint8_t data[kVoltasStateLength] = {0x33, 0x28, 0x88, 0x1A, 0x3B, 0x3B,
/// 0x3B, 0x11, 0x00, 0x40};
/// @endcode
/// @param[in] nbytes Nr. of bytes of data in the array. (>=kVoltasStateLength)
/// @param[in] repeat Nr. of times the message is to be repeated.
void IRsend::sendVoltas(const uint8_t data[], const uint16_t nbytes,
const uint16_t repeat) {
sendGeneric(0, 0,
kVoltasBitMark, kVoltasOneSpace,
kVoltasBitMark, kVoltasZeroSpace,
kVoltasBitMark, kDefaultMessageGap,
data, nbytes,
kVoltasFreq, true, repeat, kDutyDefault);
}
#endif // SEND_VOLTAS

#if DECODE_VOLTAS
/// Decode the supplied Voltas message.
/// Status: ALPHA / Untested.
/// @param[in,out] results Ptr to the data to decode & where to store the decode
/// @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.
bool IRrecv::decodeVoltas(decode_results *results, uint16_t offset,
const uint16_t nbits, const bool strict) {
if (strict && nbits != kVoltasBits) return false;

// Data + Footer
if (!matchGeneric(results->rawbuf + offset, results->state,
results->rawlen - offset, nbits,
0, 0, // No header
kVoltasBitMark, kVoltasOneSpace,
kVoltasBitMark, kVoltasZeroSpace,
kVoltasBitMark, kDefaultMessageGap, true)) return false;

// Success
results->decode_type = decode_type_t::VOLTAS;
results->bits = nbits;
return true;
}
#endif // DECODE_VOLTAS
3 changes: 3 additions & 0 deletions src/locale/defaults.h
Original file line number Diff line number Diff line change
Expand Up @@ -730,6 +730,9 @@
#ifndef D_STR_VESTEL_AC
#define D_STR_VESTEL_AC "VESTEL_AC"
#endif // D_STR_VESTEL_AC
#ifndef D_STR_VOLTAS
#define D_STR_VOLTAS "VOLTAS"
#endif // D_STR_VOLTAS
#ifndef D_STR_WHIRLPOOL_AC
#define D_STR_WHIRLPOOL_AC "WHIRLPOOL_AC"
#endif // D_STR_WHIRLPOOL_AC
Expand Down
67 changes: 67 additions & 0 deletions test/ir_Voltas_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// Copyright 2020 crankyoldgit

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

// Tests for decodeVoltas().

TEST(TestDecodeVoltas, RealExample) {
IRsendTest irsend(kGpioUnused);
IRrecv irrecv(kGpioUnused);
const uint16_t rawData[161] = {
1002, 584, 1000, 586, 1000, 2568, 1002, 2570, 1002, 586, 998, 588, 1000,
2568, 1002, 2570, 1002, 2572, 1002, 584, 1002, 586, 1000, 584, 1000, 586,
1002, 2568, 1004, 584, 1000, 586, 1002, 2568, 1002, 584, 1002, 584, 1004,
584, 1000, 2568, 1002, 586, 1000, 586, 998, 590, 998, 584, 1002, 584,
1000, 586, 1000, 2570, 1002, 2568, 1004, 584, 1000, 584, 1002, 584, 1002,
582, 1004, 584, 1002, 2568, 1002, 2570, 1004, 2570, 1000, 586, 1002, 2568,
1004, 2568, 1006, 584, 1000, 584, 1002, 2568, 1002, 2570, 1002, 2568,
1002, 586, 1002, 2570, 1000, 2570, 1002, 588, 998, 586, 1000, 2568, 1004,
2568, 1004, 2568, 1002, 588, 998, 2570, 1002, 2568, 1004, 586, 1002, 584,
1000, 586, 1000, 2570, 1000, 586, 1000, 584, 1002, 586, 1000, 2568, 1004,
584, 1000, 586, 1000, 586, 1002, 584, 1002, 586, 1000, 586, 1000, 586,
1000, 586, 1000, 2568, 1002, 2568, 1002, 2568, 1004, 586, 1000, 584,
1000, 2570, 1004, 2568, 1004, 584, 1002};
const uint8_t expected[kVoltasStateLength] = {
0x33, 0x84, 0x88, 0x18, 0x3B, 0x3B, 0x3B, 0x11, 0x00, 0xE6};

irsend.begin();
irsend.reset();
irsend.sendRaw(rawData, 161, 38);
irsend.makeDecodeResult();

ASSERT_TRUE(irrecv.decode(&irsend.capture));
ASSERT_EQ(decode_type_t::VOLTAS, irsend.capture.decode_type);
ASSERT_EQ(kVoltasBits, irsend.capture.bits);
EXPECT_STATE_EQ(expected, irsend.capture.state, irsend.capture.bits);
}

TEST(TestDecodeVoltas, SyntheticExample) {
IRsendTest irsend(kGpioUnused);
IRrecv irrecv(kGpioUnused);
irsend.begin();
irsend.reset();
const uint8_t expected[kVoltasStateLength] = {
0x33, 0x84, 0x88, 0x18, 0x3B, 0x3B, 0x3B, 0x11, 0x00, 0xE6};
// power
irsend.sendVoltas(expected);
irsend.makeDecodeResult();

ASSERT_TRUE(irrecv.decode(&irsend.capture));
EXPECT_EQ(decode_type_t::VOLTAS, irsend.capture.decode_type);
EXPECT_EQ(kVoltasBits, irsend.capture.bits);
EXPECT_STATE_EQ(expected, irsend.capture.state, irsend.capture.bits);
}

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

0 comments on commit d64f07b

Please sign in to comment.