diff --git a/ZgatewayIR.ino b/ZgatewayIR.ino index ca1492f..48c34cf 100644 --- a/ZgatewayIR.ino +++ b/ZgatewayIR.ino @@ -248,229 +248,18 @@ void IRtoMQTT(){ trc(valueRPT); } - #ifdef ESP8266 // send coolix not available for arduino IRRemote library - #ifdef IR_COOLIX - if (strstr(topicOri, "IR_COOLIX") != NULL){ - if (valueBITS == 0) valueBITS = COOLIX_BITS; - irsend.sendCOOLIX(data, valueBITS, valueRPT); + if(topicOri && (strstr(topicOri, "IR_NEC") == NULL)){ + signalSent = sendIdentifiedProtocol(topicOri, data, (unsigned char *)datacallback, valueBITS, valueRPT); + }else{ + trc(F("Using NEC protocol")); + if (valueBITS == 0) valueBITS = NEC_BITS; + #ifdef ESP8266 + irsend.sendNEC(data, valueBITS, valueRPT); + #else + for (int i=0; i <= valueRPT; i++) irsend.sendNEC(data, valueBITS); + #endif signalSent = true; - } - #endif - #endif - if (strstr(topicOri, "IR_NEC") != NULL || strstr(topicOri, subjectMQTTtoIR) != NULL ){ - if (valueBITS == 0) valueBITS = NEC_BITS; - #ifdef ESP8266 - irsend.sendNEC(data, valueBITS, valueRPT); - #else - for (int i=0; i <= valueRPT; i++) irsend.sendNEC(data, valueBITS); - #endif - signalSent = true; - } - #ifdef IR_Whynter - if (strstr(topicOri, "IR_Whynter") != NULL){ - if (valueBITS == 0) valueBITS = WHYNTER_BITS; - #ifdef ESP8266 - irsend.sendWhynter(data, valueBITS, valueRPT); - #else - for (int i=0; i <= valueRPT; i++) irsend.sendWhynter(data, valueBITS); - #endif - signalSent = true; - } - #endif - #ifdef IR_LG - if (strstr(topicOri, "IR_LG") != NULL){ - if (valueBITS == 0) valueBITS = LG_BITS; - #ifdef ESP8266 - irsend.sendLG(data, valueBITS, valueRPT); - #else - for (int i=0; i <= valueRPT; i++) irsend.sendLG(data, valueBITS); - #endif - signalSent = true; - } - #endif - #ifdef IR_Sony - if (strstr(topicOri, "IR_Sony") != NULL){ - if (valueBITS == 0) valueBITS = SONY_12_BITS; - if (valueRPT == 0) valueRPT = repeatIRwNumber; - #ifdef ESP8266 - irsend.sendSony(data, valueBITS, valueRPT); - #else - for (int i=0; i <= valueRPT; i++) irsend.sendSony(data, valueBITS); - #endif - signalSent = true; - } - #endif - #ifdef IR_DISH - if (strstr(topicOri, "IR_DISH") != NULL){ - if (valueBITS == 0) valueBITS = DISH_BITS; - #ifdef ESP8266 - irsend.sendDISH(data, valueBITS, valueRPT); - #else - for (int i=0; i <= valueRPT; i++) irsend.sendDISH(data, valueBITS); - #endif - signalSent = true; - } - #endif - #ifdef IR_RC5 - if (strstr(topicOri, "IR_RC5") != NULL){ - if (valueBITS == 0) valueBITS = RC5_BITS; - #ifdef ESP8266 - irsend.sendRC5(data, valueBITS, valueRPT); - #else - for (int i=0; i <= valueRPT; i++) irsend.sendRC5(data, valueBITS); - #endif - signalSent = true; - } - #endif - #ifdef IR_RC6 - if (strstr(topicOri, "IR_RC6") != NULL){ - if (valueBITS == 0) valueBITS = RC6_MODE0_BITS; - #ifdef ESP8266 - irsend.sendRC6(data, valueBITS, valueRPT); - #else - for (int i=0; i <= valueRPT; i++) irsend.sendRC6(data, valueBITS); - #endif - signalSent = true; - } - #endif - #ifdef IR_Sharp - if (strstr(topicOri, "IR_Sharp") != NULL){ - if (valueBITS == 0) valueBITS = SHARP_BITS; - #ifdef ESP8266 - irsend.sendSharpRaw(data, valueBITS, valueRPT); - #else - for (int i=0; i <= valueRPT; i++) irsend.sendSharpRaw(data, valueBITS); - #endif - signalSent = true; - } - #endif - #ifdef IR_SAMSUNG - if (strstr(topicOri, "IR_SAMSUNG") != NULL){ - if (valueBITS == 0) valueBITS = SAMSUNG_BITS; - #ifdef ESP8266 - irsend.sendSAMSUNG(data, valueBITS, valueRPT); - #else - for (int i=0; i <= valueRPT; i++) irsend.sendSAMSUNG(data, valueBITS); - #endif - signalSent = true; - } - #endif - #ifdef IR_JVC - if (strstr(topicOri, "IR_JVC") != NULL){ - if (valueBITS == 0) valueBITS = JVC_BITS; - if (valueRPT == 0) valueRPT = repeatIRwNumber; - #ifdef ESP8266 - irsend.sendJVC(data, valueBITS, valueRPT); - #else - for (int i=0; i <= valueRPT; i++) irsend.sendJVC(data, valueBITS); - #endif - signalSent = true; - } - #endif - #ifdef IR_PANASONIC - if (strstr(topicOri, "IR_PANASONIC") != NULL){ - if (valueRPT == 0) valueRPT = repeatIRwNumber; - #ifdef ESP8266 - if (valueBITS == 0) valueBITS = PANASONIC_BITS; - irsend.sendPanasonic(PanasonicAddress, data, valueBITS, valueRPT); - #else - for (int i=0; i <= valueRPT; i++) irsend.sendPanasonic(PanasonicAddress, data); - #endif - signalSent = true; - } - #endif - - #ifdef ESP8266 // sendings not available on arduino - #ifdef IR_RCMM - if (strstr(topicOri, "IR_RCMM") != NULL){ - if (valueBITS == 0) valueBITS = RCMM_BITS; - irsend.sendRCMM(data, valueBITS, valueRPT); - signalSent = true; - } - #endif - #ifdef IR_DENON - if (strstr(topicOri, "IR_DENON") != NULL){ - if (valueBITS == 0) valueBITS = DENON_BITS; - irsend.sendDenon(data, valueBITS, valueRPT); - signalSent = true; - } - #endif - #ifdef IR_GICABLE - if (strstr(topicOri, "IR_GICABLE") != NULL){ - if (valueBITS == 0) valueBITS = GICABLE_BITS; - if (valueRPT == 0) valueRPT = std::max(valueRPT, (uint16_t) GICABLE_MIN_REPEAT); - irsend.sendGICable(data, valueBITS, valueRPT); - signalSent = true; - } - #endif - #ifdef IR_SHERWOOD - if (strstr(topicOri, "IR_SHERWOOD") != NULL){ - if (valueBITS == 0) valueBITS = SHERWOOD_BITS; - if (valueRPT == 0) valueRPT = std::max(valueRPT, (uint16_t) SHERWOOD_MIN_REPEAT); - irsend.sendSherwood(data, valueBITS, valueRPT); - signalSent = true; - } - #endif - #ifdef IR_MITSUBISHI - if (strstr(topicOri, "IR_MITSUBISHI") != NULL){ - if (valueBITS == 0) valueBITS = MITSUBISHI_BITS; - if (valueRPT == 0) valueRPT = std::max(valueRPT, (uint16_t) MITSUBISHI_MIN_REPEAT); - irsend.sendMitsubishi(data, valueBITS, valueRPT); - signalSent = true; - } - #endif - #ifdef IR_NIKAI - if (strstr(topicOri, "IR_NIKAI") != NULL){ - if (valueBITS == 0) valueBITS = NIKAI_BITS; - irsend.sendNikai(data, valueBITS, valueRPT); - signalSent = true; - } - #endif - #ifdef IR_MIDEA - if (strstr(topicOri, "IR_MIDEA") != NULL){ - if (valueBITS == 0) valueBITS = MIDEA_BITS; - irsend.sendMidea(data, valueBITS, valueRPT); - signalSent = true; - } - #endif - #ifdef IR_MAGIQUEST - if (strstr(topicOri, "IR_MAGIQUEST") != NULL){ - if (valueBITS == 0) valueBITS = MAGIQUEST_BITS; - irsend.sendMagiQuest(data, valueBITS, valueRPT); - signalSent = true; - } - #endif - #ifdef IR_LASERTAG - if (strstr(topicOri, "IR_LASERTAG") != NULL){ - if (valueBITS == 0) valueBITS = LASERTAG_BITS; - irsend.sendLasertag(data, valueBITS, valueRPT); - signalSent = true; - } - #endif - #ifdef IR_CARRIER_AC - if (strstr(topicOri, "IR_CARRIER_AC") != NULL){ - if (valueBITS == 0) valueBITS = CARRIER_AC_BITS; - irsend.sendCarrierAC(data, valueBITS, valueRPT); - signalSent = true; - } - #endif - #ifdef IR_MITSUBISHI2 - if (strstr(topicOri, "IR_MITSUBISHI2") != NULL){ - if (valueBITS == 0) valueBITS = MITSUBISHI_BITS; - if (valueRPT == 0) valueRPT = std::max(valueRPT, (uint16_t) MITSUBISHI_MIN_REPEAT); - irsend.sendMitsubishi2(data, valueBITS, valueRPT); - signalSent = true; - } - #endif - #ifdef IR_AIWA_RC_T501 - if (strstr(topicOri, "IR_MITSUBISHI") != NULL){ - if (valueBITS == 0) valueBITS = AIWA_RC_T501_BITS; - if (valueRPT == 0) valueRPT = std::max(valueRPT, (uint16_t) AIWA_RC_T501_MIN_REPEAT); - irsend.sendAiwaRCT501(data, valueBITS, valueRPT); - signalSent = true; - } - #endif - #endif + } if (signalSent){ // we acknowledge the sending by publishing the value to an acknowledgement topic, for the moment even if it is a signal repetition we acknowledge also pub(subjectGTWIRtoMQTT, datacallback); @@ -486,7 +275,8 @@ void IRtoMQTT(){ trc(F("MQTTtoIR json")); unsigned long data = IRdata["value"]; const char * raw = IRdata["raw"]; - if (data != 0||raw) { + const char * datastring = IRdata["datastring"]; + if (data != 0||raw) { trc(F("MQTTtoIR data || raw ok")); boolean signalSent = false; trc("value"); @@ -557,220 +347,9 @@ void IRtoMQTT(){ signalSent = true; } #endif - }else if(protocol_name && (strstr(protocol_name, "IR_NEC") == NULL)){ - #ifdef ESP8266 // send coolix not available for arduino IRRemote library - #ifdef IR_COOLIX - if (strstr(protocol_name, "IR_COOLIX") != NULL){ - if (valueBITS == 0) valueBITS = COOLIX_BITS; - irsend.sendCOOLIX(data, valueBITS, valueRPT); - signalSent = true; - } - #endif - #endif - #ifdef IR_Whynter - if (strstr(protocol_name, "IR_Whynter") != NULL){ - if (valueBITS == 0) valueBITS = WHYNTER_BITS; - #ifdef ESP8266 - irsend.sendWhynter(data, valueBITS, valueRPT); - #else - for (int i=0; i <= valueRPT; i++) irsend.sendWhynter(data, valueBITS); - #endif - signalSent = true; - } - #endif - #ifdef IR_LG - if (strstr(protocol_name, "IR_LG") != NULL){ - if (valueBITS == 0) valueBITS = LG_BITS; - #ifdef ESP8266 - irsend.sendLG(data, valueBITS, valueRPT); - #else - for (int i=0; i <= valueRPT; i++) irsend.sendLG(data, valueBITS); - #endif - signalSent = true; - } - #endif - #ifdef IR_Sony - if (strstr(protocol_name, "IR_Sony") != NULL){ - if (valueBITS == 0) valueBITS = SONY_12_BITS; - #ifdef ESP8266 - irsend.sendSony(data, valueBITS, valueRPT); - #else - for (int i=0; i <= valueRPT; i++) irsend.sendSony(data, valueBITS); - #endif - signalSent = true; - } - #endif - #ifdef IR_DISH - if (strstr(protocol_name, "IR_DISH") != NULL){ - if (valueBITS == 0) valueBITS = DISH_BITS; - #ifdef ESP8266 - irsend.sendDISH(data, valueBITS, valueRPT); - #else - for (int i=0; i <= valueRPT; i++) irsend.sendDISH(data, valueBITS); - #endif - signalSent = true; - } - #endif - #ifdef IR_RC5 - if (strstr(protocol_name, "IR_RC5") != NULL){ - if (valueBITS == 0) valueBITS = RC5_BITS; - #ifdef ESP8266 - irsend.sendRC5(data, valueBITS, valueRPT); - #else - for (int i=0; i <= valueRPT; i++) irsend.sendRC5(data, valueBITS); - #endif - signalSent = true; - } - #endif - #ifdef IR_RC6 - if (strstr(protocol_name, "IR_RC6") != NULL){ - if (valueBITS == 0) valueBITS = RC6_MODE0_BITS; - #ifdef ESP8266 - irsend.sendRC6(data, valueBITS, valueRPT); - #else - for (int i=0; i <= valueRPT; i++) irsend.sendRC6(data, valueBITS); - #endif - signalSent = true; - } - #endif - #ifdef IR_Sharp - if (strstr(protocol_name, "IR_Sharp") != NULL){ - if (valueBITS == 0) valueBITS = SHARP_BITS; - #ifdef ESP8266 - irsend.sendSharpRaw(data, valueBITS, valueRPT); - #else - for (int i=0; i <= valueRPT; i++) irsend.sendSharpRaw(data, valueBITS); - #endif - signalSent = true; - } - #endif - #ifdef IR_SAMSUNG - if (strstr(protocol_name, "IR_SAMSUNG") != NULL){ - if (valueBITS == 0) valueBITS = SAMSUNG_BITS; - #ifdef ESP8266 - irsend.sendSAMSUNG(data, valueBITS, valueRPT); - #else - for (int i=0; i <= valueRPT; i++) irsend.sendSAMSUNG(data, valueBITS); - #endif - signalSent = true; - } - #endif - #ifdef IR_JVC - if (strstr(protocol_name, "IR_JVC") != NULL){ - if (valueBITS == 0) valueBITS = JVC_BITS; - #ifdef ESP8266 - irsend.sendJVC(data, valueBITS, valueRPT); - #else - for (int i=0; i <= valueRPT; i++) irsend.sendJVC(data, valueBITS); - #endif - signalSent = true; - } - #endif - #ifdef IR_PANASONIC - if (strstr(protocol_name, "IR_PANASONIC") != NULL){ - #ifdef ESP8266 - if (valueBITS == 0) valueBITS = PANASONIC_BITS; - irsend.sendPanasonic(PanasonicAddress, data, valueBITS, valueRPT); - #else - for (int i=0; i <= valueRPT; i++) irsend.sendPanasonic(PanasonicAddress, data); - #endif - signalSent = true; - } - #endif - - #ifdef ESP8266 // sendings not available on arduino - #ifdef IR_RCMM - if (strstr(protocol_name, "IR_RCMM") != NULL){ - if (valueBITS == 0) valueBITS = RCMM_BITS; - irsend.sendRCMM(data, valueBITS, valueRPT); - signalSent = true; - } - #endif - #ifdef IR_DENON - if (strstr(protocol_name, "IR_DENON") != NULL){ - if (valueBITS == 0) valueBITS = DENON_BITS; - irsend.sendDenon(data, valueBITS, valueRPT); - signalSent = true; - } - #endif - #ifdef IR_GICABLE - if (strstr(protocol_name, "IR_GICABLE") != NULL){ - if (valueBITS == 0) valueBITS = GICABLE_BITS; - if (valueRPT == repeatIRwNumber) valueRPT = std::max(valueRPT, (uint16_t) GICABLE_MIN_REPEAT); - irsend.sendGICable(data, valueBITS, valueRPT); - signalSent = true; - } - #endif - #ifdef IR_SHERWOOD - if (strstr(protocol_name, "IR_SHERWOOD") != NULL){ - if (valueBITS == 0) valueBITS = SHERWOOD_BITS; - if (valueRPT == repeatIRwNumber) valueRPT = std::max(valueRPT, (uint16_t) SHERWOOD_MIN_REPEAT); - irsend.sendSherwood(data, valueBITS, valueRPT); - signalSent = true; - } - #endif - #ifdef IR_MITSUBISHI - if (strstr(protocol_name, "IR_MITSUBISHI") != NULL){ - if (valueBITS == 0) valueBITS = MITSUBISHI_BITS; - if (valueRPT == repeatIRwNumber) valueRPT = std::max(valueRPT, (uint16_t) MITSUBISHI_MIN_REPEAT); - irsend.sendMitsubishi(data, valueBITS, valueRPT); - signalSent = true; - } - #endif - #ifdef IR_NIKAI - if (strstr(protocol_name, "IR_NIKAI") != NULL){ - if (valueBITS == 0) valueBITS = NIKAI_BITS; - irsend.sendNikai(data, valueBITS, valueRPT); - signalSent = true; - } - #endif - #ifdef IR_MIDEA - if (strstr(protocol_name, "IR_MIDEA") != NULL){ - if (valueBITS == 0) valueBITS = MIDEA_BITS; - irsend.sendMidea(data, valueBITS, valueRPT); - signalSent = true; - } - #endif - #ifdef IR_MAGIQUEST - if (strstr(protocol_name, "IR_MAGIQUEST") != NULL){ - if (valueBITS == 0) valueBITS = MAGIQUEST_BITS; - irsend.sendMagiQuest(data, valueBITS, valueRPT); - signalSent = true; - } - #endif - #ifdef IR_LASERTAG - if (strstr(protocol_name, "IR_LASERTAG") != NULL){ - if (valueBITS == 0) valueBITS = LASERTAG_BITS; - irsend.sendLasertag(data, valueBITS, valueRPT); - signalSent = true; - } - #endif - #ifdef IR_CARRIER_AC - if (strstr(protocol_name, "IR_CARRIER_AC") != NULL){ - if (valueBITS == 0) valueBITS = CARRIER_AC_BITS; - irsend.sendCarrierAC(data, valueBITS, valueRPT); - signalSent = true; - } - #endif - #ifdef IR_MITSUBISHI2 - if (strstr(protocol_name, "IR_MITSUBISHI2") != NULL){ - if (valueBITS == 0) valueBITS = MITSUBISHI_BITS; - if (valueRPT == repeatIRwNumber) valueRPT = std::max(valueRPT, (uint16_t) MITSUBISHI_MIN_REPEAT); - irsend.sendMitsubishi2(data, valueBITS, valueRPT); - signalSent = true; - } - #endif - #ifdef IR_AIWA_RC_T501 - if (strstr(protocol_name, "IR_MITSUBISHI") != NULL){ - if (valueBITS == 0) valueBITS = AIWA_RC_T501_BITS; - if (valueRPT == repeatIRwNumber) valueRPT = std::max(valueRPT, (uint16_t) AIWA_RC_T501_MIN_REPEAT); - irsend.sendAiwaRCT501(data, valueBITS, valueRPT); - signalSent = true; - } - #endif - #endif - - }else{ + }else if(protocol_name && (strstr(protocol_name, "IR_NEC") == NULL)){ + signalSent = sendIdentifiedProtocol(protocol_name, data, (unsigned char*)datastring, valueBITS, valueRPT); + }else{ trc(F("Using NEC protocol")); if (valueBITS == 0) valueBITS = NEC_BITS; #ifdef ESP8266 @@ -791,4 +370,404 @@ void IRtoMQTT(){ } } #endif + +boolean sendIdentifiedProtocol(const char * protocol_name, unsigned long data, unsigned char * datastring, unsigned int valueBITS, uint16_t valueRPT){ + #ifdef IR_Whynter + if (strstr(protocol_name, "IR_Whynter") != NULL){ + if (valueBITS == 0) valueBITS = WHYNTER_BITS; + #ifdef ESP8266 + irsend.sendWhynter(data, valueBITS, valueRPT); + #else + for (int i=0; i <= valueRPT; i++) irsend.sendWhynter(data, valueBITS); + #endif + return true; + } + #endif + #ifdef IR_LG + if (strstr(protocol_name, "IR_LG") != NULL){ + if (valueBITS == 0) valueBITS = LG_BITS; + #ifdef ESP8266 + irsend.sendLG(data, valueBITS, valueRPT); + #else + for (int i=0; i <= valueRPT; i++) irsend.sendLG(data, valueBITS); + #endif + return true; + } + #endif + #ifdef IR_Sony + if (strstr(protocol_name, "IR_Sony") != NULL){ + if (valueBITS == 0) valueBITS = SONY_12_BITS; + #ifdef ESP8266 + irsend.sendSony(data, valueBITS, valueRPT); + #else + for (int i=0; i <= valueRPT; i++) irsend.sendSony(data, valueBITS); + #endif + return true; + } + #endif + #ifdef IR_DISH + if (strstr(protocol_name, "IR_DISH") != NULL){ + if (valueBITS == 0) valueBITS = DISH_BITS; + #ifdef ESP8266 + irsend.sendDISH(data, valueBITS, valueRPT); + #else + for (int i=0; i <= valueRPT; i++) irsend.sendDISH(data, valueBITS); + #endif + return true; + } + #endif + #ifdef IR_RC5 + if (strstr(protocol_name, "IR_RC5") != NULL){ + if (valueBITS == 0) valueBITS = RC5_BITS; + #ifdef ESP8266 + irsend.sendRC5(data, valueBITS, valueRPT); + #else + for (int i=0; i <= valueRPT; i++) irsend.sendRC5(data, valueBITS); + #endif + return true; + } + #endif + #ifdef IR_RC6 + if (strstr(protocol_name, "IR_RC6") != NULL){ + if (valueBITS == 0) valueBITS = RC6_MODE0_BITS; + #ifdef ESP8266 + irsend.sendRC6(data, valueBITS, valueRPT); + #else + for (int i=0; i <= valueRPT; i++) irsend.sendRC6(data, valueBITS); + #endif + return true; + } + #endif + #ifdef IR_Sharp + if (strstr(protocol_name, "IR_Sharp") != NULL){ + if (valueBITS == 0) valueBITS = SHARP_BITS; + #ifdef ESP8266 + irsend.sendSharpRaw(data, valueBITS, valueRPT); + #else + for (int i=0; i <= valueRPT; i++) irsend.sendSharpRaw(data, valueBITS); + #endif + return true; + } + #endif + #ifdef IR_SAMSUNG + if (strstr(protocol_name, "IR_SAMSUNG") != NULL){ + if (valueBITS == 0) valueBITS = SAMSUNG_BITS; + #ifdef ESP8266 + irsend.sendSAMSUNG(data, valueBITS, valueRPT); + #else + for (int i=0; i <= valueRPT; i++) irsend.sendSAMSUNG(data, valueBITS); + #endif + return true; + } + #endif + #ifdef IR_JVC + if (strstr(protocol_name, "IR_JVC") != NULL){ + if (valueBITS == 0) valueBITS = JVC_BITS; + #ifdef ESP8266 + irsend.sendJVC(data, valueBITS, valueRPT); + #else + for (int i=0; i <= valueRPT; i++) irsend.sendJVC(data, valueBITS); + #endif + return true; + } + #endif + #ifdef IR_PANASONIC + if (strstr(protocol_name, "IR_PANASONIC") != NULL){ + #ifdef ESP8266 + if (valueBITS == 0) valueBITS = PANASONIC_BITS; + irsend.sendPanasonic(PanasonicAddress, data, valueBITS, valueRPT); + #else + for (int i=0; i <= valueRPT; i++) irsend.sendPanasonic(PanasonicAddress, data); + #endif + return true; + } + #endif + + #ifdef ESP8266 // sendings not available on arduino + #ifdef IR_COOLIX + if (strstr(protocol_name, "IR_COOLIX") != NULL){ + if (valueBITS == 0) valueBITS = kCoolixBits; + irsend.sendCOOLIX(data, valueBITS, valueRPT); + return true; + } + #endif + #ifdef IR_RCMM + if (strstr(protocol_name, "IR_RCMM") != NULL){ + if (valueBITS == 0) valueBITS = kRCMMBits; + irsend.sendRCMM(data, valueBITS, valueRPT); + return true; + } + #endif + #ifdef IR_DENON + if (strstr(protocol_name, "IR_DENON") != NULL){ + if (valueBITS == 0) valueBITS = DENON_BITS; + irsend.sendDenon(data, valueBITS, valueRPT); + return true; + } + #endif + #ifdef IR_GICABLE + if (strstr(protocol_name, "IR_GICABLE") != NULL){ + if (valueBITS == 0) valueBITS = kGicableBits; + if (valueRPT == repeatIRwNumber) valueRPT = std::max(valueRPT, kGicableMinRepeat); + irsend.sendGICable(data, valueBITS, valueRPT); + return true; + } + #endif + #ifdef IR_SHERWOOD + if (strstr(protocol_name, "IR_SHERWOOD") != NULL){ + if (valueBITS == 0) valueBITS = kSherwoodBits; + if (valueRPT == repeatIRwNumber) valueRPT = std::max(valueRPT, kSherwoodMinRepeat); + irsend.sendSherwood(data, valueBITS, valueRPT); + return true; + } + #endif + #ifdef IR_MITSUBISHI + if (strstr(protocol_name, "IR_MITSUBISHI") != NULL){ + if (valueBITS == 0) valueBITS = kMitsubishiBits; + if (valueRPT == repeatIRwNumber) valueRPT = std::max(valueRPT, kMitsubishiMinRepeat); + irsend.sendMitsubishi(data, valueBITS, valueRPT); + return true; + } + #endif + #ifdef IR_NIKAI + if (strstr(protocol_name, "IR_NIKAI") != NULL){ + if (valueBITS == 0) valueBITS = kNikaiBits; + irsend.sendNikai(data, valueBITS, valueRPT); + return true; + } + #endif + #ifdef IR_MIDEA + if (strstr(protocol_name, "IR_MIDEA") != NULL){ + if (valueBITS == 0) valueBITS = kMideaBits; + irsend.sendMidea(data, valueBITS, valueRPT); + return true; + } + #endif + #ifdef IR_MAGIQUEST + if (strstr(protocol_name, "IR_MAGIQUEST") != NULL){ + if (valueBITS == 0) valueBITS = kMagiquestBits; + irsend.sendMagiQuest(data, valueBITS, valueRPT); + return true; + } + #endif + #ifdef IR_LASERTAG + if (strstr(protocol_name, "IR_LASERTAG") != NULL){ + if (valueBITS == 0) valueBITS = kLasertagBits; + irsend.sendLasertag(data, valueBITS, valueRPT); + return true; + } + #endif + #ifdef IR_CARRIER_AC + if (strstr(protocol_name, "IR_CARRIER_AC") != NULL){ + if (valueBITS == 0) valueBITS = kCarrierAcBits; + irsend.sendCarrierAC(data, valueBITS, valueRPT); + return true; + } + #endif + #ifdef IR_MITSUBISHI2 + if (strstr(protocol_name, "IR_MITSUBISHI2") != NULL){ + if (valueBITS == 0) valueBITS = kMitsubishiBits; + if (valueRPT == repeatIRwNumber) valueRPT = std::max(valueRPT, kMitsubishiMinRepeat); + irsend.sendMitsubishi2(data, valueBITS, valueRPT); + return true; + } + #endif + #ifdef IR_AIWA_RC_T501 + if (strstr(protocol_name, "IR_AIWA_RC_T501") != NULL){ + if (valueBITS == 0) valueBITS = kAiwaRcT501Bits; + if (valueRPT == repeatIRwNumber) valueRPT = std::max(valueRPT, kAiwaRcT501MinRepeats); + irsend.sendAiwaRCT501(data, valueBITS, valueRPT); + return true; + } + #endif + #ifdef IR_SANYO + if (strstr(protocol_name, "IR_SANYO") != NULL){ + if (valueBITS == 0) valueBITS = kSanyoLC7461Bits; + irsend.sendSanyoLC7461(data, valueBITS, valueRPT); + return true; + } + #endif + #ifdef IR_DAIKIN + if (strstr(protocol_name, "IR_DAIKIN") != NULL){ + if (valueBITS == 0) valueBITS = kDaikinStateLength; + irsend.sendDaikin(datastring, valueBITS, valueRPT); + return true; + } + #endif + #ifdef IR_KELVINATOR + if (strstr(protocol_name, "IR_KELVINATOR") != NULL){ + if (valueBITS == 0) valueBITS = kKelvinatorStateLength; + irsend.sendKelvinator(datastring, valueBITS, valueRPT); + return true; + } + #endif + #ifdef IR_MITSUBISHI_AC + if (strstr(protocol_name, "IR_MITSUBISHI_AC") != NULL){ + if (valueBITS == 0) valueBITS = kMitsubishiACStateLength; + irsend.sendMitsubishiAC(datastring, valueBITS, valueRPT); + return true; + } + #endif + #ifdef IR_SANYO + if (strstr(protocol_name, "IR_SANYO") != NULL){ + if (valueBITS == 0) valueBITS = kSanyoLC7461Bits; + irsend.sendSanyoLC7461(data, valueBITS, valueRPT); + return true; + } + #endif + #ifdef IR_GREE + if (strstr(protocol_name, "IR_GREE") != NULL){ + if (valueBITS == 0) valueBITS = kGreeStateLength; + irsend.sendGree(data, valueBITS, valueRPT); + return true; + } + #endif + #ifdef IR_ARGO + if (strstr(protocol_name, "IR_ARGO") != NULL){ + if (valueBITS == 0) valueBITS = kArgoStateLength; + irsend.sendArgo(datastring, valueBITS, valueRPT); + return true; + } + #endif + #ifdef IR_TROTEC + if (strstr(protocol_name, "IR_TROTEC") != NULL){ + if (valueBITS == 0) valueBITS = kTrotecStateLength; + irsend.sendTrotec(datastring, valueBITS, valueRPT); + return true; + } + #endif + #ifdef IR_TOSHIBA_AC + if (strstr(protocol_name, "IR_TOSHIBA_AC") != NULL){ + if (valueBITS == 0) valueBITS = kToshibaACBits; + irsend.sendToshibaAC(datastring, valueBITS, valueRPT); + return true; + } + #endif + #ifdef IR_FUJITSU_AC + if (strstr(protocol_name, "IR_FUJITSU_AC") != NULL){ + irsend.sendFujitsuAC(datastring, valueBITS, valueRPT); + return true; + } + #endif + #ifdef IR_MAGIQUEST + if (strstr(protocol_name, "IR_MAGIQUEST") != NULL){ + if (valueBITS == 0) valueBITS = kMagiquestBits; + irsend.sendMagiQuest(data, valueBITS, valueRPT); + return true; + } + #endif + #ifdef IR_HAIER_AC + if (strstr(protocol_name, "IR_HAIER_AC") != NULL){ + if (valueBITS == 0) valueBITS = kHaierACStateLength; + irsend.sendHaierAC(datastring, valueBITS, valueRPT); + return true; + } + #endif + #ifdef IR_HITACHI_AC + if (strstr(protocol_name, "IR_HITACHI_AC") != NULL){ + if (valueBITS == 0) valueBITS = kHitachiAc2StateLength; + irsend.sendHitachiAC(datastring, valueBITS, valueRPT); + return true; + } + #endif + #ifdef IR_HITACHI_AC1 + if (strstr(protocol_name, "IR_HITACHI_AC1") != NULL){ + if (valueBITS == 0) valueBITS = kHitachiAc2StateLength; + irsend.sendHitachiAC1(datastring, valueBITS, valueRPT); + return true; + } + #endif + #ifdef IR_HITACHI_AC2 + if (strstr(protocol_name, "IR_HITACHI_AC2") != NULL){ + if (valueBITS == 0) valueBITS = kHitachiAc2StateLength; + irsend.sendHitachiAC2(datastring, valueBITS, valueRPT); + return true; + } + #endif + #ifdef IR_GICABLE + if (strstr(protocol_name, "IR_GICABLE") != NULL){ + if (valueBITS == 0) valueBITS = kGicableBits; + irsend.sendGICable(data, valueBITS, valueRPT); + return true; + } + #endif + #ifdef IR_HAIER_AC_YRW02 + if (strstr(protocol_name, "IR_HAIER_AC_YRW02") != NULL){ + if (valueBITS == 0) valueBITS = kHaierACYRW02StateLength; + irsend.sendHaierACYRW02(datastring, valueBITS, valueRPT); + return true; + } + #endif + #ifdef IR_WHIRLPOOL_AC + if (strstr(protocol_name, "IR_WHIRLPOOL_AC") != NULL){ + if (valueBITS == 0) valueBITS = kWhirlpoolAcStateLength; + irsend.sendWhirlpoolAC(datastring, valueBITS, valueRPT); + return true; + } + #endif + #ifdef IR_SAMSUNG_AC + if (strstr(protocol_name, "IR_SAMSUNG_AC") != NULL){ + if (valueBITS == 0) valueBITS = kSamsungAcStateLength; + irsend.sendSamsungAC(datastring, valueBITS, valueRPT); + return true; + } + #endif + #ifdef IR_LUTRON + if (strstr(protocol_name, "IR_LUTRON") != NULL){ + if (valueBITS == 0) valueBITS = kLutronBits; + irsend.sendLutron(data, valueBITS, valueRPT); + return true; + } + #endif + #ifdef IR_ELECTRA_AC + if (strstr(protocol_name, "IR_ELECTRA_AC") != NULL){ + if (valueBITS == 0) valueBITS = kElectraAcStateLength; + irsend.sendElectraAC(datastring, valueBITS, valueRPT); + return true; + } + #endif + #ifdef IR_PANASONIC_AC + if (strstr(protocol_name, "IR_PANASONIC_AC") != NULL){ + if (valueBITS == 0) valueBITS = kPanasonicAcStateLength; + irsend.sendPanasonicAC(datastring, valueBITS, valueRPT); + return true; + } + #endif + #ifdef IR_PIONEER + if (strstr(protocol_name, "IR_PIONEER") != NULL){ + if (valueBITS == 0) valueBITS = kPioneerBits; + irsend.sendPioneer(data, valueBITS, valueRPT); + return true; + } + #endif + #ifdef IR_LG2 + if (strstr(protocol_name, "IR_LG2") != NULL){ + if (valueBITS == 0) valueBITS = kLgBits; + irsend.sendLG2(data, valueBITS, valueRPT); + return true; + } + #endif + #ifdef IR_MWM + if (strstr(protocol_name, "IR_MWM") != NULL){ + irsend.sendMWM(datastring, valueBITS, valueRPT); + return true; + } + #endif + #ifdef IR_DAIKIN2 + if (strstr(protocol_name, "IR_DAIKIN2") != NULL){ + if (valueBITS == 0) valueBITS = kDaikin2StateLength; + irsend.sendDaikin2(datastring, valueBITS, valueRPT); + return true; + } + #endif + #ifdef IR_VESTEL_AC + if (strstr(protocol_name, "IR_VESTEL_AC") != NULL){ + if (valueBITS == 0) valueBITS = kVestelACBits; + irsend.sendVestelAC(data, valueBITS, valueRPT); + return true; + } + #endif + return false; + #endif +} #endif diff --git a/config_IR.h b/config_IR.h index 99dedac..b4c9a03 100644 --- a/config_IR.h +++ b/config_IR.h @@ -68,6 +68,33 @@ #define IR_DENON #define IR_AIWA_RC_T501 #define IR_JVC + #define IR_SANYO + #define IR_DAIKIN + #define IR_KELVINATOR + #define IR_MITSUBISHI_AC + #define IR_SANYO_LC7461 + #define IR_GREE + #define IR_ARGO + #define IR_TROTEC + #define IR_TOSHIBA_AC + #define IR_FUJITSU_AC + #define IR_MAGIQUEST + #define IR_HAIER_AC + #define IR_HITACHI_AC + #define IR_HITACHI_AC1 + #define IR_HITACHI_AC2 + #define IR_GICABLE + #define IR_HAIER_AC_YRW02 + #define IR_WHIRLPOOL_AC + #define IR_SAMSUNG_AC + #define IR_LUTRON + #define IR_ELECTRA_AC + #define IR_PANASONIC_AC + #define IR_PIONEER + #define IR_LG2 + #define IR_MWM + #define IR_DAIKIN2 + #define IR_VESTEL_AC #elif ESP32 #define IR_Raw #define IR_COOLIX @@ -105,14 +132,14 @@ /*-------------------PIN DEFINITIONS----------------------*/ #ifdef ESP8266 - #define IR_RECEIVER_PIN 2 - #define IR_EMITTER_PIN 16 // replace by 0 (D3) if you use IR LOLIN controller shield + #define IR_RECEIVER_PIN 2 //D4 + #define IR_EMITTER_PIN 16 //D0/ replace by 0 (D3) if you use IR LOLIN controller shield #elif ESP32 #define IR_RECEIVER_PIN 27 #define IR_EMITTER_PIN 14 #elif __AVR_ATmega2560__ #define IR_RECEIVER_PIN 2 // 2 = D2 on mega - #define IR_EMITTER_PIN 7 + #define IR_EMITTER_PIN 9 #else #define IR_RECEIVER_PIN 0 // 0 = D2 on arduino #define IR_EMITTER_PIN 9 diff --git a/lib/IRremoteESP8266/.github/Contributors.md b/lib/IRremoteESP8266/.github/Contributors.md index 151a0c0..5f75ea3 100644 --- a/lib/IRremoteESP8266/.github/Contributors.md +++ b/lib/IRremoteESP8266/.github/Contributors.md @@ -10,6 +10,8 @@ - [Jonny Graham](https://github.com/jonnygraham/) - [Stu Fisher](https://github.com/stufisher/) - [Jorge Cisneros](https://github.com/jorgecis/) +- [Denes Varga](https://github.com/denxhun/) +- [Brett T. Warden](https://github.com/bwarden/) All contributors can be found on the [contributors site](https://github.com/markszabo/IRremoteESP8266/graphs/contributors). diff --git a/lib/IRremoteESP8266/.gitignore b/lib/IRremoteESP8266/.gitignore index c9dfea7..23e21ca 100644 --- a/lib/IRremoteESP8266/.gitignore +++ b/lib/IRremoteESP8266/.gitignore @@ -35,8 +35,12 @@ test/*_test tools/*.o tools/*.a tools/gc_decode +tools/mode2_decode .pioenvs .piolibdeps .clang_complete .gcc-flags.json + +#Cygwin builds +*.exe diff --git a/lib/IRremoteESP8266/.gitmodules b/lib/IRremoteESP8266/.gitmodules index 80925b8..c28fe05 100644 --- a/lib/IRremoteESP8266/.gitmodules +++ b/lib/IRremoteESP8266/.gitmodules @@ -1,3 +1,4 @@ [submodule "lib/googletest"] path = lib/googletest url = https://github.com/google/googletest.git + branch = v1.8.x diff --git a/lib/IRremoteESP8266/.travis.yml b/lib/IRremoteESP8266/.travis.yml index 4331425..39d2d0b 100644 --- a/lib/IRremoteESP8266/.travis.yml +++ b/lib/IRremoteESP8266/.travis.yml @@ -1,14 +1,14 @@ language: c env: - - BD=esp8266:esp8266:nodemcuv2:CpuFrequency=80,FlashSize=4M3M - - BD=esp8266:esp8266:d1_mini:CpuFrequency=80,FlashSize=4M3M + - BD=esp8266:esp8266:nodemcuv2:xtal=80,eesz=4M3M,ip=lm2f,exception=disabled + - BD=esp8266:esp8266:d1_mini:xtal=80,eesz=4M3M,ip=lm2f,exception=disabled before_install: - "/sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_1.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :1 -ac -screen 0 1280x1024x16" - sleep 3 - export DISPLAY=:1.0 - - wget http://downloads.arduino.cc/arduino-1.8.2-linux64.tar.xz - - tar xf arduino-1.8.2-linux64.tar.xz - - sudo mv arduino-1.8.2 /usr/local/share/arduino + - wget http://downloads.arduino.cc/arduino-1.8.8-linux64.tar.xz + - tar xf arduino-1.8.8-linux64.tar.xz + - sudo mv arduino-1.8.8 /usr/local/share/arduino - sudo ln -s /usr/local/share/arduino/arduino /usr/local/bin/arduino - wget https://raw.githubusercontent.com/google/styleguide/gh-pages/cpplint/cpplint.py install: @@ -40,6 +40,7 @@ script: - arduino --verify --board $BD $PWD/examples/TurnOnArgoAC/TurnOnArgoAC.ino - arduino --verify --board $BD $PWD/examples/IRMQTTServer/IRMQTTServer.ino - arduino --verify --board $BD $PWD/examples/TurnOnToshibaAC/TurnOnToshibaAC.ino + - arduino --verify --board $BD $PWD/examples/ControlSamsungAC/ControlSamsungAC.ino # Also check the tools programs compile. - (cd tools; make all) # Check for lint issues. diff --git a/lib/IRremoteESP8266/README.md b/lib/IRremoteESP8266/README.md index ad039a9..a179214 100644 --- a/lib/IRremoteESP8266/README.md +++ b/lib/IRremoteESP8266/README.md @@ -1,17 +1,33 @@ # IRremote ESP8266 Library [![Build Status](https://travis-ci.org/markszabo/IRremoteESP8266.svg?branch=master)](https://travis-ci.org/markszabo/IRremoteESP8266) +[![arduino-library-badge](https://www.ardu-badge.com/badge/IRremoteESP8266.svg?)](https://www.ardu-badge.com/IRremoteESP8266) [![Average time to resolve an issue](http://isitmaintained.com/badge/resolution/markszabo/IRremoteESP8266.svg)](http://isitmaintained.com/project/markszabo/IRremoteESP8266 "Average time to resolve an issue") [![Percentage of issues still open](http://isitmaintained.com/badge/open/markszabo/IRremoteESP8266.svg)](http://isitmaintained.com/project/markszabo/IRremoteESP8266 "Percentage of issues still open") [![GitLicense](https://gitlicense.com/badge/markszabo/IRremoteESP8266)](https://gitlicense.com/license/markszabo/IRremoteESP8266) This library enables you to **send _and_ receive** infra-red signals on an [ESP8266 using the Arduino framework](https://github.com/esp8266/Arduino) using common 940nm IR LEDs and common IR receiver modules. e.g. TSOP{17,22,24,36,38,44,48}* etc. -## v2.4.2 Now Available -Version 2.4.2 of the library is now [available](https://github.com/markszabo/IRremoteESP8266/releases/latest). You can view the [Release Notes](ReleaseNotes.md) for all the significant changes. +## v2.5.5 Now Available +Version 2.5.5 of the library is now [available](https://github.com/markszabo/IRremoteESP8266/releases/latest). You can view the [Release Notes](ReleaseNotes.md) for all the significant changes. #### Upgrading from pre-v2.0 -Usage of the library slight changed at v2.0. You will need to change your usage to work with v2.0 and beyond. You can read more about the changes required on our [Upgrade to v2.0](https://github.com/markszabo/IRremoteESP8266/wiki/Upgrading-to-v2.0) page. +Usage of the library has been slightly changed in v2.0. You will need to change your usage to work with v2.0 and beyond. You can read more about the changes required on our [Upgrade to v2.0](https://github.com/markszabo/IRremoteESP8266/wiki/Upgrading-to-v2.0) page. + +#### Upgrading from pre-v2.5 +The library has changed from using constants declared as `#define` to +[const](https://google.github.io/styleguide/cppguide.html#Constant_Names) with +the appropriate naming per the +[C++ style guide](https://google.github.io/styleguide/cppguide.html). +This may potentially cause old programs to not compile. +The most likely externally used `#define`s have been _aliased_ for limited +backward compatibility for projects using the old style. Going forward, only the +new `kConstantName` style will be supported for new protocol additions. + +In the unlikely case it does break your code, then you may have been referencing +something you likely should not have. You should be able to quickly determine +the new name from the old. e.g. `CONSTANT_NAME` to `kConstantName`. +Use common sense or examining the library's code if this does affect code. ## Troubleshooting Before reporting an issue or asking for help, please try to follow our [Troubleshooting Guide](https://github.com/markszabo/IRremoteESP8266/wiki/Troubleshooting-Guide) first. diff --git a/lib/IRremoteESP8266/ReleaseNotes.md b/lib/IRremoteESP8266/ReleaseNotes.md index 23bb971..533b952 100644 --- a/lib/IRremoteESP8266/ReleaseNotes.md +++ b/lib/IRremoteESP8266/ReleaseNotes.md @@ -1,5 +1,125 @@ # Release Notes +## _v2.5.5 (20190207)_ + +**[Bug Fixes]** +- Fix decoding of Samsung A/C Extended messages. (#610) +- Fix IRMQTTServer example to work with GPIO0 as IR_RX (#608) +- Fix incorrect #define usage. (#597, #596) + +**[Features]** +- Add deep decoding/construction of Daikin2 messages (#600) +- Added Old Vestel A/C support (56 Bits) with full functions. (#607) + +**[Misc]** +- Add ControlSamsungAC example code. (#599) +- Add how to send a state/air-con to IRsendDemo.ino (#594) + + +## _v2.5.4 (20190102)_ + +**[Features]** +- Experimental basic support for 39 Byte Daikin A/C (#583) +- Handle send() repeats in A/C classes. Improve Coolix support. (#580) +- Add optional RX pin pullup and dump raw messages in IRMQTTServer.ino (#589) + +**[Misc]** +- Make auto_analyse_raw_data.py work with Python3 (#581) +- Update CI/travis config due to esp8266 core 2.5.0 changes (#591) + + +## _v2.5.3 (20181123)_ + +**[Features]** +- Add deep support for the Hitachi 28-Byte A/C Protocol (#563) +- Deep decoding for Whirlpool A/C (#572) +- Improve security options for IRMQTTServer example. (#575) +- Require a changed firmware password before upload. (#576) + +**[Misc]** +- Add missing '}' in output of Auto analyse. (#562) +- Make A/C example code a bit more simple. (#571) + + +## _v2.5.2 (20181021)_ + +**[Bug Fixes]** +- Add missing send() method to IRPanasonicAC class. (#545) +- Add missing sendWhirlpoolAC() to IRMQTTServer.ino (#558) + +**[Features]** +- Add IR receiving support to IRMQTTServer. (#543) +- Pioneer support (#547) +- Add support for a second LG protocol variant. (#552) +- Support for short Panasonic A/C messages. (#553) +- Add support for Panasonic CKP series A/Cs. (#554) +- Experimental timer/clock support for Panasonic A/Cs. (#546) +- Add Made With Magic (MWM) support (#557) + +**[Misc]** +- Grammar and typo fixes (#541, #549) +- Increase Panasonic A/C message tolerances. (#542) +- Added command mode2_decode in tools/ (#557) +- General code style cleanup (#560) + + +## _v2.5.1 (20181002)_ + +**[Bug Fixes]** +- Correct the byte used for Samsung AC Swing. (#529) +- Fix not sending Samsung A/C messages in IRMQTTServer. (#529) + +**[Features]** +- Experimental support for Electra A/C messages. (#528) +- Experimental support for Panasonic A/C messages. (#535) +- Samsung A/C fixes & improvements (#529) +- IRMQTTServer v0.6.0 (#530) + +**[Misc]** +- Change required WifiManager lib version to v0.14 +- Add alias for RAWTICK to kRawTick. (#535) +- Update sendLutron() status. (#515) +- Remove leftover debug message in IRrecvDumpV2 (#526) + + +## _v2.5.0 (20180919)_ + +**[Bug Fixes]** +- Fix HTML menu error for GICABLE in IRMQTTServer. (#516) +- Fix Mitsubishi A/C mode setting. (#514) +- Add missing ',' in auto analyse tool generated code. (#513) +- Fix Fujitsu checksum validation. (#501) +- Remove errant Repeat debug statement in IRMQTTServer. (#507) + +**[Features]** +- Mitsubishi A/C decode improvements. (#514) +- Basic support for Whirlpool A/C messages. (#511) +- Basic support for Samsung A/C messages. (#512) +- Experimental support for detailed Samsung A/C messages. (#521) +- Experimental support for detailed Coolix A/C messages. (#518) +- Experimental support for Lutron protocol. (#516) +- Calculate and use average values for timings in analysing tool. (#513) + +**[Misc]** +- Style change from using #define's for constants to `const kConstantName`. +- Improve the JVC example code. + + +## _v2.4.3 (20180727)_ + +**[Bug Fixes]** +- Handle Space Gaps better in auto analyse tool. (#482) +- Correct min repeat for GICABLE in IRMQTTServer. (#494) + +**[Features]** +- Add static IP config option to IRMQTTServer (#480) +- Full decoding/encoding support for the Haier YRW02 A/C. (#485 #486 #487) + +**[Misc]** +- Update LG (28-bit) HDR mark and space timings. (#492) +- Spelling and grammar fixes (#491) + + ## _v2.4.2 (20180601)_ **[Bug Fixes]** diff --git a/lib/IRremoteESP8266/examples/ControlSamsungAC/ControlSamsungAC.ino b/lib/IRremoteESP8266/examples/ControlSamsungAC/ControlSamsungAC.ino new file mode 100644 index 0000000..df910fe --- /dev/null +++ b/lib/IRremoteESP8266/examples/ControlSamsungAC/ControlSamsungAC.ino @@ -0,0 +1,99 @@ +/* Copyright 2019 David Conran +* +* An IR LED circuit *MUST* be connected to the ESP8266 on a pin +* as specified by kIrLed below. +* +* TL;DR: The IR LED needs to be driven by a transistor for a good result. +* +* Suggested circuit: +* https://github.com/markszabo/IRremoteESP8266/wiki#ir-sending +* +* Common mistakes & tips: +* * Don't just connect the IR LED directly to the pin, it won't +* have enough current to drive the IR LED effectively. +* * Make sure you have the IR LED polarity correct. +* See: https://learn.sparkfun.com/tutorials/polarity/diode-and-led-polarity +* * Typical digital camera/phones can be used to see if the IR LED is flashed. +* Replace the IR LED with a normal LED if you don't have a digital camera +* when debugging. +* * Avoid using the following pins unless you really know what you are doing: +* * Pin 0/D3: Can interfere with the boot/program mode & support circuits. +* * Pin 1/TX/TXD0: Any serial transmissions from the ESP8266 will interfere. +* * Pin 3/RX/RXD0: Any serial transmissions to the ESP8266 will interfere. +* * ESP-01 modules are tricky. We suggest you use a module with more GPIOs +* for your first time. e.g. ESP-12 etc. +*/ +#ifndef UNIT_TEST +#include +#endif +#include +#include +#include + +const uint16_t kIrLed = 4; // ESP8266 GPIO pin to use. Recommended: 4 (D2). +IRSamsungAc ac(kIrLed); // Set the GPIO used for sending messages. + +void printState() { + // Display the settings. + Serial.println("Samsung A/C remote is in the following state:"); + Serial.printf(" %s\n", ac.toString().c_str()); +} + +void setup() { + ac.begin(); + Serial.begin(115200); + delay(200); + + // Set up what we want to send. See ir_Samsung.cpp for all the options. + Serial.println("Default state of the remote."); + printState(); + Serial.println("Setting initial state for A/C."); + ac.off(); + ac.setFan(kSamsungAcFanLow); + ac.setMode(kSamsungAcCool); + ac.setTemp(25); + ac.setSwing(false); + printState(); +} + +void loop() { + // Turn the A/C unit on and set to cooling mode. + // Power changes require we send an extended message. + Serial.println("Sending an extended IR command to A/C ..."); + ac.on(); + ac.setMode(kSamsungAcCool); + ac.sendExtended(); + printState(); + delay(15000); // wait 15 seconds + + // Increase the fan speed. + Serial.println("Sending a normal IR command to A/C ..."); + ac.setFan(kSamsungAcFanHigh); + ac.send(); + printState(); + delay(15000); + + // Change to swing the fan. + Serial.println("Sending a normal IR command to A/C ..."); + ac.setSwing(true); + ac.send(); + printState(); + delay(15000); + + // Change to Fan mode, lower the speed, and stop the swing. + Serial.println("Sending a normal IR command to A/C ..."); + ac.setSwing(false); + ac.setMode(kSamsungAcFan); + ac.setFan(kSamsungAcFanLow); + ac.send(); + printState(); + delay(15000); + + // Turn the A/C unit off. + // Power changes require we send an extended message. + Serial.println("Sending an extended IR command to A/C ..."); + ac.off(); + ac.sendExtended(); + printState(); + delay(15000); // wait 15 seconds +} diff --git a/lib/IRremoteESP8266/examples/ControlSamsungAC/platformio.ini b/lib/IRremoteESP8266/examples/ControlSamsungAC/platformio.ini new file mode 100644 index 0000000..eeb8d1f --- /dev/null +++ b/lib/IRremoteESP8266/examples/ControlSamsungAC/platformio.ini @@ -0,0 +1,17 @@ +[platformio] +lib_extra_dirs = ../../ +src_dir=. + +[common] +build_flags = +lib_deps_builtin = +lib_deps_external = + +[env:nodemcuv2] +platform = espressif8266 +framework = arduino +board = nodemcuv2 +build_flags = ${common.build_flags} +lib_deps = + ${common.lib_deps_builtin} + ${common.lib_deps_external} diff --git a/lib/IRremoteESP8266/examples/IRGCSendDemo/IRGCSendDemo.ino b/lib/IRremoteESP8266/examples/IRGCSendDemo/IRGCSendDemo.ino index cf576f7..03c80e1 100644 --- a/lib/IRremoteESP8266/examples/IRGCSendDemo/IRGCSendDemo.ino +++ b/lib/IRremoteESP8266/examples/IRGCSendDemo/IRGCSendDemo.ino @@ -24,12 +24,13 @@ * have enough current to drive the IR LED effectively. * * Make sure you have the IR LED polarity correct. * See: https://learn.sparkfun.com/tutorials/polarity/diode-and-led-polarity - * * Typical digital camera/phones can be used to see if the IR LED is flashed. - * Replace the IR LED with a normal LED if you don't have a digital camera - * when debugging. + * * Typical digital camera/phones can be used to see if the IR LED is + * flashed. Replace the IR LED with a normal LED if you don't have a digital + * camera when debugging. * * Avoid using the following pins unless you really know what you are doing: * * Pin 0/D3: Can interfere with the boot/program mode & support circuits. - * * Pin 1/TX/TXD0: Any serial transmissions from the ESP8266 will interfere. + * * Pin 1/TX/TXD0: Any serial transmissions from the ESP8266 will + * interfere. * * Pin 3/RX/RXD0: Any serial transmissions to the ESP8266 will interfere. * * ESP-01 modules are tricky. We suggest you use a module with more GPIOs * for your first time. e.g. ESP-12 etc. @@ -45,11 +46,11 @@ // These codes can be found in GC's Control Tower database. uint16_t Samsung_power_toggle[71] = { - 38000, 1, 1, 170, 170, 20, 63, 20, 63, 20, 63, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 63, 20, 63, 20, 63, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 63, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 63, 20, - 20, 20, 63, 20, 63, 20, 63, 20, 63, 20, 63, 20, 63, 20, 1798}; - + 38000, 1, 1, 170, 170, 20, 63, 20, 63, 20, 63, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 63, 20, 63, 20, 63, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 63, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 63, 20, 20, 20, 63, 20, + 63, 20, 63, 20, 63, 20, 63, 20, 63, 20, 1798}; #define IR_LED 4 // ESP8266 GPIO pin to use. Recommended: 4 (D2). @@ -64,7 +65,7 @@ void loop() { Serial.println("Toggling power"); #if SEND_GLOBALCACHE irsend.sendGC(Samsung_power_toggle, 71); -#else // SEND_GLOBALCACHE +#else // SEND_GLOBALCACHE Serial.println("Can't send because SEND_GLOBALCACHE has been disabled."); #endif // SEND_GLOBALCACHE delay(10000); diff --git a/lib/IRremoteESP8266/examples/IRGCTCPServer/IRGCTCPServer.ino b/lib/IRremoteESP8266/examples/IRGCTCPServer/IRGCTCPServer.ino index 0361091..69f7299 100644 --- a/lib/IRremoteESP8266/examples/IRGCTCPServer/IRGCTCPServer.ino +++ b/lib/IRremoteESP8266/examples/IRGCTCPServer/IRGCTCPServer.ino @@ -9,7 +9,7 @@ * For more codes, visit: https://irdb.globalcache.com/ * * How to use this program: - * 1) Update "ssid" and "password" below for your WIFI network. + * 1) Update "kSsid" and "kPassword" below for your WIFI network. * 2) Compile and upload the sketch to your ESP8266 module. * 3) (Optional) Use the serial connection to confirm it started and get the * IP address. @@ -46,8 +46,8 @@ #include #include -const char* ssid = "..."; // Put your WIFI SSID here. -const char* password = "..."; // Put your WIFI password here. +const char* kSsid = "..."; // Put your WIFI SSID here. +const char* kPassword = "..."; // Put your WIFI Password here. WiFiServer server(4998); // Uses port 4998. WiFiClient client; @@ -103,7 +103,7 @@ void setup() { delay(100); Serial.println(" "); Serial.println("IR TCP Server"); - WiFi.begin(ssid, password); + WiFi.begin(kSsid, kPassword); while (WiFi.status() != WL_CONNECTED) { delay(900); Serial.print("."); diff --git a/lib/IRremoteESP8266/examples/IRMQTTServer/IRMQTTServer.ino b/lib/IRremoteESP8266/examples/IRMQTTServer/IRMQTTServer.ino index 88c3444..250e8b6 100644 --- a/lib/IRremoteESP8266/examples/IRMQTTServer/IRMQTTServer.ino +++ b/lib/IRremoteESP8266/examples/IRMQTTServer/IRMQTTServer.ino @@ -1,8 +1,11 @@ /* - * Send arbitrary IR codes via a web server or MQTT. + * Send & receive arbitrary IR codes via a web server or MQTT. * Copyright David Conran 2016, 2017, 2018 * - * NOTE: An IR LED circuit *MUST* be connected to ESP8266 GPIO4 (D2). See IR_LED + * NOTE: An IR LED circuit *MUST* be connected to ESP8266 GPIO4 (D2) if + * you want to send IR messages. See IR_LED below. + * A compatible IR RX modules *MUST* be connected to ESP8266 GPIO14 (D5) + * if you want to capture & decode IR nessages. See IR_RX below. * * WARN: This is very advanced & complicated example code. Not for beginners. * You are strongly suggested to try & look at other example code first. @@ -10,12 +13,21 @@ * # Instructions * * ## Before First Boot (i.e. Compile time) - * - Set the MQTT_SERVER define below to the address of your MQTT server. + * - Either: + * o Set the MQTT_SERVER define below to the address of your MQTT server. + * or + * o Disable MQTT (see '#define MQTT_ENABLE' below). + * + * - Site specific settings: + * o Search for 'CHANGE_ME' for the things you probably need to change for + * your particular situation. + * * - Arduino IDE: * o Install the following libraries via Library Manager - * - WiFiManager (https://github.com/tzapu/WiFiManager) + * - WiFiManager (https://github.com/tzapu/WiFiManager) (Version >= 0.14) * - PubSubClient (https://pubsubclient.knolleary.net/) * o You MUST change to have the following (or larger) value: + * (with REPORT_RAW_UNKNOWNS 1024 or more is recommended) * #define MQTT_MAX_PACKET_SIZE 512 * - PlatformIO IDE: * If you are using PlatformIO, this should already been done for you in @@ -79,7 +91,7 @@ * # Install a MQTT client * $ sudo apt install mosquitto-clients * # Send a 32-bit NEC code of 0x1234abcd via MQTT. - * $ mosquitto_pub -h 10.20.0.253 -t ir_server/send -m '3,1234abcd,32' + * $ mosquitto_pub -h 10.0.0.4 -t ir_server/send -m '3,1234abcd,32' * * This server will send (back) what ever IR message it just transmitted to * the MQTT topic 'ir_server/sent' to confirm it has been performed. This works @@ -88,7 +100,20 @@ * time. * Unix command line usage example: * # Listen to MQTT acknowledgements. - * $ mosquitto_sub -h 10.20.0.253 -t ir_server/sent + * $ mosquitto_sub -h 10.0.0.4 -t ir_server/sent + * + * Incoming IR messages (from an IR remote control) will be transmitted to + * the MQTT topic 'ir_server/received'. The MQTT message will be formatted + * similar to what is required to for the 'sent' topic. + * e.g. "3,C1A2F00F,32" (Protocol,Value,Bits) for simple codes + * or "18,110B805000000060110B807000001070" (Protocol,Value) for complex codes + * Note: If the protocol is listed as -1, then that is an UNKNOWN IR protocol. + * You can't use that to recreate/resend an IR message. It's only for + * matching purposes and shouldn't be trusted. + * + * Unix command line usage example: + * # Listen via MQTT for IR messages captured by this server. + * $ mosquitto_sub -h 10.0.0.4 -t ir_server/received * * If DEBUG is turned on, there is additional information printed on the Serial * Port. @@ -98,13 +123,45 @@ * main page. No need to connect to the device again via USB. \o/ * Your WiFi settings should be remembered between updates. \o/ \o/ * + * ## Security + * + * There is NO authentication set on the HTTP/HTML interface by default (see + * `HTML_PASSWORD_ENABLE` to change that), and there is NO SSL/TLS (encryption) + * used by this example code. + * i.e. All usernames & passwords are sent in clear text. + * All communication to the MQTT server is in clear text. + * e.g. This on/using the public Internet is a 'Really Bad Idea'! + * You should NOT have or use this code or device exposed on an untrusted and/or + * unprotected network. + * If you allow access to OTA firmware updates, then a 'Bad Guy' could + * potentially compromise your network. OTA updates are password protected by + * default. If you are sufficiently paranoid, you SHOULD disable uploading + * firmware via OTA. (see 'FIRMWARE_OTA') + * You SHOULD also (re)set/change all usernames & passwords. (See `CHANGE_ME`s) + * For extra bonus points: Use a separate untrusted SSID/vlan/network/ segment + * for your IoT stuff, including this device. + * Caveat Emptor. You have now been suitably warned. + * + * * Copyright Notice: * Code for this has been borrowed from lots of other OpenSource projects & * resources. I'm *NOT* claiming complete Copyright ownership of all the code. * Likewise, feel free to borrow from this as much as you want. */ - -#define MQTT_ENABLE // Comment this out if you don't want to use MQTT at all. +// ---------------- Start of User Configuration Section ------------------------ +// Change to 'true'/'false' if you do/don't want these features or functions. +#define USE_STATIC_IP false // Change to 'true' if you don't want to use DHCP. +#define REPORT_UNKNOWNS false // Report inbound IR messages that we don't know. +#define REPORT_RAW_UNKNOWNS false // Report the whole buffer, recommended: + // MQTT_MAX_PACKET_SIZE of 1024 or more +#define MQTT_ENABLE true // Whether or not MQTT is used at all. +// 'kHtmlUsername' & 'kHtmlPassword' are used by the following two items: +#define FIRMWARE_OTA true // Allow remote update of the firmware via http. + // Less secure if enabled. + // Note: Firmware OTA is also disabled until + // 'kHtmlPassword' is changed from the default. +#define HTML_PASSWORD_ENABLE false // Protect access to the HTML interface. + // Note: OTA update is always passworded. #include #include @@ -117,7 +174,7 @@ #include #include #include -#ifdef MQTT_ENABLE +#if MQTT_ENABLE // -------------------------------------------------------------------- // * * * IMPORTANT * * * // You must change to have the following value. @@ -130,35 +187,68 @@ // Configuration parameters // GPIO the IR LED is connected to/controlled by. GPIO 4 = D2. -#define IR_LED 4 +#define IR_LED 4 // <=- CHANGE_ME (optional) // define IR_LED 3 // For an ESP-01 we suggest you use RX/GPIO3/Pin 7. -#define HTTP_PORT 80 // The port the HTTP server is listening on. -#define HOSTNAME "ir_server" // Name of the device you want in mDNS. +// +// GPIO the IR RX module is connected to/controlled by. GPIO 14 = D5. +// Comment this out to disable receiving/decoding IR messages entirely. +#define IR_RX 14 // <=- CHANGE_ME (optional) +#define IR_RX_PULLUP false +const uint16_t kHttpPort = 80; // The TCP port the HTTP server is listening on. +// Name of the device you want in mDNS. +// NOTE: Changing this will change the MQTT path too unless you override it +// via MQTTprefix below. +#define HOSTNAME "ir_server" // <=- CHANGE_ME (optional) -#ifdef MQTT_ENABLE +// We obtain our network config via DHCP by default but allow an easy way to +// use a static IP config. +#if USE_STATIC_IP +const IPAddress kIPAddress = IPAddress(10, 0, 1, 78); +const IPAddress kGateway = IPAddress(10, 0, 1, 1); +const IPAddress kSubnetMask = IPAddress(255, 255, 255, 0); +#endif // USE_STATIC_IP + +#if MQTT_ENABLE // Address of your MQTT server. -#define MQTT_SERVER "10.20.0.253" // <=- CHANGE ME -#define MQTT_PORT 1883 // Default port used by MQTT servers. -// Set if your MQTT server requires a Username & Password to connect. -const char* mqtt_user = ""; -const char* mqtt_password = ""; -#define MQTT_RECONNECT_TIME 5000 // Delay(ms) between reconnect tries. +#define MQTT_SERVER "10.0.0.4" // <=- CHANGE_ME +const uint16_t kMqttPort = 1883; // Default port used by MQTT servers. +// Set if your MQTT server requires a Username & Password to connect +// ... and it probably should if you want to be more secure. +const char* kMqttUsername = ""; // <=- CHANGE_ME (optional) +const char* kMqttPassword = ""; // <=- CHANGE_ME (optional) +const uint32_t kMqttReconnectTime = 5000; // Delay(ms) between reconnect tries. #define MQTTprefix HOSTNAME // Change this if you want the MQTT topic to be // independent of the hostname. #define MQTTack MQTTprefix "/sent" // Topic we send back acknowledgements on #define MQTTcommand MQTTprefix "/send" // Topic we get new commands from. +#define MQTTrecv MQTTprefix "/received" // Topic we send received IRs to. #endif // MQTT_ENABLE -// HTML arguments we will parse for IR code information. -#define argType "type" -#define argData "code" -#define argBits "bits" -#define argRepeat "repeats" +const char* kHtmlUsername = "admin"; // <=- CHANGE_ME (optional) +const char* kHtmlPassword = "esp8266"; // <=- CHANGE_ME (required) +// If you do not change 'kHtmlPassword', Firmware OTA updates will be blocked. -#define _MY_VERSION_ "v0.5" +// This is what the default password is. People should NEVER use this password. +// Firmware uploads are blocked until the user changes kHtmlPassword to a +// different value than this. +const char* kDefaultPassword = "esp8266"; // Do NOT change this. -#if IR_LED != 1 // Disable debug output if the LED is on the TX (D1) pin. +// Let's use a larger than normal buffer so we can handle AirCon remote codes. +const uint16_t kCaptureBufferSize = 1024; +#if DECODE_AC +// Some A/C units have gaps in their protocols of ~40ms. e.g. Kelvinator +// A value this large may swallow repeats of some protocols +const uint8_t kCaptureTimeout = 50; // Milliseconds +#else // DECODE_AC +// Suits most messages, while not swallowing many repeats. +const uint8_t kCaptureTimeout = 15; // Milliseconds +#endif // DECODE_AC +// Ignore unknown messages with <10 pulses (see also REPORT_UNKNOWNS) +const uint16_t kMinUnknownSize = 2 * 10; + +// Disable debug output if any of the IR pins are on the TX (D1) pin. +#if (IR_LED != 1 && IR_RX != 1) #undef DEBUG #define DEBUG true // Change to 'false' to disable all serial output. #else @@ -168,9 +258,22 @@ const char* mqtt_password = ""; // NOTE: Make sure you set your Serial Monitor to the same speed. #define BAUD_RATE 115200 // Serial port Baud rate. +// ----------------- End of User Configuration Section ------------------------- + // Globals -ESP8266WebServer server(HTTP_PORT); +#define _MY_VERSION_ "v0.8.3" +// HTML arguments we will parse for IR code information. +#define argType "type" +#define argData "code" +#define argBits "bits" +#define argRepeat "repeats" + +ESP8266WebServer server(kHttpPort); IRsend irsend = IRsend(IR_LED); +#ifdef IR_RX +IRrecv irrecv(IR_RX, kCaptureBufferSize, kCaptureTimeout, true); +decode_results capture; // Somewhere to store inbound IR messages. +#endif // IR_RX MDNSResponder mdns; WiFiClient espClient; WiFiManager wifiManager; @@ -180,23 +283,34 @@ uint32_t lastReconnectAttempt = 0; // MQTT last attempt reconnection number bool boot = true; bool ir_lock = false; // Primitive locking for gating the IR LED. uint32_t sendReqCounter = 0; +bool lastSendSucceeded = false; // Store the success status of the last send. +uint32_t lastSendTime = 0; int8_t offset; // The calculated period offset for this chip and library. -#ifdef MQTT_ENABLE +#if MQTT_ENABLE String lastMqttCmd = "None"; uint32_t lastMqttCmdTime = 0; +uint32_t lastConnectedTime = 0; +uint32_t lastDisconnectedTime = 0; +uint32_t mqttDisconnectCounter = 0; +bool wasConnected = true; +#ifdef IR_RX +String lastIrReceived = "None"; +uint32_t lastIrReceivedTime = 0; +uint32_t irRecvCounter = 0; +#endif // IR_RX // MQTT client parameters void callback(char* topic, byte* payload, unsigned int length); -PubSubClient mqtt_client(MQTT_SERVER, MQTT_PORT, callback, espClient); +PubSubClient mqtt_client(MQTT_SERVER, kMqttPort, callback, espClient); // Create a unique MQTT client id. String mqtt_clientid = MQTTprefix + String(ESP.getChipId(), HEX); #endif // MQTT_ENABLE // Debug messages get sent to the serial port. void debug(String str) { -#ifdef DEBUG +#if DEBUG uint32_t now = millis(); Serial.printf("%07u.%03u: %s\n", now / 1000, now % 1000, str.c_str()); #endif // DEBUG @@ -248,7 +362,13 @@ bool hasUnsafeHTMLChars(String input) { // Root web page with example usage etc. void handleRoot() { - server.send(200, "text/html", +#if HTML_PASSWORD_ENABLE + if (!server.authenticate(kHtmlUsername, kHtmlPassword)) { + debug("Basic HTTP authentication failure for /."); + return server.requestAuthentication(); + } +#endif + String html = "IR MQTT server" "" "

ESP8266 IR MQTT Server

" @@ -260,15 +380,35 @@ void handleRoot() { "Period Offset: " + String(offset) + "us
" "IR Lib Version: " _IRREMOTEESP8266_VERSION_ "
" "ESP8266 Core Version: " + ESP.getCoreVersion() + "
" - "Total send requests: " + String(sendReqCounter) + "

" -#ifdef MQTT_ENABLE + "IR Send GPIO: " + String(IR_LED) + "
" + "Total send requests: " + String(sendReqCounter) + "
" + "Last message sent: " + String(lastSendSucceeded ? "Ok" : "FAILED") + + " (" + timeSince(lastSendTime) + ")
" +#ifdef IR_RX + "IR Recv GPIO: " + String(IR_RX) + +#if IR_RX_PULLUP + " (pullup)" +#endif // IR_RX_PULLUP + "
" + "Total IR Received: " + String(irRecvCounter) + "
" + "Last IR Received: " + lastIrReceived + + " (" + timeSince(lastIrReceivedTime) + ")
" +#endif // IR_RX + "

" +#if MQTT_ENABLE "

MQTT Information

" - "

Server: " MQTT_SERVER ":" + String(MQTT_PORT) + " (" + - (mqtt_client.connected() ? "Connected" : "Disconnected") + ")
" + "

Server: " MQTT_SERVER ":" + String(kMqttPort) + " (" + + (mqtt_client.connected() ? "Connected " + timeSince(lastDisconnectedTime) + : "Disconnected " + timeSince(lastConnectedTime)) + + ")
" + "Disconnections: " + String(mqttDisconnectCounter - 1) + "
" "Client id: " + mqtt_clientid + "
" "Command topic: " MQTTcommand "
" "Acknowledgements topic: " MQTTack "
" - "Last command seen: " + +#ifdef IR_RX + "IR Received topic: " MQTTrecv "
" +#endif // IR_RX + "Last MQTT command seen: " + // lastMqttCmd is unescaped untrusted input. // Avoid any possible HTML/XSS when displaying it. (hasUnsafeHTMLChars(lastMqttCmd) ? @@ -308,10 +448,12 @@ void handleRoot() { "" "" "" - "" + "" "" - "" "" + "" + "" + "" "" "" "" @@ -319,6 +461,7 @@ void handleRoot() { "" // Default "" "" + "" "" "" "" @@ -329,6 +472,7 @@ void handleRoot() { "" "" "" + "" "" "" " Code: 0x24" "" "" + "" "" "" "" @@ -400,38 +545,59 @@ void handleRoot() { "" " State code: 0x" - "" " " "" - "


" - "

Update IR Server firmware

" - "Warning:
" - "Updating your firmware may screw up your access to the device. " - "If you are going to use this, know what you are doing first " - "(and you probably do).
" - "

" - "Firmware to upload: " - "" - "
" - ""); + "
"; +#if FIRMWARE_OTA + html += "

Update IR Server firmware

" + "Warning:
"; + if (!strcmp(kHtmlPassword, kDefaultPassword)) // Deny if password unchanged + html += "OTA firmware is disabled until you change the password. " + "(See 'kHtmlPassword' in the source code.)
"; + else // default password has been changed, so allow it. + html += + "Updating your firmware may screw up your access to the device. " + "If you are going to use this, know what you are doing first " + "(and you probably do).
" + "

" + "Firmware to upload: " + "" + "
"; + +#endif // FIRMWARE_OTA + html += ""; + server.send(200, "text/html", html); } // Reset web page void handleReset() { +#if HTML_PASSWORD_ENABLE + if (!server.authenticate(kHtmlUsername, kHtmlPassword)) { + debug("Basic HTTP authentication failure for /reset."); + return server.requestAuthentication(); + } +#endif server.send(200, "text/html", "Reset Config" "" @@ -449,9 +615,11 @@ void handleReset() { // Args: // irType: Nr. of the protocol we need to send. // str: A hexadecimal string containing the state to be sent. -void parseStringAndSendAirCon(const uint16_t irType, const String str) { +// Returns: +// bool: Successfully sent or not. +bool parseStringAndSendAirCon(const uint16_t irType, const String str) { uint8_t strOffset = 0; - uint8_t state[STATE_SIZE_MAX] = {0}; // All array elements are set to 0. + uint8_t state[kStateSizeMax] = {0}; // All array elements are set to 0. uint16_t stateSize = 0; if (str.startsWith("0x") || str.startsWith("0X")) @@ -460,30 +628,39 @@ void parseStringAndSendAirCon(const uint16_t irType, const String str) { uint16_t inputLength = str.length() - strOffset; if (inputLength == 0) { debug("Zero length AirCon code encountered. Ignored."); - return; // No input. Abort. + return false; // No input. Abort. } switch (irType) { // Get the correct state size for the protocol. case KELVINATOR: - stateSize = KELVINATOR_STATE_LENGTH; + stateSize = kKelvinatorStateLength; break; case TOSHIBA_AC: - stateSize = TOSHIBA_AC_STATE_LENGTH; + stateSize = kToshibaACStateLength; break; case DAIKIN: - stateSize = DAIKIN_COMMAND_LENGTH; + stateSize = kDaikinStateLength; + break; + case DAIKIN2: + stateSize = kDaikin2StateLength; + break; + case ELECTRA_AC: + stateSize = kElectraAcStateLength; break; case MITSUBISHI_AC: - stateSize = MITSUBISHI_AC_STATE_LENGTH; + stateSize = kMitsubishiACStateLength; + break; + case PANASONIC_AC: + stateSize = kPanasonicAcStateLength; break; case TROTEC: - stateSize = TROTEC_COMMAND_LENGTH; + stateSize = kTrotecStateLength; break; case ARGO: - stateSize = ARGO_COMMAND_LENGTH; + stateSize = kArgoStateLength; break; case GREE: - stateSize = GREE_STATE_LENGTH; + stateSize = kGreeStateLength; break; case FUJITSU_AC: // Fujitsu has four distinct & different size states, so make a best guess @@ -493,34 +670,66 @@ void parseStringAndSendAirCon(const uint16_t irType, const String str) { stateSize = inputLength / 2; // Every two hex chars is a byte. // Use at least the minimum size. stateSize = std::max(stateSize, - (uint16_t) (FUJITSU_AC_STATE_LENGTH_SHORT - 1)); + (uint16_t) (kFujitsuAcStateLengthShort - 1)); // If we think it isn't a "short" message. - if (stateSize > FUJITSU_AC_STATE_LENGTH_SHORT) + if (stateSize > kFujitsuAcStateLengthShort) // Then it has to be at least the smaller version of the "normal" size. - stateSize = std::max(stateSize, - (uint16_t) (FUJITSU_AC_STATE_LENGTH - 1)); + stateSize = std::max(stateSize, (uint16_t) (kFujitsuAcStateLength - 1)); // Lastly, it should never exceed the maximum "normal" size. - stateSize = std::min(stateSize, (uint16_t) FUJITSU_AC_STATE_LENGTH); + stateSize = std::min(stateSize, kFujitsuAcStateLength); break; case HAIER_AC: - stateSize = HAIER_AC_STATE_LENGTH; + stateSize = kHaierACStateLength; + break; + case HAIER_AC_YRW02: + stateSize = kHaierACYRW02StateLength; break; case HITACHI_AC: - stateSize = HITACHI_AC_STATE_LENGTH; + stateSize = kHitachiAcStateLength; break; case HITACHI_AC1: - stateSize = HITACHI_AC1_STATE_LENGTH; + stateSize = kHitachiAc1StateLength; break; case HITACHI_AC2: - stateSize = HITACHI_AC2_STATE_LENGTH; + stateSize = kHitachiAc2StateLength; + break; + case WHIRLPOOL_AC: + stateSize = kWhirlpoolAcStateLength; + break; + case SAMSUNG_AC: + // Samsung has two distinct & different size states, so make a best guess + // which one we are being presented with based on the number of + // hexadecimal digits provided. i.e. Zero-pad if you need to to get + // the correct length/byte size. + stateSize = inputLength / 2; // Every two hex chars is a byte. + // Use at least the minimum size. + stateSize = std::max(stateSize, (uint16_t) (kSamsungAcStateLength)); + // If we think it isn't a "normal" message. + if (stateSize > kSamsungAcStateLength) + // Then it probably the extended size. + stateSize = std::max(stateSize, + (uint16_t) (kSamsungAcExtendedStateLength)); + // Lastly, it should never exceed the maximum "extended" size. + stateSize = std::min(stateSize, kSamsungAcExtendedStateLength); + break; + case MWM: + // MWM has variable size states, so make a best guess + // which one we are being presented with based on the number of + // hexadecimal digits provided. i.e. Zero-pad if you need to to get + // the correct length/byte size. + stateSize = inputLength / 2; // Every two hex chars is a byte. + // Use at least the minimum size. + stateSize = std::max(stateSize, (uint16_t) 3); + // Cap the maximum size. + stateSize = std::min(stateSize, kStateSizeMax); break; default: // Not a protocol we expected. Abort. debug("Unexpected AirCon protocol detected. Ignoring."); - return; + return false; } if (inputLength > stateSize * 2) { debug("AirCon code to large for the given protocol."); - return; + return false; } // Ptr to the least significant byte of the resulting state for this protocol. @@ -537,7 +746,7 @@ void parseStringAndSendAirCon(const uint16_t irType, const String str) { c = c - 'a' + 10; } else { debug("Aborting! Non-hexadecimal char found in AirCon state: " + str); - return; + return false; } if (i % 2 == 1) { // Odd: Upper half of the byte. *statePtr += (c << 4); @@ -564,7 +773,12 @@ void parseStringAndSendAirCon(const uint16_t irType, const String str) { irsend.sendDaikin(reinterpret_cast(state)); break; #endif -#if MITSUBISHI_AC +#if SEND_DAIKIN2 + case DAIKIN2: + irsend.sendDaikin2(reinterpret_cast(state)); + break; +#endif +#if SEND_MITSUBISHI_AC case MITSUBISHI_AC: irsend.sendMitsubishiAC(reinterpret_cast(state)); break; @@ -594,6 +808,11 @@ void parseStringAndSendAirCon(const uint16_t irType, const String str) { irsend.sendHaierAC(reinterpret_cast(state)); break; #endif +#if SEND_HAIER_AC_YRW02 + case HAIER_AC_YRW02: + irsend.sendHaierACYRW02(reinterpret_cast(state)); + break; +#endif #if SEND_HITACHI_AC case HITACHI_AC: irsend.sendHitachiAC(reinterpret_cast(state)); @@ -609,7 +828,36 @@ void parseStringAndSendAirCon(const uint16_t irType, const String str) { irsend.sendHitachiAC2(reinterpret_cast(state)); break; #endif +#if SEND_WHIRLPOOL_AC + case WHIRLPOOL_AC: + irsend.sendWhirlpoolAC(reinterpret_cast(state)); + break; +#endif +#if SEND_SAMSUNG_AC + case SAMSUNG_AC: + irsend.sendSamsungAC(reinterpret_cast(state), stateSize); + break; +#endif +#if SEND_ELECTRA_AC + case ELECTRA_AC: + irsend.sendElectraAC(reinterpret_cast(state)); + break; +#endif +#if SEND_PANASONIC_AC + case PANASONIC_AC: + irsend.sendPanasonicAC(reinterpret_cast(state)); + break; +#endif +#if SEND_MWM + case MWM: + irsend.sendMWM(reinterpret_cast(state), stateSize); + break; +#endif + default: + debug("Unexpected AirCon type in send request. Not sent."); + return false; } + return true; // We were successful as far as we can tell. } // Count how many values are in the String. @@ -658,7 +906,9 @@ uint16_t * newCodeArray(const uint16_t size) { // 20,20,20,20,20,20,20,20,20,20,20,20,20,63,20,20,20,63,20,63,20, // 63,20,63,20,63,20,63,20,1798" // Note: The leading "1:1,1," of normal GC codes should be removed. -void parseStringAndSendGC(const String str) { +// Returns: +// bool: Successfully sent or not. +bool parseStringAndSendGC(const String str) { uint16_t count; uint16_t *code_array; String tmp_str; @@ -688,6 +938,9 @@ void parseStringAndSendGC(const String str) { irsend.sendGC(code_array, count); // All done. Send it. free(code_array); // Free up the memory allocated. + if (count > 0) + return true; // We sent something. + return false; // We probably didn't. } #endif // SEND_GLOBALCACHE @@ -701,11 +954,13 @@ void parseStringAndSendGC(const String str) { // 0030,0018,0018,0018,0018,0018,0030,0018,0018,03f6" // or // "0000,0067,0000,0015,0060,0018". i.e. without the Repeat value -// Requires at least PRONTO_MIN_LENGTH comma-separated values. +// Requires at least kProntoMinLength comma-separated values. // sendPronto() only supports raw pronto code types, thus so does this. // repeats: Nr. of times the message is to be repeated. // This value is ignored if an embeddd repeat is found in str. -void parseStringAndSendPronto(const String str, uint16_t repeats) { +// Returns: +// bool: Successfully sent or not. +bool parseStringAndSendPronto(const String str, uint16_t repeats) { uint16_t count; uint16_t *code_array; int16_t index = -1; @@ -723,8 +978,8 @@ void parseStringAndSendPronto(const String str, uint16_t repeats) { count--; // We don't count the repeats value as part of the code array. } - // We need at least PRONTO_MIN_LENGTH values for the code part. - if (count < PRONTO_MIN_LENGTH) return; + // We need at least kProntoMinLength values for the code part. + if (count < kProntoMinLength) return false; // Now we know how many there are, allocate the memory to store them all. code_array = newCodeArray(count); @@ -743,6 +998,9 @@ void parseStringAndSendPronto(const String str, uint16_t repeats) { irsend.sendPronto(code_array, count, repeats); // All done. Send it. free(code_array); // Free up the memory allocated. + if (count > 0) + return true; // We sent something. + return false; // We probably didn't. } #endif // SEND_PRONTO @@ -753,7 +1011,9 @@ void parseStringAndSendPronto(const String str, uint16_t repeats) { // e.g. "38000,9000,4500,600,1450,600,900,650,1500,..." // Requires at least two comma-separated values. // First value is the transmission frequency in Hz or kHz. -void parseStringAndSendRaw(const String str) { +// Returns: +// bool: Successfully sent or not. +bool parseStringAndSendRaw(const String str) { uint16_t count; uint16_t freq = 38000; // Default to 38kHz. uint16_t *raw_array; @@ -763,7 +1023,7 @@ void parseStringAndSendRaw(const String str) { // We expect the frequency as the first comma separated value, so we need at // least two values. If not, bail out. - if (count < 2) return; + if (count < 2) return false; count--; // We don't count the frequency value as part of the raw array. // Now we know how many there are, allocate the memory to store them all. @@ -785,11 +1045,20 @@ void parseStringAndSendRaw(const String str) { irsend.sendRaw(raw_array, count, freq); // All done. Send it. free(raw_array); // Free up the memory allocated. + if (count > 0) + return true; // We sent something. + return false; // We probably didn't. } #endif // SEND_RAW // Parse the URL args to find the IR code. void handleIr() { +#if HTML_PASSWORD_ENABLE + if (!server.authenticate(kHtmlUsername, kHtmlPassword)) { + debug("Basic HTTP authentication failure for /ir."); + return server.requestAuthentication(); + } +#endif uint64_t data = 0; String data_str = ""; int ir_type = 3; // Default to NEC codes. @@ -809,7 +1078,8 @@ void handleIr() { repeat = atoi(server.arg(i).c_str()); } debug("New code received via HTTP"); - sendIRCode(ir_type, data, data_str.c_str(), nbits, repeat); + lastSendSucceeded = sendIRCode(ir_type, data, data_str.c_str(), nbits, + repeat); handleRoot(); } @@ -832,6 +1102,10 @@ void setup_wifi() { // We start by connecting to a WiFi network wifiManager.setTimeout(300); // Time out after 5 mins. +#if USE_STATIC_IP + // Use a static IP config rather than the one supplied via DHCP. + wifiManager.setSTAStaticIPConfig(kIPAddress, kGateway, kSubnetMask); +#endif // USE_STATIC_IP if (!wifiManager.autoConnect()) { debug("Wifi failed to connect and hit timeout."); delay(3000); @@ -846,15 +1120,25 @@ void setup_wifi() { void setup(void) { irsend.begin(); offset = irsend.calibrate(); +#ifdef IR_RX +#if IR_RX_PULLUP + pinMode(IR_RX, INPUT_PULLUP); +#endif // IR_RX_PULLUP +#if DECODE_HASH + // Ignore messages with less than minimum on or off pulses. + irrecv.setUnknownThreshold(kMinUnknownSize); +#endif // DECODE_HASH + irrecv.enableIRIn(); // Start the receiver +#endif // IR_RX - #ifdef DEBUG +#if DEBUG // Use SERIAL_TX_ONLY so that the RX pin can be freed up for GPIO/IR use. Serial.begin(BAUD_RATE, SERIAL_8N1, SERIAL_TX_ONLY); while (!Serial) // Wait for the serial connection to be establised. delay(50); Serial.println(); debug("IRMQTTServer " _MY_VERSION_" has booted."); - #endif // DEBUG +#endif // DEBUG setup_wifi(); @@ -874,38 +1158,47 @@ void setup(void) { // Setup a reset page to cause WiFiManager information to be reset. server.on("/reset", handleReset); +#if FIRMWARE_OTA // Setup the URL to allow Over-The-Air (OTA) firmware updates. - server.on("/update", HTTP_POST, [](){ - server.sendHeader("Connection", "close"); - server.send(200, "text/plain", (Update.hasError())?"FAIL":"OK"); - ESP.restart(); - }, [](){ - HTTPUpload& upload = server.upload(); - if (upload.status == UPLOAD_FILE_START) { - WiFiUDP::stopAll(); - debug("Update: " + upload.filename); - uint32_t maxSketchSpace = (ESP.getFreeSketchSpace() - 0x1000) & - 0xFFFFF000; - if (!Update.begin(maxSketchSpace)) { // start with max available size -#ifdef DEBUG - Update.printError(Serial); + if (strcmp(kHtmlPassword, kDefaultPassword)) { // Allow if password changed. + server.on("/update", HTTP_POST, [](){ + server.sendHeader("Connection", "close"); + server.send(200, "text/plain", (Update.hasError())?"FAIL":"OK"); + ESP.restart(); + }, [](){ + if (!server.authenticate(kHtmlUsername, kHtmlPassword)) { + debug("Basic HTTP authentication failure for /update."); + return server.requestAuthentication(); + } + HTTPUpload& upload = server.upload(); + if (upload.status == UPLOAD_FILE_START) { + WiFiUDP::stopAll(); + debug("Update: " + upload.filename); + uint32_t maxSketchSpace = (ESP.getFreeSketchSpace() - 0x1000) & + 0xFFFFF000; + if (!Update.begin(maxSketchSpace)) { // start with max available size +#if DEBUG + Update.printError(Serial); #endif // DEBUG - } - } else if (upload.status == UPLOAD_FILE_WRITE) { - if (Update.write(upload.buf, upload.currentSize) != - upload.currentSize) { -#ifdef DEBUG - Update.printError(Serial); + } + } else if (upload.status == UPLOAD_FILE_WRITE) { + if (Update.write(upload.buf, upload.currentSize) != + upload.currentSize) { +#if DEBUG + Update.printError(Serial); #endif // DEBUG + } + } else if (upload.status == UPLOAD_FILE_END) { + // true to set the size to the current progress + if (Update.end(true)) { + debug("Update Success: " + (String) upload.totalSize + + "\nRebooting..."); + } } - } else if (upload.status == UPLOAD_FILE_END) { - if (Update.end(true)) { // true to set the size to the current progress - debug("Update Success: " + (String) upload.totalSize + - "\nRebooting..."); - } - } - yield(); - }); + yield(); + }); + } +#endif // FIRMWARE_OTA // Set up an error page. server.onNotFound(handleNotFound); @@ -914,7 +1207,7 @@ void setup(void) { debug("HTTP server started"); } -#ifdef MQTT_ENABLE +#if MQTT_ENABLE // MQTT subscribing to topic void subscribing(const String topic_name) { // subscription to topic for receiving data @@ -929,11 +1222,11 @@ bool reconnect() { while (!mqtt_client.connected() && tries <= 3) { int connected = false; // Attempt to connect - debug("Attempting MQTT connection to " MQTT_SERVER ":" + String(MQTT_PORT) + + debug("Attempting MQTT connection to " MQTT_SERVER ":" + String(kMqttPort) + "... "); - if (mqtt_user && mqtt_password) - connected = mqtt_client.connect(mqtt_clientid.c_str(), mqtt_user, - mqtt_password); + if (kMqttUsername && kMqttPassword) + connected = mqtt_client.connect(mqtt_clientid.c_str(), kMqttUsername, + kMqttPassword); else connected = mqtt_client.connect(mqtt_clientid.c_str()); if (connected) { @@ -955,32 +1248,77 @@ bool reconnect() { #endif // MQTT_ENABLE void loop(void) { - server.handleClient(); + server.handleClient(); // Handle any web activity -#ifdef MQTT_ENABLE +#if MQTT_ENABLE + uint32_t now = millis(); // MQTT client connection management if (!mqtt_client.connected()) { - uint32_t now = millis(); - // Reconnect if it's longer than MQTT_RECONNECT_TIME since we last tried. - if (now - lastReconnectAttempt > MQTT_RECONNECT_TIME) { + if (wasConnected) { + lastDisconnectedTime = now; + wasConnected = false; + mqttDisconnectCounter++; + } + // Reconnect if it's longer than kMqttReconnectTime since we last tried. + if (now - lastReconnectAttempt > kMqttReconnectTime) { lastReconnectAttempt = now; debug("client mqtt not connected, trying to connect"); // Attempt to reconnect if (reconnect()) { lastReconnectAttempt = 0; + wasConnected = true; if (boot) { mqtt_client.publish(MQTTack, "IR Server just booted"); boot = false; } else { - mqtt_client.publish(MQTTack, "IR Server just (re)connected to MQTT"); + String text = "IR Server just (re)connected to MQTT. " + "Lost connection about " + timeSince(lastConnectedTime); + mqtt_client.publish(MQTTack, text.c_str()); } + lastConnectedTime = now; + debug("successful client mqtt connection"); } } } else { + lastConnectedTime = now; // MQTT loop mqtt_client.loop(); } #endif // MQTT_ENABLE +#ifdef IR_RX + // Check if an IR code has been received via the IR RX module. +#if REPORT_UNKNOWNS + if (irrecv.decode(&capture)) { +#else + if (irrecv.decode(&capture) && capture.decode_type != UNKNOWN) { +#endif // REPORT_UNKNOWNS + lastIrReceivedTime = millis(); + lastIrReceived = String(capture.decode_type) + "," + + resultToHexidecimal(&capture); +#if REPORT_RAW_UNKNOWNS + if (capture.decode_type == UNKNOWN) { + lastIrReceived += ";"; + for (uint16_t i = 1; i < capture.rawlen; i++) { + uint32_t usecs; + for (usecs = capture.rawbuf[i] * kRawTick; usecs > UINT16_MAX; + usecs -= UINT16_MAX) { + lastIrReceived += uint64ToString(UINT16_MAX); + lastIrReceived += ",0,"; + } + lastIrReceived += uint64ToString(usecs, 10); + if (i < capture.rawlen - 1) + lastIrReceived += ","; + } + } +#endif // REPORT_RAW_UNKNOWNS + // If it isn't an AC code, add the bits. + if (!hasACState(capture.decode_type)) + lastIrReceived += "," + String(capture.bits); + mqtt_client.publish(MQTTrecv, lastIrReceived.c_str()); + irRecvCounter++; + debug("Incoming IR message sent to MQTT: " + lastIrReceived); + } +#endif // IR_RX delay(100); } @@ -1012,118 +1350,123 @@ uint64_t getUInt64fromHex(char const *str) { // code_str: The unparsed code to be sent. Used by complex protocol encodings. // bits: Nr. of bits in the protocol. 0 means use the protocol's default. // repeat: Nr. of times the message is to be repeated. (Not all protcols.) -void sendIRCode(int const ir_type, uint64_t const code, char const * code_str, +// Returns: +// bool: Successfully sent or not. +bool sendIRCode(int const ir_type, uint64_t const code, char const * code_str, uint16_t bits, uint16_t repeat) { // Create a pseudo-lock so we don't try to send two codes at the same time. while (ir_lock) delay(20); ir_lock = true; + bool success = true; // Assume success. + // send the IR message. switch (ir_type) { #if SEND_RC5 case RC5: // 1 if (bits == 0) - bits = RC5_BITS; + bits = kRC5Bits; irsend.sendRC5(code, bits, repeat); break; #endif #if SEND_RC6 case RC6: // 2 if (bits == 0) - bits = RC6_MODE0_BITS; + bits = kRC6Mode0Bits; irsend.sendRC6(code, bits, repeat); break; #endif #if SEND_NEC case NEC: // 3 if (bits == 0) - bits = NEC_BITS; + bits = kNECBits; irsend.sendNEC(code, bits, repeat); break; #endif #if SEND_SONY case SONY: // 4 if (bits == 0) - bits = SONY_12_BITS; - repeat = std::max(repeat, (uint16_t) SONY_MIN_REPEAT); + bits = kSony12Bits; + repeat = std::max(repeat, kSonyMinRepeat); irsend.sendSony(code, bits, repeat); break; #endif #if SEND_PANASONIC case PANASONIC: // 5 if (bits == 0) - bits = PANASONIC_BITS; + bits = kPanasonicBits; irsend.sendPanasonic64(code, bits, repeat); break; #endif #if SEND_JVC case JVC: // 6 if (bits == 0) - bits = JVC_BITS; + bits = kJvcBits; irsend.sendJVC(code, bits, repeat); break; #endif #if SEND_SAMSUNG case SAMSUNG: // 7 if (bits == 0) - bits = SAMSUNG_BITS; + bits = kSamsungBits; irsend.sendSAMSUNG(code, bits, repeat); break; #endif #if SEND_WHYNTER case WHYNTER: // 8 if (bits == 0) - bits = WHYNTER_BITS; + bits = kWhynterBits; irsend.sendWhynter(code, bits, repeat); break; #endif #if SEND_AIWA_RC_T501 case AIWA_RC_T501: // 9 if (bits == 0) - bits = AIWA_RC_T501_BITS; - repeat = std::max(repeat, (uint16_t) AIWA_RC_T501_MIN_REPEAT); + bits = kAiwaRcT501Bits; + repeat = std::max(repeat, kAiwaRcT501MinRepeats); irsend.sendAiwaRCT501(code, bits, repeat); break; #endif #if SEND_LG case LG: // 10 if (bits == 0) - bits = LG_BITS; + bits = kLgBits; irsend.sendLG(code, bits, repeat); break; #endif #if SEND_MITSUBISHI case MITSUBISHI: // 12 if (bits == 0) - bits = MITSUBISHI_BITS; - repeat = std::max(repeat, (uint16_t) MITSUBISHI_MIN_REPEAT); + bits = kMitsubishiBits; + repeat = std::max(repeat, kMitsubishiMinRepeat); irsend.sendMitsubishi(code, bits, repeat); break; #endif #if SEND_DISH case DISH: // 13 if (bits == 0) - bits = DISH_BITS; - repeat = std::max(repeat, (uint16_t) DISH_MIN_REPEAT); + bits = kDishBits; + repeat = std::max(repeat, kDishMinRepeat); irsend.sendDISH(code, bits, repeat); break; #endif #if SEND_SHARP case SHARP: // 14 if (bits == 0) - bits = SHARP_BITS; + bits = kSharpBits; irsend.sendSharpRaw(code, bits, repeat); break; #endif #if SEND_COOLIX case COOLIX: // 15 if (bits == 0) - bits = COOLIX_BITS; + bits = kCoolixBits; irsend.sendCOOLIX(code, bits, repeat); break; #endif case DAIKIN: // 16 + case DAIKIN2: // 53 case KELVINATOR: // 18 case MITSUBISHI_AC: // 20 case GREE: // 24 @@ -1132,10 +1475,16 @@ void sendIRCode(int const ir_type, uint64_t const code, char const * code_str, case TOSHIBA_AC: // 32 case FUJITSU_AC: // 33 case HAIER_AC: // 38 + case HAIER_AC_YRW02: // 44 case HITACHI_AC: // 40 case HITACHI_AC1: // 41 case HITACHI_AC2: // 42 - parseStringAndSendAirCon(ir_type, code_str); + case WHIRLPOOL_AC: // 45 + case SAMSUNG_AC: // 46 + case ELECTRA_AC: // 48 + case PANASONIC_AC: // 49 + case MWM: // 52 + success = parseStringAndSendAirCon(ir_type, code_str); break; #if SEND_DENON case DENON: // 17 @@ -1147,105 +1496,141 @@ void sendIRCode(int const ir_type, uint64_t const code, char const * code_str, #if SEND_SHERWOOD case SHERWOOD: // 19 if (bits == 0) - bits = SHERWOOD_BITS; - repeat = std::max(repeat, (uint16_t) SHERWOOD_MIN_REPEAT); + bits = kSherwoodBits; + repeat = std::max(repeat, kSherwoodMinRepeat); irsend.sendSherwood(code, bits, repeat); break; #endif #if SEND_RCMM case RCMM: // 21 if (bits == 0) - bits = RCMM_BITS; + bits = kRCMMBits; irsend.sendRCMM(code, bits, repeat); break; #endif #if SEND_SANYO case SANYO_LC7461: // 22 if (bits == 0) - bits = SANYO_LC7461_BITS; + bits = kSanyoLC7461Bits; irsend.sendSanyoLC7461(code, bits, repeat); break; #endif #if SEND_RC5 case RC5X: // 23 if (bits == 0) - bits = RC5X_BITS; + bits = kRC5XBits; irsend.sendRC5(code, bits, repeat); break; #endif #if SEND_PRONTO case PRONTO: // 25 - parseStringAndSendPronto(code_str, repeat); + success = parseStringAndSendPronto(code_str, repeat); break; #endif #if SEND_NIKAI case NIKAI: // 29 if (bits == 0) - bits = NIKAI_BITS; + bits = kNikaiBits; irsend.sendNikai(code, bits, repeat); break; #endif #if SEND_RAW case RAW: // 30 - parseStringAndSendRaw(code_str); + success = parseStringAndSendRaw(code_str); break; #endif #if SEND_GLOBALCACHE case GLOBALCACHE: // 31 - parseStringAndSendGC(code_str); + success = parseStringAndSendGC(code_str); break; #endif #if SEND_MIDEA case MIDEA: // 34 if (bits == 0) - bits = MIDEA_BITS; + bits = kMideaBits; irsend.sendMidea(code, bits, repeat); break; #endif #if SEND_MAGIQUEST case MAGIQUEST: // 35 if (bits == 0) - bits = MAGIQUEST_BITS; + bits = kMagiquestBits; irsend.sendMagiQuest(code, bits, repeat); break; #endif #if SEND_LASERTAG case LASERTAG: // 36 if (bits == 0) - bits = LASERTAG_BITS; + bits = kLasertagBits; irsend.sendLasertag(code, bits, repeat); break; #endif #if SEND_CARRIER_AC case CARRIER_AC: // 37 if (bits == 0) - bits = CARRIER_AC_BITS; + bits = kCarrierAcBits; irsend.sendCarrierAC(code, bits, repeat); break; #endif #if SEND_MITSUBISHI2 case MITSUBISHI2: // 39 if (bits == 0) - bits = MITSUBISHI_BITS; - repeat = std::max(repeat, (uint16_t) MITSUBISHI_MIN_REPEAT); + bits = kMitsubishiBits; + repeat = std::max(repeat, kMitsubishiMinRepeat); irsend.sendMitsubishi2(code, bits, repeat); break; #endif #if SEND_GICABLE case GICABLE: // 43 if (bits == 0) - bits = GICABLE_BITS; - repeat = std::max(repeat, (uint16_t) GICABLE_BITS); + bits = kGicableBits; + repeat = std::max(repeat, kGicableMinRepeat); irsend.sendGICable(code, bits, repeat); break; #endif +#if SEND_LUTRON + case LUTRON: // 47 + if (bits == 0) + bits = kLutronBits; + irsend.sendLutron(code, bits, repeat); + break; +#endif +#if SEND_PIONEER + case PIONEER: // 50 + if (bits == 0) + bits = kPioneerBits; + irsend.sendPioneer(code, bits, repeat); + break; +#endif +#if SEND_LG + case LG2: // 51 + if (bits == 0) + bits = kLgBits; + irsend.sendLG2(code, bits, repeat); + break; +#endif +#if SEND_VESTEL_AC + case VESTEL_AC: // 54 + if (bits == 0) + bits = kVestelACBits; + irsend.sendVestelAC(code, bits, repeat); + break; +#endif + default: + // If we got here, we didn't know how to send it. + success = false; } - sendReqCounter++; + lastSendTime = millis(); // Release the lock. ir_lock = false; - // Indicate that we sent the message. - debug("Sent the IR message."); + // Indicate that we sent the message or not. + if (success) { + sendReqCounter++; + debug("Sent the IR message:"); + } else { + debug("Failed to send IR Message:"); + } debug("Type: " + String(ir_type)); // For "long" codes we basically repeat what we got. if (hasACState((decode_type_t) ir_type) || @@ -1254,31 +1639,34 @@ void sendIRCode(int const ir_type, uint64_t const code, char const * code_str, ir_type == GLOBALCACHE) { debug("Code: "); debug(code_str); - debug("Repeats: " + String(repeat)); // Confirm what we were asked to send was sent. -#ifdef MQTT_ENABLE - if (ir_type == PRONTO && repeat > 0) - mqtt_client.publish(MQTTack, (String(ir_type) + ",R" + - String(repeat) + "," + - String(code_str)).c_str()); - else - mqtt_client.publish(MQTTack, (String(ir_type) + "," + - String(code_str)).c_str()); +#if MQTT_ENABLE + if (success) { + if (ir_type == PRONTO && repeat > 0) + mqtt_client.publish(MQTTack, (String(ir_type) + ",R" + + String(repeat) + "," + + String(code_str)).c_str()); + else + mqtt_client.publish(MQTTack, (String(ir_type) + "," + + String(code_str)).c_str()); + } #endif // MQTT_ENABLE } else { // For "short" codes, we break it down a bit more before we report. debug("Code: 0x" + uint64ToString(code, 16)); debug("Bits: " + String(bits)); debug("Repeats: " + String(repeat)); -#ifdef MQTT_ENABLE - mqtt_client.publish(MQTTack, (String(ir_type) + "," + - uint64ToString(code, 16) - + "," + String(bits) + "," + - String(repeat)).c_str()); +#if MQTT_ENABLE + if (success) + mqtt_client.publish(MQTTack, (String(ir_type) + "," + + uint64ToString(code, 16) + + "," + String(bits) + "," + + String(repeat)).c_str()); #endif // MQTT_ENABLE } + return success; } -#ifdef MQTT_ENABLE +#if MQTT_ENABLE void receivingMQTT(String const topic_name, String const callback_str) { char* tok_ptr; uint64_t code = 0; @@ -1318,9 +1706,10 @@ void receivingMQTT(String const topic_name, String const callback_str) { // send received MQTT value by IR signal - sendIRCode(ir_type, code, - callback_str.substring(callback_str.indexOf(",") + 1).c_str(), - nbits, repeat); + lastSendSucceeded = sendIRCode( + ir_type, code, + callback_str.substring(callback_str.indexOf(",") + 1).c_str(), + nbits, repeat); } // Callback function, when the gateway receive an MQTT value on the topics diff --git a/lib/IRremoteESP8266/examples/IRMQTTServer/platformio.ini b/lib/IRremoteESP8266/examples/IRMQTTServer/platformio.ini index c87e569..27b44dd 100644 --- a/lib/IRremoteESP8266/examples/IRMQTTServer/platformio.ini +++ b/lib/IRremoteESP8266/examples/IRMQTTServer/platformio.ini @@ -7,7 +7,7 @@ build_flags = -DMQTT_MAX_PACKET_SIZE=512 lib_deps_builtin = lib_deps_external = PubSubClient - WifiManager@0.12 + WifiManager@0.14 [env:nodemcuv2] platform = espressif8266 diff --git a/lib/IRremoteESP8266/examples/IRServer/IRServer.ino b/lib/IRremoteESP8266/examples/IRServer/IRServer.ino index 87e0d2c..b378d3b 100644 --- a/lib/IRremoteESP8266/examples/IRServer/IRServer.ino +++ b/lib/IRremoteESP8266/examples/IRServer/IRServer.ino @@ -4,7 +4,7 @@ * Copyright 2015 Mark Szabo * * An IR LED circuit *MUST* be connected to the ESP8266 on a pin - * as specified by IR_LED below. + * as specified by kIrLed below. * * TL;DR: The IR LED needs to be driven by a transistor for a good result. * @@ -36,15 +36,15 @@ #include #include -const char* ssid = "....."; -const char* password = "....."; +const char* kSsid = "....."; +const char* kPassword = "....."; MDNSResponder mdns; ESP8266WebServer server(80); -#define IR_LED 4 // ESP8266 GPIO pin to use. Recommended: 4 (D2). +const uint16_t kIrLed = 4; // ESP8266 GPIO pin to use. Recommended: 4 (D2). -IRsend irsend(IR_LED); // Set the GPIO to be used to sending the message. +IRsend irsend(kIrLed); // Set the GPIO to be used to sending the message. void handleRoot() { server.send(200, "text/html", @@ -90,7 +90,7 @@ void setup(void) { irsend.begin(); Serial.begin(115200); - WiFi.begin(ssid, password); + WiFi.begin(kSsid, kPassword); Serial.println(""); // Wait for connection @@ -100,7 +100,7 @@ void setup(void) { } Serial.println(""); Serial.print("Connected to "); - Serial.println(ssid); + Serial.println(kSsid); Serial.print("IP address: "); Serial.println(WiFi.localIP().toString()); diff --git a/lib/IRremoteESP8266/examples/IRrecvDemo/IRrecvDemo.ino b/lib/IRremoteESP8266/examples/IRrecvDemo/IRrecvDemo.ino index c7936e5..09babe4 100644 --- a/lib/IRremoteESP8266/examples/IRrecvDemo/IRrecvDemo.ino +++ b/lib/IRremoteESP8266/examples/IRrecvDemo/IRrecvDemo.ino @@ -3,7 +3,7 @@ * This is very simple teaching code to show you how to use the library. * If you are trying to decode your Infra-Red remote(s) for later replay, * use the IRrecvDumpV2.ino example code instead of this. - * An IR detector/demodulator must be connected to the input RECV_PIN. + * An IR detector/demodulator must be connected to the input kRecvPin. * Copyright 2009 Ken Shirriff, http://arcfn.com * Example circuit diagram: * https://github.com/markszabo/IRremoteESP8266/wiki#ir-receiving @@ -25,9 +25,9 @@ // An IR detector/demodulator is connected to GPIO pin 14(D5 on a NodeMCU // board). -uint16_t RECV_PIN = 14; +const uint16_t kRecvPin = 14; -IRrecv irrecv(RECV_PIN); +IRrecv irrecv(kRecvPin); decode_results results; @@ -38,7 +38,7 @@ void setup() { delay(50); Serial.println(); Serial.print("IRrecvDemo is now running and waiting for IR message on Pin "); - Serial.println(RECV_PIN); + Serial.println(kRecvPin); } void loop() { diff --git a/lib/IRremoteESP8266/examples/IRrecvDump/IRrecvDump.ino b/lib/IRremoteESP8266/examples/IRrecvDump/IRrecvDump.ino index 8564496..34f10dc 100644 --- a/lib/IRremoteESP8266/examples/IRrecvDump/IRrecvDump.ino +++ b/lib/IRremoteESP8266/examples/IRrecvDump/IRrecvDump.ino @@ -86,10 +86,10 @@ void dump(decode_results *results) { if (i % 100 == 0) yield(); // Preemptive yield every 100th entry to feed the WDT. if (i & 1) { - Serial.print(results->rawbuf[i] * RAWTICK, DEC); + Serial.print(results->rawbuf[i] * kRawTick, DEC); } else { Serial.print(", "); - Serial.print((uint32_t) results->rawbuf[i] * RAWTICK, DEC); + Serial.print((uint32_t) results->rawbuf[i] * kRawTick, DEC); } } Serial.println("};"); diff --git a/lib/IRremoteESP8266/examples/IRrecvDumpV2/IRrecvDumpV2.ino b/lib/IRremoteESP8266/examples/IRrecvDumpV2/IRrecvDumpV2.ino index 105a7d4..515d6a0 100644 --- a/lib/IRremoteESP8266/examples/IRrecvDumpV2/IRrecvDumpV2.ino +++ b/lib/IRremoteESP8266/examples/IRrecvDumpV2/IRrecvDumpV2.ino @@ -1,6 +1,6 @@ /* * IRremoteESP8266: IRrecvDumpV2 - dump details of IR codes with IRrecv - * An IR detector/demodulator must be connected to the input RECV_PIN. + * An IR detector/demodulator must be connected to the input kRecvPin. * * Copyright 2009 Ken Shirriff, http://arcfn.com * Copyright 2017 David Conran @@ -9,6 +9,8 @@ * https://github.com/markszabo/IRremoteESP8266/wiki#ir-receiving * * Changes: + * Version 0.4 July, 2018 + * - Minor improvements and more A/C unit support. * Version 0.3 November, 2017 * - Support for A/C decoding for some protcols. * Version 0.2 April, 2017 @@ -20,36 +22,43 @@ #ifndef UNIT_TEST #include #endif -#include #include +#include #include -#if DECODE_AC +// The following are only needed for extended decoding of A/C Messages +#include #include #include #include #include +#include #include #include +#include +#include +#include #include -#endif // DECODE_AC +#include +#include + // ==================== start of TUNEABLE PARAMETERS ==================== // An IR detector/demodulator is connected to GPIO pin 14 // e.g. D5 on a NodeMCU board. -#define RECV_PIN 14 +const uint16_t kRecvPin = 14; // The Serial connection baud rate. // i.e. Status message will be sent to the PC at this baud rate. // Try to avoid slow speeds like 9600, as you will miss messages and // cause other problems. 115200 (or faster) is recommended. // NOTE: Make sure you set your Serial Monitor to the same speed. -#define BAUD_RATE 115200 +const uint32_t kBaudRate = 115200; // As this program is a special purpose capture/decoder, let us use a larger // than normal buffer so we can handle Air Conditioner remote codes. -#define CAPTURE_BUFFER_SIZE 1024 +const uint16_t kCaptureBufferSize = 1024; -// TIMEOUT is the Nr. of milli-Seconds of no-more-data before we consider a +// kTimeout is the Nr. of milli-Seconds of no-more-data before we consider a // message ended. // This parameter is an interesting trade-off. The longer the timeout, the more // complex a message it can capture. e.g. Some device protocols will send @@ -61,33 +70,34 @@ // them is often also around 20+ms. This can result in the raw data be 2-3+ // times larger than needed as it has captured 2-3+ messages in a single // capture. Setting a low timeout value can resolve this. -// So, choosing the best TIMEOUT value for your use particular case is +// So, choosing the best kTimeout value for your use particular case is // quite nuanced. Good luck and happy hunting. -// NOTE: Don't exceed MAX_TIMEOUT_MS. Typically 130ms. +// NOTE: Don't exceed kMaxTimeoutMs. Typically 130ms. #if DECODE_AC -#define TIMEOUT 50U // Some A/C units have gaps in their protocols of ~40ms. - // e.g. Kelvinator - // A value this large may swallow repeats of some protocols -#else // DECODE_AC -#define TIMEOUT 15U // Suits most messages, while not swallowing many repeats. +// Some A/C units have gaps in their protocols of ~40ms. e.g. Kelvinator +// A value this large may swallow repeats of some protocols +const uint8_t kTimeout = 50; +#else // DECODE_AC +// Suits most messages, while not swallowing many repeats. +const uint8_t kTimeout = 15; #endif // DECODE_AC // Alternatives: -// #define TIMEOUT 90U // Suits messages with big gaps like XMP-1 & some aircon - // units, but can accidentally swallow repeated messages - // in the rawData[] output. -// #define TIMEOUT MAX_TIMEOUT_MS // This will set it to our currently allowed - // maximum. Values this high are problematic - // because it is roughly the typical boundary - // where most messages repeat. - // e.g. It will stop decoding a message and - // start sending it to serial at precisely - // the time when the next message is likely - // to be transmitted, and may miss it. +// const uint8_t kTimeout = 90; +// Suits messages with big gaps like XMP-1 & some aircon units, but can +// accidentally swallow repeated messages in the rawData[] output. +// +// const uint8_t kTimeout = kMaxTimeoutMs; +// This will set it to our currently allowed maximum. +// Values this high are problematic because it is roughly the typical boundary +// where most messages repeat. +// e.g. It will stop decoding a message and start sending it to serial at +// precisely the time when the next message is likely to be transmitted, +// and may miss it. // Set the smallest sized "UNKNOWN" message packets we actually care about. // This value helps reduce the false-positive detection rate of IR background // noise as real messages. The chances of background IR noise getting detected -// as a message increases with the length of the TIMEOUT value. (See above) +// as a message increases with the length of the kTimeout value. (See above) // The downside of setting this message too large is you can miss some valid // short messages for protocols that this library doesn't yet decode. // @@ -96,12 +106,11 @@ // Set lower if you are sure your setup is working, but it doesn't see messages // from your device. (e.g. Other IR remotes work.) // NOTE: Set this value very high to effectively turn off UNKNOWN detection. -#define MIN_UNKNOWN_SIZE 12 +const uint16_t kMinUnknownSize = 12; // ==================== end of TUNEABLE PARAMETERS ==================== - // Use turn on the save buffer feature for more complete capture coverage. -IRrecv irrecv(RECV_PIN, CAPTURE_BUFFER_SIZE, TIMEOUT, true); +IRrecv irrecv(kRecvPin, kCaptureBufferSize, kTimeout, true); decode_results results; // Somewhere to store the results @@ -115,6 +124,13 @@ void dumpACInfo(decode_results *results) { description = ac.toString(); } #endif // DECODE_DAIKIN +#if DECODE_DAIKIN2 + if (results->decode_type == DAIKIN2) { + IRDaikin2 ac(0); + ac.setRaw(results->state); + description = ac.toString(); + } +#endif // DECODE_DAIKIN2 #if DECODE_FUJITSU_AC if (results->decode_type == FUJITSU_AC) { IRFujitsuAC ac(0); @@ -129,6 +145,13 @@ void dumpACInfo(decode_results *results) { description = ac.toString(); } #endif // DECODE_KELVINATOR +#if DECODE_MITSUBISHI_AC + if (results->decode_type == MITSUBISHI_AC) { + IRMitsubishiAC ac(0); + ac.setRaw(results->state); + description = ac.toString(); + } +#endif // DECODE_MITSUBISHI_AC #if DECODE_TOSHIBA_AC if (results->decode_type == TOSHIBA_AC) { IRToshibaAC ac(0); @@ -157,23 +180,73 @@ void dumpACInfo(decode_results *results) { description = ac.toString(); } #endif // DECODE_HAIER_AC +#if DECODE_HAIER_AC_YRW02 + if (results->decode_type == HAIER_AC_YRW02) { + IRHaierACYRW02 ac(0); + ac.setRaw(results->state); + description = ac.toString(); + } +#endif // DECODE_HAIER_AC_YRW02 +#if DECODE_SAMSUNG_AC + if (results->decode_type == SAMSUNG_AC) { + IRSamsungAc ac(0); + ac.setRaw(results->state, results->bits / 8); + description = ac.toString(); + } +#endif // DECODE_SAMSUNG_AC +#if DECODE_COOLIX + if (results->decode_type == COOLIX) { + IRCoolixAC ac(0); + ac.setRaw(results->value); // Coolix uses value instead of state. + description = ac.toString(); + } +#endif // DECODE_COOLIX +#if DECODE_PANASONIC_AC + if (results->decode_type == PANASONIC_AC && + results->bits > kPanasonicAcShortBits) { + IRPanasonicAc ac(0); + ac.setRaw(results->state); + description = ac.toString(); + } +#endif // DECODE_PANASONIC_AC +#if DECODE_HITACHI_AC + if (results->decode_type == HITACHI_AC) { + IRHitachiAc ac(0); + ac.setRaw(results->state); + description = ac.toString(); + } +#endif // DECODE_HITACHI_AC +#if DECODE_WHIRLPOOL_AC + if (results->decode_type == WHIRLPOOL_AC) { + IRWhirlpoolAc ac(0); + ac.setRaw(results->state); + description = ac.toString(); + } +#endif // DECODE_WHIRLPOOL_AC +#if DECODE_VESTEL_AC + if (results->decode_type == VESTEL_AC) { + IRVestelAC ac(0); + ac.setRaw(results->value); // Like Coolix, use value instead of state. + description = ac.toString(); + } +#endif // DECODE_VESTEL_AC // If we got a human-readable description of the message, display it. - if (description != "") Serial.println("Mesg Desc.: " + description); + if (description != "") Serial.println("Mesg Desc.: " + description); } // The section of code run only once at start-up. void setup() { - Serial.begin(BAUD_RATE, SERIAL_8N1, SERIAL_TX_ONLY); + Serial.begin(kBaudRate, SERIAL_8N1, SERIAL_TX_ONLY); while (!Serial) // Wait for the serial connection to be establised. delay(50); Serial.println(); Serial.print("IRrecvDumpV2 is now running and waiting for IR input on Pin "); - Serial.println(RECV_PIN); + Serial.println(kRecvPin); #if DECODE_HASH // Ignore messages with less than minimum on or off pulses. - irrecv.setUnknownThreshold(MIN_UNKNOWN_SIZE); -#endif // DECODE_HASH + irrecv.setUnknownThreshold(kMinUnknownSize); +#endif // DECODE_HASH irrecv.enableIRIn(); // Start the receiver } @@ -186,10 +259,11 @@ void loop() { uint32_t now = millis(); Serial.printf("Timestamp : %06u.%03u\n", now / 1000, now % 1000); if (results.overflow) - Serial.printf("WARNING: IR code is too big for buffer (>= %d). " - "This result shouldn't be trusted until this is resolved. " - "Edit & increase CAPTURE_BUFFER_SIZE.\n", - CAPTURE_BUFFER_SIZE); + Serial.printf( + "WARNING: IR code is too big for buffer (>= %d). " + "This result shouldn't be trusted until this is resolved. " + "Edit & increase kCaptureBufferSize.\n", + kCaptureBufferSize); // Display the basic output of what we found. Serial.print(resultToHumanReadableBasic(&results)); dumpACInfo(&results); // Display any extra A/C info if we have it. @@ -207,6 +281,6 @@ void loop() { // Output the results as source code Serial.println(resultToSourceCode(&results)); Serial.println(""); // Blank line between entries - yield(); // Feed the WDT (again) + yield(); // Feed the WDT (again) } } diff --git a/lib/IRremoteESP8266/examples/IRsendDemo/IRsendDemo.ino b/lib/IRremoteESP8266/examples/IRsendDemo/IRsendDemo.ino index 51d1979..19f1186 100644 --- a/lib/IRremoteESP8266/examples/IRsendDemo/IRsendDemo.ino +++ b/lib/IRremoteESP8266/examples/IRsendDemo/IRsendDemo.ino @@ -1,11 +1,11 @@ /* IRremoteESP8266: IRsendDemo - demonstrates sending IR codes with IRsend. * - * Version 1.0 April, 2017 + * Version 1.1 January, 2019 * Based on Ken Shirriff's IrsendDemo Version 0.1 July, 2009, * Copyright 2009 Ken Shirriff, http://arcfn.com * * An IR LED circuit *MUST* be connected to the ESP8266 on a pin - * as specified by IR_LED below. + * as specified by kIrLed below. * * TL;DR: The IR LED needs to be driven by a transistor for a good result. * @@ -34,9 +34,9 @@ #include #include -#define IR_LED 4 // ESP8266 GPIO pin to use. Recommended: 4 (D2). +const uint16_t kIrLed = 4; // ESP8266 GPIO pin to use. Recommended: 4 (D2). -IRsend irsend(IR_LED); // Set the GPIO to be used to sending the message. +IRsend irsend(kIrLed); // Set the GPIO to be used to sending the message. // Example of data captured by IRrecvDumpV2.ino uint16_t rawData[67] = {9000, 4500, 650, 550, 650, 1650, 600, 550, 650, 550, @@ -46,6 +46,10 @@ uint16_t rawData[67] = {9000, 4500, 650, 550, 650, 1650, 600, 550, 650, 550, 650, 550, 650, 550, 600, 550, 650, 550, 650, 550, 650, 1650, 600, 550, 650, 1650, 650, 1650, 650, 1650, 650, 1650, 650, 1650, 650, 1650, 600}; +// Example Samsung A/C state captured from IRrecvDumpV2.ino +uint8_t samsungState[kSamsungAcStateLength] = { + 0x02, 0x92, 0x0F, 0x00, 0x00, 0x00, 0xF0, + 0x01, 0xE2, 0xFE, 0x71, 0x40, 0x11, 0xF0}; void setup() { irsend.begin(); @@ -53,19 +57,16 @@ void setup() { } void loop() { -#if SEND_NEC Serial.println("NEC"); - irsend.sendNEC(0x00FFE01FUL, 32); -#endif // SEND_NEC + irsend.sendNEC(0x00FFE01FUL); delay(2000); -#if SEND_SONY Serial.println("Sony"); - irsend.sendSony(0xa90, 12, 2); -#endif // SEND_SONY + irsend.sendSony(0xa90, 12, 2); // 12 bits & 2 repeats delay(2000); -#if SEND_RAW Serial.println("a rawData capture from IRrecvDumpV2"); irsend.sendRaw(rawData, 67, 38); // Send a raw data capture at 38kHz. -#endif // SEND_RAW + delay(2000); + Serial.println("a Samsung A/C state from IRrecvDumpV2"); + irsend.sendSamsungAC(samsungState); delay(2000); } diff --git a/lib/IRremoteESP8266/examples/IRsendProntoDemo/IRsendProntoDemo.ino b/lib/IRremoteESP8266/examples/IRsendProntoDemo/IRsendProntoDemo.ino index c527d89..3bef217 100644 --- a/lib/IRremoteESP8266/examples/IRsendProntoDemo/IRsendProntoDemo.ino +++ b/lib/IRremoteESP8266/examples/IRsendProntoDemo/IRsendProntoDemo.ino @@ -6,7 +6,7 @@ * Version 1.0 June, 2017 * * An IR LED circuit *MUST* be connected to ESP8266 pin 4 (D2), unless you - * change the IR_LED value below. + * change the kIrLed value below. * * TL;DR: The IR LED needs to be driven by a transistor for a good result. * @@ -35,9 +35,9 @@ #include #include -#define IR_LED 4 // ESP8266 GPIO pin to use. Recommended: 4 (D2). +const uint16_t kIrLed = 4; // ESP8266 GPIO pin to use. Recommended: 4 (D2). -IRsend irsend(IR_LED); // Set the GPIO to be used to sending the message. +IRsend irsend(kIrLed); // Set the GPIO to be used to sending the message. // Panasonic Plasma TV Descrete code (Power On). // Acquired from: diff --git a/lib/IRremoteESP8266/examples/JVCPanasonicSendDemo/JVCPanasonicSendDemo.ino b/lib/IRremoteESP8266/examples/JVCPanasonicSendDemo/JVCPanasonicSendDemo.ino index c98db14..ee24229 100644 --- a/lib/IRremoteESP8266/examples/JVCPanasonicSendDemo/JVCPanasonicSendDemo.ino +++ b/lib/IRremoteESP8266/examples/JVCPanasonicSendDemo/JVCPanasonicSendDemo.ino @@ -5,7 +5,7 @@ * JVC and Panasonic protocol added by Kristian Lauszus (Thanks to zenwheel and other people at the original blog post) * * An IR LED circuit *MUST* be connected to the ESP8266 on a pin - * as specified by IR_LED below. + * as specified by kIrLed below. * * TL;DR: The IR LED needs to be driven by a transistor for a good result. * @@ -34,14 +34,13 @@ #include #include -#define PanasonicAddress 0x4004 // Panasonic address (Pre data) -#define PanasonicPower 0x100BCBD // Panasonic Power button +const uint16_t kPanasonicAddress = 0x4004; // Panasonic address (Pre data) +const uint32_t kPanasonicPower = 0x100BCBD; // Panasonic Power button +const uint16_t kJVCPower = 0xC5E8; -#define JVCPower 0xC5E8 +const uint16_t kIrLed = 4; // ESP8266 GPIO pin to use. Recommended: 4 (D2). -#define IR_LED 4 // ESP8266 GPIO pin to use. Recommended: 4 (D2). - -IRsend irsend(IR_LED); // Set the GPIO to be used to sending the message. +IRsend irsend(kIrLed); // Set the GPIO to be used to sending the message. void setup() { irsend.begin(); @@ -50,18 +49,15 @@ void setup() { void loop() { // This should turn your TV on and off #if SEND_PANASONIC - irsend.sendPanasonic(PanasonicAddress, PanasonicPower); + irsend.sendPanasonic(kPanasonicAddress, kPanasonicPower); #else // SEND_PANASONIC Serial.println("Can't send because SEND_PANASONIC has been disabled."); #endif // SEND_PANASONIC #if SEND_JVC - irsend.sendJVC(JVCPower, 16, 0); // hex value, 16 bits, no repeat - // see http://www.sbprojects.com/knowledge/ir/jvc.php for information - delayMicroseconds(50); - irsend.sendJVC(JVCPower, 16, 1); // hex value, 16 bits, repeat - delayMicroseconds(50); + irsend.sendJVC(kJVCPower, 16, 1); // hex value, 16 bits, single repeat #else // SEND_JVC Serial.println("Can't send because SEND_JVC has been disabled."); #endif // SEND_JVC + delay(10000); // Wait 10 seconds before we repeat everything. } diff --git a/lib/IRremoteESP8266/examples/LGACSend/LGACSend.ino b/lib/IRremoteESP8266/examples/LGACSend/LGACSend.ino index 493d2a8..9139983 100644 --- a/lib/IRremoteESP8266/examples/LGACSend/LGACSend.ino +++ b/lib/IRremoteESP8266/examples/LGACSend/LGACSend.ino @@ -64,9 +64,9 @@ void Ac_Activate(unsigned int temperature, unsigned int air_flow, else ac_msbits4 = 0; // cooling unsigned int ac_msbits5 = (temperature < 15) ? 0 : temperature - 15; - unsigned int ac_msbits6; + unsigned int ac_msbits6 = 0; - if (0 <= air_flow && air_flow <= 2) { + if (air_flow <= 2) { if (kAc_Type == 0) ac_msbits6 = kAc_Flow_Tower[air_flow]; else @@ -132,7 +132,7 @@ void setup() { } void loop() { - char b; + char b = ' '; Serial.println("# a : mode or temp b : air_flow, temp, swing, clean," " cooling/heating"); Serial.println("# 0 : off 0"); @@ -162,7 +162,7 @@ void loop() { default: Serial.println("b="); // Prompt User for input while (Serial.available() == 0) {} - char b = Serial.read(); + b = Serial.read(); } /* @@ -198,7 +198,7 @@ void loop() { Ac_Change_Air_Swing(1); break; case '3': // 1 : clean on, power on - if (b == '0' | b == '1') + if (b == '0' || b == '1') Ac_Air_Clean(b); break; case '4': diff --git a/lib/IRremoteESP8266/examples/LGACSend/platformio.ini b/lib/IRremoteESP8266/examples/LGACSend/platformio.ini new file mode 100644 index 0000000..eeb8d1f --- /dev/null +++ b/lib/IRremoteESP8266/examples/LGACSend/platformio.ini @@ -0,0 +1,17 @@ +[platformio] +lib_extra_dirs = ../../ +src_dir=. + +[common] +build_flags = +lib_deps_builtin = +lib_deps_external = + +[env:nodemcuv2] +platform = espressif8266 +framework = arduino +board = nodemcuv2 +build_flags = ${common.build_flags} +lib_deps = + ${common.lib_deps_builtin} + ${common.lib_deps_external} diff --git a/lib/IRremoteESP8266/examples/TurnOnArgoAC/TurnOnArgoAC.ino b/lib/IRremoteESP8266/examples/TurnOnArgoAC/TurnOnArgoAC.ino index 1f37ecb..3993d11 100644 --- a/lib/IRremoteESP8266/examples/TurnOnArgoAC/TurnOnArgoAC.ino +++ b/lib/IRremoteESP8266/examples/TurnOnArgoAC/TurnOnArgoAC.ino @@ -1,6 +1,6 @@ -/* Copyright 2017 crankyoldgit +/* Copyright 2017, 2018 crankyoldgit * An IR LED circuit *MUST* be connected to the ESP8266 on a pin -* as specified by IR_LED below. +* as specified by kIrLed below. * * TL;DR: The IR LED needs to be driven by a transistor for a good result. * @@ -30,11 +30,11 @@ #include #include -#define IR_LED 4 // ESP8266 GPIO pin to use. Recommended: 4 (D2). -IRArgoAC argoir(IR_LED); // Set the GPIO to be used to sending the message. +const uint16_t kIrLed = 4; // ESP8266 GPIO pin to use. Recommended: 4 (D2). +IRArgoAC ac(kIrLed); // Set the GPIO to be used to sending the message. void setup() { - argoir.begin(); + ac.begin(); Serial.begin(115200); } @@ -42,14 +42,14 @@ void loop() { Serial.println("Sending..."); // Set up what we want to send. See ir_Argo.cpp for all the options. - argoir.setPower(true); - argoir.setFan(ARGO_FAN_1); - argoir.setCoolMode(ARGO_COOL_AUTO); - argoir.setTemp(25); + ac.setPower(true); + ac.setFan(kArgoFan1); + ac.setCoolMode(kArgoCoolAuto); + ac.setTemp(25); #if SEND_ARGO // Now send the IR signal. - argoir.send(); + ac.send(); #else // SEND_ARGO Serial.println("Can't send because SEND_ARGO has been disabled."); #endif // SEND_ARGO diff --git a/lib/IRremoteESP8266/examples/TurnOnDaikinAC/TurnOnDaikinAC.ino b/lib/IRremoteESP8266/examples/TurnOnDaikinAC/TurnOnDaikinAC.ino index ac58721..b3ab757 100644 --- a/lib/IRremoteESP8266/examples/TurnOnDaikinAC/TurnOnDaikinAC.ino +++ b/lib/IRremoteESP8266/examples/TurnOnDaikinAC/TurnOnDaikinAC.ino @@ -1,7 +1,7 @@ /* Copyright 2017 sillyfrog * * An IR LED circuit *MUST* be connected to the ESP8266 on a pin -* as specified by IR_LED below. +* as specified by kIrLed below. * * TL;DR: The IR LED needs to be driven by a transistor for a good result. * @@ -31,11 +31,11 @@ #include #include -#define IR_LED 4 // ESP8266 GPIO pin to use. Recommended: 4 (D2). -IRDaikinESP daikinir(IR_LED); // Set the GPIO to be used to sending the message +const uint16_t kIrLed = 4; // ESP8266 GPIO pin to use. Recommended: 4 (D2). +IRDaikinESP ac(kIrLed); // Set the GPIO to be used to sending the message void setup() { - daikinir.begin(); + ac.begin(); Serial.begin(115200); } @@ -44,25 +44,25 @@ void loop() { Serial.println("Sending..."); // Set up what we want to send. See ir_Daikin.cpp for all the options. - daikinir.on(); - daikinir.setFan(1); - daikinir.setMode(DAIKIN_COOL); - daikinir.setTemp(25); - daikinir.setSwingVertical(false); - daikinir.setSwingHorizontal(false); + ac.on(); + ac.setFan(1); + ac.setMode(kDaikinCool); + ac.setTemp(25); + ac.setSwingVertical(false); + ac.setSwingHorizontal(false); // Set the current time to 1:33PM (13:33) // Time works in minutes past midnight - daikinir.setCurrentTime((13*60) + 33); - // Turn off about 1 hour later at 2:30PM (15:30) - daikinir.enableOffTimer((14*60) + 30); + ac.setCurrentTime(13 * 60 + 33); + // Turn off about 1 hour later at 2:30PM (14:30) + ac.enableOffTimer(14 * 60 + 30); // Display what we are going to send. - Serial.println(daikinir.toString()); + Serial.println(ac.toString()); // Now send the IR signal. #if SEND_DAIKIN - daikinir.send(); + ac.send(); #endif // SEND_DAIKIN delay(15000); diff --git a/lib/IRremoteESP8266/examples/TurnOnFujitsuAC/TurnOnFujitsuAC.ino b/lib/IRremoteESP8266/examples/TurnOnFujitsuAC/TurnOnFujitsuAC.ino index 86c6ab9..823a3f4 100644 --- a/lib/IRremoteESP8266/examples/TurnOnFujitsuAC/TurnOnFujitsuAC.ino +++ b/lib/IRremoteESP8266/examples/TurnOnFujitsuAC/TurnOnFujitsuAC.ino @@ -1,26 +1,28 @@ -// Copyright 2017 Jonny Graham +// Copyright 2017 Jonny Graham, 2018 David Conran +#ifndef UNIT_TEST +#include +#endif +#include #include #include -IRFujitsuAC fujitsu(5); // IR led controlled by Pin D1. +const uint16_t kIrLed = 4; // ESP8266 GPIO pin to use. Recommended: 4 (D2). +IRFujitsuAC ac(kIrLed); void printState() { // Display the settings. Serial.println("Fujitsu A/C remote is in the following state:"); - Serial.printf(" Command:%d, Mode: %d, Temp: %dC, Fan Speed: %d," \ - " Swing Mode: %d\n", - fujitsu.getCmd(), fujitsu.getMode(), fujitsu.getTemp(), - fujitsu.getFanSpeed(), fujitsu.getSwing()); + Serial.printf(" %s\n", ac.toString().c_str()); // Display the encoded IR sequence. - unsigned char* ir_code = fujitsu.getRaw(); + unsigned char* ir_code = ac.getRaw(); Serial.print("IR Code: 0x"); - for (uint8_t i = 0; i < fujitsu.getStateLength(); i++) + for (uint8_t i = 0; i < ac.getStateLength(); i++) Serial.printf("%02X", ir_code[i]); Serial.println(); } void setup() { - fujitsu.begin(); + ac.begin(); Serial.begin(115200); delay(200); @@ -28,18 +30,18 @@ void setup() { Serial.println("Default state of the remote."); printState(); Serial.println("Setting desired state for A/C."); - fujitsu.setCmd(FUJITSU_AC_CMD_TURN_ON); - fujitsu.setSwing(FUJITSU_AC_SWING_BOTH); - fujitsu.setMode(FUJITSU_AC_MODE_COOL); - fujitsu.setFanSpeed(FUJITSU_AC_FAN_HIGH); - fujitsu.setTemp(24); + ac.setCmd(kFujitsuAcCmdTurnOn); + ac.setSwing(kFujitsuAcSwingBoth); + ac.setMode(kFujitsuAcModeCool); + ac.setFanSpeed(kFujitsuAcFanHigh); + ac.setTemp(24); // 24C } void loop() { // Now send the IR signal. Serial.println("Sending IR command to A/C ..."); #if SEND_FUJITSU_AC - fujitsu.send(); + ac.send(); #else // SEND_FUJITSU_AC Serial.println("Can't send because SEND_FUJITSU_AC has been disabled."); #endif // SEND_FUJITSU_AC diff --git a/lib/IRremoteESP8266/examples/TurnOnKelvinatorAC/TurnOnKelvinatorAC.ino b/lib/IRremoteESP8266/examples/TurnOnKelvinatorAC/TurnOnKelvinatorAC.ino index 069cd2d..b9b7007 100644 --- a/lib/IRremoteESP8266/examples/TurnOnKelvinatorAC/TurnOnKelvinatorAC.ino +++ b/lib/IRremoteESP8266/examples/TurnOnKelvinatorAC/TurnOnKelvinatorAC.ino @@ -1,7 +1,7 @@ -/* Copyright 2016 David Conran +/* Copyright 2016, 2018 David Conran * * An IR LED circuit *MUST* be connected to the ESP8266 on a pin -* as specified by IR_LED below. +* as specified by kIrLed below. * * TL;DR: The IR LED needs to be driven by a transistor for a good result. * @@ -30,30 +30,23 @@ #include #include -#define IR_LED 4 // ESP8266 GPIO pin to use. Recommended: 4 (D2). -IRKelvinatorAC kelvir(IR_LED); // Set the GPIO to be used for sending messages. +const uint16_t kIrLed = 4; // ESP8266 GPIO pin to use. Recommended: 4 (D2). +IRKelvinatorAC ac(kIrLed); // Set the GPIO to be used for sending messages. void printState() { // Display the settings. Serial.println("Kelvinator A/C remote is in the following state:"); - Serial.printf(" Basic\n Power: %d, Mode: %d, Temp: %dC, Fan Speed: %d\n", - kelvir.getPower(), kelvir.getMode(), kelvir.getTemp(), - kelvir.getFan()); - Serial.printf(" Options\n X-Fan: %d, Light: %d, Ion Filter: %d\n", - kelvir.getXFan(), kelvir.getLight(), kelvir.getIonFilter()); - Serial.printf(" Swing (V): %d, Swing (H): %d, Turbo: %d, Quiet: %d\n", - kelvir.getSwingVertical(), kelvir.getSwingHorizontal(), - kelvir.getTurbo(), kelvir.getQuiet()); + Serial.printf(" %s\n", ac.toString().c_str()); // Display the encoded IR sequence. - unsigned char* ir_code = kelvir.getRaw(); + unsigned char* ir_code = ac.getRaw(); Serial.print("IR Code: 0x"); - for (uint8_t i = 0; i < KELVINATOR_STATE_LENGTH; i++) + for (uint8_t i = 0; i < kKelvinatorStateLength; i++) Serial.printf("%02X", ir_code[i]); Serial.println(); } void setup() { - kelvir.begin(); + ac.begin(); Serial.begin(115200); delay(200); @@ -62,22 +55,22 @@ void setup() { Serial.println("Default state of the remote."); printState(); Serial.println("Setting desired state for A/C."); - kelvir.on(); - kelvir.setFan(1); - kelvir.setMode(KELVINATOR_COOL); - kelvir.setTemp(26); - kelvir.setSwingVertical(false); - kelvir.setSwingHorizontal(true); - kelvir.setXFan(true); - kelvir.setIonFilter(false); - kelvir.setLight(true); + ac.on(); + ac.setFan(1); + ac.setMode(kKelvinatorCool); + ac.setTemp(26); + ac.setSwingVertical(false); + ac.setSwingHorizontal(true); + ac.setXFan(true); + ac.setIonFilter(false); + ac.setLight(true); } void loop() { // Now send the IR signal. #if SEND_KELVINATOR Serial.println("Sending IR command to A/C ..."); - kelvir.send(); + ac.send(); #endif // SEND_KELVINATOR printState(); delay(5000); diff --git a/lib/IRremoteESP8266/examples/TurnOnMitsubishiAC/TurnOnMitsubishiAC.ino b/lib/IRremoteESP8266/examples/TurnOnMitsubishiAC/TurnOnMitsubishiAC.ino index 598a91d..e719af6 100644 --- a/lib/IRremoteESP8266/examples/TurnOnMitsubishiAC/TurnOnMitsubishiAC.ino +++ b/lib/IRremoteESP8266/examples/TurnOnMitsubishiAC/TurnOnMitsubishiAC.ino @@ -1,7 +1,7 @@ -/* Copyright 2017 David Conran +/* Copyright 2017, 2018 David Conran * * An IR LED circuit *MUST* be connected to the ESP8266 on a pin -* as specified by IR_LED below. +* as specified by kIrLed below. * * TL;DR: The IR LED needs to be driven by a transistor for a good result. * @@ -30,26 +30,23 @@ #include #include -#define IR_LED 4 // ESP8266 GPIO pin to use. Recommended: 4 (D2). -IRMitsubishiAC mitsubir(IR_LED); // Set the GPIO used for sending messages. +const uint16_t kIrLed = 4; // ESP8266 GPIO pin to use. Recommended: 4 (D2). +IRMitsubishiAC ac(kIrLed); // Set the GPIO used for sending messages. void printState() { // Display the settings. Serial.println("Mitsubishi A/C remote is in the following state:"); - Serial.printf(" Power: %d, Mode: %d, Temp: %dC, Fan Speed: %d," \ - " Vane Mode: %d\n", - mitsubir.getPower(), mitsubir.getMode(), mitsubir.getTemp(), - mitsubir.getFan(), mitsubir.getVane()); + Serial.printf(" %s\n", ac.toString().c_str()); // Display the encoded IR sequence. - unsigned char* ir_code = mitsubir.getRaw(); + unsigned char* ir_code = ac.getRaw(); Serial.print("IR Code: 0x"); - for (uint8_t i = 0; i < MITSUBISHI_AC_STATE_LENGTH; i++) + for (uint8_t i = 0; i < kMitsubishiACStateLength; i++) Serial.printf("%02X", ir_code[i]); Serial.println(); } void setup() { - mitsubir.begin(); + ac.begin(); Serial.begin(115200); delay(200); @@ -57,18 +54,18 @@ void setup() { Serial.println("Default state of the remote."); printState(); Serial.println("Setting desired state for A/C."); - mitsubir.on(); - mitsubir.setFan(1); - mitsubir.setMode(MITSUBISHI_AC_COOL); - mitsubir.setTemp(26); - mitsubir.setVane(MITSUBISHI_AC_VANE_AUTO); + ac.on(); + ac.setFan(1); + ac.setMode(kMitsubishiAcCool); + ac.setTemp(26); + ac.setVane(kMitsubishiAcVaneAuto); } void loop() { // Now send the IR signal. #if SEND_MITSUBISHI_AC Serial.println("Sending IR command to A/C ..."); - mitsubir.send(); + ac.send(); #endif // SEND_MITSUBISHI_AC printState(); delay(5000); diff --git a/lib/IRremoteESP8266/examples/TurnOnToshibaAC/TurnOnToshibaAC.ino b/lib/IRremoteESP8266/examples/TurnOnToshibaAC/TurnOnToshibaAC.ino index 89e5125..d781780 100644 --- a/lib/IRremoteESP8266/examples/TurnOnToshibaAC/TurnOnToshibaAC.ino +++ b/lib/IRremoteESP8266/examples/TurnOnToshibaAC/TurnOnToshibaAC.ino @@ -1,7 +1,7 @@ -/* Copyright 2017 David Conran +/* Copyright 2017, 2018 David Conran * * An IR LED circuit *MUST* be connected to the ESP8266 on a pin -* as specified by IR_LED below. +* as specified by kIrLed below. * * TL;DR: The IR LED needs to be driven by a transistor for a good result. * @@ -30,25 +30,23 @@ #include #include -#define IR_LED 4 // ESP8266 GPIO pin to use. Recommended: 4 (D2). -IRToshibaAC toshibair(IR_LED); // Set the GPIO to be used for sending messages. +const uint16_t kIrLed = 4; // ESP8266 GPIO pin to use. Recommended: 4 (D2). +IRToshibaAC ac(kIrLed); // Set the GPIO to be used for sending messages. void printState() { // Display the settings. Serial.println("Toshiba A/C remote is in the following state:"); - Serial.printf(" Power: %d, Mode: %d, Temp: %dC, Fan Speed: %d\n", - toshibair.getPower(), toshibair.getMode(), toshibair.getTemp(), - toshibair.getFan()); + Serial.printf(" %s\n", ac.toString().c_str()); // Display the encoded IR sequence. - unsigned char* ir_code = toshibair.getRaw(); + unsigned char* ir_code = ac.getRaw(); Serial.print("IR Code: 0x"); - for (uint8_t i = 0; i < TOSHIBA_AC_STATE_LENGTH; i++) + for (uint8_t i = 0; i < kToshibaACStateLength; i++) Serial.printf("%02X", ir_code[i]); Serial.println(); } void setup() { - toshibair.begin(); + ac.begin(); Serial.begin(115200); delay(200); @@ -56,17 +54,17 @@ void setup() { Serial.println("Default state of the remote."); printState(); Serial.println("Setting desired state for A/C."); - toshibair.on(); - toshibair.setFan(1); - toshibair.setMode(TOSHIBA_AC_COOL); - toshibair.setTemp(26); + ac.on(); + ac.setFan(1); + ac.setMode(kToshibaAcCool); + ac.setTemp(26); } void loop() { // Now send the IR signal. #if SEND_TOSHIBA_AC Serial.println("Sending IR command to A/C ..."); - toshibair.send(); + ac.send(); #endif // SEND_TOSHIBA_AC printState(); delay(5000); diff --git a/lib/IRremoteESP8266/examples/TurnOnTrotecAC/TurnOnTrotecAC.ino b/lib/IRremoteESP8266/examples/TurnOnTrotecAC/TurnOnTrotecAC.ino index 28bd3f3..b7881ee 100644 --- a/lib/IRremoteESP8266/examples/TurnOnTrotecAC/TurnOnTrotecAC.ino +++ b/lib/IRremoteESP8266/examples/TurnOnTrotecAC/TurnOnTrotecAC.ino @@ -1,6 +1,6 @@ /* Copyright 2017 stufisher * An IR LED circuit *MUST* be connected to the ESP8266 on a pin -* as specified by IR_LED below. +* as specified by kIrLed below. * * TL;DR: The IR LED needs to be driven by a transistor for a good result. * @@ -30,11 +30,11 @@ #include #include -#define IR_LED 4 // ESP8266 GPIO pin to use. Recommended: 4 (D2). -IRTrotecESP trotecir(IR_LED); // Set the GPIO to be used for sending messages. +const uint16_t kIrLed = 4; // ESP8266 GPIO pin to use. Recommended: 4 (D2). +IRTrotecESP ac(kIrLed); // Set the GPIO to be used for sending messages. void setup() { - trotecir.begin(); + ac.begin(); Serial.begin(115200); } @@ -42,14 +42,14 @@ void loop() { Serial.println("Sending..."); // Set up what we want to send. See ir_Trotec.cpp for all the options. - trotecir.setPower(true); - trotecir.setSpeed(TROTEC_FAN_LOW); - trotecir.setMode(TROTEC_COOL); - trotecir.setTemp(25); + ac.setPower(true); + ac.setSpeed(kTrotecFanLow); + ac.setMode(kTrotecCool); + ac.setTemp(25); // Now send the IR signal. #if SEND_TROTEC - trotecir.send(); + ac.send(); #else // SEND_TROTEC Serial.println("Can't send because SEND_TROTEC has been disabled."); #endif // SEND_TROTEC diff --git a/lib/IRremoteESP8266/keywords.txt b/lib/IRremoteESP8266/keywords.txt index 6f01f11..bf72a58 100644 --- a/lib/IRremoteESP8266/keywords.txt +++ b/lib/IRremoteESP8266/keywords.txt @@ -21,15 +21,23 @@ ####################################### IRArgoAC KEYWORD1 +IRCoolixAC KEYWORD1 +IRDaikin2 KEYWORD1 IRDaikinESP KEYWORD1 IRFujitsuAC KEYWORD1 IRGreeAC KEYWORD1 IRHaierAC KEYWORD1 +IRHaierACYRW02 KEYWORD1 +IRHitachiAc KEYWORD1 IRKelvinatorAC KEYWORD1 IRMideaAC KEYWORD1 IRMitsubishiAC KEYWORD1 +IRPanasonicAc KEYWORD1 +IRSamsungAc KEYWORD1 IRToshibaAC KEYWORD1 IRTrotecESP KEYWORD1 +IRVestelAC KEYWORD1 +IRWhirlpoolAc KEYWORD1 IRrecv KEYWORD1 IRsend KEYWORD1 IRtimer KEYWORD1 @@ -42,6 +50,8 @@ match_result_t KEYWORD1 ####################################### _delayMicroseconds KEYWORD2 +_setMode KEYWORD2 +_setTemp KEYWORD2 add KEYWORD2 addbit KEYWORD2 begin KEYWORD2 @@ -51,60 +61,82 @@ calcBlockChecksum KEYWORD2 calcChecksum KEYWORD2 calcLGChecksum KEYWORD2 calcUSecPeriod KEYWORD2 +calculateChecksum KEYWORD2 calibrate KEYWORD2 +cancelOffTimer KEYWORD2 +cancelOnTimer KEYWORD2 cancelTimers KEYWORD2 checkheader KEYWORD2 checksum KEYWORD2 clearBit KEYWORD2 +clearOnTimerFlag KEYWORD2 +clearSensorTemp KEYWORD2 +clearSleepTimerFlag KEYWORD2 compare KEYWORD2 copyIrParams KEYWORD2 +countBits KEYWORD2 decode KEYWORD2 decodeAiwaRCT501 KEYWORD2 decodeCOOLIX KEYWORD2 decodeCarrierAC KEYWORD2 decodeDISH KEYWORD2 decodeDaikin KEYWORD2 +decodeDaikin2 KEYWORD2 decodeDenon KEYWORD2 +decodeElectraAC KEYWORD2 decodeFujitsuAC KEYWORD2 decodeGICable KEYWORD2 decodeGree KEYWORD2 decodeHaierAC KEYWORD2 +decodeHaierACYRW02 KEYWORD2 decodeHash KEYWORD2 decodeHitachiAC KEYWORD2 decodeJVC KEYWORD2 decodeKelvinator KEYWORD2 decodeLG KEYWORD2 decodeLasertag KEYWORD2 +decodeLutron KEYWORD2 +decodeMWM KEYWORD2 decodeMagiQuest KEYWORD2 decodeMidea KEYWORD2 decodeMitsubishi KEYWORD2 decodeMitsubishi2 KEYWORD2 +decodeMitsubishiAC KEYWORD2 decodeNEC KEYWORD2 decodeNikai KEYWORD2 decodePanasonic KEYWORD2 +decodePanasonicAC KEYWORD2 +decodePioneer KEYWORD2 decodeRC5 KEYWORD2 decodeRC6 KEYWORD2 decodeRCMM KEYWORD2 decodeSAMSUNG KEYWORD2 +decodeSamsungAC KEYWORD2 decodeSanyo KEYWORD2 decodeSanyoLC7461 KEYWORD2 decodeSharp KEYWORD2 decodeSony KEYWORD2 decodeToshibaAC KEYWORD2 +decodeVestelAC KEYWORD2 +decodeWhirlpoolAC KEYWORD2 decodeWhynter KEYWORD2 disableIRIn KEYWORD2 disableOffTimer KEYWORD2 disableOnTimer KEYWORD2 +disableSleepTimer KEYWORD2 elapsed KEYWORD2 enableIRIn KEYWORD2 enableIROut KEYWORD2 enableOffTimer KEYWORD2 enableOnTimer KEYWORD2 +enableSleepTimer KEYWORD2 +enableTimer KEYWORD2 encodeJVC KEYWORD2 encodeLG KEYWORD2 encodeMagiQuest KEYWORD2 encodeNEC KEYWORD2 encodePanasonic KEYWORD2 +encodePioneer KEYWORD2 encodeRC5 KEYWORD2 encodeRC5X KEYWORD2 encodeRC6 KEYWORD2 @@ -112,9 +144,15 @@ encodeSAMSUNG KEYWORD2 encodeSanyoLC7461 KEYWORD2 encodeSharp KEYWORD2 encodeSony KEYWORD2 +encodeTime KEYWORD2 +fixChecksum KEYWORD2 fixup KEYWORD2 +getBeep KEYWORD2 getBit KEYWORD2 getBufSize KEYWORD2 +getButton KEYWORD2 +getClean KEYWORD2 +getClock KEYWORD2 getCmd KEYWORD2 getCommand KEYWORD2 getCoolMode KEYWORD2 @@ -123,12 +161,17 @@ getCurrTime KEYWORD2 getCurrentTime KEYWORD2 getEcono KEYWORD2 getEye KEYWORD2 +getEyeAuto KEYWORD2 getFan KEYWORD2 getFanSpeed KEYWORD2 getFlap KEYWORD2 +getFreshAir KEYWORD2 +getFreshAirHigh KEYWORD2 getHealth KEYWORD2 getHeatMode KEYWORD2 +getIon KEYWORD2 getIonFilter KEYWORD2 +getLed KEYWORD2 getLight KEYWORD2 getMax KEYWORD2 getMode KEYWORD2 @@ -141,28 +184,43 @@ getOnTime KEYWORD2 getOnTimer KEYWORD2 getOnTimerEnabled KEYWORD2 getPower KEYWORD2 +getPowerToggle KEYWORD2 getPowerful KEYWORD2 +getPurify KEYWORD2 getQuiet KEYWORD2 getRClevel KEYWORD2 getRaw KEYWORD2 getSensor KEYWORD2 +getSensorTemp KEYWORD2 getSleep KEYWORD2 +getSleepTime KEYWORD2 +getSleepTimerEnabled KEYWORD2 getSpeed KEYWORD2 +getStartClock KEYWORD2 getStateLength KEYWORD2 +getStopClock KEYWORD2 +getSuper KEYWORD2 getSwing KEYWORD2 getSwingHorizontal KEYWORD2 getSwingVertical KEYWORD2 getSwingVerticalAuto KEYWORD2 getSwingVerticalPosition KEYWORD2 getTemp KEYWORD2 +getTempOffset KEYWORD2 +getTempRaw KEYWORD2 getTime KEYWORD2 getTimer KEYWORD2 getTurbo KEYWORD2 getVane KEYWORD2 getXFan KEYWORD2 +getZoneFollow KEYWORD2 getiFeel KEYWORD2 hasACState KEYWORD2 invertBits KEYWORD2 +isOffTimerEnabled KEYWORD2 +isOnTimerEnabled KEYWORD2 +isTimeCommand KEYWORD2 +isTimerEnabled KEYWORD2 ledOff KEYWORD2 ledOn KEYWORD2 mark KEYWORD2 @@ -177,6 +235,7 @@ printState KEYWORD2 readbits KEYWORD2 renderTime KEYWORD2 reset KEYWORD2 +resultToHexidecimal KEYWORD2 resultToHumanReadableBasic KEYWORD2 resultToSourceCode KEYWORD2 resultToTimingInfo KEYWORD2 @@ -189,21 +248,28 @@ sendCOOLIX KEYWORD2 sendCarrierAC KEYWORD2 sendDISH KEYWORD2 sendDaikin KEYWORD2 +sendDaikin2 KEYWORD2 sendData KEYWORD2 sendDenon KEYWORD2 +sendElectraAC KEYWORD2 +sendExtended KEYWORD2 sendFujitsuAC KEYWORD2 sendGC KEYWORD2 sendGICable KEYWORD2 sendGeneric KEYWORD2 sendGree KEYWORD2 sendHaierAC KEYWORD2 +sendHaierACYRW02 KEYWORD2 sendHitachiAC KEYWORD2 sendHitachiAC1 KEYWORD2 sendHitachiAC2 KEYWORD2 sendJVC KEYWORD2 sendKelvinator KEYWORD2 sendLG KEYWORD2 +sendLG2 KEYWORD2 sendLasertag KEYWORD2 +sendLutron KEYWORD2 +sendMWM KEYWORD2 sendMagiQuest KEYWORD2 sendMidea KEYWORD2 sendMitsubishi KEYWORD2 @@ -213,12 +279,15 @@ sendNEC KEYWORD2 sendNikai KEYWORD2 sendPanasonic KEYWORD2 sendPanasonic64 KEYWORD2 +sendPanasonicAC KEYWORD2 +sendPioneer KEYWORD2 sendPronto KEYWORD2 sendRC5 KEYWORD2 sendRC6 KEYWORD2 sendRCMM KEYWORD2 sendRaw KEYWORD2 sendSAMSUNG KEYWORD2 +sendSamsungAC KEYWORD2 sendSanyoLC7461 KEYWORD2 sendSharp KEYWORD2 sendSharpRaw KEYWORD2 @@ -226,9 +295,16 @@ sendSherwood KEYWORD2 sendSony KEYWORD2 sendToshibaAC KEYWORD2 sendTrotec KEYWORD2 +sendVestelAC KEYWORD2 +sendWhirlpoolAC KEYWORD2 sendWhynter KEYWORD2 serialPrintUint64 KEYWORD2 +setAuto KEYWORD2 +setBeep KEYWORD2 setBit KEYWORD2 +setButton KEYWORD2 +setClean KEYWORD2 +setClock KEYWORD2 setCmd KEYWORD2 setCommand KEYWORD2 setCoolMode KEYWORD2 @@ -236,12 +312,17 @@ setCurrTime KEYWORD2 setCurrentTime KEYWORD2 setEcono KEYWORD2 setEye KEYWORD2 +setEyeAuto KEYWORD2 setFan KEYWORD2 setFanSpeed KEYWORD2 setFlap KEYWORD2 +setFreshAir KEYWORD2 +setFreshAirHigh KEYWORD2 setHealth KEYWORD2 setHeatMode KEYWORD2 +setIon KEYWORD2 setIonFilter KEYWORD2 +setLed KEYWORD2 setLight KEYWORD2 setMax KEYWORD2 setMode KEYWORD2 @@ -251,23 +332,32 @@ setNight KEYWORD2 setOffTimer KEYWORD2 setOnTimer KEYWORD2 setPower KEYWORD2 +setPowerToggle KEYWORD2 setPowerful KEYWORD2 +setPurify KEYWORD2 setQuiet KEYWORD2 setRaw KEYWORD2 setRoomTemp KEYWORD2 setSensor KEYWORD2 +setSensorTemp KEYWORD2 +setSensorTempRaw KEYWORD2 setSleep KEYWORD2 setSpeed KEYWORD2 +setStartClock KEYWORD2 +setStopClock KEYWORD2 +setSuper KEYWORD2 setSwing KEYWORD2 setSwingHorizontal KEYWORD2 setSwingVertical KEYWORD2 setTemp KEYWORD2 +setTempRaw KEYWORD2 setTime KEYWORD2 setTimer KEYWORD2 setTurbo KEYWORD2 setUnknownThreshold KEYWORD2 setVane KEYWORD2 setXFan KEYWORD2 +setZoneFollow KEYWORD2 setiFeel KEYWORD2 space KEYWORD2 stateReset KEYWORD2 @@ -283,6 +373,7 @@ toggleRC6 KEYWORD2 typeToString KEYWORD2 uint64ToString KEYWORD2 validChecksum KEYWORD2 +xorBytes KEYWORD2 ####################################### # Constants (LITERAL1) @@ -290,15 +381,9 @@ validChecksum KEYWORD2 AIWA_RC_T501 LITERAL1 AIWA_RC_T501_BITS LITERAL1 -AIWA_RC_T501_MIN_REPEAT LITERAL1 -AIWA_RC_T501_POST_BITS LITERAL1 -AIWA_RC_T501_POST_DATA LITERAL1 -AIWA_RC_T501_PRE_BITS LITERAL1 -AIWA_RC_T501_PRE_DATA LITERAL1 ALLOW_DELAY_CALLS LITERAL1 ARDB1 LITERAL1 ARGO LITERAL1 -ARGO_BIT_MARK LITERAL1 ARGO_COMMAND_LENGTH LITERAL1 ARGO_COOL_AUTO LITERAL1 ARGO_COOL_OFF LITERAL1 @@ -316,65 +401,21 @@ ARGO_FLAP_5 LITERAL1 ARGO_FLAP_6 LITERAL1 ARGO_FLAP_AUTO LITERAL1 ARGO_FLAP_FULL LITERAL1 -ARGO_HDR_MARK LITERAL1 -ARGO_HDR_SPACE LITERAL1 ARGO_HEAT_AUTO LITERAL1 ARGO_HEAT_BLINK LITERAL1 ARGO_HEAT_ON LITERAL1 ARGO_MAX_TEMP LITERAL1 ARGO_MIN_TEMP LITERAL1 -ARGO_ONE_SPACE LITERAL1 -ARGO_ZERO_SPACE LITERAL1 ARRAH2E LITERAL1 CARRIER_AC LITERAL1 CARRIER_AC_BITS LITERAL1 -CARRIER_AC_BIT_MARK LITERAL1 -CARRIER_AC_GAP LITERAL1 -CARRIER_AC_HDR_MARK LITERAL1 -CARRIER_AC_HDR_SPACE LITERAL1 -CARRIER_AC_MIN_REPEAT LITERAL1 -CARRIER_AC_ONE_SPACE LITERAL1 -CARRIER_AC_ZERO_SPACE LITERAL1 COOLIX LITERAL1 COOLIX_BITS LITERAL1 -COOLIX_BIT_MARK LITERAL1 -COOLIX_BIT_MARK_TICKS LITERAL1 -COOLIX_HDR_MARK LITERAL1 -COOLIX_HDR_MARK_TICKS LITERAL1 -COOLIX_HDR_SPACE LITERAL1 -COOLIX_HDR_SPACE_TICKS LITERAL1 -COOLIX_MIN_GAP_TICKS LITERAL1 -COOLIX_ONE_SPACE LITERAL1 -COOLIX_ONE_SPACE_TICKS LITERAL1 -COOLIX_TICK LITERAL1 -COOLIX_ZERO_SPACE LITERAL1 -COOLIX_ZERO_SPACE_TICKS LITERAL1 DAIKIN LITERAL1 +DAIKIN2 LITERAL1 DAIKIN_AUTO LITERAL1 -DAIKIN_BITS LITERAL1 -DAIKIN_BIT_ECONO LITERAL1 -DAIKIN_BIT_EYE LITERAL1 -DAIKIN_BIT_MARK LITERAL1 -DAIKIN_BIT_MOLD LITERAL1 -DAIKIN_BIT_OFF_TIMER LITERAL1 -DAIKIN_BIT_ON_TIMER LITERAL1 -DAIKIN_BIT_POWER LITERAL1 -DAIKIN_BIT_POWERFUL LITERAL1 -DAIKIN_BIT_SENSOR LITERAL1 -DAIKIN_BIT_SILENT LITERAL1 -DAIKIN_BYTE_ECONO LITERAL1 -DAIKIN_BYTE_EYE LITERAL1 -DAIKIN_BYTE_MOLD LITERAL1 -DAIKIN_BYTE_OFF_TIMER LITERAL1 -DAIKIN_BYTE_ON_TIMER LITERAL1 -DAIKIN_BYTE_POWER LITERAL1 -DAIKIN_BYTE_POWERFUL LITERAL1 -DAIKIN_BYTE_SENSOR LITERAL1 -DAIKIN_BYTE_SILENT LITERAL1 DAIKIN_COMMAND_LENGTH LITERAL1 DAIKIN_COOL LITERAL1 -DAIKIN_CURBIT LITERAL1 -DAIKIN_CURINDEX LITERAL1 DAIKIN_DEBUG LITERAL1 DAIKIN_DRY LITERAL1 DAIKIN_FAN LITERAL1 @@ -382,31 +423,25 @@ DAIKIN_FAN_AUTO LITERAL1 DAIKIN_FAN_MAX LITERAL1 DAIKIN_FAN_MIN LITERAL1 DAIKIN_FAN_QUIET LITERAL1 -DAIKIN_FIRST_HEADER64 LITERAL1 -DAIKIN_GAP LITERAL1 -DAIKIN_HDR_MARK LITERAL1 -DAIKIN_HDR_SPACE LITERAL1 DAIKIN_HEAT LITERAL1 -DAIKIN_MARK_EXCESS LITERAL1 DAIKIN_MAX_TEMP LITERAL1 DAIKIN_MIN_TEMP LITERAL1 -DAIKIN_ONE_SPACE LITERAL1 -DAIKIN_RAW_BITS LITERAL1 -DAIKIN_TOLERANCE LITERAL1 -DAIKIN_ZERO_SPACE LITERAL1 DECODE_AC LITERAL1 DECODE_AIWA_RC_T501 LITERAL1 DECODE_ARGO LITERAL1 DECODE_CARRIER_AC LITERAL1 DECODE_COOLIX LITERAL1 DECODE_DAIKIN LITERAL1 +DECODE_DAIKIN2 LITERAL1 DECODE_DENON LITERAL1 DECODE_DISH LITERAL1 +DECODE_ELECTRA_AC LITERAL1 DECODE_FUJITSU_AC LITERAL1 DECODE_GICABLE LITERAL1 DECODE_GLOBALCACHE LITERAL1 DECODE_GREE LITERAL1 DECODE_HAIER_AC LITERAL1 +DECODE_HAIER_AC_YRW02 LITERAL1 DECODE_HASH LITERAL1 DECODE_HITACHI_AC LITERAL1 DECODE_HITACHI_AC1 LITERAL1 @@ -415,69 +450,44 @@ DECODE_JVC LITERAL1 DECODE_KELVINATOR LITERAL1 DECODE_LASERTAG LITERAL1 DECODE_LG LITERAL1 +DECODE_LUTRON LITERAL1 DECODE_MAGIQUEST LITERAL1 DECODE_MIDEA LITERAL1 DECODE_MITSUBISHI LITERAL1 DECODE_MITSUBISHI2 LITERAL1 DECODE_MITSUBISHI_AC LITERAL1 +DECODE_MWM LITERAL1 DECODE_NEC LITERAL1 DECODE_NIKAI LITERAL1 DECODE_PANASONIC LITERAL1 +DECODE_PANASONIC_AC LITERAL1 +DECODE_PIONEER LITERAL1 DECODE_PRONTO LITERAL1 DECODE_RC5 LITERAL1 DECODE_RC6 LITERAL1 DECODE_RCMM LITERAL1 DECODE_SAMSUNG LITERAL1 +DECODE_SAMSUNG_AC LITERAL1 DECODE_SANYO LITERAL1 DECODE_SHARP LITERAL1 DECODE_SHERWOOD LITERAL1 DECODE_SONY LITERAL1 DECODE_TOSHIBA_AC LITERAL1 DECODE_TROTEC LITERAL1 +DECODE_VESTEL_AC LITERAL1 +DECODE_WHIRLPOOL_AC LITERAL1 DECODE_WHYNTER LITERAL1 DENON LITERAL1 DENON_48_BITS LITERAL1 DENON_BITS LITERAL1 -DENON_BIT_MARK LITERAL1 -DENON_BIT_MARK_TICKS LITERAL1 -DENON_HDR_MARK LITERAL1 -DENON_HDR_MARK_TICKS LITERAL1 -DENON_HDR_SPACE LITERAL1 -DENON_HDR_SPACE_TICKS LITERAL1 DENON_LEGACY_BITS LITERAL1 -DENON_MANUFACTURER LITERAL1 -DENON_MIN_COMMAND_LENGTH LITERAL1 -DENON_MIN_COMMAND_LENGTH_TICKS LITERAL1 -DENON_MIN_GAP_TICKS LITERAL1 -DENON_ONE_SPACE LITERAL1 -DENON_ONE_SPACE_TICKS LITERAL1 -DENON_TICK LITERAL1 -DENON_ZERO_SPACE LITERAL1 -DENON_ZERO_SPACE_TICKS LITERAL1 +DG11J13A LITERAL1 +DG11J191 LITERAL1 DISH LITERAL1 DISH_BITS LITERAL1 -DISH_BIT_MARK LITERAL1 -DISH_BIT_MARK_TICKS LITERAL1 -DISH_HDR_MARK LITERAL1 -DISH_HDR_MARK_TICKS LITERAL1 -DISH_HDR_SPACE LITERAL1 -DISH_HDR_SPACE_TICKS LITERAL1 -DISH_MIN_REPEAT LITERAL1 -DISH_ONE_SPACE LITERAL1 -DISH_ONE_SPACE_TICKS LITERAL1 -DISH_RPT_SPACE LITERAL1 -DISH_RPT_SPACE_TICKS LITERAL1 -DISH_TICK LITERAL1 -DISH_ZERO_SPACE LITERAL1 -DISH_ZERO_SPACE_TICKS LITERAL1 -DUTY_DEFAULT LITERAL1 -DUTY_MAX LITERAL1 -FNV_BASIS_32 LITERAL1 -FNV_PRIME_32 LITERAL1 -FOOTER LITERAL1 +ELECTRA_AC LITERAL1 FUJITSU_AC LITERAL1 FUJITSU_AC_BITS LITERAL1 -FUJITSU_AC_BIT_MARK LITERAL1 FUJITSU_AC_CMD_STAY_ON LITERAL1 FUJITSU_AC_CMD_STEP_HORIZ LITERAL1 FUJITSU_AC_CMD_STEP_VERT LITERAL1 @@ -488,11 +498,8 @@ FUJITSU_AC_FAN_HIGH LITERAL1 FUJITSU_AC_FAN_LOW LITERAL1 FUJITSU_AC_FAN_MED LITERAL1 FUJITSU_AC_FAN_QUIET LITERAL1 -FUJITSU_AC_HDR_MARK LITERAL1 -FUJITSU_AC_HDR_SPACE LITERAL1 FUJITSU_AC_MAX_TEMP LITERAL1 FUJITSU_AC_MIN_BITS LITERAL1 -FUJITSU_AC_MIN_GAP LITERAL1 FUJITSU_AC_MIN_REPEAT LITERAL1 FUJITSU_AC_MIN_TEMP LITERAL1 FUJITSU_AC_MODE_AUTO LITERAL1 @@ -500,57 +507,26 @@ FUJITSU_AC_MODE_COOL LITERAL1 FUJITSU_AC_MODE_DRY LITERAL1 FUJITSU_AC_MODE_FAN LITERAL1 FUJITSU_AC_MODE_HEAT LITERAL1 -FUJITSU_AC_ONE_SPACE LITERAL1 FUJITSU_AC_STATE_LENGTH LITERAL1 FUJITSU_AC_STATE_LENGTH_SHORT LITERAL1 FUJITSU_AC_SWING_BOTH LITERAL1 FUJITSU_AC_SWING_HORIZ LITERAL1 FUJITSU_AC_SWING_OFF LITERAL1 FUJITSU_AC_SWING_VERT LITERAL1 -FUJITSU_AC_ZERO_SPACE LITERAL1 GICABLE LITERAL1 GICABLE_BITS LITERAL1 -GICABLE_BIT_MARK LITERAL1 -GICABLE_HDR_MARK LITERAL1 -GICABLE_HDR_SPACE LITERAL1 -GICABLE_MIN_COMMAND_LENGTH LITERAL1 -GICABLE_MIN_GAP LITERAL1 -GICABLE_MIN_REPEAT LITERAL1 -GICABLE_ONE_SPACE LITERAL1 -GICABLE_RPT_SPACE LITERAL1 -GICABLE_ZERO_SPACE LITERAL1 GLOBALCACHE LITERAL1 -GLOBALCACHE_FREQ_INDEX LITERAL1 -GLOBALCACHE_MIN_USEC LITERAL1 -GLOBALCACHE_RPT_INDEX LITERAL1 -GLOBALCACHE_RPT_START_INDEX LITERAL1 -GLOBALCACHE_START_INDEX LITERAL1 GREE LITERAL1 GREE_AUTO LITERAL1 -GREE_BITS LITERAL1 -GREE_BIT_MARK LITERAL1 -GREE_BLOCK_FOOTER LITERAL1 -GREE_BLOCK_FOOTER_BITS LITERAL1 GREE_COOL LITERAL1 GREE_DRY LITERAL1 GREE_FAN LITERAL1 -GREE_FAN_MASK LITERAL1 GREE_FAN_MAX LITERAL1 -GREE_HDR_MARK LITERAL1 -GREE_HDR_SPACE LITERAL1 GREE_HEAT LITERAL1 -GREE_LIGHT_MASK LITERAL1 GREE_MAX_TEMP LITERAL1 GREE_MIN_TEMP LITERAL1 -GREE_MODE_MASK LITERAL1 -GREE_MSG_SPACE LITERAL1 -GREE_ONE_SPACE LITERAL1 -GREE_POWER1_MASK LITERAL1 -GREE_POWER2_MASK LITERAL1 -GREE_SLEEP_MASK LITERAL1 GREE_STATE_LENGTH LITERAL1 GREE_SWING_AUTO LITERAL1 -GREE_SWING_AUTO_MASK LITERAL1 GREE_SWING_DOWN LITERAL1 GREE_SWING_DOWN_AUTO LITERAL1 GREE_SWING_LAST_POS LITERAL1 @@ -558,16 +534,10 @@ GREE_SWING_MIDDLE LITERAL1 GREE_SWING_MIDDLE_AUTO LITERAL1 GREE_SWING_MIDDLE_DOWN LITERAL1 GREE_SWING_MIDDLE_UP LITERAL1 -GREE_SWING_POS_MASK LITERAL1 GREE_SWING_UP LITERAL1 GREE_SWING_UP_AUTO LITERAL1 -GREE_TURBO_MASK LITERAL1 -GREE_XFAN_MASK LITERAL1 -GREE_ZERO_SPACE LITERAL1 HAIER_AC LITERAL1 HAIER_AC_AUTO LITERAL1 -HAIER_AC_BITS LITERAL1 -HAIER_AC_BIT_MARK LITERAL1 HAIER_AC_CMD_FAN LITERAL1 HAIER_AC_CMD_HEALTH LITERAL1 HAIER_AC_CMD_MODE LITERAL1 @@ -587,394 +557,159 @@ HAIER_AC_FAN_AUTO LITERAL1 HAIER_AC_FAN_HIGH LITERAL1 HAIER_AC_FAN_LOW LITERAL1 HAIER_AC_FAN_MED LITERAL1 -HAIER_AC_HDR LITERAL1 -HAIER_AC_HDR_GAP LITERAL1 HAIER_AC_HEAT LITERAL1 HAIER_AC_MAX_TEMP LITERAL1 -HAIER_AC_MAX_TIME LITERAL1 -HAIER_AC_MIN_GAP LITERAL1 HAIER_AC_MIN_TEMP LITERAL1 -HAIER_AC_ONE_SPACE LITERAL1 -HAIER_AC_PREFIX LITERAL1 HAIER_AC_STATE_LENGTH LITERAL1 HAIER_AC_SWING_CHG LITERAL1 HAIER_AC_SWING_DOWN LITERAL1 HAIER_AC_SWING_OFF LITERAL1 HAIER_AC_SWING_UP LITERAL1 -HAIER_AC_ZERO_SPACE LITERAL1 -HEADER LITERAL1 +HAIER_AC_YRW02 LITERAL1 +HAIER_AC_YRW02_AUTO LITERAL1 +HAIER_AC_YRW02_BUTTON_FAN LITERAL1 +HAIER_AC_YRW02_BUTTON_HEALTH LITERAL1 +HAIER_AC_YRW02_BUTTON_MODE LITERAL1 +HAIER_AC_YRW02_BUTTON_POWER LITERAL1 +HAIER_AC_YRW02_BUTTON_SLEEP LITERAL1 +HAIER_AC_YRW02_BUTTON_SWING LITERAL1 +HAIER_AC_YRW02_BUTTON_TEMP_DOWN LITERAL1 +HAIER_AC_YRW02_BUTTON_TEMP_UP LITERAL1 +HAIER_AC_YRW02_BUTTON_TURBO LITERAL1 +HAIER_AC_YRW02_COOL LITERAL1 +HAIER_AC_YRW02_DRY LITERAL1 +HAIER_AC_YRW02_FAN LITERAL1 +HAIER_AC_YRW02_FAN_AUTO LITERAL1 +HAIER_AC_YRW02_FAN_HIGH LITERAL1 +HAIER_AC_YRW02_FAN_LOW LITERAL1 +HAIER_AC_YRW02_FAN_MED LITERAL1 +HAIER_AC_YRW02_HEAT LITERAL1 +HAIER_AC_YRW02_STATE_LENGTH LITERAL1 +HAIER_AC_YRW02_SWING_AUTO LITERAL1 +HAIER_AC_YRW02_SWING_BOTTOM LITERAL1 +HAIER_AC_YRW02_SWING_DOWN LITERAL1 +HAIER_AC_YRW02_SWING_MIDDLE LITERAL1 +HAIER_AC_YRW02_SWING_OFF LITERAL1 +HAIER_AC_YRW02_SWING_TOP LITERAL1 +HAIER_AC_YRW02_TURBO_HIGH LITERAL1 +HAIER_AC_YRW02_TURBO_LOW LITERAL1 +HAIER_AC_YRW02_TURBO_OFF LITERAL1 HIGH LITERAL1 HITACHI_AC LITERAL1 HITACHI_AC1 LITERAL1 HITACHI_AC1_BITS LITERAL1 -HITACHI_AC1_HDR_MARK LITERAL1 -HITACHI_AC1_HDR_SPACE LITERAL1 HITACHI_AC1_STATE_LENGTH LITERAL1 HITACHI_AC2 LITERAL1 HITACHI_AC2_BITS LITERAL1 HITACHI_AC2_STATE_LENGTH LITERAL1 HITACHI_AC_BITS LITERAL1 -HITACHI_AC_BIT_MARK LITERAL1 -HITACHI_AC_HDR_MARK LITERAL1 -HITACHI_AC_HDR_SPACE LITERAL1 -HITACHI_AC_MIN_GAP LITERAL1 -HITACHI_AC_ONE_SPACE LITERAL1 HITACHI_AC_STATE_LENGTH LITERAL1 -HITACHI_AC_ZERO_SPACE LITERAL1 ICACHE_RAM_ATTR LITERAL1 JVC LITERAL1 JVC_BITS LITERAL1 -JVC_BIT_MARK LITERAL1 -JVC_BIT_MARK_TICKS LITERAL1 -JVC_HDR_MARK LITERAL1 -JVC_HDR_MARK_TICKS LITERAL1 -JVC_HDR_SPACE LITERAL1 -JVC_HDR_SPACE_TICKS LITERAL1 -JVC_MIN_GAP_TICKS LITERAL1 -JVC_ONE_SPACE LITERAL1 -JVC_ONE_SPACE_TICKS LITERAL1 -JVC_RPT_LENGTH LITERAL1 -JVC_RPT_LENGTH_TICKS LITERAL1 -JVC_TICK LITERAL1 -JVC_ZERO_SPACE LITERAL1 -JVC_ZERO_SPACE_TICKS LITERAL1 KELVINATOR LITERAL1 KELVINATOR_AUTO LITERAL1 KELVINATOR_AUTO_TEMP LITERAL1 -KELVINATOR_BASIC_FAN_MASK LITERAL1 KELVINATOR_BASIC_FAN_MAX LITERAL1 -KELVINATOR_BITS LITERAL1 -KELVINATOR_BIT_MARK LITERAL1 -KELVINATOR_BIT_MARK_TICKS LITERAL1 -KELVINATOR_CHECKSUM_START LITERAL1 -KELVINATOR_CMD_FOOTER LITERAL1 -KELVINATOR_CMD_FOOTER_BITS LITERAL1 KELVINATOR_COOL LITERAL1 KELVINATOR_DRY LITERAL1 KELVINATOR_FAN LITERAL1 KELVINATOR_FAN_AUTO LITERAL1 -KELVINATOR_FAN_MASK LITERAL1 KELVINATOR_FAN_MAX LITERAL1 -KELVINATOR_FAN_OFFSET LITERAL1 -KELVINATOR_GAP_SPACE LITERAL1 -KELVINATOR_GAP_SPACE_TICKS LITERAL1 -KELVINATOR_HDR_MARK LITERAL1 -KELVINATOR_HDR_MARK_TICKS LITERAL1 -KELVINATOR_HDR_SPACE LITERAL1 -KELVINATOR_HDR_SPACE_TICKS LITERAL1 KELVINATOR_HEAT LITERAL1 -KELVINATOR_ION_FILTER LITERAL1 -KELVINATOR_ION_FILTER_OFFSET LITERAL1 -KELVINATOR_LIGHT LITERAL1 -KELVINATOR_LIGHT_OFFSET LITERAL1 KELVINATOR_MAX_TEMP LITERAL1 KELVINATOR_MIN_TEMP LITERAL1 -KELVINATOR_MODE_MASK LITERAL1 -KELVINATOR_ONE_SPACE LITERAL1 -KELVINATOR_ONE_SPACE_TICKS LITERAL1 -KELVINATOR_POWER LITERAL1 -KELVINATOR_QUIET LITERAL1 -KELVINATOR_QUIET_OFFSET LITERAL1 -KELVINATOR_SLEEP_1_AND_3 LITERAL1 KELVINATOR_STATE_LENGTH LITERAL1 -KELVINATOR_TICK LITERAL1 -KELVINATOR_TURBO LITERAL1 -KELVINATOR_TURBO_OFFSET LITERAL1 -KELVINATOR_VENT_SWING LITERAL1 -KELVINATOR_VENT_SWING_H LITERAL1 -KELVINATOR_VENT_SWING_OFFSET LITERAL1 -KELVINATOR_VENT_SWING_V LITERAL1 -KELVINATOR_XFAN LITERAL1 -KELVINATOR_XFAN_OFFSET LITERAL1 -KELVINATOR_ZERO_SPACE LITERAL1 -KELVINATOR_ZERO_SPACE_TICKS LITERAL1 LASERTAG LITERAL1 LASERTAG_BITS LITERAL1 -LASERTAG_DELTA LITERAL1 -LASERTAG_EXCESS LITERAL1 -LASERTAG_MIN_GAP LITERAL1 -LASERTAG_MIN_REPEAT LITERAL1 -LASERTAG_TICK LITERAL1 -LASERTAG_TOLERANCE LITERAL1 LG LITERAL1 +LG2 LITERAL1 LG32_BITS LITERAL1 -LG32_HDR_MARK LITERAL1 -LG32_HDR_MARK_TICKS LITERAL1 -LG32_HDR_SPACE LITERAL1 -LG32_HDR_SPACE_TICKS LITERAL1 -LG32_RPT_HDR_MARK LITERAL1 -LG32_RPT_HDR_MARK_TICKS LITERAL1 LG_BITS LITERAL1 -LG_BIT_MARK LITERAL1 -LG_BIT_MARK_TICKS LITERAL1 -LG_HDR_MARK LITERAL1 -LG_HDR_MARK_TICKS LITERAL1 -LG_HDR_SPACE LITERAL1 -LG_HDR_SPACE_TICKS LITERAL1 -LG_MIN_GAP LITERAL1 -LG_MIN_GAP_TICKS LITERAL1 -LG_MIN_MESSAGE_LENGTH LITERAL1 -LG_MIN_MESSAGE_LENGTH_TICKS LITERAL1 -LG_ONE_SPACE LITERAL1 -LG_ONE_SPACE_TICKS LITERAL1 -LG_RPT_SPACE LITERAL1 -LG_RPT_SPACE_TICKS LITERAL1 -LG_TICK LITERAL1 -LG_ZERO_SPACE LITERAL1 -LG_ZERO_SPACE_TICKS LITERAL1 LOW LITERAL1 +LUTRON LITERAL1 MAGIQUEST LITERAL1 MAGIQUEST_BITS LITERAL1 -MAGIQUEST_GAP LITERAL1 -MAGIQUEST_MARK_ONE LITERAL1 -MAGIQUEST_MARK_ZERO LITERAL1 -MAGIQUEST_ONE_RATIO LITERAL1 -MAGIQUEST_PERIOD LITERAL1 -MAGIQUEST_SPACE_ONE LITERAL1 -MAGIQUEST_SPACE_ZERO LITERAL1 -MAGIQUEST_TOTAL_USEC LITERAL1 -MAGIQUEST_ZERO_RATIO LITERAL1 -MARK_EXCESS LITERAL1 -MAX_ACCURATE_USEC_DELAY LITERAL1 -MAX_TIMEOUT_MS LITERAL1 MIDEA LITERAL1 MIDEA_AC_AUTO LITERAL1 -MIDEA_AC_CHECKSUM_MASK LITERAL1 MIDEA_AC_COOL LITERAL1 MIDEA_AC_DRY LITERAL1 MIDEA_AC_FAN LITERAL1 MIDEA_AC_FAN_AUTO LITERAL1 MIDEA_AC_FAN_HI LITERAL1 MIDEA_AC_FAN_LOW LITERAL1 -MIDEA_AC_FAN_MASK LITERAL1 MIDEA_AC_FAN_MED LITERAL1 MIDEA_AC_HEAT LITERAL1 MIDEA_AC_MAX_TEMP_C LITERAL1 MIDEA_AC_MAX_TEMP_F LITERAL1 MIDEA_AC_MIN_TEMP_C LITERAL1 MIDEA_AC_MIN_TEMP_F LITERAL1 -MIDEA_AC_MODE_MASK LITERAL1 MIDEA_AC_POWER LITERAL1 MIDEA_AC_SLEEP LITERAL1 -MIDEA_AC_STATE_MASK LITERAL1 -MIDEA_AC_TEMP_MASK LITERAL1 MIDEA_BITS LITERAL1 -MIDEA_BIT_MARK LITERAL1 -MIDEA_BIT_MARK_TICKS LITERAL1 -MIDEA_HDR_MARK LITERAL1 -MIDEA_HDR_MARK_TICKS LITERAL1 -MIDEA_HDR_SPACE LITERAL1 -MIDEA_HDR_SPACE_TICKS LITERAL1 -MIDEA_MIN_GAP_TICKS LITERAL1 -MIDEA_MIN_REPEAT LITERAL1 -MIDEA_ONE_SPACE LITERAL1 -MIDEA_ONE_SPACE_TICKS LITERAL1 -MIDEA_TICK LITERAL1 -MIDEA_TOLERANCE LITERAL1 -MIDEA_ZERO_SPACE LITERAL1 -MIDEA_ZERO_SPACE_TICKS LITERAL1 -MIN_LASERTAG_SAMPLES LITERAL1 -MIN_RC5_SAMPLES LITERAL1 -MIN_RC6_SAMPLES LITERAL1 MITSUBISHI LITERAL1 MITSUBISHI2 LITERAL1 -MITSUBISHI2_BIT_MARK LITERAL1 -MITSUBISHI2_HDR_SPACE LITERAL1 -MITSUBISHI2_MIN_GAP LITERAL1 -MITSUBISHI2_ONE_SPACE LITERAL1 -MITSUBISHI2_ZERO_SPACE LITERAL1 MITSUBISHI_AC LITERAL1 MITSUBISHI_AC_AUTO LITERAL1 -MITSUBISHI_AC_BIT_MARK LITERAL1 MITSUBISHI_AC_COOL LITERAL1 MITSUBISHI_AC_DRY LITERAL1 MITSUBISHI_AC_FAN_AUTO LITERAL1 MITSUBISHI_AC_FAN_MAX LITERAL1 MITSUBISHI_AC_FAN_REAL_MAX LITERAL1 MITSUBISHI_AC_FAN_SILENT LITERAL1 -MITSUBISHI_AC_HDR_MARK LITERAL1 -MITSUBISHI_AC_HDR_SPACE LITERAL1 MITSUBISHI_AC_HEAT LITERAL1 MITSUBISHI_AC_MAX_TEMP LITERAL1 -MITSUBISHI_AC_MIN_REPEAT LITERAL1 MITSUBISHI_AC_MIN_TEMP LITERAL1 -MITSUBISHI_AC_ONE_SPACE LITERAL1 MITSUBISHI_AC_POWER LITERAL1 -MITSUBISHI_AC_RPT_MARK LITERAL1 -MITSUBISHI_AC_RPT_SPACE LITERAL1 MITSUBISHI_AC_STATE_LENGTH LITERAL1 MITSUBISHI_AC_VANE_AUTO LITERAL1 MITSUBISHI_AC_VANE_AUTO_MOVE LITERAL1 -MITSUBISHI_AC_ZERO_SPACE LITERAL1 MITSUBISHI_BITS LITERAL1 -MITSUBISHI_BIT_MARK LITERAL1 -MITSUBISHI_BIT_MARK_TICKS LITERAL1 -MITSUBISHI_MIN_COMMAND_LENGTH LITERAL1 -MITSUBISHI_MIN_GAP LITERAL1 -MITSUBISHI_MIN_REPEAT LITERAL1 -MITSUBISHI_ONE_SPACE LITERAL1 -MITSUBISHI_TICK LITERAL1 -MITSUBISHI_ZERO_SPACE LITERAL1 +MWM LITERAL1 NEC LITERAL1 NEC_BITS LITERAL1 -NEC_BIT_MARK LITERAL1 -NEC_BIT_MARK_TICKS LITERAL1 -NEC_HDR_MARK LITERAL1 -NEC_HDR_MARK_TICKS LITERAL1 -NEC_HDR_SPACE LITERAL1 -NEC_HDR_SPACE_TICKS LITERAL1 NEC_LIKE LITERAL1 -NEC_MIN_COMMAND_LENGTH LITERAL1 -NEC_MIN_COMMAND_LENGTH_TICKS LITERAL1 -NEC_MIN_GAP LITERAL1 -NEC_ONE_SPACE LITERAL1 -NEC_ONE_SPACE_TICKS LITERAL1 -NEC_RPT_LENGTH LITERAL1 -NEC_RPT_SPACE LITERAL1 -NEC_RPT_SPACE_TICKS LITERAL1 -NEC_TICK LITERAL1 -NEC_ZERO_SPACE LITERAL1 -NEC_ZERO_SPACE_TICKS LITERAL1 NIKAI LITERAL1 NIKAI_BITS LITERAL1 -NIKAI_BIT_MARK LITERAL1 -NIKAI_BIT_MARK_TICKS LITERAL1 -NIKAI_HDR_MARK LITERAL1 -NIKAI_HDR_MARK_TICKS LITERAL1 -NIKAI_HDR_SPACE LITERAL1 -NIKAI_HDR_SPACE_TICKS LITERAL1 -NIKAI_MIN_GAP LITERAL1 -NIKAI_MIN_GAP_TICKS LITERAL1 -NIKAI_ONE_SPACE LITERAL1 -NIKAI_ONE_SPACE_TICKS LITERAL1 -NIKAI_ZERO_SPACE LITERAL1 -NIKAI_ZERO_SPACE_TICKS LITERAL1 -OFFSET_ERR LITERAL1 -OFFSET_START LITERAL1 +ONCE LITERAL1 PANASONIC LITERAL1 +PANASONIC_AC LITERAL1 PANASONIC_BITS LITERAL1 -PANASONIC_BIT_MARK LITERAL1 -PANASONIC_BIT_MARK_TICKS LITERAL1 -PANASONIC_HDR_MARK LITERAL1 -PANASONIC_HDR_MARK_TICKS LITERAL1 -PANASONIC_HDR_SPACE LITERAL1 -PANASONIC_HDR_SPACE_TICKS LITERAL1 -PANASONIC_MANUFACTURER LITERAL1 -PANASONIC_MIN_COMMAND_LENGTH LITERAL1 -PANASONIC_MIN_COMMAND_LENGTH_TICKS LITERAL1 -PANASONIC_MIN_GAP_TICKS LITERAL1 -PANASONIC_ONE_SPACE LITERAL1 -PANASONIC_ONE_SPACE_TICKS LITERAL1 -PANASONIC_TICK LITERAL1 -PANASONIC_ZERO_SPACE LITERAL1 -PANASONIC_ZERO_SPACE_TICKS LITERAL1 -PERIOD_OFFSET LITERAL1 +PIONEER LITERAL1 PRONTO LITERAL1 -PRONTO_DATA_OFFSET LITERAL1 -PRONTO_FREQ_FACTOR LITERAL1 -PRONTO_FREQ_OFFSET LITERAL1 -PRONTO_MIN_LENGTH LITERAL1 -PRONTO_SEQ_1_LEN_OFFSET LITERAL1 -PRONTO_SEQ_2_LEN_OFFSET LITERAL1 -PRONTO_TYPE_OFFSET LITERAL1 RAW LITERAL1 -RAWBUF LITERAL1 RAWTICK LITERAL1 RC5 LITERAL1 RC5X LITERAL1 RC5X_BITS LITERAL1 RC5_BITS LITERAL1 -RC5_MIN_COMMAND_LENGTH LITERAL1 -RC5_MIN_GAP LITERAL1 -RC5_RAW_BITS LITERAL1 -RC5_T1 LITERAL1 -RC5_TOGGLE_MASK LITERAL1 RC6 LITERAL1 RC6_36_BITS LITERAL1 -RC6_36_TOGGLE_MASK LITERAL1 -RC6_HDR_MARK LITERAL1 -RC6_HDR_MARK_TICKS LITERAL1 -RC6_HDR_SPACE LITERAL1 -RC6_HDR_SPACE_TICKS LITERAL1 RC6_MODE0_BITS LITERAL1 -RC6_RPT_LENGTH LITERAL1 -RC6_RPT_LENGTH_TICKS LITERAL1 -RC6_TICK LITERAL1 -RC6_TOGGLE_MASK LITERAL1 RCMM LITERAL1 RCMM_BITS LITERAL1 -RCMM_BIT_MARK LITERAL1 -RCMM_BIT_MARK_TICKS LITERAL1 -RCMM_BIT_SPACE_0 LITERAL1 -RCMM_BIT_SPACE_0_TICKS LITERAL1 -RCMM_BIT_SPACE_1 LITERAL1 -RCMM_BIT_SPACE_1_TICKS LITERAL1 -RCMM_BIT_SPACE_2 LITERAL1 -RCMM_BIT_SPACE_2_TICKS LITERAL1 -RCMM_BIT_SPACE_3 LITERAL1 -RCMM_BIT_SPACE_3_TICKS LITERAL1 -RCMM_EXCESS LITERAL1 -RCMM_HDR_MARK LITERAL1 -RCMM_HDR_MARK_TICKS LITERAL1 -RCMM_HDR_SPACE LITERAL1 -RCMM_HDR_SPACE_TICKS LITERAL1 -RCMM_MIN_GAP LITERAL1 -RCMM_MIN_GAP_TICKS LITERAL1 -RCMM_RPT_LENGTH LITERAL1 -RCMM_RPT_LENGTH_TICKS LITERAL1 -RCMM_TICK LITERAL1 -RCMM_TOLERANCE LITERAL1 -REPEAT LITERAL1 SAMSUNG LITERAL1 +SAMSUNG_AC LITERAL1 SAMSUNG_BITS LITERAL1 -SAMSUNG_BIT_MARK LITERAL1 -SAMSUNG_BIT_MARK_TICKS LITERAL1 -SAMSUNG_HDR_MARK LITERAL1 -SAMSUNG_HDR_MARK_TICKS LITERAL1 -SAMSUNG_HDR_SPACE LITERAL1 -SAMSUNG_HDR_SPACE_TICKS LITERAL1 -SAMSUNG_MIN_MESSAGE_LENGTH LITERAL1 -SAMSUNG_MIN_MESSAGE_LENGTH_TICKS LITERAL1 -SAMSUNG_ONE_SPACE LITERAL1 -SAMSUNG_ONE_SPACE_TICKS LITERAL1 -SAMSUNG_RPT_SPACE LITERAL1 -SAMSUNG_RPT_SPACE_TICKS LITERAL1 -SAMSUNG_TICK LITERAL1 -SAMSUNG_ZERO_SPACE LITERAL1 -SAMSUNG_ZERO_SPACE_TICKS LITERAL1 SANYO LITERAL1 SANYO_LC7461 LITERAL1 -SANYO_LC7461_ADDRESS_BITS LITERAL1 -SANYO_LC7461_ADDRESS_MASK LITERAL1 SANYO_LC7461_BITS LITERAL1 -SANYO_LC7461_BIT_MARK LITERAL1 -SANYO_LC7461_COMMAND_BITS LITERAL1 -SANYO_LC7461_COMMAND_MASK LITERAL1 -SANYO_LC7461_HDR_MARK LITERAL1 -SANYO_LC7461_HDR_SPACE LITERAL1 -SANYO_LC7461_MIN_COMMAND_LENGTH LITERAL1 -SANYO_LC7461_MIN_GAP LITERAL1 -SANYO_LC7461_ONE_SPACE LITERAL1 -SANYO_LC7461_ZERO_SPACE LITERAL1 SANYO_SA8650B_BITS LITERAL1 -SANYO_SA8650B_DOUBLE_SPACE_USECS LITERAL1 -SANYO_SA8650B_HDR_MARK LITERAL1 -SANYO_SA8650B_HDR_SPACE LITERAL1 -SANYO_SA8650B_ONE_MARK LITERAL1 -SANYO_SA8650B_RPT_LENGTH LITERAL1 -SANYO_SA8650B_ZERO_MARK LITERAL1 SEND_AIWA_RC_T501 LITERAL1 SEND_ARGO LITERAL1 SEND_CARRIER_AC LITERAL1 SEND_COOLIX LITERAL1 SEND_DAIKIN LITERAL1 +SEND_DAIKIN2 LITERAL1 SEND_DENON LITERAL1 SEND_DISH LITERAL1 +SEND_ELECTRA_AC LITERAL1 SEND_FUJITSU_AC LITERAL1 SEND_GICABLE LITERAL1 SEND_GLOBALCACHE LITERAL1 SEND_GREE LITERAL1 SEND_HAIER_AC LITERAL1 +SEND_HAIER_AC_YRW02 LITERAL1 SEND_HITACHI_AC LITERAL1 SEND_HITACHI_AC1 LITERAL1 SEND_HITACHI_AC2 LITERAL1 @@ -982,129 +717,1113 @@ SEND_JVC LITERAL1 SEND_KELVINATOR LITERAL1 SEND_LASERTAG LITERAL1 SEND_LG LITERAL1 +SEND_LUTRON LITERAL1 SEND_MAGIQUEST LITERAL1 SEND_MIDEA LITERAL1 SEND_MITSUBISHI LITERAL1 SEND_MITSUBISHI2 LITERAL1 SEND_MITSUBISHI_AC LITERAL1 +SEND_MWM LITERAL1 SEND_NEC LITERAL1 SEND_NIKAI LITERAL1 SEND_PANASONIC LITERAL1 +SEND_PANASONIC_AC LITERAL1 +SEND_PIONEER LITERAL1 SEND_PRONTO LITERAL1 SEND_RAW LITERAL1 SEND_RC5 LITERAL1 SEND_RC6 LITERAL1 SEND_RCMM LITERAL1 SEND_SAMSUNG LITERAL1 +SEND_SAMSUNG_AC LITERAL1 SEND_SANYO LITERAL1 SEND_SHARP LITERAL1 SEND_SHERWOOD LITERAL1 SEND_SONY LITERAL1 SEND_TOSHIBA_AC LITERAL1 SEND_TROTEC LITERAL1 +SEND_VESTEL_AC LITERAL1 +SEND_WHIRLPOOL_AC LITERAL1 SEND_WHYNTER LITERAL1 SHARP LITERAL1 -SHARP_ADDRESS_MASK LITERAL1 SHARP_BITS LITERAL1 -SHARP_BIT_MARK LITERAL1 -SHARP_BIT_MARK_TICKS LITERAL1 -SHARP_COMMAND_BITS LITERAL1 -SHARP_COMMAND_MASK LITERAL1 -SHARP_GAP LITERAL1 -SHARP_GAP_TICKS LITERAL1 -SHARP_ONE_SPACE LITERAL1 -SHARP_ONE_SPACE_TICKS LITERAL1 -SHARP_TOGGLE_MASK LITERAL1 -SHARP_ZERO_SPACE LITERAL1 -SHARP_ZERO_SPACE_TICKS LITERAL1 SHERWOOD LITERAL1 SHERWOOD_BITS LITERAL1 -SHERWOOD_MIN_REPEAT LITERAL1 SONY LITERAL1 SONY_12_BITS LITERAL1 SONY_15_BITS LITERAL1 SONY_20_BITS LITERAL1 -SONY_HDR_MARK LITERAL1 -SONY_HDR_MARK_TICKS LITERAL1 -SONY_MIN_BITS LITERAL1 -SONY_MIN_GAP LITERAL1 -SONY_MIN_GAP_TICKS LITERAL1 -SONY_MIN_REPEAT LITERAL1 -SONY_ONE_MARK LITERAL1 -SONY_ONE_MARK_TICKS LITERAL1 -SONY_RPT_LENGTH LITERAL1 -SONY_RPT_LENGTH_TICKS LITERAL1 -SONY_SPACE LITERAL1 -SONY_SPACE_TICKS LITERAL1 -SONY_TICK LITERAL1 -SONY_ZERO_MARK LITERAL1 -SONY_ZERO_MARK_TICKS LITERAL1 -STATE_IDLE LITERAL1 -STATE_MARK LITERAL1 -STATE_SIZE_MAX LITERAL1 -STATE_SPACE LITERAL1 -STATE_STOP LITERAL1 TIMEOUT_MS LITERAL1 -TOLERANCE LITERAL1 TOSHIBA_AC LITERAL1 TOSHIBA_AC_AUTO LITERAL1 -TOSHIBA_AC_BITS LITERAL1 -TOSHIBA_AC_BIT_MARK LITERAL1 TOSHIBA_AC_COOL LITERAL1 TOSHIBA_AC_DRY LITERAL1 TOSHIBA_AC_FAN_AUTO LITERAL1 TOSHIBA_AC_FAN_MAX LITERAL1 -TOSHIBA_AC_HDR_MARK LITERAL1 -TOSHIBA_AC_HDR_SPACE LITERAL1 TOSHIBA_AC_HEAT LITERAL1 TOSHIBA_AC_MAX_TEMP LITERAL1 -TOSHIBA_AC_MIN_GAP LITERAL1 -TOSHIBA_AC_MIN_REPEAT LITERAL1 TOSHIBA_AC_MIN_TEMP LITERAL1 -TOSHIBA_AC_ONE_SPACE LITERAL1 TOSHIBA_AC_POWER LITERAL1 TOSHIBA_AC_STATE_LENGTH LITERAL1 -TOSHIBA_AC_ZERO_SPACE LITERAL1 TROTEC LITERAL1 TROTEC_AUTO LITERAL1 TROTEC_COMMAND_LENGTH LITERAL1 TROTEC_COOL LITERAL1 -TROTEC_DEF_TEMP LITERAL1 TROTEC_DRY LITERAL1 TROTEC_FAN LITERAL1 TROTEC_FAN_HIGH LITERAL1 TROTEC_FAN_LOW LITERAL1 TROTEC_FAN_MED LITERAL1 -TROTEC_GAP LITERAL1 -TROTEC_GAP_END LITERAL1 -TROTEC_HDR_MARK LITERAL1 -TROTEC_HDR_SPACE LITERAL1 -TROTEC_INTRO1 LITERAL1 -TROTEC_INTRO2 LITERAL1 TROTEC_MAX_TEMP LITERAL1 TROTEC_MAX_TIMER LITERAL1 TROTEC_MIN_TEMP LITERAL1 TROTEC_MIN_TIMER LITERAL1 -TROTEC_OFF LITERAL1 -TROTEC_ON LITERAL1 -TROTEC_ONE_MARK LITERAL1 -TROTEC_ONE_SPACE LITERAL1 -TROTEC_SLEEP_ON LITERAL1 -TROTEC_TIMER_ON LITERAL1 -TROTEC_ZERO_MARK LITERAL1 -TROTEC_ZERO_SPACE LITERAL1 UNKNOWN LITERAL1 -UNKNOWN_THRESHOLD LITERAL1 UNUSED LITERAL1 +VESTEL_AC LITERAL1 +WHIRLPOOL_AC LITERAL1 WHYNTER LITERAL1 WHYNTER_BITS LITERAL1 -WHYNTER_BIT_MARK LITERAL1 -WHYNTER_HDR_MARK LITERAL1 -WHYNTER_HDR_MARK_TICKS LITERAL1 -WHYNTER_HDR_SPACE LITERAL1 -WHYNTER_HDR_SPACE_TICKS LITERAL1 -WHYNTER_MIN_COMMAND_LENGTH LITERAL1 -WHYNTER_ONE_SPACE LITERAL1 -WHYNTER_ONE_SPACE_TICKS LITERAL1 -WHYNTER_TICK LITERAL1 -WHYNTER_ZERO_SPACE LITERAL1 +kAiwaRcT501Bits LITERAL1 +kAiwaRcT501MinRepeats LITERAL1 +kAiwaRcT501PostBits LITERAL1 +kAiwaRcT501PostData LITERAL1 +kAiwaRcT501PreBits LITERAL1 +kAiwaRcT501PreData LITERAL1 +kArgoBitMark LITERAL1 +kArgoCoolAuto LITERAL1 +kArgoCoolHum LITERAL1 +kArgoCoolOff LITERAL1 +kArgoCoolOn LITERAL1 +kArgoDefaultRepeat LITERAL1 +kArgoFan1 LITERAL1 +kArgoFan2 LITERAL1 +kArgoFan3 LITERAL1 +kArgoFanAuto LITERAL1 +kArgoFlap1 LITERAL1 +kArgoFlap2 LITERAL1 +kArgoFlap3 LITERAL1 +kArgoFlap4 LITERAL1 +kArgoFlap5 LITERAL1 +kArgoFlap6 LITERAL1 +kArgoFlapAuto LITERAL1 +kArgoFlapFull LITERAL1 +kArgoHdrMark LITERAL1 +kArgoHdrSpace LITERAL1 +kArgoHeatAuto LITERAL1 +kArgoHeatBlink LITERAL1 +kArgoHeatOn LITERAL1 +kArgoMaxTemp LITERAL1 +kArgoMinTemp LITERAL1 +kArgoOneSpace LITERAL1 +kArgoStateLength LITERAL1 +kArgoZeroSpace LITERAL1 +kCarrierAcBitMark LITERAL1 +kCarrierAcBits LITERAL1 +kCarrierAcGap LITERAL1 +kCarrierAcHdrMark LITERAL1 +kCarrierAcHdrSpace LITERAL1 +kCarrierAcMinRepeat LITERAL1 +kCarrierAcOneSpace LITERAL1 +kCarrierAcZeroSpace LITERAL1 +kCoolixAuto LITERAL1 +kCoolixBitMark LITERAL1 +kCoolixBitMarkTicks LITERAL1 +kCoolixBits LITERAL1 +kCoolixClean LITERAL1 +kCoolixCool LITERAL1 +kCoolixDefaultRepeat LITERAL1 +kCoolixDefaultState LITERAL1 +kCoolixDry LITERAL1 +kCoolixFan LITERAL1 +kCoolixFanAuto LITERAL1 +kCoolixFanAuto0 LITERAL1 +kCoolixFanFixed LITERAL1 +kCoolixFanMask LITERAL1 +kCoolixFanMax LITERAL1 +kCoolixFanMed LITERAL1 +kCoolixFanMin LITERAL1 +kCoolixFanTempCode LITERAL1 +kCoolixFanZoneFollow LITERAL1 +kCoolixHdrMark LITERAL1 +kCoolixHdrMarkTicks LITERAL1 +kCoolixHdrSpace LITERAL1 +kCoolixHdrSpaceTicks LITERAL1 +kCoolixHeat LITERAL1 +kCoolixLed LITERAL1 +kCoolixMinGap LITERAL1 +kCoolixMinGapTicks LITERAL1 +kCoolixModeMask LITERAL1 +kCoolixOff LITERAL1 +kCoolixOneSpace LITERAL1 +kCoolixOneSpaceTicks LITERAL1 +kCoolixPrefix LITERAL1 +kCoolixSensorTempIgnoreCode LITERAL1 +kCoolixSensorTempMask LITERAL1 +kCoolixSensorTempMax LITERAL1 +kCoolixSensorTempMin LITERAL1 +kCoolixSleep LITERAL1 +kCoolixSwing LITERAL1 +kCoolixTempMap LITERAL1 +kCoolixTempMask LITERAL1 +kCoolixTempMax LITERAL1 +kCoolixTempMin LITERAL1 +kCoolixTempRange LITERAL1 +kCoolixTick LITERAL1 +kCoolixTurbo LITERAL1 +kCoolixUnknown LITERAL1 +kCoolixZeroSpace LITERAL1 +kCoolixZeroSpaceTicks LITERAL1 +kCoolixZoneFollowMask LITERAL1 +kDaikin2BeepMask LITERAL1 +kDaikin2BitClean LITERAL1 +kDaikin2BitEye LITERAL1 +kDaikin2BitEyeAuto LITERAL1 +kDaikin2BitFreshAir LITERAL1 +kDaikin2BitFreshAirHigh LITERAL1 +kDaikin2BitMark LITERAL1 +kDaikin2BitMold LITERAL1 +kDaikin2BitPurify LITERAL1 +kDaikin2BitSleepTimer LITERAL1 +kDaikin2Bits LITERAL1 +kDaikin2DefaultRepeat LITERAL1 +kDaikin2Gap LITERAL1 +kDaikin2HdrMark LITERAL1 +kDaikin2HdrSpace LITERAL1 +kDaikin2LeaderMark LITERAL1 +kDaikin2LeaderSpace LITERAL1 +kDaikin2LightMask LITERAL1 +kDaikin2OneSpace LITERAL1 +kDaikin2Section1Length LITERAL1 +kDaikin2Section2Length LITERAL1 +kDaikin2Sections LITERAL1 +kDaikin2StateLength LITERAL1 +kDaikin2SwingHAuto LITERAL1 +kDaikin2SwingHSwing LITERAL1 +kDaikin2SwingVAuto LITERAL1 +kDaikin2SwingVBreeze LITERAL1 +kDaikin2SwingVCirculate LITERAL1 +kDaikin2SwingVHigh LITERAL1 +kDaikin2SwingVLow LITERAL1 +kDaikin2ZeroSpace LITERAL1 +kDaikinAuto LITERAL1 +kDaikinBeepLoud LITERAL1 +kDaikinBeepOff LITERAL1 +kDaikinBeepQuiet LITERAL1 +kDaikinBitEcono LITERAL1 +kDaikinBitEye LITERAL1 +kDaikinBitMark LITERAL1 +kDaikinBitMold LITERAL1 +kDaikinBitOffTimer LITERAL1 +kDaikinBitOnTimer LITERAL1 +kDaikinBitPower LITERAL1 +kDaikinBitPowerful LITERAL1 +kDaikinBitSensor LITERAL1 +kDaikinBitSilent LITERAL1 +kDaikinBits LITERAL1 +kDaikinByteEcono LITERAL1 +kDaikinByteEye LITERAL1 +kDaikinByteMold LITERAL1 +kDaikinByteOffTimer LITERAL1 +kDaikinByteOnTimer LITERAL1 +kDaikinBytePower LITERAL1 +kDaikinBytePowerful LITERAL1 +kDaikinByteSensor LITERAL1 +kDaikinByteSilent LITERAL1 +kDaikinCool LITERAL1 +kDaikinCurBit LITERAL1 +kDaikinCurIndex LITERAL1 +kDaikinDefaultRepeat LITERAL1 +kDaikinDry LITERAL1 +kDaikinFan LITERAL1 +kDaikinFanAuto LITERAL1 +kDaikinFanMax LITERAL1 +kDaikinFanMin LITERAL1 +kDaikinFanQuiet LITERAL1 +kDaikinFirstHeader64 LITERAL1 +kDaikinGap LITERAL1 +kDaikinHdrMark LITERAL1 +kDaikinHdrSpace LITERAL1 +kDaikinHeat LITERAL1 +kDaikinLightBright LITERAL1 +kDaikinLightDim LITERAL1 +kDaikinLightOff LITERAL1 +kDaikinMarkExcess LITERAL1 +kDaikinMaxTemp LITERAL1 +kDaikinMinTemp LITERAL1 +kDaikinOneSpace LITERAL1 +kDaikinRawBits LITERAL1 +kDaikinStateLength LITERAL1 +kDaikinTolerance LITERAL1 +kDaikinUnusedTime LITERAL1 +kDaikinZeroSpace LITERAL1 +kDenonBitMark LITERAL1 +kDenonBitMarkTicks LITERAL1 +kDenonBits LITERAL1 +kDenonHdrMark LITERAL1 +kDenonHdrMarkTicks LITERAL1 +kDenonHdrSpace LITERAL1 +kDenonHdrSpaceTicks LITERAL1 +kDenonLegacyBits LITERAL1 +kDenonManufacturer LITERAL1 +kDenonMinCommandLengthTicks LITERAL1 +kDenonMinGap LITERAL1 +kDenonMinGapTicks LITERAL1 +kDenonOneSpace LITERAL1 +kDenonOneSpaceTicks LITERAL1 +kDenonTick LITERAL1 +kDenonZeroSpace LITERAL1 +kDenonZeroSpaceTicks LITERAL1 +kDishBitMark LITERAL1 +kDishBitMarkTicks LITERAL1 +kDishBits LITERAL1 +kDishHdrMark LITERAL1 +kDishHdrMarkTicks LITERAL1 +kDishHdrSpace LITERAL1 +kDishHdrSpaceTicks LITERAL1 +kDishMinRepeat LITERAL1 +kDishOneSpace LITERAL1 +kDishOneSpaceTicks LITERAL1 +kDishRptSpace LITERAL1 +kDishRptSpaceTicks LITERAL1 +kDishTick LITERAL1 +kDishZeroSpace LITERAL1 +kDishZeroSpaceTicks LITERAL1 +kDutyDefault LITERAL1 +kDutyMax LITERAL1 +kElectraAcBitMark LITERAL1 +kElectraAcBits LITERAL1 +kElectraAcHdrMark LITERAL1 +kElectraAcHdrSpace LITERAL1 +kElectraAcMessageGap LITERAL1 +kElectraAcOneSpace LITERAL1 +kElectraAcStateLength LITERAL1 +kElectraAcZeroSpace LITERAL1 +kFnvBasis32 LITERAL1 +kFnvPrime32 LITERAL1 +kFooter LITERAL1 +kFujitsuAcBitMark LITERAL1 +kFujitsuAcBits LITERAL1 +kFujitsuAcCmdStayOn LITERAL1 +kFujitsuAcCmdStepHoriz LITERAL1 +kFujitsuAcCmdStepVert LITERAL1 +kFujitsuAcCmdTurnOff LITERAL1 +kFujitsuAcCmdTurnOn LITERAL1 +kFujitsuAcFanAuto LITERAL1 +kFujitsuAcFanHigh LITERAL1 +kFujitsuAcFanLow LITERAL1 +kFujitsuAcFanMed LITERAL1 +kFujitsuAcFanQuiet LITERAL1 +kFujitsuAcHdrMark LITERAL1 +kFujitsuAcHdrSpace LITERAL1 +kFujitsuAcMaxTemp LITERAL1 +kFujitsuAcMinBits LITERAL1 +kFujitsuAcMinGap LITERAL1 +kFujitsuAcMinRepeat LITERAL1 +kFujitsuAcMinTemp LITERAL1 +kFujitsuAcModeAuto LITERAL1 +kFujitsuAcModeCool LITERAL1 +kFujitsuAcModeDry LITERAL1 +kFujitsuAcModeFan LITERAL1 +kFujitsuAcModeHeat LITERAL1 +kFujitsuAcOneSpace LITERAL1 +kFujitsuAcStateLength LITERAL1 +kFujitsuAcStateLengthShort LITERAL1 +kFujitsuAcSwingBoth LITERAL1 +kFujitsuAcSwingHoriz LITERAL1 +kFujitsuAcSwingOff LITERAL1 +kFujitsuAcSwingVert LITERAL1 +kFujitsuAcZeroSpace LITERAL1 +kGicableBitMark LITERAL1 +kGicableBits LITERAL1 +kGicableHdrMark LITERAL1 +kGicableHdrSpace LITERAL1 +kGicableMinCommandLength LITERAL1 +kGicableMinGap LITERAL1 +kGicableMinRepeat LITERAL1 +kGicableOneSpace LITERAL1 +kGicableRptSpace LITERAL1 +kGicableZeroSpace LITERAL1 +kGlobalCacheFreqIndex LITERAL1 +kGlobalCacheMaxRepeat LITERAL1 +kGlobalCacheMinUsec LITERAL1 +kGlobalCacheRptIndex LITERAL1 +kGlobalCacheRptStartIndex LITERAL1 +kGlobalCacheStartIndex LITERAL1 +kGreeAuto LITERAL1 +kGreeBitMark LITERAL1 +kGreeBits LITERAL1 +kGreeBlockFooter LITERAL1 +kGreeBlockFooterBits LITERAL1 +kGreeCool LITERAL1 +kGreeDefaultRepeat LITERAL1 +kGreeDry LITERAL1 +kGreeFan LITERAL1 +kGreeFanMask LITERAL1 +kGreeFanMax LITERAL1 +kGreeHdrMark LITERAL1 +kGreeHdrSpace LITERAL1 +kGreeHeat LITERAL1 +kGreeLightMask LITERAL1 +kGreeMaxTemp LITERAL1 +kGreeMinTemp LITERAL1 +kGreeModeMask LITERAL1 +kGreeMsgSpace LITERAL1 +kGreeOneSpace LITERAL1 +kGreePower1Mask LITERAL1 +kGreePower2Mask LITERAL1 +kGreeSleepMask LITERAL1 +kGreeStateLength LITERAL1 +kGreeSwingAuto LITERAL1 +kGreeSwingAutoMask LITERAL1 +kGreeSwingDown LITERAL1 +kGreeSwingDownAuto LITERAL1 +kGreeSwingLastPos LITERAL1 +kGreeSwingMiddle LITERAL1 +kGreeSwingMiddleAuto LITERAL1 +kGreeSwingMiddleDown LITERAL1 +kGreeSwingMiddleUp LITERAL1 +kGreeSwingPosMask LITERAL1 +kGreeSwingUp LITERAL1 +kGreeSwingUpAuto LITERAL1 +kGreeTurboMask LITERAL1 +kGreeXfanMask LITERAL1 +kGreeZeroSpace LITERAL1 +kHaierACBits LITERAL1 +kHaierACStateLength LITERAL1 +kHaierACYRW02Bits LITERAL1 +kHaierACYRW02StateLength LITERAL1 +kHaierAcAuto LITERAL1 +kHaierAcBitMark LITERAL1 +kHaierAcCmdFan LITERAL1 +kHaierAcCmdHealth LITERAL1 +kHaierAcCmdMode LITERAL1 +kHaierAcCmdOff LITERAL1 +kHaierAcCmdOn LITERAL1 +kHaierAcCmdSleep LITERAL1 +kHaierAcCmdSwing LITERAL1 +kHaierAcCmdTempDown LITERAL1 +kHaierAcCmdTempUp LITERAL1 +kHaierAcCmdTimerCancel LITERAL1 +kHaierAcCmdTimerSet LITERAL1 +kHaierAcCool LITERAL1 +kHaierAcDefTemp LITERAL1 +kHaierAcDefaultRepeat LITERAL1 +kHaierAcDry LITERAL1 +kHaierAcFan LITERAL1 +kHaierAcFanAuto LITERAL1 +kHaierAcFanHigh LITERAL1 +kHaierAcFanLow LITERAL1 +kHaierAcFanMed LITERAL1 +kHaierAcHdr LITERAL1 +kHaierAcHdrGap LITERAL1 +kHaierAcHeat LITERAL1 +kHaierAcMaxTemp LITERAL1 +kHaierAcMaxTime LITERAL1 +kHaierAcMinGap LITERAL1 +kHaierAcMinTemp LITERAL1 +kHaierAcOneSpace LITERAL1 +kHaierAcPrefix LITERAL1 +kHaierAcSwingChg LITERAL1 +kHaierAcSwingDown LITERAL1 +kHaierAcSwingOff LITERAL1 +kHaierAcSwingUp LITERAL1 +kHaierAcYrw02Auto LITERAL1 +kHaierAcYrw02ButtonFan LITERAL1 +kHaierAcYrw02ButtonHealth LITERAL1 +kHaierAcYrw02ButtonMode LITERAL1 +kHaierAcYrw02ButtonPower LITERAL1 +kHaierAcYrw02ButtonSleep LITERAL1 +kHaierAcYrw02ButtonSwing LITERAL1 +kHaierAcYrw02ButtonTempDown LITERAL1 +kHaierAcYrw02ButtonTempUp LITERAL1 +kHaierAcYrw02ButtonTurbo LITERAL1 +kHaierAcYrw02Cool LITERAL1 +kHaierAcYrw02DefaultRepeat LITERAL1 +kHaierAcYrw02Dry LITERAL1 +kHaierAcYrw02Fan LITERAL1 +kHaierAcYrw02FanAuto LITERAL1 +kHaierAcYrw02FanHigh LITERAL1 +kHaierAcYrw02FanLow LITERAL1 +kHaierAcYrw02FanMed LITERAL1 +kHaierAcYrw02Heat LITERAL1 +kHaierAcYrw02Power LITERAL1 +kHaierAcYrw02Prefix LITERAL1 +kHaierAcYrw02Sleep LITERAL1 +kHaierAcYrw02SwingAuto LITERAL1 +kHaierAcYrw02SwingBottom LITERAL1 +kHaierAcYrw02SwingDown LITERAL1 +kHaierAcYrw02SwingMiddle LITERAL1 +kHaierAcYrw02SwingOff LITERAL1 +kHaierAcYrw02SwingTop LITERAL1 +kHaierAcYrw02TurboHigh LITERAL1 +kHaierAcYrw02TurboLow LITERAL1 +kHaierAcYrw02TurboOff LITERAL1 +kHaierAcZeroSpace LITERAL1 +kHeader LITERAL1 +kHitachiAc1Bits LITERAL1 +kHitachiAc1HdrMark LITERAL1 +kHitachiAc1HdrSpace LITERAL1 +kHitachiAc1StateLength LITERAL1 +kHitachiAc2Bits LITERAL1 +kHitachiAc2StateLength LITERAL1 +kHitachiAcAuto LITERAL1 +kHitachiAcAutoTemp LITERAL1 +kHitachiAcBitMark LITERAL1 +kHitachiAcBits LITERAL1 +kHitachiAcCool LITERAL1 +kHitachiAcDefaultRepeat LITERAL1 +kHitachiAcDry LITERAL1 +kHitachiAcFan LITERAL1 +kHitachiAcFanAuto LITERAL1 +kHitachiAcFanHigh LITERAL1 +kHitachiAcFanLow LITERAL1 +kHitachiAcHdrMark LITERAL1 +kHitachiAcHdrSpace LITERAL1 +kHitachiAcHeat LITERAL1 +kHitachiAcMaxTemp LITERAL1 +kHitachiAcMinGap LITERAL1 +kHitachiAcMinTemp LITERAL1 +kHitachiAcOneSpace LITERAL1 +kHitachiAcStateLength LITERAL1 +kHitachiAcZeroSpace LITERAL1 +kIdleState LITERAL1 +kJvcBitMark LITERAL1 +kJvcBitMarkTicks LITERAL1 +kJvcBits LITERAL1 +kJvcHdrMark LITERAL1 +kJvcHdrMarkTicks LITERAL1 +kJvcHdrSpace LITERAL1 +kJvcHdrSpaceTicks LITERAL1 +kJvcMinGap LITERAL1 +kJvcMinGapTicks LITERAL1 +kJvcOneSpace LITERAL1 +kJvcOneSpaceTicks LITERAL1 +kJvcRptLength LITERAL1 +kJvcRptLengthTicks LITERAL1 +kJvcTick LITERAL1 +kJvcZeroSpace LITERAL1 +kJvcZeroSpaceTicks LITERAL1 +kKelvinatorAuto LITERAL1 +kKelvinatorAutoTemp LITERAL1 +kKelvinatorBasicFanMask LITERAL1 +kKelvinatorBasicFanMax LITERAL1 +kKelvinatorBitMark LITERAL1 +kKelvinatorBitMarkTicks LITERAL1 +kKelvinatorBits LITERAL1 +kKelvinatorChecksumStart LITERAL1 +kKelvinatorCmdFooter LITERAL1 +kKelvinatorCmdFooterBits LITERAL1 +kKelvinatorCool LITERAL1 +kKelvinatorDefaultRepeat LITERAL1 +kKelvinatorDry LITERAL1 +kKelvinatorFan LITERAL1 +kKelvinatorFanAuto LITERAL1 +kKelvinatorFanMask LITERAL1 +kKelvinatorFanMax LITERAL1 +kKelvinatorFanOffset LITERAL1 +kKelvinatorGapSpace LITERAL1 +kKelvinatorGapSpaceTicks LITERAL1 +kKelvinatorHdrMark LITERAL1 +kKelvinatorHdrMarkTicks LITERAL1 +kKelvinatorHdrSpace LITERAL1 +kKelvinatorHdrSpaceTicks LITERAL1 +kKelvinatorHeat LITERAL1 +kKelvinatorIonFilter LITERAL1 +kKelvinatorIonFilterOffset LITERAL1 +kKelvinatorLight LITERAL1 +kKelvinatorLightOffset LITERAL1 +kKelvinatorMaxTemp LITERAL1 +kKelvinatorMinTemp LITERAL1 +kKelvinatorModeMask LITERAL1 +kKelvinatorOneSpace LITERAL1 +kKelvinatorOneSpaceTicks LITERAL1 +kKelvinatorPower LITERAL1 +kKelvinatorQuiet LITERAL1 +kKelvinatorQuietOffset LITERAL1 +kKelvinatorSleep1And3 LITERAL1 +kKelvinatorStateLength LITERAL1 +kKelvinatorTick LITERAL1 +kKelvinatorTurbo LITERAL1 +kKelvinatorTurboOffset LITERAL1 +kKelvinatorVentSwing LITERAL1 +kKelvinatorVentSwingH LITERAL1 +kKelvinatorVentSwingOffset LITERAL1 +kKelvinatorVentSwingV LITERAL1 +kKelvinatorXfan LITERAL1 +kKelvinatorXfanOffset LITERAL1 +kKelvinatorZeroSpace LITERAL1 +kKelvinatorZeroSpaceTicks LITERAL1 +kLasertagBits LITERAL1 +kLasertagDelta LITERAL1 +kLasertagExcess LITERAL1 +kLasertagMinGap LITERAL1 +kLasertagMinRepeat LITERAL1 +kLasertagMinSamples LITERAL1 +kLasertagTick LITERAL1 +kLasertagTolerance LITERAL1 +kLg2BitMark LITERAL1 +kLg2BitMarkTicks LITERAL1 +kLg2HdrMark LITERAL1 +kLg2HdrMarkTicks LITERAL1 +kLg2HdrSpace LITERAL1 +kLg2HdrSpaceTicks LITERAL1 +kLg32Bits LITERAL1 +kLg32HdrMark LITERAL1 +kLg32HdrMarkTicks LITERAL1 +kLg32HdrSpace LITERAL1 +kLg32HdrSpaceTicks LITERAL1 +kLg32RptHdrMark LITERAL1 +kLg32RptHdrMarkTicks LITERAL1 +kLgBitMark LITERAL1 +kLgBitMarkTicks LITERAL1 +kLgBits LITERAL1 +kLgHdrMark LITERAL1 +kLgHdrMarkTicks LITERAL1 +kLgHdrSpace LITERAL1 +kLgHdrSpaceTicks LITERAL1 +kLgMinGap LITERAL1 +kLgMinGapTicks LITERAL1 +kLgMinMessageLength LITERAL1 +kLgMinMessageLengthTicks LITERAL1 +kLgOneSpace LITERAL1 +kLgOneSpaceTicks LITERAL1 +kLgRptSpace LITERAL1 +kLgRptSpaceTicks LITERAL1 +kLgTick LITERAL1 +kLgZeroSpace LITERAL1 +kLgZeroSpaceTicks LITERAL1 +kLutronBits LITERAL1 +kLutronDelta LITERAL1 +kLutronGap LITERAL1 +kLutronTick LITERAL1 +kMWMDelta LITERAL1 +kMWMExcess LITERAL1 +kMWMMaxWidth LITERAL1 +kMWMMinGap LITERAL1 +kMWMMinSamples LITERAL1 +kMWMTick LITERAL1 +kMWMTolerance LITERAL1 +kMagiQuestGap LITERAL1 +kMagiQuestMarkOne LITERAL1 +kMagiQuestMarkZero LITERAL1 +kMagiQuestOneRatio LITERAL1 +kMagiQuestSpaceOne LITERAL1 +kMagiQuestSpaceZero LITERAL1 +kMagiQuestTotalUsec LITERAL1 +kMagiQuestZeroRatio LITERAL1 +kMagiquestBits LITERAL1 +kMark LITERAL1 +kMarkExcess LITERAL1 +kMarkState LITERAL1 +kMaxAccurateUsecDelay LITERAL1 +kMaxTimeoutMs LITERAL1 +kMideaACAuto LITERAL1 +kMideaACChecksumMask LITERAL1 +kMideaACCool LITERAL1 +kMideaACDry LITERAL1 +kMideaACFan LITERAL1 +kMideaACFanAuto LITERAL1 +kMideaACFanHigh LITERAL1 +kMideaACFanLow LITERAL1 +kMideaACFanMask LITERAL1 +kMideaACFanMed LITERAL1 +kMideaACHeat LITERAL1 +kMideaACMaxTempC LITERAL1 +kMideaACMaxTempF LITERAL1 +kMideaACMinTempC LITERAL1 +kMideaACMinTempF LITERAL1 +kMideaACModeMask LITERAL1 +kMideaACPower LITERAL1 +kMideaACSleep LITERAL1 +kMideaACStateMask LITERAL1 +kMideaACTempMask LITERAL1 +kMideaBitMark LITERAL1 +kMideaBitMarkTicks LITERAL1 +kMideaBits LITERAL1 +kMideaHdrMark LITERAL1 +kMideaHdrMarkTicks LITERAL1 +kMideaHdrSpace LITERAL1 +kMideaHdrSpaceTicks LITERAL1 +kMideaMinGap LITERAL1 +kMideaMinGapTicks LITERAL1 +kMideaMinRepeat LITERAL1 +kMideaOneSpace LITERAL1 +kMideaOneSpaceTicks LITERAL1 +kMideaTick LITERAL1 +kMideaTolerance LITERAL1 +kMideaZeroSpace LITERAL1 +kMideaZeroSpaceTicks LITERAL1 +kMitsubishi2BitMark LITERAL1 +kMitsubishi2HdrMark LITERAL1 +kMitsubishi2HdrSpace LITERAL1 +kMitsubishi2MinGap LITERAL1 +kMitsubishi2OneSpace LITERAL1 +kMitsubishi2ZeroSpace LITERAL1 +kMitsubishiACBits LITERAL1 +kMitsubishiACMinRepeat LITERAL1 +kMitsubishiACStateLength LITERAL1 +kMitsubishiAcAuto LITERAL1 +kMitsubishiAcBitMark LITERAL1 +kMitsubishiAcCool LITERAL1 +kMitsubishiAcDry LITERAL1 +kMitsubishiAcFanAuto LITERAL1 +kMitsubishiAcFanMax LITERAL1 +kMitsubishiAcFanRealMax LITERAL1 +kMitsubishiAcFanSilent LITERAL1 +kMitsubishiAcHdrMark LITERAL1 +kMitsubishiAcHdrSpace LITERAL1 +kMitsubishiAcHeat LITERAL1 +kMitsubishiAcMaxTemp LITERAL1 +kMitsubishiAcMinTemp LITERAL1 +kMitsubishiAcNoTimer LITERAL1 +kMitsubishiAcOneSpace LITERAL1 +kMitsubishiAcPower LITERAL1 +kMitsubishiAcRptMark LITERAL1 +kMitsubishiAcRptSpace LITERAL1 +kMitsubishiAcStartStopTimer LITERAL1 +kMitsubishiAcStartTimer LITERAL1 +kMitsubishiAcStopTimer LITERAL1 +kMitsubishiAcVaneAuto LITERAL1 +kMitsubishiAcVaneAutoMove LITERAL1 +kMitsubishiAcZeroSpace LITERAL1 +kMitsubishiBitMark LITERAL1 +kMitsubishiBitMarkTicks LITERAL1 +kMitsubishiBits LITERAL1 +kMitsubishiMinCommandLength LITERAL1 +kMitsubishiMinCommandLengthTicks LITERAL1 +kMitsubishiMinGap LITERAL1 +kMitsubishiMinGapTicks LITERAL1 +kMitsubishiMinRepeat LITERAL1 +kMitsubishiOneSpace LITERAL1 +kMitsubishiOneSpaceTicks LITERAL1 +kMitsubishiTick LITERAL1 +kMitsubishiZeroSpace LITERAL1 +kMitsubishiZeroSpaceTicks LITERAL1 +kNECBits LITERAL1 +kNecBitMark LITERAL1 +kNecBitMarkTicks LITERAL1 +kNecHdrMark LITERAL1 +kNecHdrMarkTicks LITERAL1 +kNecHdrSpace LITERAL1 +kNecHdrSpaceTicks LITERAL1 +kNecMinCommandLength LITERAL1 +kNecMinCommandLengthTicks LITERAL1 +kNecMinGap LITERAL1 +kNecMinGapTicks LITERAL1 +kNecOneSpace LITERAL1 +kNecOneSpaceTicks LITERAL1 +kNecRptLength LITERAL1 +kNecRptSpace LITERAL1 +kNecRptSpaceTicks LITERAL1 +kNecTick LITERAL1 +kNecZeroSpace LITERAL1 +kNecZeroSpaceTicks LITERAL1 +kNikaiBitMark LITERAL1 +kNikaiBitMarkTicks LITERAL1 +kNikaiBits LITERAL1 +kNikaiHdrMark LITERAL1 +kNikaiHdrMarkTicks LITERAL1 +kNikaiHdrSpace LITERAL1 +kNikaiHdrSpaceTicks LITERAL1 +kNikaiMinGap LITERAL1 +kNikaiMinGapTicks LITERAL1 +kNikaiOneSpace LITERAL1 +kNikaiOneSpaceTicks LITERAL1 +kNikaiTick LITERAL1 +kNikaiZeroSpace LITERAL1 +kNikaiZeroSpaceTicks LITERAL1 +kNoRepeat LITERAL1 +kPanasonicAcAuto LITERAL1 +kPanasonicAcBits LITERAL1 +kPanasonicAcChecksumInit LITERAL1 +kPanasonicAcCool LITERAL1 +kPanasonicAcDefaultRepeat LITERAL1 +kPanasonicAcDry LITERAL1 +kPanasonicAcExcess LITERAL1 +kPanasonicAcFan LITERAL1 +kPanasonicAcFanAuto LITERAL1 +kPanasonicAcFanMax LITERAL1 +kPanasonicAcFanMin LITERAL1 +kPanasonicAcFanModeTemp LITERAL1 +kPanasonicAcFanOffset LITERAL1 +kPanasonicAcHeat LITERAL1 +kPanasonicAcMaxTemp LITERAL1 +kPanasonicAcMessageGap LITERAL1 +kPanasonicAcMinTemp LITERAL1 +kPanasonicAcOffTimer LITERAL1 +kPanasonicAcOnTimer LITERAL1 +kPanasonicAcPower LITERAL1 +kPanasonicAcPowerful LITERAL1 +kPanasonicAcPowerfulCkp LITERAL1 +kPanasonicAcQuiet LITERAL1 +kPanasonicAcQuietCkp LITERAL1 +kPanasonicAcSection1Length LITERAL1 +kPanasonicAcSectionGap LITERAL1 +kPanasonicAcShortBits LITERAL1 +kPanasonicAcStateLength LITERAL1 +kPanasonicAcStateShortLength LITERAL1 +kPanasonicAcSwingHAuto LITERAL1 +kPanasonicAcSwingHFullLeft LITERAL1 +kPanasonicAcSwingHFullRight LITERAL1 +kPanasonicAcSwingHLeft LITERAL1 +kPanasonicAcSwingHMiddle LITERAL1 +kPanasonicAcSwingHRight LITERAL1 +kPanasonicAcSwingVAuto LITERAL1 +kPanasonicAcSwingVDown LITERAL1 +kPanasonicAcSwingVUp LITERAL1 +kPanasonicAcTimeMax LITERAL1 +kPanasonicAcTimeSpecial LITERAL1 +kPanasonicAcTolerance LITERAL1 +kPanasonicBitMark LITERAL1 +kPanasonicBitMarkTicks LITERAL1 +kPanasonicBits LITERAL1 +kPanasonicCkp LITERAL1 +kPanasonicDke LITERAL1 +kPanasonicEndGap LITERAL1 +kPanasonicFreq LITERAL1 +kPanasonicHdrMark LITERAL1 +kPanasonicHdrMarkTicks LITERAL1 +kPanasonicHdrSpace LITERAL1 +kPanasonicHdrSpaceTicks LITERAL1 +kPanasonicJke LITERAL1 +kPanasonicKnownGoodState LITERAL1 +kPanasonicLke LITERAL1 +kPanasonicManufacturer LITERAL1 +kPanasonicMinCommandLength LITERAL1 +kPanasonicMinCommandLengthTicks LITERAL1 +kPanasonicMinGap LITERAL1 +kPanasonicMinGapTicks LITERAL1 +kPanasonicNke LITERAL1 +kPanasonicOneSpace LITERAL1 +kPanasonicOneSpaceTicks LITERAL1 +kPanasonicTick LITERAL1 +kPanasonicUnknown LITERAL1 +kPanasonicZeroSpace LITERAL1 +kPanasonicZeroSpaceTicks LITERAL1 +kPeriodOffset LITERAL1 +kPioneerBits LITERAL1 +kProntoDataOffset LITERAL1 +kProntoFreqFactor LITERAL1 +kProntoFreqOffset LITERAL1 +kProntoMinLength LITERAL1 +kProntoSeq1LenOffset LITERAL1 +kProntoSeq2LenOffset LITERAL1 +kProntoTypeOffset LITERAL1 +kRC5Bits LITERAL1 +kRC5RawBits LITERAL1 +kRC5XBits LITERAL1 +kRC6Mode0Bits LITERAL1 +kRC6_36Bits LITERAL1 +kRCMMBits LITERAL1 +kRawBuf LITERAL1 +kRawTick LITERAL1 +kRc5MinCommandLength LITERAL1 +kRc5MinGap LITERAL1 +kRc5SamplesMin LITERAL1 +kRc5T1 LITERAL1 +kRc5ToggleMask LITERAL1 +kRc6HdrMark LITERAL1 +kRc6HdrMarkTicks LITERAL1 +kRc6HdrSpace LITERAL1 +kRc6HdrSpaceTicks LITERAL1 +kRc6RptLength LITERAL1 +kRc6RptLengthTicks LITERAL1 +kRc6Tick LITERAL1 +kRc6ToggleMask LITERAL1 +kRc6_36ToggleMask LITERAL1 +kRcmmBitMark LITERAL1 +kRcmmBitMarkTicks LITERAL1 +kRcmmBitSpace0 LITERAL1 +kRcmmBitSpace0Ticks LITERAL1 +kRcmmBitSpace1 LITERAL1 +kRcmmBitSpace1Ticks LITERAL1 +kRcmmBitSpace2 LITERAL1 +kRcmmBitSpace2Ticks LITERAL1 +kRcmmBitSpace3 LITERAL1 +kRcmmBitSpace3Ticks LITERAL1 +kRcmmExcess LITERAL1 +kRcmmHdrMark LITERAL1 +kRcmmHdrMarkTicks LITERAL1 +kRcmmHdrSpace LITERAL1 +kRcmmHdrSpaceTicks LITERAL1 +kRcmmMinGap LITERAL1 +kRcmmMinGapTicks LITERAL1 +kRcmmRptLength LITERAL1 +kRcmmRptLengthTicks LITERAL1 +kRcmmTick LITERAL1 +kRcmmTolerance LITERAL1 +kRepeat LITERAL1 +kSamsungACSectionLength LITERAL1 +kSamsungAcAuto LITERAL1 +kSamsungAcAutoTemp LITERAL1 +kSamsungAcBeepMask LITERAL1 +kSamsungAcBitMark LITERAL1 +kSamsungAcBits LITERAL1 +kSamsungAcCleanMask10 LITERAL1 +kSamsungAcCleanMask11 LITERAL1 +kSamsungAcCool LITERAL1 +kSamsungAcDefaultRepeat LITERAL1 +kSamsungAcDry LITERAL1 +kSamsungAcExtendedBits LITERAL1 +kSamsungAcExtendedStateLength LITERAL1 +kSamsungAcFan LITERAL1 +kSamsungAcFanAuto LITERAL1 +kSamsungAcFanAuto2 LITERAL1 +kSamsungAcFanHigh LITERAL1 +kSamsungAcFanLow LITERAL1 +kSamsungAcFanMask LITERAL1 +kSamsungAcFanMed LITERAL1 +kSamsungAcFanTurbo LITERAL1 +kSamsungAcHdrMark LITERAL1 +kSamsungAcHdrSpace LITERAL1 +kSamsungAcHeat LITERAL1 +kSamsungAcMaxTemp LITERAL1 +kSamsungAcMinTemp LITERAL1 +kSamsungAcModeMask LITERAL1 +kSamsungAcOneSpace LITERAL1 +kSamsungAcPowerMask1 LITERAL1 +kSamsungAcPowerMask2 LITERAL1 +kSamsungAcPowerSection LITERAL1 +kSamsungAcQuietMask11 LITERAL1 +kSamsungAcSectionGap LITERAL1 +kSamsungAcSectionMark LITERAL1 +kSamsungAcSectionSpace LITERAL1 +kSamsungAcSections LITERAL1 +kSamsungAcStateLength LITERAL1 +kSamsungAcSwingMask LITERAL1 +kSamsungAcSwingMove LITERAL1 +kSamsungAcSwingStop LITERAL1 +kSamsungAcTempMask LITERAL1 +kSamsungAcZeroSpace LITERAL1 +kSamsungBitMark LITERAL1 +kSamsungBitMarkTicks LITERAL1 +kSamsungBits LITERAL1 +kSamsungHdrMark LITERAL1 +kSamsungHdrMarkTicks LITERAL1 +kSamsungHdrSpace LITERAL1 +kSamsungHdrSpaceTicks LITERAL1 +kSamsungMinGap LITERAL1 +kSamsungMinGapTicks LITERAL1 +kSamsungMinMessageLength LITERAL1 +kSamsungMinMessageLengthTicks LITERAL1 +kSamsungOneSpace LITERAL1 +kSamsungOneSpaceTicks LITERAL1 +kSamsungRptSpace LITERAL1 +kSamsungRptSpaceTicks LITERAL1 +kSamsungTick LITERAL1 +kSamsungZeroSpace LITERAL1 +kSamsungZeroSpaceTicks LITERAL1 +kSanyoLC7461AddressBits LITERAL1 +kSanyoLC7461Bits LITERAL1 +kSanyoLC7461CommandBits LITERAL1 +kSanyoLc7461AddressMask LITERAL1 +kSanyoLc7461BitMark LITERAL1 +kSanyoLc7461CommandMask LITERAL1 +kSanyoLc7461HdrMark LITERAL1 +kSanyoLc7461HdrSpace LITERAL1 +kSanyoLc7461MinCommandLength LITERAL1 +kSanyoLc7461MinGap LITERAL1 +kSanyoLc7461OneSpace LITERAL1 +kSanyoLc7461ZeroSpace LITERAL1 +kSanyoSA8650BBits LITERAL1 +kSanyoSa8650bDoubleSpaceUsecs LITERAL1 +kSanyoSa8650bHdrMark LITERAL1 +kSanyoSa8650bHdrSpace LITERAL1 +kSanyoSa8650bOneMark LITERAL1 +kSanyoSa8650bRptLength LITERAL1 +kSanyoSa8650bZeroMark LITERAL1 +kSharpAddressBits LITERAL1 +kSharpAddressMask LITERAL1 +kSharpBitMark LITERAL1 +kSharpBitMarkTicks LITERAL1 +kSharpBits LITERAL1 +kSharpCommandBits LITERAL1 +kSharpCommandMask LITERAL1 +kSharpGap LITERAL1 +kSharpGapTicks LITERAL1 +kSharpOneSpace LITERAL1 +kSharpOneSpaceTicks LITERAL1 +kSharpTick LITERAL1 +kSharpToggleMask LITERAL1 +kSharpZeroSpace LITERAL1 +kSharpZeroSpaceTicks LITERAL1 +kSherwoodBits LITERAL1 +kSherwoodMinRepeat LITERAL1 +kSingleRepeat LITERAL1 +kSony12Bits LITERAL1 +kSony15Bits LITERAL1 +kSony20Bits LITERAL1 +kSonyHdrMark LITERAL1 +kSonyHdrMarkTicks LITERAL1 +kSonyMinBits LITERAL1 +kSonyMinGap LITERAL1 +kSonyMinGapTicks LITERAL1 +kSonyMinRepeat LITERAL1 +kSonyOneMark LITERAL1 +kSonyOneMarkTicks LITERAL1 +kSonyRptLength LITERAL1 +kSonyRptLengthTicks LITERAL1 +kSonySpace LITERAL1 +kSonySpaceTicks LITERAL1 +kSonyTick LITERAL1 +kSonyZeroMark LITERAL1 +kSonyZeroMarkTicks LITERAL1 +kSpace LITERAL1 +kSpaceState LITERAL1 +kStartOffset LITERAL1 +kStateSizeMax LITERAL1 +kStopState LITERAL1 +kTimeoutMs LITERAL1 +kTolerance LITERAL1 +kToshibaACBits LITERAL1 +kToshibaACMinRepeat LITERAL1 +kToshibaACStateLength LITERAL1 +kToshibaAcAuto LITERAL1 +kToshibaAcBitMark LITERAL1 +kToshibaAcCool LITERAL1 +kToshibaAcDry LITERAL1 +kToshibaAcFanAuto LITERAL1 +kToshibaAcFanMax LITERAL1 +kToshibaAcHdrMark LITERAL1 +kToshibaAcHdrSpace LITERAL1 +kToshibaAcHeat LITERAL1 +kToshibaAcMaxTemp LITERAL1 +kToshibaAcMinGap LITERAL1 +kToshibaAcMinTemp LITERAL1 +kToshibaAcOneSpace LITERAL1 +kToshibaAcPower LITERAL1 +kToshibaAcZeroSpace LITERAL1 +kTrotecAuto LITERAL1 +kTrotecCool LITERAL1 +kTrotecDefTemp LITERAL1 +kTrotecDefaultRepeat LITERAL1 +kTrotecDry LITERAL1 +kTrotecFan LITERAL1 +kTrotecFanHigh LITERAL1 +kTrotecFanLow LITERAL1 +kTrotecFanMed LITERAL1 +kTrotecGap LITERAL1 +kTrotecGapEnd LITERAL1 +kTrotecHdrMark LITERAL1 +kTrotecHdrSpace LITERAL1 +kTrotecIntro1 LITERAL1 +kTrotecIntro2 LITERAL1 +kTrotecMaxTemp LITERAL1 +kTrotecMaxTimer LITERAL1 +kTrotecMinTemp LITERAL1 +kTrotecMinTimer LITERAL1 +kTrotecOff LITERAL1 +kTrotecOn LITERAL1 +kTrotecOneMark LITERAL1 +kTrotecOneSpace LITERAL1 +kTrotecSleepOn LITERAL1 +kTrotecStateLength LITERAL1 +kTrotecTimerOn LITERAL1 +kTrotecZeroMark LITERAL1 +kTrotecZeroSpace LITERAL1 +kUnknownThreshold LITERAL1 +kVestelACAuto LITERAL1 +kVestelACBitMark LITERAL1 +kVestelACBits LITERAL1 +kVestelACCRCMask LITERAL1 +kVestelACCool LITERAL1 +kVestelACDry LITERAL1 +kVestelACFan LITERAL1 +kVestelACFanAuto LITERAL1 +kVestelACFanAutoCool LITERAL1 +kVestelACFanAutoHot LITERAL1 +kVestelACFanHigh LITERAL1 +kVestelACFanLow LITERAL1 +kVestelACFanMed LITERAL1 +kVestelACHdrMark LITERAL1 +kVestelACHdrSpace LITERAL1 +kVestelACHeat LITERAL1 +kVestelACIon LITERAL1 +kVestelACMaxTemp LITERAL1 +kVestelACMinTempC LITERAL1 +kVestelACMinTempH LITERAL1 +kVestelACNormal LITERAL1 +kVestelACOneSpace LITERAL1 +kVestelACSleep LITERAL1 +kVestelACSwing LITERAL1 +kVestelACTolerance LITERAL1 +kVestelACTurbo LITERAL1 +kVestelACZeroSpace LITERAL1 +kWhirlpoolAcAltTempMask LITERAL1 +kWhirlpoolAcAltTempPos LITERAL1 +kWhirlpoolAcAuto LITERAL1 +kWhirlpoolAcAutoTemp LITERAL1 +kWhirlpoolAcBitMark LITERAL1 +kWhirlpoolAcBits LITERAL1 +kWhirlpoolAcChecksumByte1 LITERAL1 +kWhirlpoolAcChecksumByte2 LITERAL1 +kWhirlpoolAcClockPos LITERAL1 +kWhirlpoolAcCommand6thSense LITERAL1 +kWhirlpoolAcCommandFanSpeed LITERAL1 +kWhirlpoolAcCommandIFeel LITERAL1 +kWhirlpoolAcCommandLight LITERAL1 +kWhirlpoolAcCommandMode LITERAL1 +kWhirlpoolAcCommandOffTimer LITERAL1 +kWhirlpoolAcCommandOnTimer LITERAL1 +kWhirlpoolAcCommandPos LITERAL1 +kWhirlpoolAcCommandPower LITERAL1 +kWhirlpoolAcCommandSleep LITERAL1 +kWhirlpoolAcCommandSuper LITERAL1 +kWhirlpoolAcCommandSwing LITERAL1 +kWhirlpoolAcCommandTemp LITERAL1 +kWhirlpoolAcCool LITERAL1 +kWhirlpoolAcDefaultRepeat LITERAL1 +kWhirlpoolAcDry LITERAL1 +kWhirlpoolAcFan LITERAL1 +kWhirlpoolAcFanAuto LITERAL1 +kWhirlpoolAcFanHigh LITERAL1 +kWhirlpoolAcFanLow LITERAL1 +kWhirlpoolAcFanMask LITERAL1 +kWhirlpoolAcFanMedium LITERAL1 +kWhirlpoolAcFanPos LITERAL1 +kWhirlpoolAcGap LITERAL1 +kWhirlpoolAcHdrMark LITERAL1 +kWhirlpoolAcHdrSpace LITERAL1 +kWhirlpoolAcHeat LITERAL1 +kWhirlpoolAcHourMask LITERAL1 +kWhirlpoolAcLightMask LITERAL1 +kWhirlpoolAcMaxTemp LITERAL1 +kWhirlpoolAcMinGap LITERAL1 +kWhirlpoolAcMinTemp LITERAL1 +kWhirlpoolAcMinuteMask LITERAL1 +kWhirlpoolAcModeMask LITERAL1 +kWhirlpoolAcModePos LITERAL1 +kWhirlpoolAcOffTimerPos LITERAL1 +kWhirlpoolAcOnTimerPos LITERAL1 +kWhirlpoolAcOneSpace LITERAL1 +kWhirlpoolAcPowerToggleMask LITERAL1 +kWhirlpoolAcPowerTogglePos LITERAL1 +kWhirlpoolAcSections LITERAL1 +kWhirlpoolAcSleepMask LITERAL1 +kWhirlpoolAcSleepPos LITERAL1 +kWhirlpoolAcStateLength LITERAL1 +kWhirlpoolAcSuperMask LITERAL1 +kWhirlpoolAcSuperPos LITERAL1 +kWhirlpoolAcSwing1Mask LITERAL1 +kWhirlpoolAcSwing2Mask LITERAL1 +kWhirlpoolAcTempMask LITERAL1 +kWhirlpoolAcTempPos LITERAL1 +kWhirlpoolAcTimerEnableMask LITERAL1 +kWhirlpoolAcZeroSpace LITERAL1 +kWhynterBitMark LITERAL1 +kWhynterBitMarkTicks LITERAL1 +kWhynterBits LITERAL1 +kWhynterHdrMark LITERAL1 +kWhynterHdrMarkTicks LITERAL1 +kWhynterHdrSpace LITERAL1 +kWhynterHdrSpaceTicks LITERAL1 +kWhynterMinCommandLength LITERAL1 +kWhynterMinCommandLengthTicks LITERAL1 +kWhynterMinGap LITERAL1 +kWhynterMinGapTicks LITERAL1 +kWhynterOneSpace LITERAL1 +kWhynterOneSpaceTicks LITERAL1 +kWhynterTick LITERAL1 +kWhynterZeroSpace LITERAL1 +kWhynterZeroSpaceTicks LITERAL1 diff --git a/lib/IRremoteESP8266/library.json b/lib/IRremoteESP8266/library.json index dac47af..e8e33c6 100644 --- a/lib/IRremoteESP8266/library.json +++ b/lib/IRremoteESP8266/library.json @@ -1,6 +1,6 @@ { "name": "IRremoteESP8266", - "version": "2.4.2", + "version": "2.5.5", "keywords": "infrared, ir, remote, esp8266", "description": "Send and receive infrared signals with multiple protocols (ESP8266)", "repository": diff --git a/lib/IRremoteESP8266/library.properties b/lib/IRremoteESP8266/library.properties index f972c06..1237fe8 100644 --- a/lib/IRremoteESP8266/library.properties +++ b/lib/IRremoteESP8266/library.properties @@ -1,5 +1,5 @@ name=IRremoteESP8266 -version=2.4.2 +version=2.5.5 author=Sebastien Warin, Mark Szabo, Ken Shirriff, David Conran maintainer=Mark Szabo, David Conran, Sebastien Warin, Roi Dayan, Massimiliano Pinto sentence=Send and receive infrared signals with multiple protocols (ESP8266) diff --git a/lib/IRremoteESP8266/src/IRrecv.cpp b/lib/IRremoteESP8266/src/IRrecv.cpp index 3dc4364..9e926de 100644 --- a/lib/IRremoteESP8266/src/IRrecv.cpp +++ b/lib/IRremoteESP8266/src/IRrecv.cpp @@ -7,13 +7,14 @@ #include #ifndef UNIT_TEST extern "C" { - #include - #include +#include +#include } #include #endif #include #include "IRremoteESP8266.h" +#include "IRutils.h" #ifdef UNIT_TEST #undef ICACHE_RAM_ATTR @@ -34,8 +35,7 @@ irparams_t *irparams_save; // A copy of the interrupt state while decoding. #ifndef UNIT_TEST static void ICACHE_RAM_ATTR read_timeout(void *arg __attribute__((unused))) { os_intr_lock(); - if (irparams.rawlen) - irparams.rcvstate = STATE_STOP; + if (irparams.rawlen) irparams.rcvstate = kStopState; os_intr_unlock(); } @@ -57,25 +57,24 @@ static void ICACHE_RAM_ATTR gpio_intr() { if (rawlen >= irparams.bufsize) { irparams.overflow = true; - irparams.rcvstate = STATE_STOP; + irparams.rcvstate = kStopState; } - if (irparams.rcvstate == STATE_STOP) - return; + if (irparams.rcvstate == kStopState) return; - if (irparams.rcvstate == STATE_IDLE) { - irparams.rcvstate = STATE_MARK; + if (irparams.rcvstate == kIdleState) { + irparams.rcvstate = kMarkState; irparams.rawbuf[rawlen] = 1; } else { if (now < start) - irparams.rawbuf[rawlen] = (UINT32_MAX - start + now) / RAWTICK; + irparams.rawbuf[rawlen] = (UINT32_MAX - start + now) / kRawTick; else - irparams.rawbuf[rawlen] = (now - start) / RAWTICK; + irparams.rawbuf[rawlen] = (now - start) / kRawTick; } irparams.rawlen++; start = now; - #define ONCE 0 +#define ONCE 0 os_timer_arm(&timer, irparams.timeout, ONCE); } #endif // UNIT_TEST @@ -85,9 +84,9 @@ static void ICACHE_RAM_ATTR gpio_intr() { // Class constructor // Args: // recvpin: GPIO pin the IR receiver module's data pin is connected to. -// bufsize: Nr. of entries to have in the capture buffer. (Default: RAWBUF) +// bufsize: Nr. of entries to have in the capture buffer. (Default: kRawBuf) // timeout: Nr. of milli-Seconds of no signal before we stop capturing data. -// (Default: TIMEOUT_MS) +// (Default: kTimeoutMs) // save_buffer: Use a second (save) buffer to decode from. (Def: false) // Returns: // An IRrecv class object. @@ -97,11 +96,12 @@ IRrecv::IRrecv(uint16_t recvpin, uint16_t bufsize, uint8_t timeout, irparams.bufsize = bufsize; // Ensure we are going to be able to store all possible values in the // capture buffer. - irparams.timeout = std::min(timeout, (uint8_t) MAX_TIMEOUT_MS); + irparams.timeout = std::min(timeout, (uint8_t)kMaxTimeoutMs); irparams.rawbuf = new uint16_t[bufsize]; if (irparams.rawbuf == NULL) { - DPRINTLN("Could not allocate memory for the primary IR buffer.\n" - "Try a smaller size for CAPTURE_BUFFER_SIZE.\nRebooting!"); + DPRINTLN( + "Could not allocate memory for the primary IR buffer.\n" + "Try a smaller size for CAPTURE_BUFFER_SIZE.\nRebooting!"); #ifndef UNIT_TEST ESP.restart(); // Mem alloc failure. Reboot. #endif @@ -112,8 +112,9 @@ IRrecv::IRrecv(uint16_t recvpin, uint16_t bufsize, uint8_t timeout, irparams_save->rawbuf = new uint16_t[bufsize]; // Check we allocated the memory successfully. if (irparams_save->rawbuf == NULL) { - DPRINTLN("Could not allocate memory for the second IR buffer.\n" - "Try a smaller size for CAPTURE_BUFFER_SIZE.\nRebooting!"); + DPRINTLN( + "Could not allocate memory for the second IR buffer.\n" + "Try a smaller size for CAPTURE_BUFFER_SIZE.\nRebooting!"); #ifndef UNIT_TEST ESP.restart(); // Mem alloc failure. Reboot. #endif @@ -122,15 +123,15 @@ IRrecv::IRrecv(uint16_t recvpin, uint16_t bufsize, uint8_t timeout, irparams_save = NULL; } #if DECODE_HASH - unknown_threshold = UNKNOWN_THRESHOLD; + unknown_threshold = kUnknownThreshold; #endif // DECODE_HASH } // Class destructor IRrecv::~IRrecv(void) { - delete [] irparams.rawbuf; + delete[] irparams.rawbuf; if (irparams_save != NULL) { - delete [] irparams_save->rawbuf; + delete[] irparams_save->rawbuf; delete irparams_save; } } @@ -159,7 +160,7 @@ void IRrecv::disableIRIn() { } void IRrecv::resume() { - irparams.rcvstate = STATE_IDLE; + irparams.rcvstate = kIdleState; irparams.rawlen = 0; irparams.overflow = false; } @@ -167,15 +168,15 @@ void IRrecv::resume() { // Make a copy of the interrupt state & buffer data. // Needed because irparams is marked as volatile, thus memcpy() isn't allowed. // Only call this when you know the interrupt handlers won't modify anything. -// i.e. In STATE_STOP. +// i.e. In kStopState. // // Args: // src: Pointer to an irparams_t structure to copy from. // dst: Pointer to an irparams_t structure to copy to. void IRrecv::copyIrParams(volatile irparams_t *src, irparams_t *dst) { // Typecast src and dst addresses to (char *) - char *csrc = (char *) src; // NOLINT(readability/casting) - char *cdst = (char *) dst; // NOLINT(readability/casting) + char *csrc = (char *)src; // NOLINT(readability/casting) + char *cdst = (char *)dst; // NOLINT(readability/casting) // Save the pointer to the destination's rawbuf so we don't lose it as // the for-loop/copy after this will overwrite it with src's rawbuf pointer. @@ -184,22 +185,18 @@ void IRrecv::copyIrParams(volatile irparams_t *src, irparams_t *dst) { dst_rawbuf_ptr = dst->rawbuf; // Copy contents of src[] to dst[] - for (uint16_t i = 0; i < sizeof(irparams_t); i++) - cdst[i] = csrc[i]; + for (uint16_t i = 0; i < sizeof(irparams_t); i++) cdst[i] = csrc[i]; // Restore the buffer pointer dst->rawbuf = dst_rawbuf_ptr; // Copy the rawbuf - for (uint16_t i = 0; i < dst->bufsize; i++) - dst->rawbuf[i] = src->rawbuf[i]; + for (uint16_t i = 0; i < dst->bufsize; i++) dst->rawbuf[i] = src->rawbuf[i]; } // Obtain the maximum number of entries possible in the capture buffer. // i.e. It's size. -uint16_t IRrecv::getBufSize() { - return irparams.bufsize; -} +uint16_t IRrecv::getBufSize() { return irparams.bufsize; } #if DECODE_HASH // Set the minimum length we will consider for reporting UNKNOWN message types. @@ -223,8 +220,7 @@ void IRrecv::setUnknownThreshold(uint16_t length) { bool IRrecv::decode(decode_results *results, irparams_t *save) { // Proceed only if an IR message been received. #ifndef UNIT_TEST - if (irparams.rcvstate != STATE_STOP) - return false; + if (irparams.rcvstate != kStopState) return false; #endif // Clear the entry we are currently pointing to when we got the timeout. @@ -240,8 +236,7 @@ bool IRrecv::decode(decode_results *results, irparams_t *save) { bool resumed = false; // Flag indicating if we have resumed. // If we were requested to use a save buffer previously, do so. - if (save == NULL) - save = irparams_save; + if (save == NULL) save = irparams_save; if (save == NULL) { // We haven't been asked to copy it so use the existing memory. @@ -273,8 +268,7 @@ bool IRrecv::decode(decode_results *results, irparams_t *save) { // Try decodeAiwaRCT501() before decodeSanyoLC7461() & decodeNEC() // because the protocols are similar. This protocol is more specific than // those ones, so should got before them. - if (decodeAiwaRCT501(results)) - return true; + if (decodeAiwaRCT501(results)) return true; #endif #if DECODE_SANYO DPRINTLN("Attempting Sanyo LC7461 decode"); @@ -282,8 +276,7 @@ bool IRrecv::decode(decode_results *results, irparams_t *save) { // similar in timings & structure, but the Sanyo one is much longer than the // NEC protocol (42 vs 32 bits) so this one should be tried first to try to // reduce false detection as a NEC packet. - if (decodeSanyoLC7461(results)) - return true; + if (decodeSanyoLC7461(results)) return true; #endif #if DECODE_CARRIER_AC DPRINTLN("Attempting Carrier AC decode"); @@ -291,141 +284,131 @@ bool IRrecv::decode(decode_results *results, irparams_t *save) { // similar in timings & structure, but the Carrier one is much longer than the // NEC protocol (3x32 bits vs 1x32 bits) so this one should be tried first to // try to reduce false detection as a NEC packet. - if (decodeCarrierAC(results)) - return true; + if (decodeCarrierAC(results)) return true; +#endif +#if DECODE_PIONEER + DPRINTLN("Attempting Pioneer decode"); + // Try decodePioneer() before decodeNEC() because the protocols are + // similar in timings & structure, but the Pioneer one is much longer than the + // NEC protocol (2x32 bits vs 1x32 bits) so this one should be tried first to + // try to reduce false detection as a NEC packet. + if (decodePioneer(results)) return true; #endif #if DECODE_NEC DPRINTLN("Attempting NEC decode"); - if (decodeNEC(results)) - return true; + if (decodeNEC(results)) return true; #endif #if DECODE_SONY DPRINTLN("Attempting Sony decode"); - if (decodeSony(results)) - return true; + if (decodeSony(results)) return true; #endif #if DECODE_MITSUBISHI DPRINTLN("Attempting Mitsubishi decode"); - if (decodeMitsubishi(results)) - return true; + if (decodeMitsubishi(results)) return true; +#endif +#if DECODE_MITSUBISHI_AC + DPRINTLN("Attempting Mitsubishi AC decode"); + if (decodeMitsubishiAC(results)) return true; #endif #if DECODE_MITSUBISHI2 DPRINTLN("Attempting Mitsubishi2 decode"); - if (decodeMitsubishi2(results)) - return true; + if (decodeMitsubishi2(results)) return true; #endif #if DECODE_RC5 DPRINTLN("Attempting RC5 decode"); - if (decodeRC5(results)) - return true; + if (decodeRC5(results)) return true; #endif #if DECODE_RC6 DPRINTLN("Attempting RC6 decode"); - if (decodeRC6(results)) - return true; + if (decodeRC6(results)) return true; #endif #if DECODE_RCMM DPRINTLN("Attempting RC-MM decode"); - if (decodeRCMM(results)) - return true; + if (decodeRCMM(results)) return true; #endif #if DECODE_FUJITSU_AC // Fujitsu A/C needs to precede Panasonic and Denon as it has a short // message which looks exactly the same as a Panasonic/Denon message. DPRINTLN("Attempting Fujitsu A/C decode"); - if (decodeFujitsuAC(results)) - return true; + if (decodeFujitsuAC(results)) return true; #endif #if DECODE_DENON // Denon needs to precede Panasonic as it is a special case of Panasonic. DPRINTLN("Attempting Denon decode"); - if (decodeDenon(results, DENON_48_BITS) || - decodeDenon(results, DENON_BITS) || - decodeDenon(results, DENON_LEGACY_BITS)) + if (decodeDenon(results, DENON_48_BITS) || decodeDenon(results, DENON_BITS) || + decodeDenon(results, kDenonLegacyBits)) return true; #endif #if DECODE_PANASONIC DPRINTLN("Attempting Panasonic decode"); - if (decodePanasonic(results)) - return true; + if (decodePanasonic(results)) return true; #endif #if DECODE_LG DPRINTLN("Attempting LG (28-bit) decode"); - if (decodeLG(results, LG_BITS, true)) - return true; + if (decodeLG(results, kLgBits, true)) return true; DPRINTLN("Attempting LG (32-bit) decode"); // LG32 should be tried before Samsung - if (decodeLG(results, LG32_BITS, true)) - return true; + if (decodeLG(results, kLg32Bits, true)) return true; #endif #if DECODE_GICABLE // Note: Needs to happen before JVC decode, because it looks similar except // with a required NEC-like repeat code. DPRINTLN("Attempting GICable decode"); - if (decodeGICable(results)) - return true; + if (decodeGICable(results)) return true; #endif #if DECODE_JVC DPRINTLN("Attempting JVC decode"); - if (decodeJVC(results)) - return true; + if (decodeJVC(results)) return true; #endif #if DECODE_SAMSUNG DPRINTLN("Attempting SAMSUNG decode"); - if (decodeSAMSUNG(results)) - return true; + if (decodeSAMSUNG(results)) return true; #endif #if DECODE_WHYNTER DPRINTLN("Attempting Whynter decode"); - if (decodeWhynter(results)) - return true; + if (decodeWhynter(results)) return true; #endif #if DECODE_DISH DPRINTLN("Attempting DISH decode"); - if (decodeDISH(results)) - return true; + if (decodeDISH(results)) return true; #endif #if DECODE_SHARP DPRINTLN("Attempting Sharp decode"); - if (decodeSharp(results)) - return true; + if (decodeSharp(results)) return true; #endif #if DECODE_COOLIX DPRINTLN("Attempting Coolix decode"); - if (decodeCOOLIX(results)) - return true; + if (decodeCOOLIX(results)) return true; #endif #if DECODE_NIKAI DPRINTLN("Attempting Nikai decode"); - if (decodeNikai(results)) - return true; + if (decodeNikai(results)) return true; #endif #if DECODE_KELVINATOR -// Kelvinator based-devices use a similar code to Gree ones, to avoid false -// matches this needs to happen before decodeGree(). + // Kelvinator based-devices use a similar code to Gree ones, to avoid false + // matches this needs to happen before decodeGree(). DPRINTLN("Attempting Kelvinator decode"); - if (decodeKelvinator(results)) - return true; + if (decodeKelvinator(results)) return true; #endif #if DECODE_DAIKIN DPRINTLN("Attempting Daikin decode"); - if (decodeDaikin(results)) - return true; + if (decodeDaikin(results)) return true; +#endif +#if DECODE_DAIKIN2 + DPRINTLN("Attempting Daikin2 decode"); + if (decodeDaikin2(results)) return true; #endif #if DECODE_TOSHIBA_AC DPRINTLN("Attempting Toshiba AC decode"); - if (decodeToshibaAC(results)) - return true; + if (decodeToshibaAC(results)) return true; #endif #if DECODE_MIDEA DPRINTLN("Attempting Midea decode"); - if (decodeMidea(results)) - return true; + if (decodeMidea(results)) return true; #endif #if DECODE_MAGIQUEST DPRINTLN("Attempting Magiquest decode"); - if (decodeMagiQuest(results)) - return true; + if (decodeMagiQuest(results)) return true; #endif /* NOTE: Disabled due to poor quality. #if DECODE_SANYO @@ -444,43 +427,75 @@ bool IRrecv::decode(decode_results *results, irparams_t *save) { // other protocols that are NEC-like as well, as turning off strict may // cause this to match other valid protocols. DPRINTLN("Attempting NEC (non-strict) decode"); - if (decodeNEC(results, NEC_BITS, false)) { + if (decodeNEC(results, kNECBits, false)) { results->decode_type = NEC_LIKE; return true; } #endif #if DECODE_LASERTAG DPRINTLN("Attempting Lasertag decode"); - if (decodeLasertag(results)) - return true; + if (decodeLasertag(results)) return true; #endif #if DECODE_GREE // Gree based-devices use a similar code to Kelvinator ones, to avoid false // matches this needs to happen after decodeKelvinator(). DPRINTLN("Attempting Gree decode"); - if (decodeGree(results)) - return true; + if (decodeGree(results)) return true; #endif #if DECODE_HAIER_AC DPRINTLN("Attempting Haier AC decode"); - if (decodeHaierAC(results)) - return true; + if (decodeHaierAC(results)) return true; +#endif +#if DECODE_HAIER_AC_YRW02 + DPRINTLN("Attempting Haier AC YR-W02 decode"); + if (decodeHaierACYRW02(results)) return true; #endif #if DECODE_HITACHI_AC2 // HitachiAC2 should be checked before HitachiAC DPRINTLN("Attempting Hitachi AC2 decode"); - if (decodeHitachiAC(results, HITACHI_AC2_BITS)) - return true; + if (decodeHitachiAC(results, kHitachiAc2Bits)) return true; #endif #if DECODE_HITACHI_AC DPRINTLN("Attempting Hitachi AC decode"); - if (decodeHitachiAC(results, HITACHI_AC_BITS)) - return true; + if (decodeHitachiAC(results, kHitachiAcBits)) return true; #endif #if DECODE_HITACHI_AC1 DPRINTLN("Attempting Hitachi AC1 decode"); - if (decodeHitachiAC(results, HITACHI_AC1_BITS)) - return true; + if (decodeHitachiAC(results, kHitachiAc1Bits)) return true; +#endif +#if DECODE_WHIRLPOOL_AC + DPRINTLN("Attempting Whirlpool AC decode"); + if (decodeWhirlpoolAC(results)) return true; +#endif +#if DECODE_SAMSUNG_AC + DPRINTLN("Attempting Samsung AC (extended) decode"); + // Check the extended size first, as it should fail fast due to longer length. + if (decodeSamsungAC(results, kSamsungAcExtendedBits, false)) return true; + // Now check for the more common length. + DPRINTLN("Attempting Samsung AC decode"); + if (decodeSamsungAC(results, kSamsungAcBits)) return true; +#endif +#if DECODE_ELECTRA_AC + DPRINTLN("Attempting Electra AC decode"); + if (decodeElectraAC(results)) return true; +#endif +#if DECODE_PANASONIC_AC + DPRINTLN("Attempting Panasonic AC decode"); + if (decodePanasonicAC(results)) return true; + DPRINTLN("Attempting Panasonic AC short decode"); + if (decodePanasonicAC(results, kPanasonicAcShortBits)) return true; +#endif +#if DECODE_LUTRON + DPRINTLN("Attempting Lutron decode"); + if (decodeLutron(results)) return true; +#endif +#if DECODE_MWM + DPRINTLN("Attempting MWM decode"); + if (decodeMWM(results)) return true; +#endif +#if DECODE_VESTEL_AC + DPRINTLN("Attempting Vestel AC decode"); + if (decodeVestelAC(results)) return true; #endif #if DECODE_HASH // decodeHash returns a hash on any input. @@ -506,8 +521,8 @@ bool IRrecv::decode(decode_results *results, irparams_t *save) { // Nr. of ticks. uint32_t IRrecv::ticksLow(uint32_t usecs, uint8_t tolerance, uint16_t delta) { // max() used to ensure the result can't drop below 0 before the cast. - return((uint32_t) std::max( - (int32_t) (usecs * (1.0 - tolerance / 100.0) - delta), 0)); + return ((uint32_t)std::max( + (int32_t)(usecs * (1.0 - tolerance / 100.0) - delta), 0)); } // Calculate the upper bound of the nr. of ticks. @@ -519,7 +534,7 @@ uint32_t IRrecv::ticksLow(uint32_t usecs, uint8_t tolerance, uint16_t delta) { // Returns: // Nr. of ticks. uint32_t IRrecv::ticksHigh(uint32_t usecs, uint8_t tolerance, uint16_t delta) { - return((uint32_t) (usecs * (1.0 + tolerance / 100.0)) + 1 + delta); + return ((uint32_t)(usecs * (1.0 + tolerance / 100.0)) + 1 + delta); } // Check if we match a pulse(measured) with the desired within @@ -533,9 +548,9 @@ uint32_t IRrecv::ticksHigh(uint32_t usecs, uint8_t tolerance, uint16_t delta) { // // Returns: // Boolean: true if it matches, false if it doesn't. -bool IRrecv::match(uint32_t measured, uint32_t desired, - uint8_t tolerance, uint16_t delta) { - measured *= RAWTICK; // Convert to uSecs. +bool IRrecv::match(uint32_t measured, uint32_t desired, uint8_t tolerance, + uint16_t delta) { + measured *= kRawTick; // Convert to uSecs. DPRINT("Matching: "); DPRINT(ticksLow(desired, tolerance, delta)); DPRINT(" <= "); @@ -546,7 +561,6 @@ bool IRrecv::match(uint32_t measured, uint32_t desired, measured <= ticksHigh(desired, tolerance, delta)); } - // Check if we match a pulse(measured) of at least desired within // tolerance percent and/or a fixed delta margin. // @@ -561,7 +575,7 @@ bool IRrecv::match(uint32_t measured, uint32_t desired, // Boolean: true if it matches, false if it doesn't. bool IRrecv::matchAtLeast(uint32_t measured, uint32_t desired, uint8_t tolerance, uint16_t delta) { - measured *= RAWTICK; // Convert to uSecs. + measured *= kRawTick; // Convert to uSecs. DPRINT("Matching ATLEAST "); DPRINT(measured); DPRINT(" vs "); @@ -594,10 +608,10 @@ bool IRrecv::matchAtLeast(uint32_t measured, uint32_t desired, // // Returns: // Boolean: true if it matches, false if it doesn't. -bool IRrecv::matchMark(uint32_t measured, uint32_t desired, - uint8_t tolerance, int16_t excess) { +bool IRrecv::matchMark(uint32_t measured, uint32_t desired, uint8_t tolerance, + int16_t excess) { DPRINT("Matching MARK "); - DPRINT(measured * RAWTICK); + DPRINT(measured * kRawTick); DPRINT(" vs "); DPRINT(desired); DPRINT(" + "); @@ -617,10 +631,10 @@ bool IRrecv::matchMark(uint32_t measured, uint32_t desired, // // Returns: // Boolean: true if it matches, false if it doesn't. -bool IRrecv::matchSpace(uint32_t measured, uint32_t desired, - uint8_t tolerance, int16_t excess) { +bool IRrecv::matchSpace(uint32_t measured, uint32_t desired, uint8_t tolerance, + int16_t excess) { DPRINT("Matching SPACE "); - DPRINT(measured * RAWTICK); + DPRINT(measured * kRawTick); DPRINT(" vs "); DPRINT(desired); DPRINT(" - "); @@ -662,9 +676,8 @@ int16_t IRrecv::compare(uint16_t oldval, uint16_t newval) { */ bool IRrecv::decodeHash(decode_results *results) { // Require at least some samples to prevent triggering on noise - if (results->rawlen < unknown_threshold) - return false; - int32_t hash = FNV_BASIS_32; + if (results->rawlen < unknown_threshold) return false; + int32_t hash = kFnvBasis32; // 'rawlen - 2' to avoid the look ahead from going out of bounds. // Should probably be -3 to avoid comparing the trailing space entry, // however it is left this way for compatibility with previously captured @@ -672,7 +685,7 @@ bool IRrecv::decodeHash(decode_results *results) { for (uint16_t i = 1; i < results->rawlen - 2; i++) { int16_t value = compare(results->rawbuf[i], results->rawbuf[i + 2]); // Add value into the hash - hash = (hash * FNV_PRIME_32) ^ value; + hash = (hash * kFnvPrime32) ^ value; } results->value = hash & 0xFFFFFFFF; results->bits = results->rawlen / 2; @@ -684,7 +697,8 @@ bool IRrecv::decodeHash(decode_results *results) { #endif // DECODE_HASH // Match & decode the typical data section of an IR message. -// The data value constructed as the Most Significant Bit first. +// The data value is stored in the least significant bits reguardless of the +// bit ordering requested. // // Args: // data_ptr: A pointer to where we are at in the capture buffer. @@ -693,34 +707,35 @@ bool IRrecv::decodeHash(decode_results *results) { // onespace: Nr. of uSeconds in an expected space signal for a '1' bit. // zeromark: Nr. of uSeconds in an expected mark signal for a '0' bit. // zerospace: Nr. of uSeconds in an expected space signal for a '0' bit. -// tolerance: Percentage error margin to allow. +// tolerance: Percentage error margin to allow. (Def: kTolerance) +// excess: Nr. of useconds. (Def: kMarkExcess) +// MSBfirst: Bit order to save the data in. (Def: true) // Returns: // A match_result_t structure containing the success (or not), the data value, // and how many buffer entries were used. -match_result_t IRrecv::matchData(volatile uint16_t *data_ptr, - const uint16_t nbits, const uint16_t onemark, - const uint32_t onespace, - const uint16_t zeromark, - const uint32_t zerospace, - const uint8_t tolerance) { +match_result_t IRrecv::matchData( + volatile uint16_t *data_ptr, const uint16_t nbits, const uint16_t onemark, + const uint32_t onespace, const uint16_t zeromark, const uint32_t zerospace, + const uint8_t tolerance, const int16_t excess, const bool MSBfirst) { match_result_t result; result.success = false; // Fail by default. result.data = 0; - for (result.used = 0; - result.used < nbits * 2; + for (result.used = 0; result.used < nbits * 2; result.used += 2, data_ptr += 2) { // Is the bit a '1'? - if (matchMark(*data_ptr, onemark, tolerance) && - matchSpace(*(data_ptr + 1), onespace, tolerance)) + if (matchMark(*data_ptr, onemark, tolerance, excess) && + matchSpace(*(data_ptr + 1), onespace, tolerance, excess)) { result.data = (result.data << 1) | 1; - // or is the bit a '0'? - else if (matchMark(*data_ptr, zeromark, tolerance) && - matchSpace(*(data_ptr + 1), zerospace, tolerance)) - result.data <<= 1; - else + } else if (matchMark(*data_ptr, zeromark, tolerance, excess) && + matchSpace(*(data_ptr + 1), zerospace, tolerance, excess)) { + result.data <<= 1; // The bit is a '0'. + } else { + if (!MSBfirst) result.data = reverseBits(result.data, result.used / 2); return result; // It's neither, so fail. + } } result.success = true; + if (!MSBfirst) result.data = reverseBits(result.data, nbits); return result; } diff --git a/lib/IRremoteESP8266/src/IRrecv.h b/lib/IRremoteESP8266/src/IRrecv.h index af98441..24df9b9 100644 --- a/lib/IRremoteESP8266/src/IRrecv.h +++ b/lib/IRremoteESP8266/src/IRrecv.h @@ -15,59 +15,68 @@ #include "IRremoteESP8266.h" // Constants -#define HEADER 2U // Usual nr. of header entries. -#define FOOTER 2U // Usual nr. of footer (stop bits) entries. -#define OFFSET_START 1U // Usual rawbuf entry to start processing from. -#define MS_TO_USEC(x) (x * 1000U) // Convert milli-Seconds to micro-Seconds. +const uint16_t kHeader = 2; // Usual nr. of header entries. +const uint16_t kFooter = 2; // Usual nr. of footer (stop bits) entries. +const uint16_t kStartOffset = 1; // Usual rawbuf entry to start from. +#define MS_TO_USEC(x) (x * 1000U) // Convert milli-Seconds to micro-Seconds. // Marks tend to be 100us too long, and spaces 100us too short // when received due to sensor lag. -#define MARK_EXCESS 50U -#define RAWBUF 100U // Default length of raw capture buffer -#define REPEAT UINT64_MAX -#define UNKNOWN_THRESHOLD 6U // Default min size of reported UNKNOWN messages. +const uint16_t kMarkExcess = 50; +const uint16_t kRawBuf = 100; // Default length of raw capture buffer +const uint64_t kRepeat = UINT64_MAX; +// Default min size of reported UNKNOWN messages. +const uint16_t kUnknownThreshold = 6; + // receiver states -#define STATE_IDLE 2U -#define STATE_MARK 3U -#define STATE_SPACE 4U -#define STATE_STOP 5U -#define TOLERANCE 25U // default percent tolerance in measurements -#define RAWTICK 2U // Capture tick to uSec factor. +const uint8_t kIdleState = 2; +const uint8_t kMarkState = 3; +const uint8_t kSpaceState = 4; +const uint8_t kStopState = 5; +const uint8_t kTolerance = 25; // default percent tolerance in measurements. +const uint16_t kRawTick = 2; // Capture tick to uSec factor. +#define RAWTICK kRawTick // Deprecated. For legacy user code support only. // How long (ms) before we give up wait for more data? -// Don't exceed MAX_TIMEOUT_MS without a good reason. -// That is the capture buffers maximum value size. (UINT16_MAX / RAWTICK) +// Don't exceed kMaxTimeoutMs without a good reason. +// That is the capture buffers maximum value size. (UINT16_MAX / kRawTick) // Typically messages/protocols tend to repeat around the 100ms timeframe, // thus we should timeout before that to give us some time to try to decode // before we need to start capturing a possible new message. // Typically 15ms suits most applications. However, some protocols demand a // higher value. e.g. 90ms for XMP-1 and some aircon units. -#define TIMEOUT_MS 15U // In MilliSeconds. -#define MAX_TIMEOUT_MS (RAWTICK * UINT16_MAX / MS_TO_USEC(1)) +const uint8_t kTimeoutMs = 15; // In MilliSeconds. +#define TIMEOUT_MS kTimeoutMs // For legacy documentation. +const uint16_t kMaxTimeoutMs = kRawTick * (UINT16_MAX / MS_TO_USEC(1)); // Use FNV hash algorithm: http://isthe.com/chongo/tech/comp/fnv/#FNV-param -#define FNV_PRIME_32 16777619UL -#define FNV_BASIS_32 2166136261UL +const uint32_t kFnvPrime32 = 16777619UL; +const uint32_t kFnvBasis32 = 2166136261UL; +#if DECODE_AC // Hitachi AC is the current largest state size. -#define STATE_SIZE_MAX HITACHI_AC2_STATE_LENGTH +const uint16_t kStateSizeMax = kHitachiAc2StateLength; +#else +// Just define something +const uint16_t kStateSizeMax = 0; +#endif // Types // information for the interrupt handler typedef struct { - uint8_t recvpin; // pin for IR data from detector - uint8_t rcvstate; // state machine - uint16_t timer; // state timer, counts 50uS ticks. - uint16_t bufsize; // max. nr. of entries in the capture buffer. - uint16_t *rawbuf; // raw data + uint8_t recvpin; // pin for IR data from detector + uint8_t rcvstate; // state machine + uint16_t timer; // state timer, counts 50uS ticks. + uint16_t bufsize; // max. nr. of entries in the capture buffer. + uint16_t *rawbuf; // raw data // uint16_t is used for rawlen as it saves 3 bytes of iram in the interrupt // handler. Don't ask why, I don't know. It just does. - uint16_t rawlen; // counter of entries in rawbuf. - uint8_t overflow; // Buffer overflow indicator. - uint8_t timeout; // Nr. of milliSeconds before we give up. + uint16_t rawlen; // counter of entries in rawbuf. + uint8_t overflow; // Buffer overflow indicator. + uint8_t timeout; // Nr. of milliSeconds before we give up. } irparams_t; // results from a data match typedef struct { - bool success; // Was the match successful? + bool success; // Was the match successful? uint64_t data; // The data found. uint16_t used; // How many buffer positions were used. } match_result_t; @@ -83,17 +92,15 @@ class decode_results { // structure to save us a handful of valuable bytes of memory. union { struct { - uint64_t value; // Decoded value + uint64_t value; // Decoded value uint32_t address; // Decoded device address. uint32_t command; // Decoded command. }; -#if DECODE_AC // Only include state if we must. It's big. - uint8_t state[STATE_SIZE_MAX]; // Complex multi-byte A/C result. -#endif + uint8_t state[kStateSizeMax]; // Multi-byte results. }; - uint16_t bits; // Number of bits in decoded value + uint16_t bits; // Number of bits in decoded value volatile uint16_t *rawbuf; // Raw intervals in .5 us ticks - uint16_t rawlen; // Number of records in rawbuf. + uint16_t rawlen; // Number of records in rawbuf. bool overflow; bool repeat; // Is the result a repeat code? }; @@ -101,10 +108,10 @@ class decode_results { // main class for receiving IR class IRrecv { public: - explicit IRrecv(uint16_t recvpin, uint16_t bufsize = RAWBUF, - uint8_t timeout = TIMEOUT_MS, + explicit IRrecv(uint16_t recvpin, uint16_t bufsize = kRawBuf, + uint8_t timeout = kTimeoutMs, bool save_buffer = false); // Constructor - ~IRrecv(); // Destructor + ~IRrecv(); // Destructor bool decode(decode_results *results, irparams_t *save = NULL); void enableIRIn(); void disableIRIn(); @@ -114,13 +121,13 @@ class IRrecv { void setUnknownThreshold(uint16_t length); #endif static bool match(uint32_t measured, uint32_t desired, - uint8_t tolerance = TOLERANCE, uint16_t delta = 0); + uint8_t tolerance = kTolerance, uint16_t delta = 0); static bool matchMark(uint32_t measured, uint32_t desired, - uint8_t tolerance = TOLERANCE, - int16_t excess = MARK_EXCESS); + uint8_t tolerance = kTolerance, + int16_t excess = kMarkExcess); static bool matchSpace(uint32_t measured, uint32_t desired, - uint8_t tolerance = TOLERANCE, - int16_t excess = MARK_EXCESS); + uint8_t tolerance = kTolerance, + int16_t excess = kMarkExcess); #ifndef UNIT_TEST private: @@ -132,84 +139,93 @@ class IRrecv { // These are called by decode void copyIrParams(volatile irparams_t *src, irparams_t *dst); int16_t compare(uint16_t oldval, uint16_t newval); - static uint32_t ticksLow(uint32_t usecs, uint8_t tolerance = TOLERANCE, - uint16_t delta = 0); - static uint32_t ticksHigh(uint32_t usecs, uint8_t tolerance = TOLERANCE, + static uint32_t ticksLow(uint32_t usecs, uint8_t tolerance = kTolerance, uint16_t delta = 0); + static uint32_t ticksHigh(uint32_t usecs, uint8_t tolerance = kTolerance, + uint16_t delta = 0); bool matchAtLeast(uint32_t measured, uint32_t desired, - uint8_t tolerance = TOLERANCE, uint16_t delta = 0); + uint8_t tolerance = kTolerance, uint16_t delta = 0); match_result_t matchData(volatile uint16_t *data_ptr, const uint16_t nbits, const uint16_t onemark, const uint32_t onespace, const uint16_t zeromark, const uint32_t zerospace, - const uint8_t tolerance = TOLERANCE); + const uint8_t tolerance = kTolerance, + const int16_t excess = kMarkExcess, + const bool MSBfirst = true); bool decodeHash(decode_results *results); #if (DECODE_NEC || DECODE_SHERWOOD || DECODE_AIWA_RC_T501 || SEND_SANYO) - bool decodeNEC(decode_results *results, uint16_t nbits = NEC_BITS, + bool decodeNEC(decode_results *results, uint16_t nbits = kNECBits, bool strict = true); #endif #if DECODE_SONY - bool decodeSony(decode_results *results, uint16_t nbits = SONY_MIN_BITS, + bool decodeSony(decode_results *results, uint16_t nbits = kSonyMinBits, bool strict = false); #endif #if DECODE_SANYO // DISABLED due to poor quality. // bool decodeSanyo(decode_results *results, - // uint16_t nbits = SANYO_SA8650B_BITS, + // uint16_t nbits = kSanyoSA8650BBits, // bool strict = false); bool decodeSanyoLC7461(decode_results *results, - uint16_t nbits = SANYO_LC7461_BITS, - bool strict = true); + uint16_t nbits = kSanyoLC7461Bits, bool strict = true); #endif #if DECODE_MITSUBISHI bool decodeMitsubishi(decode_results *results, - uint16_t nbits = MITSUBISHI_BITS, - bool strict = true); + uint16_t nbits = kMitsubishiBits, bool strict = true); #endif #if DECODE_MITSUBISHI2 bool decodeMitsubishi2(decode_results *results, - uint16_t nbits = MITSUBISHI_BITS, - bool strict = true); + uint16_t nbits = kMitsubishiBits, bool strict = true); #endif -#if (DECODE_RC5 || DECODE_R6 || DECODE_LASERTAG) +#if DECODE_MITSUBISHI_AC + bool decodeMitsubishiAC(decode_results *results, + uint16_t nbits = kMitsubishiACBits, + bool strict = false); +#endif +#if (DECODE_RC5 || DECODE_R6 || DECODE_LASERTAG || DECODE_MWM) int16_t getRClevel(decode_results *results, uint16_t *offset, uint16_t *used, - uint16_t bitTime, uint8_t tolerance = TOLERANCE, - int16_t excess = MARK_EXCESS, uint16_t delta = 0); + uint16_t bitTime, uint8_t tolerance = kTolerance, + int16_t excess = kMarkExcess, uint16_t delta = 0, + uint8_t maxwidth = 3); #endif #if DECODE_RC5 - bool decodeRC5(decode_results *results, uint16_t nbits = RC5X_BITS, + bool decodeRC5(decode_results *results, uint16_t nbits = kRC5XBits, bool strict = true); #endif #if DECODE_RC6 - bool decodeRC6(decode_results *results, uint16_t nbits = RC6_MODE0_BITS, + bool decodeRC6(decode_results *results, uint16_t nbits = kRC6Mode0Bits, bool strict = false); #endif #if DECODE_RCMM - bool decodeRCMM(decode_results *results, uint16_t nbits = RCMM_BITS, + bool decodeRCMM(decode_results *results, uint16_t nbits = kRCMMBits, bool strict = false); #endif #if (DECODE_PANASONIC || DECODE_DENON) - bool decodePanasonic(decode_results *results, uint16_t nbits = PANASONIC_BITS, + bool decodePanasonic(decode_results *results, uint16_t nbits = kPanasonicBits, bool strict = false, - uint32_t manufacturer = PANASONIC_MANUFACTURER); + uint32_t manufacturer = kPanasonicManufacturer); #endif #if DECODE_LG - bool decodeLG(decode_results *results, uint16_t nbits = LG_BITS, + bool decodeLG(decode_results *results, uint16_t nbits = kLgBits, bool strict = false); #endif #if DECODE_JVC - bool decodeJVC(decode_results *results, uint16_t nbits = JVC_BITS, + bool decodeJVC(decode_results *results, uint16_t nbits = kJvcBits, bool strict = true); #endif #if DECODE_SAMSUNG - bool decodeSAMSUNG(decode_results *results, uint16_t nbits = SAMSUNG_BITS, + bool decodeSAMSUNG(decode_results *results, uint16_t nbits = kSamsungBits, bool strict = true); #endif +#if DECODE_SAMSUNG_AC + bool decodeSamsungAC(decode_results *results, uint16_t nbits = kSamsungAcBits, + bool strict = true); +#endif #if DECODE_WHYNTER - bool decodeWhynter(decode_results *results, uint16_t nbits = WHYNTER_BITS, + bool decodeWhynter(decode_results *results, uint16_t nbits = kWhynterBits, bool strict = true); #endif #if DECODE_COOLIX - bool decodeCOOLIX(decode_results *results, uint16_t nbits = COOLIX_BITS, + bool decodeCOOLIX(decode_results *results, uint16_t nbits = kCoolixBits, bool strict = true); #endif #if DECODE_DENON @@ -217,77 +233,111 @@ class IRrecv { bool strict = true); #endif #if DECODE_DISH - bool decodeDISH(decode_results *results, uint16_t nbits = DISH_BITS, + bool decodeDISH(decode_results *results, uint16_t nbits = kDishBits, bool strict = true); #endif #if (DECODE_SHARP || DECODE_DENON) - bool decodeSharp(decode_results *results, uint16_t nbits = SHARP_BITS, + bool decodeSharp(decode_results *results, uint16_t nbits = kSharpBits, bool strict = true, bool expansion = true); #endif #if DECODE_AIWA_RC_T501 bool decodeAiwaRCT501(decode_results *results, - uint16_t nbits = AIWA_RC_T501_BITS, bool strict = true); + uint16_t nbits = kAiwaRcT501Bits, bool strict = true); #endif #if DECODE_NIKAI - bool decodeNikai(decode_results *results, uint16_t nbits = NIKAI_BITS, + bool decodeNikai(decode_results *results, uint16_t nbits = kNikaiBits, bool strict = true); #endif #if DECODE_MAGIQUEST - bool decodeMagiQuest(decode_results *results, uint16_t nbits = MAGIQUEST_BITS, + bool decodeMagiQuest(decode_results *results, uint16_t nbits = kMagiquestBits, bool strict = true); #endif #if DECODE_KELVINATOR bool decodeKelvinator(decode_results *results, - uint16_t nbits = KELVINATOR_BITS, - bool strict = true); + uint16_t nbits = kKelvinatorBits, bool strict = true); #endif #if DECODE_DAIKIN - bool decodeDaikin(decode_results *results, uint16_t nbits = DAIKIN_RAW_BITS, + bool decodeDaikin(decode_results *results, uint16_t nbits = kDaikinRawBits, bool strict = true); #endif +#if DECODE_DAIKIN2 + bool decodeDaikin2(decode_results *results, uint16_t nbits = kDaikin2Bits, + bool strict = true); +#endif #if DECODE_TOSHIBA_AC bool decodeToshibaAC(decode_results *results, - uint16_t nbytes = TOSHIBA_AC_BITS, - bool strict = true); + uint16_t nbytes = kToshibaACBits, bool strict = true); #endif #if DECODE_MIDEA - bool decodeMidea(decode_results *results, uint16_t nbits = MIDEA_BITS, + bool decodeMidea(decode_results *results, uint16_t nbits = kMideaBits, bool strict = true); #endif #if DECODE_FUJITSU_AC - bool decodeFujitsuAC(decode_results *results, - uint16_t nbits = FUJITSU_AC_BITS, + bool decodeFujitsuAC(decode_results *results, uint16_t nbits = kFujitsuAcBits, bool strict = false); #endif #if DECODE_LASERTAG - bool decodeLasertag(decode_results *results, uint16_t nbits = LASERTAG_BITS, + bool decodeLasertag(decode_results *results, uint16_t nbits = kLasertagBits, bool strict = true); #endif #if DECODE_CARRIER_AC - bool decodeCarrierAC(decode_results *results, - uint16_t nbits = CARRIER_AC_BITS, + bool decodeCarrierAC(decode_results *results, uint16_t nbits = kCarrierAcBits, bool strict = true); #endif #if DECODE_GREE - bool decodeGree(decode_results *results, - uint16_t nbits = GREE_BITS, bool strict = true); + bool decodeGree(decode_results *results, uint16_t nbits = kGreeBits, + bool strict = true); #endif -#if DECODE_HAIER_AC - bool decodeHaierAC(decode_results *results, - uint16_t nbits = HAIER_AC_BITS, bool strict = true); +#if (DECODE_HAIER_AC | DECODE_HAIER_AC_YRW02) + bool decodeHaierAC(decode_results *results, uint16_t nbits = kHaierACBits, + bool strict = true); +#endif +#if DECODE_HAIER_AC_YRW02 + bool decodeHaierACYRW02(decode_results *results, + uint16_t nbits = kHaierACYRW02Bits, + bool strict = true); #endif #if (DECODE_HITACHI_AC || DECODE_HITACHI_AC2) - bool decodeHitachiAC(decode_results *results, - uint16_t nbits = HITACHI_AC_BITS, bool strict = true); + bool decodeHitachiAC(decode_results *results, uint16_t nbits = kHitachiAcBits, + bool strict = true); #endif #if DECODE_HITACHI_AC1 bool decodeHitachiAC1(decode_results *results, - uint16_t nbits = HITACHI_AC1_BITS, bool strict = true); + uint16_t nbits = kHitachiAc1Bits, bool strict = true); #endif #if DECODE_GICABLE - bool decodeGICable(decode_results *results, uint16_t nbits = GICABLE_BITS, + bool decodeGICable(decode_results *results, uint16_t nbits = kGicableBits, bool strict = true); #endif +#if DECODE_WHIRLPOOL_AC + bool decodeWhirlpoolAC(decode_results *results, + uint16_t nbits = kWhirlpoolAcBits, bool strict = true); +#endif +#if DECODE_LUTRON + bool decodeLutron(decode_results *results, uint16_t nbits = kLutronBits, + bool strict = true); +#endif +#if DECODE_ELECTRA_AC + bool decodeElectraAC(decode_results *results, uint16_t nbits = kElectraAcBits, + bool strict = true); +#endif +#if DECODE_PANASONIC_AC + bool decodePanasonicAC(decode_results *results, + uint16_t nbits = kPanasonicAcBits, bool strict = true); +#endif +#if DECODE_PIONEER + bool decodePioneer(decode_results *results, + const uint16_t nbits = kPioneerBits, + const bool strict = true); +#endif +#if DECODE_MWM + bool decodeMWM(decode_results *results, uint16_t nbits = 24, + bool strict = true); +#endif +#if DECODE_VESTEL_AC + bool decodeVestelAC(decode_results *results, uint16_t nbits = kVestelACBits, + bool strict = true); +#endif }; #endif // IRRECV_H_ diff --git a/lib/IRremoteESP8266/src/IRremoteESP8266.h b/lib/IRremoteESP8266/src/IRremoteESP8266.h index 2e553f2..8912d58 100644 --- a/lib/IRremoteESP8266/src/IRremoteESP8266.h +++ b/lib/IRremoteESP8266/src/IRremoteESP8266.h @@ -33,7 +33,8 @@ * (https://github.com/mharizanov/Daikin-AC-remote-control-over-the-Internet/) * Fujitsu A/C code added by jonnygraham * Trotec AC code by stufisher - * Carrier AC code by crankyoldgit + * Carrier & Haier AC code by crankyoldgit + * Vestel AC code by Erdem U. Altınyurt * * GPL license, all text above must be included in any redistribution ****************************************************/ @@ -48,137 +49,169 @@ #endif // Library Version -#define _IRREMOTEESP8266_VERSION_ "2.4.2" +#define _IRREMOTEESP8266_VERSION_ "2.5.5" // Supported IR protocols // Each protocol you include costs memory and, during decode, costs time // Disable (set to false) all the protocols you do not need/want! // The Air Conditioner protocols are the most expensive memory-wise. // -#define DECODE_HASH true // Semi-unique code for unknown messages +#define DECODE_HASH true // Semi-unique code for unknown messages -#define SEND_RAW true +#define SEND_RAW true -#define DECODE_NEC true -#define SEND_NEC true +#define DECODE_NEC true +#define SEND_NEC true -#define DECODE_SHERWOOD true // Doesn't exist. Actually is DECODE_NEC -#define SEND_SHERWOOD true +#define DECODE_SHERWOOD true // Doesn't exist. Actually is DECODE_NEC +#define SEND_SHERWOOD true -#define DECODE_RC5 true -#define SEND_RC5 true +#define DECODE_RC5 true +#define SEND_RC5 true -#define DECODE_RC6 true -#define SEND_RC6 true +#define DECODE_RC6 true +#define SEND_RC6 true -#define DECODE_RCMM true -#define SEND_RCMM true +#define DECODE_RCMM true +#define SEND_RCMM true -#define DECODE_SONY true -#define SEND_SONY true +#define DECODE_SONY true +#define SEND_SONY true -#define DECODE_PANASONIC true -#define SEND_PANASONIC true +#define DECODE_PANASONIC true +#define SEND_PANASONIC true -#define DECODE_JVC true -#define SEND_JVC true +#define DECODE_JVC true +#define SEND_JVC true -#define DECODE_SAMSUNG true -#define SEND_SAMSUNG true +#define DECODE_SAMSUNG true +#define SEND_SAMSUNG true -#define DECODE_WHYNTER true -#define SEND_WHYNTER true +#define DECODE_SAMSUNG_AC true +#define SEND_SAMSUNG_AC true -#define DECODE_AIWA_RC_T501 true -#define SEND_AIWA_RC_T501 true +#define DECODE_WHYNTER true +#define SEND_WHYNTER true -#define DECODE_LG true -#define SEND_LG true +#define DECODE_AIWA_RC_T501 true +#define SEND_AIWA_RC_T501 true -#define DECODE_SANYO true -#define SEND_SANYO true +#define DECODE_LG true +#define SEND_LG true -#define DECODE_MITSUBISHI true -#define SEND_MITSUBISHI true +#define DECODE_SANYO true +#define SEND_SANYO true -#define DECODE_MITSUBISHI2 true -#define SEND_MITSUBISHI2 true +#define DECODE_MITSUBISHI true +#define SEND_MITSUBISHI true -#define DECODE_DISH true -#define SEND_DISH true +#define DECODE_MITSUBISHI2 true +#define SEND_MITSUBISHI2 true -#define DECODE_SHARP true -#define SEND_SHARP true +#define DECODE_DISH true +#define SEND_DISH true -#define DECODE_DENON true -#define SEND_DENON true +#define DECODE_SHARP true +#define SEND_SHARP true -#define DECODE_KELVINATOR true -#define SEND_KELVINATOR true +#define DECODE_DENON true +#define SEND_DENON true -#define DECODE_MITSUBISHI_AC false // Not written. -#define SEND_MITSUBISHI_AC true +#define DECODE_KELVINATOR true +#define SEND_KELVINATOR true -#define DECODE_FUJITSU_AC true -#define SEND_FUJITSU_AC true +#define DECODE_MITSUBISHI_AC true // Beta. +#define SEND_MITSUBISHI_AC true -#define DECODE_DAIKIN true -#define SEND_DAIKIN true +#define DECODE_FUJITSU_AC true +#define SEND_FUJITSU_AC true -#define DECODE_COOLIX true -#define SEND_COOLIX true +#define DECODE_DAIKIN true +#define SEND_DAIKIN true -#define DECODE_GLOBALCACHE false // Not written. -#define SEND_GLOBALCACHE true +#define DECODE_COOLIX true +#define SEND_COOLIX true -#define DECODE_GREE true -#define SEND_GREE true +#define DECODE_GLOBALCACHE false // Not written. +#define SEND_GLOBALCACHE true -#define DECODE_PRONTO false // Not written. -#define SEND_PRONTO true +#define DECODE_GREE true +#define SEND_GREE true -#define DECODE_ARGO false // Not written. -#define SEND_ARGO true +#define DECODE_PRONTO false // Not written. +#define SEND_PRONTO true -#define DECODE_TROTEC false // Not implemented. -#define SEND_TROTEC true +#define DECODE_ARGO false // Not written. +#define SEND_ARGO true -#define DECODE_NIKAI true -#define SEND_NIKAI true +#define DECODE_TROTEC false // Not implemented. +#define SEND_TROTEC true -#define DECODE_TOSHIBA_AC true -#define SEND_TOSHIBA_AC true +#define DECODE_NIKAI true +#define SEND_NIKAI true -#define DECODE_MAGIQUEST true -#define SEND_MAGIQUEST true +#define DECODE_TOSHIBA_AC true +#define SEND_TOSHIBA_AC true -#define DECODE_MIDEA true -#define SEND_MIDEA true +#define DECODE_MAGIQUEST true +#define SEND_MAGIQUEST true -#define DECODE_LASERTAG true -#define SEND_LASERTAG true +#define DECODE_MIDEA true +#define SEND_MIDEA true -#define DECODE_CARRIER_AC true -#define SEND_CARRIER_AC true +#define DECODE_LASERTAG true +#define SEND_LASERTAG true -#define DECODE_HAIER_AC true -#define SEND_HAIER_AC true +#define DECODE_CARRIER_AC true +#define SEND_CARRIER_AC true -#define DECODE_HITACHI_AC true -#define SEND_HITACHI_AC true +#define DECODE_HAIER_AC true +#define SEND_HAIER_AC true -#define DECODE_HITACHI_AC1 true -#define SEND_HITACHI_AC1 true +#define DECODE_HITACHI_AC true +#define SEND_HITACHI_AC true -#define DECODE_HITACHI_AC2 true -#define SEND_HITACHI_AC2 true +#define DECODE_HITACHI_AC1 true +#define SEND_HITACHI_AC1 true -#define DECODE_GICABLE true -#define SEND_GICABLE true +#define DECODE_HITACHI_AC2 true +#define SEND_HITACHI_AC2 true + +#define DECODE_GICABLE true +#define SEND_GICABLE true + +#define DECODE_HAIER_AC_YRW02 true +#define SEND_HAIER_AC_YRW02 true + +#define DECODE_WHIRLPOOL_AC true +#define SEND_WHIRLPOOL_AC true + +#define DECODE_LUTRON true +#define SEND_LUTRON true + +#define DECODE_ELECTRA_AC true +#define SEND_ELECTRA_AC true + +#define DECODE_PANASONIC_AC true +#define SEND_PANASONIC_AC true + +#define DECODE_MWM true +#define SEND_MWM true + +#define DECODE_PIONEER true +#define SEND_PIONEER true + +#define DECODE_DAIKIN2 true +#define SEND_DAIKIN2 true + +#define DECODE_VESTEL_AC true +#define SEND_VESTEL_AC true #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 || \ - DECODE_HITACHI_AC1 || DECODE_HITACHI_AC2) + DECODE_HITACHI_AC1 || DECODE_HITACHI_AC2 || DECODE_HAIER_AC_YRW02 || \ + DECODE_WHIRLPOOL_AC || DECODE_SAMSUNG_AC || DECODE_ELECTRA_AC || \ + DECODE_PANASONIC_AC || DECODE_MWM || DECODE_DAIKIN2 || DECODE_VESTEL_AC ) #define DECODE_AC true // We need some common infrastructure for decoding A/Cs. #else #define DECODE_AC false // We don't need that infrastructure. @@ -202,127 +235,229 @@ enum decode_type_t { RC6, NEC, SONY, - PANASONIC, + PANASONIC, // (5) JVC, SAMSUNG, WHYNTER, AIWA_RC_T501, - LG, + LG, // (10) SANYO, MITSUBISHI, DISH, SHARP, - COOLIX, + COOLIX, // (15) DAIKIN, DENON, KELVINATOR, SHERWOOD, - MITSUBISHI_AC, + MITSUBISHI_AC, // (20) RCMM, SANYO_LC7461, RC5X, GREE, - PRONTO, // Technically not a protocol, but an encoding. + PRONTO, // Technically not a protocol, but an encoding. (25) NEC_LIKE, ARGO, TROTEC, NIKAI, - RAW, // Technically not a protocol, but an encoding. + RAW, // Technically not a protocol, but an encoding. (30) GLOBALCACHE, // Technically not a protocol, but an encoding. TOSHIBA_AC, FUJITSU_AC, MIDEA, - MAGIQUEST, + MAGIQUEST, // (35) LASERTAG, CARRIER_AC, HAIER_AC, MITSUBISHI2, - HITACHI_AC, + HITACHI_AC, // (40) HITACHI_AC1, HITACHI_AC2, - GICABLE + GICABLE, + HAIER_AC_YRW02, + WHIRLPOOL_AC, // (45) + SAMSUNG_AC, + LUTRON, + ELECTRA_AC, + PANASONIC_AC, + PIONEER, // 50 + LG2, + MWM, + DAIKIN2, + VESTEL_AC, }; // Message lengths & required repeat values -#define AIWA_RC_T501_BITS 15U -#define AIWA_RC_T501_MIN_REPEAT 1U -#define COOLIX_BITS 24U -#define CARRIER_AC_BITS 32U -#define CARRIER_AC_MIN_REPEAT 0U +const uint16_t kNoRepeat = 0; +const uint16_t kSingleRepeat = 1; + +const uint16_t kAiwaRcT501Bits = 15; +const uint16_t kAiwaRcT501MinRepeats = kSingleRepeat; +const uint16_t kArgoStateLength = 12; +const uint16_t kArgoDefaultRepeat = kNoRepeat; +const uint16_t kCoolixBits = 24; +const uint16_t kCoolixDefaultRepeat = kNoRepeat; +const uint16_t kCarrierAcBits = 32; +const uint16_t kCarrierAcMinRepeat = kNoRepeat; // Daikin has a lot of static stuff that is discarded -#define DAIKIN_RAW_BITS 583U -#define DAIKIN_COMMAND_LENGTH 27U -#define DAIKIN_BITS (DAIKIN_COMMAND_LENGTH * 8) -#define DENON_BITS SHARP_BITS -#define DENON_48_BITS PANASONIC_BITS -#define DENON_LEGACY_BITS 14U -#define DISH_BITS 16U -#define DISH_MIN_REPEAT 3U -#define GICABLE_BITS 16U -#define GICABLE_MIN_REPEAT 1U -#define GREE_STATE_LENGTH 8U -#define GREE_BITS (GREE_STATE_LENGTH * 8) -#define HAIER_AC_STATE_LENGTH 9U -#define HAIER_AC_BITS (HAIER_AC_STATE_LENGTH * 8) -#define HITACHI_AC_STATE_LENGTH 28U -#define HITACHI_AC_BITS (HITACHI_AC_STATE_LENGTH * 8) -#define HITACHI_AC1_STATE_LENGTH 13U -#define HITACHI_AC1_BITS (HITACHI_AC1_STATE_LENGTH * 8) -#define HITACHI_AC2_STATE_LENGTH 53U -#define HITACHI_AC2_BITS (HITACHI_AC2_STATE_LENGTH * 8) -#define JVC_BITS 16U -#define KELVINATOR_STATE_LENGTH 16U -#define KELVINATOR_BITS (KELVINATOR_STATE_LENGTH * 8) -#define LG_BITS 28U -#define LG32_BITS 32U -#define MITSUBISHI_BITS 16U +const uint16_t kDaikinRawBits = 583; +const uint16_t kDaikinStateLength = 27; +const uint16_t kDaikinBits = kDaikinStateLength * 8; +const uint16_t kDaikinDefaultRepeat = kNoRepeat; +const uint16_t kDaikin2StateLength = 39; +const uint16_t kDaikin2Bits = kDaikin2StateLength * 8; +const uint16_t kDaikin2DefaultRepeat = kNoRepeat; +const uint16_t kDenonBits = 15; +const uint16_t kDenonLegacyBits = 14; +const uint16_t kDishBits = 16; +const uint16_t kDishMinRepeat = 3; +const uint16_t kElectraAcStateLength = 13; +const uint16_t kElectraAcBits = kElectraAcStateLength * 8; +const uint16_t kFujitsuAcMinRepeat = kNoRepeat; +const uint16_t kFujitsuAcStateLength = 16; +const uint16_t kFujitsuAcStateLengthShort = 7; +const uint16_t kFujitsuAcBits = kFujitsuAcStateLength * 8; +const uint16_t kFujitsuAcMinBits = (kFujitsuAcStateLengthShort - 1) * 8; +const uint16_t kGicableBits = 16; +const uint16_t kGicableMinRepeat = kSingleRepeat; +const uint16_t kGreeStateLength = 8; +const uint16_t kGreeBits = kGreeStateLength * 8; +const uint16_t kGreeDefaultRepeat = kNoRepeat; +const uint16_t kHaierACStateLength = 9; +const uint16_t kHaierACBits = kHaierACStateLength * 8; +const uint16_t kHaierAcDefaultRepeat = kNoRepeat; +const uint16_t kHaierACYRW02StateLength = 14; +const uint16_t kHaierACYRW02Bits = kHaierACYRW02StateLength * 8; +const uint16_t kHaierAcYrw02DefaultRepeat = kNoRepeat; +const uint16_t kHitachiAcStateLength = 28; +const uint16_t kHitachiAcBits = kHitachiAcStateLength * 8; +const uint16_t kHitachiAcDefaultRepeat = kNoRepeat; +const uint16_t kHitachiAc1StateLength = 13; +const uint16_t kHitachiAc1Bits = kHitachiAc1StateLength * 8; +const uint16_t kHitachiAc2StateLength = 53; +const uint16_t kHitachiAc2Bits = kHitachiAc2StateLength * 8; +const uint16_t kJvcBits = 16; +const uint16_t kKelvinatorStateLength = 16; +const uint16_t kKelvinatorBits = kKelvinatorStateLength * 8; +const uint16_t kKelvinatorDefaultRepeat = kNoRepeat; +const uint16_t kLasertagBits = 13; +const uint16_t kLasertagMinRepeat = kNoRepeat; +const uint16_t kLgBits = 28; +const uint16_t kLg32Bits = 32; +const uint16_t kLutronBits = 35; +const uint16_t kMagiquestBits = 56; +const uint16_t kMideaBits = 48; +const uint16_t kMideaMinRepeat = kNoRepeat; +const uint16_t kMitsubishiBits = 16; // TODO(anyone): Verify that the Mitsubishi repeat is really needed. -#define MITSUBISHI_MIN_REPEAT 1U // Based on marcosamarinho's code. -#define MITSUBISHI_AC_STATE_LENGTH 18U -#define MITSUBISHI_AC_MIN_REPEAT 1U -#define FUJITSU_AC_MIN_REPEAT 0U -#define FUJITSU_AC_STATE_LENGTH 16U -#define FUJITSU_AC_STATE_LENGTH_SHORT 7U -#define FUJITSU_AC_BITS (FUJITSU_AC_STATE_LENGTH * 8) -#define FUJITSU_AC_MIN_BITS ((FUJITSU_AC_STATE_LENGTH_SHORT - 1) * 8) -#define NEC_BITS 32U -#define PANASONIC_BITS 48U -#define PANASONIC_MANUFACTURER 0x4004ULL -#define PRONTO_MIN_LENGTH 6U -#define RC5_RAW_BITS 14U -#define RC5_BITS RC5_RAW_BITS - 2U -#define RC5X_BITS RC5_RAW_BITS - 1U -#define RC6_MODE0_BITS 20U // Excludes the 'start' bit. -#define RC6_36_BITS 36U // Excludes the 'start' bit. -#define RCMM_BITS 24U -#define SAMSUNG_BITS 32U -#define SANYO_SA8650B_BITS 12U -#define SANYO_LC7461_ADDRESS_BITS 13U -#define SANYO_LC7461_COMMAND_BITS 8U -#define SANYO_LC7461_BITS ((SANYO_LC7461_ADDRESS_BITS + \ - SANYO_LC7461_COMMAND_BITS) * 2) -#define SHARP_ADDRESS_BITS 5U -#define SHARP_COMMAND_BITS 8U -#define SHARP_BITS (SHARP_ADDRESS_BITS + SHARP_COMMAND_BITS + 2) // 15U -#define SHERWOOD_BITS NEC_BITS -#define SHERWOOD_MIN_REPEAT 1U -#define SONY_12_BITS 12U -#define SONY_15_BITS 15U -#define SONY_20_BITS 20U -#define SONY_MIN_BITS SONY_12_BITS -#define SONY_MIN_REPEAT 2U -#define TOSHIBA_AC_STATE_LENGTH 9U -#define TOSHIBA_AC_BITS (TOSHIBA_AC_STATE_LENGTH * 8) -#define TOSHIBA_AC_MIN_REPEAT 1U -#define TROTEC_COMMAND_LENGTH 9U -#define WHYNTER_BITS 32U -#define ARGO_COMMAND_LENGTH 12U -#define NIKAI_BITS 24U -#define MAGIQUEST_BITS 56U -#define MIDEA_BITS 48U -#define MIDEA_MIN_REPEAT 0U -#define LASERTAG_BITS 13U -#define LASERTAG_MIN_REPEAT 0U +// Based on marcosamarinho's code. +const uint16_t kMitsubishiMinRepeat = kSingleRepeat; +const uint16_t kMitsubishiACStateLength = 18; +const uint16_t kMitsubishiACBits = kMitsubishiACStateLength * 8; +const uint16_t kMitsubishiACMinRepeat = kSingleRepeat; +const uint16_t kNikaiBits = 24; +const uint16_t kNECBits = 32; +const uint16_t kPanasonicBits = 48; +const uint32_t kPanasonicManufacturer = 0x4004; +const uint16_t kPanasonicAcStateLength = 27; +const uint16_t kPanasonicAcStateShortLength = 16; +const uint16_t kPanasonicAcBits = kPanasonicAcStateLength * 8; +const uint16_t kPanasonicAcShortBits = kPanasonicAcStateShortLength * 8; +const uint16_t kPanasonicAcDefaultRepeat = kNoRepeat; +const uint16_t kPioneerBits = 64; +const uint16_t kProntoMinLength = 6; +const uint16_t kRC5RawBits = 14; +const uint16_t kRC5Bits = kRC5RawBits - 2; +const uint16_t kRC5XBits = kRC5RawBits - 1; +const uint16_t kRC6Mode0Bits = 20; // Excludes the 'start' bit. +const uint16_t kRC6_36Bits = 36; // Excludes the 'start' bit. +const uint16_t kRCMMBits = 24; +const uint16_t kSamsungBits = 32; +const uint16_t kSamsungAcStateLength = 14; +const uint16_t kSamsungAcBits = kSamsungAcStateLength * 8; +const uint16_t kSamsungAcExtendedStateLength = 21; +const uint16_t kSamsungAcExtendedBits = kSamsungAcExtendedStateLength * 8; +const uint16_t kSamsungAcDefaultRepeat = kNoRepeat; +const uint16_t kSanyoSA8650BBits = 12; +const uint16_t kSanyoLC7461AddressBits = 13; +const uint16_t kSanyoLC7461CommandBits = 8; +const uint16_t kSanyoLC7461Bits = (kSanyoLC7461AddressBits + + kSanyoLC7461CommandBits) * 2; +const uint8_t kSharpAddressBits = 5; +const uint8_t kSharpCommandBits = 8; +const uint16_t kSharpBits = kSharpAddressBits + kSharpCommandBits + 2; // 15 +const uint8_t kSherwoodBits = kNECBits; +const uint16_t kSherwoodMinRepeat = kSingleRepeat; +const uint16_t kSony12Bits = 12; +const uint16_t kSony15Bits = 15; +const uint16_t kSony20Bits = 20; +const uint16_t kSonyMinBits = 12; +const uint16_t kSonyMinRepeat = 2; +const uint16_t kToshibaACStateLength = 9; +const uint16_t kToshibaACBits = kToshibaACStateLength * 8; +const uint16_t kToshibaACMinRepeat = kSingleRepeat; +const uint16_t kTrotecStateLength = 9; +const uint16_t kTrotecDefaultRepeat = kNoRepeat; +const uint16_t kWhirlpoolAcStateLength = 21; +const uint16_t kWhirlpoolAcBits = kWhirlpoolAcStateLength * 8; +const uint16_t kWhirlpoolAcDefaultRepeat = kNoRepeat; +const uint16_t kWhynterBits = 32; +const uint8_t kVestelACBits = 56; + + +// Legacy defines. (Deprecated) +#define AIWA_RC_T501_BITS kAiwaRcT501Bits +#define ARGO_COMMAND_LENGTH kArgoStateLength +#define COOLIX_BITS kCoolixBits +#define CARRIER_AC_BITS kCarrierAcBits +#define DAIKIN_COMMAND_LENGTH kDaikinStateLength +#define DENON_BITS kDenonBits +#define DENON_48_BITS kPanasonicBits +#define DENON_LEGACY_BITS kDenonLegacyBits +#define DISH_BITS kDishBits +#define FUJITSU_AC_MIN_REPEAT kFujitsuAcMinRepeat +#define FUJITSU_AC_STATE_LENGTH kFujitsuAcStateLength +#define FUJITSU_AC_STATE_LENGTH_SHORT kFujitsuAcStateLengthShort +#define FUJITSU_AC_BITS kFujitsuAcBits +#define FUJITSU_AC_MIN_BITS kFujitsuAcMinBits +#define GICABLE_BITS kGicableBits +#define GREE_STATE_LENGTH kGreeStateLength +#define HAIER_AC_STATE_LENGTH kHaierACStateLength +#define HAIER_AC_YRW02_STATE_LENGTH kHaierACYRW02StateLength +#define HITACHI_AC_STATE_LENGTH kHitachiAcStateLength +#define HITACHI_AC_BITS kHitachiAcBits +#define HITACHI_AC1_STATE_LENGTH kHitachiAc1StateLength +#define HITACHI_AC1_BITS kHitachiAc1Bits +#define HITACHI_AC2_STATE_LENGTH kHitachiAc2StateLength +#define HITACHI_AC2_BITS kHitachiAc2Bits +#define JVC_BITS kJvcBits +#define KELVINATOR_STATE_LENGTH kKelvinatorStateLength +#define LASERTAG_BITS kLasertagBits +#define LG_BITS kLgBits +#define LG32_BITS kLg32Bits +#define MAGIQUEST_BITS kMagiquestBits +#define MIDEA_BITS kMideaBits +#define MITSUBISHI_BITS kMitsubishiBits +#define MITSUBISHI_AC_STATE_LENGTH kMitsubishiACStateLength +#define NEC_BITS kNECBits +#define NIKAI_BITS kNikaiBits +#define PANASONIC_BITS kPanasonicBits +#define RC5_BITS kRC5Bits +#define RC5X_BITS kRC5XBits +#define RC6_MODE0_BITS kRC6Mode0Bits +#define RC6_36_BITS kRC6_36Bits +#define RCMM_BITS kRCMMBits +#define SANYO_LC7461_BITS kSanyoLC7461Bits +#define SAMSUNG_BITS kSamsungBits +#define SANYO_SA8650B_BITS kSanyoSA8650BBits +#define SHARP_BITS kSharpBits +#define SHERWOOD_BITS kSherwoodBits +#define SONY_12_BITS kSony12Bits +#define SONY_15_BITS kSony15Bits +#define SONY_20_BITS kSony20Bits +#define TOSHIBA_AC_STATE_LENGTH kToshibaACStateLength +#define TROTEC_COMMAND_LENGTH kTrotecStateLength +#define WHYNTER_BITS kWhynterBits // Turn on Debugging information by uncommenting the following line. // #define DEBUG 1 diff --git a/lib/IRremoteESP8266/src/IRsend.cpp b/lib/IRremoteESP8266/src/IRsend.cpp index ff1efe9..1dae43d 100644 --- a/lib/IRremoteESP8266/src/IRsend.cpp +++ b/lib/IRremoteESP8266/src/IRsend.cpp @@ -34,9 +34,8 @@ // to change the duty cycle etc. // Returns: // An IRsend object. -IRsend::IRsend(uint16_t IRsendPin, bool inverted, - bool use_modulation) : IRpin(IRsendPin), - periodOffset(PERIOD_OFFSET) { +IRsend::IRsend(uint16_t IRsendPin, bool inverted, bool use_modulation) + : IRpin(IRsendPin), periodOffset(kPeriodOffset) { if (inverted) { outputOn = LOW; outputOff = HIGH; @@ -46,9 +45,9 @@ IRsend::IRsend(uint16_t IRsendPin, bool inverted, } modulation = use_modulation; if (modulation) - _dutycycle = DUTY_DEFAULT; + _dutycycle = kDutyDefault; else - _dutycycle = DUTY_MAX; + _dutycycle = kDutyMax; } // Enable the pin for output. @@ -82,12 +81,13 @@ void IRsend::ledOn() { // nr. of uSeconds. uint32_t IRsend::calcUSecPeriod(uint32_t hz, bool use_offset) { if (hz == 0) hz = 1; // Avoid Zero hz. Divide by Zero is nasty. - uint32_t period = (1000000UL + hz/2) / hz; // The equiv of round(1000000/hz). + uint32_t period = + (1000000UL + hz / 2) / hz; // The equiv of round(1000000/hz). // Apply the offset and ensure we don't result in a <= 0 value. if (use_offset) - return std::max((uint32_t) 1, period + periodOffset); + return std::max((uint32_t)1, period + periodOffset); else - return std::max((uint32_t) 1, period); + return std::max((uint32_t)1, period); } // Set the output frequency modulation and duty cycle. @@ -104,15 +104,15 @@ uint32_t IRsend::calcUSecPeriod(uint32_t hz, bool use_offset) { void IRsend::enableIROut(uint32_t freq, uint8_t duty) { // Set the duty cycle to use if we want freq. modulation. if (modulation) { - _dutycycle = std::min(duty, (uint8_t) DUTY_MAX); + _dutycycle = std::min(duty, kDutyMax); } else { - _dutycycle = DUTY_MAX; + _dutycycle = kDutyMax; } if (freq < 1000) // Were we given kHz? Supports the old call usage. freq *= 1000; uint32_t period = calcUSecPeriod(freq); // Nr. of uSeconds the LED will be on per pulse. - onTimePeriod = (period * _dutycycle) / DUTY_MAX; + onTimePeriod = (period * _dutycycle) / kDutyMax; // Nr. of uSeconds the LED will be off per pulse. offTimePeriod = period - onTimePeriod; } @@ -124,7 +124,7 @@ void IRsend::enableIROut(uint32_t freq, uint8_t duty) { void IRsend::_delayMicroseconds(uint32_t usec) { // delayMicroseconds() is only accurate to 16383us. // Ref: https://www.arduino.cc/en/Reference/delayMicroseconds - if (usec <= MAX_ACCURATE_USEC_DELAY) { + if (usec <= kMaxAccurateUsecDelay) { #ifndef UNIT_TEST delayMicroseconds(usec); #endif @@ -146,9 +146,9 @@ void IRsend::_delayMicroseconds(uint32_t usec) { // NOTE: Use this only if you know what you are doing as it may cause the WDT // to reset the ESP8266. void IRsend::_delayMicroseconds(uint32_t usec) { - for (; usec > MAX_ACCURATE_USEC_DELAY; usec -= MAX_ACCURATE_USEC_DELAY) + for (; usec > kMaxAccurateUsecDelay; usec -= kMaxAccurateUsecDelay) #ifndef UNIT_TEST - delayMicroseconds(MAX_ACCURATE_USEC_DELAY); + delayMicroseconds(kMaxAccurateUsecDelay); delayMicroseconds(static_cast(usec)); #endif // UNIT_TEST } @@ -190,14 +190,14 @@ uint16_t IRsend::mark(uint16_t usec) { ledOn(); // Calculate how long we should pulse on for. // e.g. Are we to close to the end of our requested mark time (usec)? - _delayMicroseconds(std::min((uint32_t) onTimePeriod, usec - elapsed)); + _delayMicroseconds(std::min((uint32_t)onTimePeriod, usec - elapsed)); ledOff(); counter++; if (elapsed + onTimePeriod >= usec) return counter; // LED is now off & we've passed our allotted time. // Wait for the lesser of the rest of the duty cycle, or the time remaining. - _delayMicroseconds(std::min(usec - elapsed - onTimePeriod, - (uint32_t) offTimePeriod)); + _delayMicroseconds( + std::min(usec - elapsed - onTimePeriod, (uint32_t)offTimePeriod)); elapsed = usecTimer.elapsed(); // Update & recache the actual elapsed time. } return counter; @@ -238,7 +238,7 @@ int8_t IRsend::calibrate(uint16_t hz) { uint32_t timeTaken = usecTimer.elapsed(); // Record the time it took. // While it shouldn't be necessary, assume at least 1 pulse, to avoid a // divide by 0 situation. - pulses = std::max(pulses, (uint16_t) 1U); + pulses = std::max(pulses, (uint16_t)1U); uint32_t calcPeriod = calcUSecPeriod(hz); // e.g. @38kHz it should be 26us. // Assuming 38kHz for the example calculations: // In a 65535us pulse, we should have 2520.5769 pulses @ 26us periods. @@ -250,9 +250,9 @@ int8_t IRsend::calibrate(uint16_t hz) { // // Calculate the actual period from the actual time & the actual pulses // generated. - double_t actualPeriod = (double_t) timeTaken / (double_t) pulses; + double_t actualPeriod = (double_t)timeTaken / (double_t)pulses; // Store the difference between the actual time per period vs. calculated. - periodOffset = (int8_t) ((double_t) calcPeriod - actualPeriod); + periodOffset = (int8_t)((double_t)calcPeriod - actualPeriod); return periodOffset; } @@ -268,9 +268,9 @@ int8_t IRsend::calibrate(uint16_t hz) { // data: The data to be transmitted. // nbits: Nr. of bits of data to be sent. // MSBfirst: Flag for bit transmission order. Defaults to MSB->LSB order. -void IRsend::sendData(uint16_t onemark, uint32_t onespace, - uint16_t zeromark, uint32_t zerospace, - uint64_t data, uint16_t nbits, bool MSBfirst) { +void IRsend::sendData(uint16_t onemark, uint32_t onespace, uint16_t zeromark, + uint32_t zerospace, uint64_t data, uint16_t nbits, + bool MSBfirst) { if (nbits == 0) // If we are asked to send nothing, just return. return; if (MSBfirst) { // Send the MSB first. @@ -281,7 +281,7 @@ void IRsend::sendData(uint16_t onemark, uint32_t onespace, nbits--; } // Send the supplied data. - for (uint64_t mask = 1ULL << (nbits - 1); mask; mask >>= 1) + for (uint64_t mask = 1ULL << (nbits - 1); mask; mask >>= 1) if (data & mask) { // Send a 1 mark(onemark); space(onespace); @@ -376,10 +376,10 @@ void IRsend::sendGeneric(const uint16_t headermark, const uint32_t headerspace, const uint16_t onemark, const uint32_t onespace, const uint16_t zeromark, const uint32_t zerospace, const uint16_t footermark, const uint32_t gap, - const uint32_t mesgtime, - const uint64_t data, const uint16_t nbits, - const uint16_t frequency, const bool MSBfirst, - const uint16_t repeat, const uint8_t dutycycle) { + const uint32_t mesgtime, const uint64_t data, + const uint16_t nbits, const uint16_t frequency, + const bool MSBfirst, const uint16_t repeat, + const uint8_t dutycycle) { // Setup enableIROut(frequency, dutycycle); IRtimer usecs = IRtimer(); @@ -389,14 +389,14 @@ void IRsend::sendGeneric(const uint16_t headermark, const uint32_t headerspace, usecs.reset(); // Header - if (headermark) mark(headermark); - if (headerspace) space(headerspace); + if (headermark) mark(headermark); + if (headerspace) space(headerspace); // Data sendData(onemark, onespace, zeromark, zerospace, data, nbits, MSBfirst); // Footer - if (footermark) mark(footermark); + if (footermark) mark(footermark); uint32_t elapsed = usecs.elapsed(); // Avoid potential unsigned integer underflow. e.g. when mesgtime is 0. if (elapsed >= mesgtime) @@ -445,16 +445,16 @@ void IRsend::sendGeneric(const uint16_t headermark, const uint32_t headerspace, // We always send a message, even for repeat=0, hence '<= repeat'. for (uint16_t r = 0; r <= repeat; r++) { // Header - if (headermark) mark(headermark); - if (headerspace) space(headerspace); + if (headermark) mark(headermark); + if (headerspace) space(headerspace); // Data for (uint16_t i = 0; i < nbytes; i++) - sendData(onemark, onespace, zeromark, zerospace, - *(dataptr + i), 8, MSBfirst); + sendData(onemark, onespace, zeromark, zerospace, *(dataptr + i), 8, + MSBfirst); // Footer - if (footermark) mark(footermark); + if (footermark) mark(footermark); space(gap); } } @@ -492,61 +492,114 @@ void IRsend::sendRaw(uint16_t buf[], uint16_t len, uint16_t hz) { void IRsend::send(uint16_t type, uint64_t data, uint16_t nbits) { switch (type) { #if SEND_NEC - case NEC: sendNEC(data, nbits); break; + case NEC: + sendNEC(data, nbits); + break; #endif #if SEND_SONY - case SONY: sendSony(data, nbits); break; + case SONY: + sendSony(data, nbits); + break; #endif #if SEND_RC5 - case RC5: sendRC5(data, nbits); break; + case RC5: + sendRC5(data, nbits); + break; #endif #if SEND_RC6 - case RC6: sendRC6(data, nbits); break; + case RC6: + sendRC6(data, nbits); + break; #endif #if SEND_DISH - case DISH: sendDISH(data, nbits); break; + case DISH: + sendDISH(data, nbits); + break; #endif #if SEND_JVC - case JVC: sendJVC(data, nbits); break; + case JVC: + sendJVC(data, nbits); + break; #endif #if SEND_SAMSUNG - case SAMSUNG: sendSAMSUNG(data, nbits); break; + case SAMSUNG: + sendSAMSUNG(data, nbits); + break; #endif #if SEND_LG - case LG: sendLG(data, nbits); break; + case LG: + sendLG(data, nbits); + break; +#endif +#if SEND_LG + case LG2: + sendLG2(data, nbits); + break; #endif #if SEND_WHYNTER - case WHYNTER: sendWhynter(data, nbits); break; + case WHYNTER: + sendWhynter(data, nbits); + break; #endif #if SEND_COOLIX - case COOLIX: sendCOOLIX(data, nbits); break; + case COOLIX: + sendCOOLIX(data, nbits); + break; #endif #if SEND_DENON - case DENON: sendDenon(data, nbits); break; + case DENON: + sendDenon(data, nbits); + break; #endif #if SEND_SHERWOOD - case SHERWOOD: sendSherwood(data, nbits); break; + case SHERWOOD: + sendSherwood(data, nbits); + break; #endif #if SEND_RCMM - case RCMM: sendRCMM(data, nbits); break; + case RCMM: + sendRCMM(data, nbits); + break; #endif #if SEND_MITSUBISHI - case MITSUBISHI: sendMitsubishi(data, nbits); break; + case MITSUBISHI: + sendMitsubishi(data, nbits); + break; #endif #if SEND_MITSUBISHI2 - case MITSUBISHI2: sendMitsubishi2(data, nbits); break; + case MITSUBISHI2: + sendMitsubishi2(data, nbits); + break; #endif #if SEND_SHARP - case SHARP: sendSharpRaw(data, nbits); break; + case SHARP: + sendSharpRaw(data, nbits); + break; #endif #if SEND_AIWA_RC_T501 - case AIWA_RC_T501: sendAiwaRCT501(data, nbits); break; + case AIWA_RC_T501: + sendAiwaRCT501(data, nbits); + break; #endif #if SEND_MIDEA - case MIDEA: sendMidea(data, nbits); break; + case MIDEA: + sendMidea(data, nbits); + break; #endif #if SEND_GICABLE - case GICABLE: sendGICable(data, nbits); break; + case GICABLE: + sendGICable(data, nbits); + break; +#endif +#if SEND_PIONEER + case PIONEER: + sendPioneer(data, nbits); + break; +#endif +#if SEND_VESTEL_AC + case VESTEL_AC: + sendVestelAC(data, nbits); + break; #endif } } diff --git a/lib/IRremoteESP8266/src/IRsend.h b/lib/IRremoteESP8266/src/IRsend.h index bebf74a..fddbb8f 100644 --- a/lib/IRremoteESP8266/src/IRsend.h +++ b/lib/IRremoteESP8266/src/IRsend.h @@ -22,12 +22,12 @@ // Offset (in microseconds) to use in Period time calculations to account for // code excution time in producing the software PWM signal. // Value was calculated on Wemos D1 mini using v2.4.1 with v2.4.0 ESP core -#define PERIOD_OFFSET -5 -#define DUTY_DEFAULT 50 -#define DUTY_MAX 100 // Percentage +const int8_t kPeriodOffset = -5; +const uint8_t kDutyDefault = 50; // Percentage +const uint8_t kDutyMax = 100; // Percentage // delayMicroseconds() is only accurate to 16383us. // Ref: https://www.arduino.cc/en/Reference/delayMicroseconds -#define MAX_ACCURATE_USEC_DELAY 16383U +const uint16_t kMaxAccurateUsecDelay = 16383; // Classes class IRsend { @@ -35,7 +35,7 @@ class IRsend { explicit IRsend(uint16_t IRsendPin, bool inverted = false, bool use_modulation = true); void begin(); - void enableIROut(uint32_t freq, uint8_t duty = DUTY_DEFAULT); + void enableIROut(uint32_t freq, uint8_t duty = kDutyDefault); VIRTUAL void _delayMicroseconds(uint32_t usec); VIRTUAL uint16_t mark(uint16_t usec); VIRTUAL void space(uint32_t usec); @@ -55,10 +55,10 @@ class IRsend { const uint16_t onemark, const uint32_t onespace, const uint16_t zeromark, const uint32_t zerospace, const uint16_t footermark, const uint32_t gap, - const uint32_t mesgtime, - const uint64_t data, const uint16_t nbits, - const uint16_t frequency, const bool MSBfirst, - const uint16_t repeat, const uint8_t dutycycle); + const uint32_t mesgtime, const uint64_t data, + const uint16_t nbits, const uint16_t frequency, + const bool MSBfirst, const uint16_t repeat, + const uint8_t dutycycle); void sendGeneric(const uint16_t headermark, const uint32_t headerspace, const uint16_t onemark, const uint32_t onespace, const uint16_t zeromark, const uint32_t zerospace, @@ -66,9 +66,10 @@ class IRsend { const uint8_t *dataptr, const uint16_t nbytes, const uint16_t frequency, const bool MSBfirst, const uint16_t repeat, const uint8_t dutycycle); -void send(uint16_t type, uint64_t data, uint16_t nbits); + void send(uint16_t type, uint64_t data, uint16_t nbits); #if (SEND_NEC || SEND_SHERWOOD || SEND_AIWA_RC_T501 || SEND_SANYO) - void sendNEC(uint64_t data, uint16_t nbits = NEC_BITS, uint16_t repeat = 0); + void sendNEC(uint64_t data, uint16_t nbits = kNECBits, + uint16_t repeat = kNoRepeat); uint32_t encodeNEC(uint16_t address, uint16_t command); #endif #if SEND_SONY @@ -77,22 +78,30 @@ void send(uint16_t type, uint64_t data, uint16_t nbits); // Legacy use of this procedure was to only send a single code so call it with // repeat=0 for backward compatibility. As of v2.0 it defaults to sending // a Sony command that will be accepted be a device. - void sendSony(uint64_t data, uint16_t nbits = SONY_20_BITS, - uint16_t repeat = SONY_MIN_REPEAT); + void sendSony(uint64_t data, uint16_t nbits = kSony20Bits, + uint16_t repeat = kSonyMinRepeat); uint32_t encodeSony(uint16_t nbits, uint16_t command, uint16_t address, uint16_t extended = 0); #endif #if SEND_SHERWOOD - void sendSherwood(uint64_t data, uint16_t nbits = SHERWOOD_BITS, - uint16_t repeat = SHERWOOD_MIN_REPEAT); + void sendSherwood(uint64_t data, uint16_t nbits = kSherwoodBits, + uint16_t repeat = kSherwoodMinRepeat); #endif #if SEND_SAMSUNG - void sendSAMSUNG(uint64_t data, uint16_t nbits = SAMSUNG_BITS, - uint16_t repeat = 0); + void sendSAMSUNG(uint64_t data, uint16_t nbits = kSamsungBits, + uint16_t repeat = kNoRepeat); uint32_t encodeSAMSUNG(uint8_t customer, uint8_t command); #endif +#if SEND_SAMSUNG_AC + void sendSamsungAC(unsigned char data[], + uint16_t nbytes = kSamsungAcStateLength, + uint16_t repeat = kSamsungAcDefaultRepeat); +#endif #if SEND_LG - void sendLG(uint64_t data, uint16_t nbits = LG_BITS, uint16_t repeat = 0); + void sendLG(uint64_t data, uint16_t nbits = kLgBits, + uint16_t repeat = kNoRepeat); + void sendLG2(uint64_t data, uint16_t nbits = kLgBits, + uint16_t repeat = kNoRepeat); uint32_t encodeLG(uint16_t address, uint16_t command); #endif #if (SEND_SHARP || SEND_DENON) @@ -100,41 +109,44 @@ void send(uint16_t type, uint64_t data, uint16_t nbits); uint16_t expansion = 1, uint16_t check = 0, bool MSBfirst = false); void sendSharp(uint16_t address, uint16_t command, - uint16_t nbits = SHARP_BITS, uint16_t repeat = 0); - void sendSharpRaw(uint64_t data, uint16_t nbits = SHARP_BITS, - uint16_t repeat = 0); + uint16_t nbits = kSharpBits, uint16_t repeat = kNoRepeat); + void sendSharpRaw(uint64_t data, uint16_t nbits = kSharpBits, + uint16_t repeat = kNoRepeat); #endif #if SEND_JVC - void sendJVC(uint64_t data, uint16_t nbits = JVC_BITS, uint16_t repeat = 0); + void sendJVC(uint64_t data, uint16_t nbits = kJvcBits, + uint16_t repeat = kNoRepeat); uint16_t encodeJVC(uint8_t address, uint8_t command); #endif #if SEND_DENON void sendDenon(uint64_t data, uint16_t nbits = DENON_BITS, - uint16_t repeat = 0); + uint16_t repeat = kNoRepeat); #endif #if SEND_SANYO uint64_t encodeSanyoLC7461(uint16_t address, uint8_t command); - void sendSanyoLC7461(uint64_t data, uint16_t nbits = SANYO_LC7461_BITS, - uint16_t repeat = 0); + void sendSanyoLC7461(uint64_t data, uint16_t nbits = kSanyoLC7461Bits, + uint16_t repeat = kNoRepeat); #endif #if SEND_DISH // sendDISH() should typically be called with repeat=3 as DISH devices // expect the code to be sent at least 4 times. (code + 3 repeats = 4 codes) // Legacy use of this procedure was only to send a single code // so use repeat=0 for backward compatibility. - void sendDISH(uint64_t data, uint16_t nbits = DISH_BITS, - uint16_t repeat = DISH_MIN_REPEAT); + void sendDISH(uint64_t data, uint16_t nbits = kDishBits, + uint16_t repeat = kDishMinRepeat); #endif #if (SEND_PANASONIC || SEND_DENON) - void sendPanasonic64(uint64_t data, uint16_t nbits = PANASONIC_BITS, - uint16_t repeat = 0); + void sendPanasonic64(uint64_t data, uint16_t nbits = kPanasonicBits, + uint16_t repeat = kNoRepeat); void sendPanasonic(uint16_t address, uint32_t data, - uint16_t nbits = PANASONIC_BITS, uint16_t repeat = 0); + uint16_t nbits = kPanasonicBits, + uint16_t repeat = kNoRepeat); uint64_t encodePanasonic(uint16_t manufacturer, uint8_t device, uint8_t subdevice, uint8_t function); #endif #if SEND_RC5 - void sendRC5(uint64_t data, uint16_t nbits = RC5X_BITS, uint16_t repeat = 0); + void sendRC5(uint64_t data, uint16_t nbits = kRC5XBits, + uint16_t repeat = kNoRepeat); uint16_t encodeRC5(uint8_t address, uint8_t command, bool key_released = false); uint16_t encodeRC5X(uint8_t address, uint8_t command, @@ -142,126 +154,163 @@ void send(uint16_t type, uint64_t data, uint16_t nbits); uint64_t toggleRC5(uint64_t data); #endif #if SEND_RC6 - void sendRC6(uint64_t data, uint16_t nbits = RC6_MODE0_BITS, - uint16_t repeat = 0); + void sendRC6(uint64_t data, uint16_t nbits = kRC6Mode0Bits, + uint16_t repeat = kNoRepeat); uint64_t encodeRC6(uint32_t address, uint8_t command, - uint16_t mode = RC6_MODE0_BITS); - uint64_t toggleRC6(uint64_t data, uint16_t nbits = RC6_MODE0_BITS); + uint16_t mode = kRC6Mode0Bits); + uint64_t toggleRC6(uint64_t data, uint16_t nbits = kRC6Mode0Bits); #endif #if SEND_RCMM - void sendRCMM(uint64_t data, uint16_t nbits = RCMM_BITS, uint16_t repeat = 0); + void sendRCMM(uint64_t data, uint16_t nbits = kRCMMBits, + uint16_t repeat = kNoRepeat); #endif #if SEND_COOLIX - void sendCOOLIX(uint64_t data, uint16_t nbits = COOLIX_BITS, - uint16_t repeat = 0); + void sendCOOLIX(uint64_t data, uint16_t nbits = kCoolixBits, + uint16_t repeat = kCoolixDefaultRepeat); #endif #if SEND_WHYNTER - void sendWhynter(uint64_t data, uint16_t nbits = WHYNTER_BITS, - uint16_t repeat = 0); + void sendWhynter(uint64_t data, uint16_t nbits = kWhynterBits, + uint16_t repeat = kNoRepeat); #endif #if SEND_MITSUBISHI - void sendMitsubishi(uint64_t data, uint16_t nbits = MITSUBISHI_BITS, - uint16_t repeat = MITSUBISHI_MIN_REPEAT); + void sendMitsubishi(uint64_t data, uint16_t nbits = kMitsubishiBits, + uint16_t repeat = kMitsubishiMinRepeat); #endif #if SEND_MITSUBISHI2 - void sendMitsubishi2(uint64_t data, uint16_t nbits = MITSUBISHI_BITS, - uint16_t repeat = MITSUBISHI_MIN_REPEAT); + void sendMitsubishi2(uint64_t data, uint16_t nbits = kMitsubishiBits, + uint16_t repeat = kMitsubishiMinRepeat); #endif #if SEND_MITSUBISHI_AC void sendMitsubishiAC(unsigned char data[], - uint16_t nbytes = MITSUBISHI_AC_STATE_LENGTH, - uint16_t repeat = MITSUBISHI_AC_MIN_REPEAT); + uint16_t nbytes = kMitsubishiACStateLength, + uint16_t repeat = kMitsubishiACMinRepeat); #endif #if SEND_FUJITSU_AC - void sendFujitsuAC(unsigned char data[], - uint16_t nbytes, - uint16_t repeat = FUJITSU_AC_MIN_REPEAT); + void sendFujitsuAC(unsigned char data[], uint16_t nbytes, + uint16_t repeat = kFujitsuAcMinRepeat); #endif #if SEND_GLOBALCACHE void sendGC(uint16_t buf[], uint16_t len); #endif #if SEND_KELVINATOR void sendKelvinator(unsigned char data[], - uint16_t nbytes = KELVINATOR_STATE_LENGTH, - uint16_t repeat = 0); + uint16_t nbytes = kKelvinatorStateLength, + uint16_t repeat = kKelvinatorDefaultRepeat); #endif #if SEND_DAIKIN - void sendDaikin(unsigned char data[], - uint16_t nbytes = DAIKIN_COMMAND_LENGTH, - uint16_t repeat = 0); - void sendDaikinGapHeader(); + void sendDaikin(unsigned char data[], uint16_t nbytes = kDaikinStateLength, + uint16_t repeat = kDaikinDefaultRepeat); +#endif +#if SEND_DAIKIN2 + void sendDaikin2(unsigned char data[], uint16_t nbytes = kDaikin2StateLength, + uint16_t repeat = kDaikin2DefaultRepeat); #endif #if SEND_AIWA_RC_T501 - void sendAiwaRCT501(uint64_t data, uint16_t nbits = AIWA_RC_T501_BITS, - uint16_t repeat = AIWA_RC_T501_MIN_REPEAT); + void sendAiwaRCT501(uint64_t data, uint16_t nbits = kAiwaRcT501Bits, + uint16_t repeat = kAiwaRcT501MinRepeats); #endif #if SEND_GREE - void sendGree(uint64_t data, uint16_t nbits = GREE_BITS, uint16_t repeat = 0); - void sendGree(uint8_t data[], uint16_t nbytes = GREE_STATE_LENGTH, - uint16_t repeat = 0); + void sendGree(uint64_t data, uint16_t nbits = kGreeBits, + uint16_t repeat = kGreeDefaultRepeat); + void sendGree(uint8_t data[], uint16_t nbytes = kGreeStateLength, + uint16_t repeat = kGreeDefaultRepeat); #endif #if SEND_PRONTO - void sendPronto(uint16_t data[], uint16_t len, uint16_t repeat = 0); + void sendPronto(uint16_t data[], uint16_t len, uint16_t repeat = kNoRepeat); #endif #if SEND_ARGO - void sendArgo(unsigned char data[], - uint16_t nbytes = ARGO_COMMAND_LENGTH, - uint16_t repeat = 0); + void sendArgo(unsigned char data[], uint16_t nbytes = kArgoStateLength, + uint16_t repeat = kArgoDefaultRepeat); #endif #if SEND_TROTEC - void sendTrotec(unsigned char data[], - uint16_t nbytes = TROTEC_COMMAND_LENGTH, - uint16_t repeat = 0); + void sendTrotec(unsigned char data[], uint16_t nbytes = kTrotecStateLength, + uint16_t repeat = kTrotecDefaultRepeat); #endif #if SEND_NIKAI - void sendNikai(uint64_t data, uint16_t nbits = NIKAI_BITS, - uint16_t repeat = 0); + void sendNikai(uint64_t data, uint16_t nbits = kNikaiBits, + uint16_t repeat = kNoRepeat); #endif #if SEND_TOSHIBA_AC void sendToshibaAC(unsigned char data[], - uint16_t nbytes = TOSHIBA_AC_STATE_LENGTH, - uint16_t repeat = TOSHIBA_AC_MIN_REPEAT); + uint16_t nbytes = kToshibaACStateLength, + uint16_t repeat = kToshibaACMinRepeat); #endif #if SEND_MIDEA - void sendMidea(uint64_t data, uint16_t nbits = MIDEA_BITS, - uint16_t repeat = MIDEA_MIN_REPEAT); + void sendMidea(uint64_t data, uint16_t nbits = kMideaBits, + uint16_t repeat = kMideaMinRepeat); #endif #if SEND_MAGIQUEST - void sendMagiQuest(uint64_t data, uint16_t nbits = MAGIQUEST_BITS, - uint16_t repeat = 0); + void sendMagiQuest(uint64_t data, uint16_t nbits = kMagiquestBits, + uint16_t repeat = kNoRepeat); uint64_t encodeMagiQuest(uint32_t wand_id, uint16_t magnitude); #endif #if SEND_LASERTAG - void sendLasertag(uint64_t data, uint16_t nbits = LASERTAG_BITS, - uint16_t repeat = LASERTAG_MIN_REPEAT); + void sendLasertag(uint64_t data, uint16_t nbits = kLasertagBits, + uint16_t repeat = kLasertagMinRepeat); #endif #if SEND_CARRIER_AC - void sendCarrierAC(uint64_t data, uint16_t nbits = CARRIER_AC_BITS, - uint16_t repeat = CARRIER_AC_MIN_REPEAT); + void sendCarrierAC(uint64_t data, uint16_t nbits = kCarrierAcBits, + uint16_t repeat = kCarrierAcMinRepeat); #endif -#if SEND_HAIER_AC - void sendHaierAC(unsigned char data[], - uint16_t nbytes = HAIER_AC_STATE_LENGTH, - uint16_t repeat = 0); +#if (SEND_HAIER_AC || SEND_HAIER_AC_YRW02) + void sendHaierAC(unsigned char data[], uint16_t nbytes = kHaierACStateLength, + uint16_t repeat = kHaierAcDefaultRepeat); +#endif +#if SEND_HAIER_AC_YRW02 + void sendHaierACYRW02(unsigned char data[], + uint16_t nbytes = kHaierACYRW02StateLength, + uint16_t repeat = kHaierAcYrw02DefaultRepeat); #endif #if SEND_HITACHI_AC void sendHitachiAC(unsigned char data[], - uint16_t nbytes = HITACHI_AC_STATE_LENGTH, - uint16_t repeat = 0); + uint16_t nbytes = kHitachiAcStateLength, + uint16_t repeat = kHitachiAcDefaultRepeat); #endif #if SEND_HITACHI_AC1 void sendHitachiAC1(unsigned char data[], - uint16_t nbytes = HITACHI_AC1_STATE_LENGTH, - uint16_t repeat = 0); + uint16_t nbytes = kHitachiAc1StateLength, + uint16_t repeat = kNoRepeat); #endif #if SEND_HITACHI_AC2 void sendHitachiAC2(unsigned char data[], - uint16_t nbytes = HITACHI_AC2_STATE_LENGTH, - uint16_t repeat = 0); + uint16_t nbytes = kHitachiAc2StateLength, + uint16_t repeat = kNoRepeat); #endif #if SEND_GICABLE - void sendGICable(uint64_t data, uint16_t nbits = GICABLE_BITS, - uint16_t repeat = GICABLE_MIN_REPEAT); + void sendGICable(uint64_t data, uint16_t nbits = kGicableBits, + uint16_t repeat = kGicableMinRepeat); +#endif +#if SEND_WHIRLPOOL_AC + void sendWhirlpoolAC(unsigned char data[], + uint16_t nbytes = kWhirlpoolAcStateLength, + uint16_t repeat = kWhirlpoolAcDefaultRepeat); +#endif +#if SEND_LUTRON + void sendLutron(uint64_t data, uint16_t nbits = kLutronBits, + uint16_t repeat = kNoRepeat); +#endif +#if SEND_ELECTRA_AC + void sendElectraAC(unsigned char data[], + uint16_t nbytes = kElectraAcStateLength, + uint16_t repeat = kNoRepeat); +#endif +#if SEND_PANASONIC_AC + void sendPanasonicAC(unsigned char data[], + uint16_t nbytes = kPanasonicAcStateLength, + uint16_t repeat = kPanasonicAcDefaultRepeat); +#endif +#if SEND_PIONEER + void sendPioneer(const uint64_t data, const uint16_t nbits = kPioneerBits, + const uint16_t repeat = kNoRepeat); + uint64_t encodePioneer(uint16_t address, uint16_t command); +#endif +#if SEND_MWM + void sendMWM(unsigned char data[], uint16_t nbytes, + uint16_t repeat = kNoRepeat); +#endif +#if SEND_VESTEL_AC + void sendVestelAC(const uint64_t data, const uint16_t nbits = kVestelACBits, + const uint16_t repeat = kNoRepeat); #endif protected: diff --git a/lib/IRremoteESP8266/src/IRtimer.cpp b/lib/IRremoteESP8266/src/IRtimer.cpp index d6c65b3..029637c 100644 --- a/lib/IRremoteESP8266/src/IRtimer.cpp +++ b/lib/IRremoteESP8266/src/IRtimer.cpp @@ -13,9 +13,7 @@ extern uint32_t _IRtimer_unittest_now; // This class performs a simple time in useconds since instantiated. // Handles when the system timer wraps around (once). -IRtimer::IRtimer() { - reset(); -} +IRtimer::IRtimer() { reset(); } void IRtimer::reset() { #ifndef UNIT_TEST @@ -31,7 +29,7 @@ uint32_t IRtimer::elapsed() { #else uint32_t now = _IRtimer_unittest_now; #endif - if (start <= now) // Check if the system timer has wrapped. + if (start <= now) // Check if the system timer has wrapped. return now - start; // No wrap. else return UINT32_MAX - start + now; // Has wrapped. @@ -39,7 +37,5 @@ uint32_t IRtimer::elapsed() { // Only used in unit testing. #ifdef UNIT_TEST -void IRtimer::add(uint32_t usecs) { - _IRtimer_unittest_now += usecs; -} +void IRtimer::add(uint32_t usecs) { _IRtimer_unittest_now += usecs; } #endif // UNIT_TEST diff --git a/lib/IRremoteESP8266/src/IRutils.cpp b/lib/IRremoteESP8266/src/IRutils.cpp index 89c2281..7c9347d 100644 --- a/lib/IRremoteESP8266/src/IRutils.cpp +++ b/lib/IRremoteESP8266/src/IRutils.cpp @@ -21,10 +21,9 @@ // Returns: // The reversed bit pattern. uint64_t reverseBits(uint64_t input, uint16_t nbits) { - if (nbits <= 1) - return input; // Reversing <= 1 bits makes no change at all. + if (nbits <= 1) return input; // Reversing <= 1 bits makes no change at all. // Cap the nr. of bits to rotate to the max nr. of bits in the input. - nbits = std::min(nbits, (uint16_t) (sizeof(input) * 8)); + nbits = std::min(nbits, (uint16_t)(sizeof(input) * 8)); uint64_t output = 0; for (uint16_t i = 0; i < nbits; i++) { output <<= 1; @@ -62,7 +61,7 @@ std::string uint64ToString(uint64_t input, uint8_t base) { input /= base; if (c < 10) - c +='0'; + c += '0'; else c += 'A' - 10; result = c + result; @@ -92,57 +91,179 @@ void serialPrintUint64(uint64_t input, uint8_t base) { String typeToString(const decode_type_t protocol, const bool isRepeat) { String result = ""; #else -std::string typeToString(const decode_type_t protocol, - const bool isRepeat) { +std::string typeToString(const decode_type_t protocol, const bool isRepeat) { std::string result = ""; #endif switch (protocol) { default: - case UNKNOWN: result = "UNKNOWN"; break; - case UNUSED: result = "UNUSED"; break; - case AIWA_RC_T501: result = "AIWA_RC_T501"; break; - case ARGO: result = "ARGO"; break; - case CARRIER_AC: result = "CARRIER_AC"; break; - case COOLIX: result = "COOLIX"; break; - case DAIKIN: result = "DAIKIN"; break; - case DENON: result = "DENON"; break; - case DISH: result = "DISH"; break; - case FUJITSU_AC: result = "FUJITSU_AC"; break; - case GICABLE: result = "GICABLE"; break; - case GLOBALCACHE: result = "GLOBALCACHE"; break; - case GREE: result = "GREE"; break; - case HAIER_AC: result = "HAIER_AC"; break; - case HITACHI_AC: result = "HITACHI_AC"; break; - case HITACHI_AC1: result = "HITACHI_AC1"; break; - case HITACHI_AC2: result = "HITACHI_AC2"; break; - case JVC: result = "JVC"; break; - case KELVINATOR: result = "KELVINATOR"; break; - case LG: result = "LG"; break; - case LASERTAG: result = "LASERTAG"; break; - case MAGIQUEST: result = "MAGIQUEST"; break; - case MIDEA: result = "MIDEA"; break; - case MITSUBISHI: result = "MITSUBISHI"; break; - case MITSUBISHI2: result = "MITSUBISHI2"; break; - case MITSUBISHI_AC: result = "MITSUBISHI_AC"; break; - case NEC: result = "NEC"; break; - case NEC_LIKE: result = "NEC (non-strict)"; break; - case NIKAI: result = "NIKAI"; break; - case PANASONIC: result = "PANASONIC"; break; - case PRONTO: result = "PRONTO"; break; - case RAW: result = "RAW"; break; - case RC5: result = "RC5"; break; - case RC5X: result = "RC5X"; break; - case RC6: result = "RC6"; break; - case RCMM: result = "RCMM"; break; - case SAMSUNG: result = "SAMSUNG"; break; - case SANYO: result = "SANYO"; break; - case SANYO_LC7461: result = "SANYO_LC7461"; break; - case SHARP: result = "SHARP"; break; - case SHERWOOD: result = "SHERWOOD"; break; - case SONY: result = "SONY"; break; - case TOSHIBA_AC: result = "TOSHIBA_AC"; break; - case TROTEC: result = "TROTEC"; break; - case WHYNTER: result = "WHYNTER"; break; + case UNKNOWN: + result = "UNKNOWN"; + break; + case UNUSED: + result = "UNUSED"; + break; + case AIWA_RC_T501: + result = "AIWA_RC_T501"; + break; + case ARGO: + result = "ARGO"; + break; + case CARRIER_AC: + result = "CARRIER_AC"; + break; + case COOLIX: + result = "COOLIX"; + break; + case DAIKIN: + result = "DAIKIN"; + break; + case DAIKIN2: + result = "DAIKIN2"; + break; + case DENON: + result = "DENON"; + break; + case DISH: + result = "DISH"; + break; + case ELECTRA_AC: + result = "ELECTRA_AC"; + break; + case FUJITSU_AC: + result = "FUJITSU_AC"; + break; + case GICABLE: + result = "GICABLE"; + break; + case GLOBALCACHE: + result = "GLOBALCACHE"; + break; + case GREE: + result = "GREE"; + break; + case HAIER_AC: + result = "HAIER_AC"; + break; + case HAIER_AC_YRW02: + result = "HAIER_AC_YRW02"; + break; + case HITACHI_AC: + result = "HITACHI_AC"; + break; + case HITACHI_AC1: + result = "HITACHI_AC1"; + break; + case HITACHI_AC2: + result = "HITACHI_AC2"; + break; + case JVC: + result = "JVC"; + break; + case KELVINATOR: + result = "KELVINATOR"; + break; + case LG: + result = "LG"; + break; + case LG2: + result = "LG2"; + break; + case LASERTAG: + result = "LASERTAG"; + break; + case LUTRON: + result = "LUTRON"; + break; + case MAGIQUEST: + result = "MAGIQUEST"; + break; + case MIDEA: + result = "MIDEA"; + break; + case MITSUBISHI: + result = "MITSUBISHI"; + break; + case MITSUBISHI2: + result = "MITSUBISHI2"; + break; + case MITSUBISHI_AC: + result = "MITSUBISHI_AC"; + break; + case MWM: + result = "MWM"; + break; + case NEC: + result = "NEC"; + break; + case NEC_LIKE: + result = "NEC (non-strict)"; + break; + case NIKAI: + result = "NIKAI"; + break; + case PANASONIC: + result = "PANASONIC"; + break; + case PANASONIC_AC: + result = "PANASONIC_AC"; + break; + case PIONEER: + result = "PIONEER"; + break; + case PRONTO: + result = "PRONTO"; + break; + case RAW: + result = "RAW"; + break; + case RC5: + result = "RC5"; + break; + case RC5X: + result = "RC5X"; + break; + case RC6: + result = "RC6"; + break; + case RCMM: + result = "RCMM"; + break; + case SAMSUNG: + result = "SAMSUNG"; + break; + case SAMSUNG_AC: + result = "SAMSUNG_AC"; + break; + case SANYO: + result = "SANYO"; + break; + case SANYO_LC7461: + result = "SANYO_LC7461"; + break; + case SHARP: + result = "SHARP"; + break; + case SHERWOOD: + result = "SHERWOOD"; + break; + case SONY: + result = "SONY"; + break; + case TOSHIBA_AC: + result = "TOSHIBA_AC"; + break; + case TROTEC: + result = "TROTEC"; + break; + case VESTEL_AC: + result = "VESTEL_AC"; + break; + case WHIRLPOOL_AC: + result = "WHIRLPOOL_AC"; + break; + case WHYNTER: + result = "WHYNTER"; + break; } if (isRepeat) result += " (Repeat)"; return result; @@ -152,15 +273,22 @@ std::string typeToString(const decode_type_t protocol, bool hasACState(const decode_type_t protocol) { switch (protocol) { case DAIKIN: + case DAIKIN2: + case ELECTRA_AC: case FUJITSU_AC: case GREE: case HAIER_AC: + case HAIER_AC_YRW02: case HITACHI_AC: case HITACHI_AC1: case HITACHI_AC2: case KELVINATOR: case MITSUBISHI_AC: + case MWM: + case PANASONIC_AC: + case SAMSUNG_AC: case TOSHIBA_AC: + case WHIRLPOOL_AC: return true; default: return false; @@ -176,7 +304,7 @@ bool hasACState(const decode_type_t protocol) { uint16_t getCorrectedRawLength(const decode_results *results) { uint16_t extended_length = results->rawlen - 1; for (uint16_t i = 0; i < results->rawlen - 1; i++) { - uint32_t usecs = results->rawbuf[i] * RAWTICK; + uint32_t usecs = results->rawbuf[i] * kRawTick; // Add two extra entries for multiple larger than UINT16_MAX it is. extended_length += (usecs / (UINT16_MAX + 1)) * 2; } @@ -196,14 +324,13 @@ std::string resultToSourceCode(const decode_results *results) { output += "uint16_t "; // variable type output += "rawData["; // array name output += uint64ToString(getCorrectedRawLength(results), 10); - // array size - output += "] = {"; // Start declaration + // array size + output += "] = {"; // Start declaration // Dump data for (uint16_t i = 1; i < results->rawlen; i++) { uint32_t usecs; - for (usecs = results->rawbuf[i] * RAWTICK; - usecs > UINT16_MAX; + for (usecs = results->rawbuf[i] * kRawTick; usecs > UINT16_MAX; usecs -= UINT16_MAX) { output += uint64ToString(UINT16_MAX); if (i % 2) @@ -213,12 +340,12 @@ std::string resultToSourceCode(const decode_results *results) { } output += uint64ToString(usecs, 10); if (i < results->rawlen - 1) - output += ", "; // ',' not needed on the last one - if (i % 2 == 0) output += " "; // Extra if it was even. + output += ", "; // ',' not needed on the last one + if (i % 2 == 0) output += " "; // Extra if it was even. } // End declaration - output +="};"; + output += "};"; // Comment output += " // " + typeToString(results->decode_type, results->repeat); @@ -235,10 +362,9 @@ std::string resultToSourceCode(const decode_results *results) { output += "uint8_t state[" + uint64ToString(nbytes) + "] = {"; for (uint16_t i = 0; i < nbytes; i++) { output += "0x"; - if (results->state[i] < 0x10) output += "0"; + if (results->state[i] < 0x10) output += "0"; output += uint64ToString(results->state[i], 16); - if (i < nbytes - 1) - output += ", "; + if (i < nbytes - 1) output += ", "; } output += "};\n"; #endif // DECODE_AC @@ -254,8 +380,8 @@ std::string resultToSourceCode(const decode_results *results) { uint64ToString(results->command, 16) + ";\n"; } // Most protocols have data - output += "uint64_t data = 0x" + uint64ToString(results->value, 16) + - ";\n"; + output += + "uint64_t data = 0x" + uint64ToString(results->value, 16) + ";\n"; } } return output; @@ -279,19 +405,39 @@ std::string resultToTimingInfo(const decode_results *results) { output += "-"; // even else output += " +"; // odd - value = uint64ToString(results->rawbuf[i] * RAWTICK); + value = uint64ToString(results->rawbuf[i] * kRawTick); // Space pad the value till it is at least 6 chars long. - while (value.length() < 6) - value = " " + value; + while (value.length() < 6) value = " " + value; output += value; - if (i < results->rawlen - 1) - output += ", "; // ',' not needed for last one - if (!(i % 8)) output += "\n"; // Newline every 8 entries. + if (i < results->rawlen - 1) output += ", "; // ',' not needed for last one + if (!(i % 8)) output += "\n"; // Newline every 8 entries. } output += "\n"; return output; } +// Convert the decode_results structure's value/state to simple hexadecimal. +// +#ifdef ARDUINO +String resultToHexidecimal(const decode_results *result) { + String output = ""; +#else +std::string resultToHexidecimal(const decode_results *result) { + std::string output = ""; +#endif + if (hasACState(result->decode_type)) { +#if DECODE_AC + for (uint16_t i = 0; result->bits > i * 8; i++) { + if (result->state[i] < 0x10) output += "0"; // Zero pad + output += uint64ToString(result->state[i], 16); + } +#endif // DECODE_AC + } else { + output += uint64ToString(result->value, 16); + } + return output; +} + // Dump out the decode_results structure. // #ifdef ARDUINO @@ -302,21 +448,13 @@ std::string resultToHumanReadableBasic(const decode_results *results) { std::string output = ""; #endif // Show Encoding standard - output += "Encoding : " + - typeToString(results->decode_type, results->repeat) + "\n"; + output += + "Encoding : " + typeToString(results->decode_type, results->repeat) + + "\n"; // Show Code & length output += "Code : "; - if (hasACState(results->decode_type)) { -#if DECODE_AC - for (uint16_t i = 0; results->bits > i * 8; i++) { - if (results->state[i] < 0x10) output += "0"; // Zero pad - output += uint64ToString(results->state[i], 16); - } -#endif // DECODE_AC - } else { - output += uint64ToString(results->value, 16); - } + output += resultToHexidecimal(results); output += " (" + uint64ToString(results->bits) + " bits)\n"; return output; } @@ -324,17 +462,66 @@ std::string resultToHumanReadableBasic(const decode_results *results) { uint8_t sumBytes(uint8_t *start, const uint16_t length, const uint8_t init) { uint8_t checksum = init; uint8_t *ptr; - for (ptr = start; ptr - start < length; ptr++) - checksum += *ptr; + for (ptr = start; ptr - start < length; ptr++) checksum += *ptr; return checksum; } +uint8_t xorBytes(uint8_t *start, const uint16_t length, const uint8_t init) { + uint8_t checksum = init; + uint8_t *ptr; + for (ptr = start; ptr - start < length; ptr++) checksum ^= *ptr; + return checksum; +} + +// Count the number of bits of a certain type. +// Args: +// start: Ptr to the start of data to count bits in. +// length: How many bytes to count. +// ones: Count the binary 1 bits. False for counting the 0 bits. +// init: Start the counting from this value. +// Returns: +// Nr. of bits found. +uint16_t countBits(const uint8_t *start, const uint16_t length, const bool ones, + const uint16_t init) { + uint16_t count = init; + for (uint16_t offset = 0; offset < length; offset++) + for (uint8_t currentbyte = *(start + offset); + currentbyte; + currentbyte >>= 1) + if (currentbyte & 1) count++; + if (ones || length == 0) + return count; + else + return (length * 8) - count; +} + +// Count the number of bits of a certain type. +// Args: +// data: The value you want bits counted for, starting from the LSB. +// length: How many bits to count. +// ones: Count the binary 1 bits. False for counting the 0 bits. +// init: Start the counting from this value. +// Returns: +// Nr. of bits found. +uint16_t countBits(const uint64_t data, const uint8_t length, const bool ones, + const uint16_t init) { + uint16_t count = init; + uint8_t bitsSoFar = length; + for (uint64_t remainder = data; remainder && bitsSoFar; + remainder >>= 1, bitsSoFar--) + if (remainder & 1) count++; + if (ones || length == 0) + return count; + else + return length - count; +} + uint64_t invertBits(const uint64_t data, const uint16_t nbits) { // No change if we are asked to invert no bits. - if (nbits == 0) return data; + if (nbits == 0) return data; uint64_t result = ~data; // If we are asked to invert all the bits or more than we have, it's simple. - if (nbits >= sizeof(data) * 8) return result; + if (nbits >= sizeof(data) * 8) return result; // Mask off any unwanted bits and return the result. return (result & ((1ULL << nbits) - 1)); } diff --git a/lib/IRremoteESP8266/src/IRutils.h b/lib/IRremoteESP8266/src/IRutils.h index 3da62df..ff045e9 100644 --- a/lib/IRremoteESP8266/src/IRutils.h +++ b/lib/IRremoteESP8266/src/IRutils.h @@ -23,6 +23,7 @@ void serialPrintUint64(uint64_t input, uint8_t base = 10); String resultToSourceCode(const decode_results *results); String resultToTimingInfo(const decode_results *results); String resultToHumanReadableBasic(const decode_results *results); +String resultToHexidecimal(const decode_results *result); #else std::string uint64ToString(uint64_t input, uint8_t base = 10); std::string typeToString(const decode_type_t protocol, @@ -30,10 +31,16 @@ std::string typeToString(const decode_type_t protocol, std::string resultToSourceCode(const decode_results *results); std::string resultToTimingInfo(const decode_results *results); std::string resultToHumanReadableBasic(const decode_results *results); +std::string resultToHexidecimal(const decode_results *result); #endif bool hasACState(const decode_type_t protocol); uint16_t getCorrectedRawLength(const decode_results *results); uint8_t sumBytes(uint8_t *start, const uint16_t length, const uint8_t init = 0); +uint8_t xorBytes(uint8_t *start, const uint16_t length, const uint8_t init = 0); +uint16_t countBits(const uint8_t *start, const uint16_t length, + const bool ones = true, const uint16_t init = 0); +uint16_t countBits(const uint64_t data, const uint8_t length, + const bool ones = true, const uint16_t init = 0); uint64_t invertBits(const uint64_t data, const uint16_t nbits); #endif // IRUTILS_H_ diff --git a/lib/IRremoteESP8266/src/ir_Aiwa.cpp b/lib/IRremoteESP8266/src/ir_Aiwa.cpp index 6863caa..617711a 100644 --- a/lib/IRremoteESP8266/src/ir_Aiwa.cpp +++ b/lib/IRremoteESP8266/src/ir_Aiwa.cpp @@ -13,12 +13,12 @@ // Added by David Conran. (Inspired by IRremoteESP8266's implementation: // https://github.com/z3t0/Arduino-IRremote) -#define AIWA_RC_T501_PRE_BITS 26U -#define AIWA_RC_T501_POST_BITS 1U +const uint16_t kAiwaRcT501PreBits = 26; +const uint16_t kAiwaRcT501PostBits = 1; // NOTE: These are the compliment (inverted) of lirc values as // lirc uses a '0' for a mark, and a '1' for a space. -#define AIWA_RC_T501_PRE_DATA 0x1D8113FULL // 26-bits -#define AIWA_RC_T501_POST_DATA 1ULL +const uint64_t kAiwaRcT501PreData = 0x1D8113FULL; // 26-bits +const uint64_t kAiwaRcT501PostData = 1ULL; #if SEND_AIWA_RC_T501 // Send an Aiwa RC T501 formatted message. @@ -26,7 +26,7 @@ // Args: // data: The message to be sent. // nbits: The number of bits of the message to be sent. -// Typically AIWA_RC_T501_BITS. Max is 37 = (64 - 27) +// Typically kAiwaRcT501Bits. Max is 37 = (64 - 27) // repeat: The number of times the command is to be repeated. // // Status: BETA / Should work. @@ -37,10 +37,9 @@ void IRsend::sendAiwaRCT501(uint64_t data, uint16_t nbits, uint16_t repeat) { // Appears to be an extended NEC1 protocol. i.e. 42 bits instead of 32 bits. // So use sendNEC instead, however the twist is it has a fixed 26 bit // prefix, and a fixed postfix bit. - uint64_t new_data = ( - (AIWA_RC_T501_PRE_DATA << (nbits + AIWA_RC_T501_POST_BITS)) | - (data << AIWA_RC_T501_POST_BITS) | AIWA_RC_T501_POST_DATA); - nbits += AIWA_RC_T501_PRE_BITS + AIWA_RC_T501_POST_BITS; + uint64_t new_data = ((kAiwaRcT501PreData << (nbits + kAiwaRcT501PostBits)) | + (data << kAiwaRcT501PostBits) | kAiwaRcT501PostData); + nbits += kAiwaRcT501PreBits + kAiwaRcT501PostBits; if (nbits > sizeof(new_data) * 8) return; // We are overflowing. Abort, and don't send. sendNEC(new_data, nbits, repeat); @@ -52,7 +51,7 @@ void IRsend::sendAiwaRCT501(uint64_t data, uint16_t nbits, uint16_t repeat) { // // Args: // results: Ptr to the data to decode and where to store the decode result. -// nbits: The number of data bits to expect. Typically AIWA_RC_T501_BITS. +// nbits: The number of data bits to expect. Typically kAiwaRcT501Bits. // strict: Flag indicating if we should perform strict matching. // Returns: // boolean: True if it can decode it, false if it can't. @@ -71,12 +70,11 @@ void IRsend::sendAiwaRCT501(uint64_t data, uint16_t nbits, uint16_t repeat) { bool IRrecv::decodeAiwaRCT501(decode_results *results, uint16_t nbits, bool strict) { // Compliance - if (strict && nbits != AIWA_RC_T501_BITS) + if (strict && nbits != kAiwaRcT501Bits) return false; // Doesn't match our protocol defn. // Add on the pre & post bits to our requested bit length. - uint16_t expected_nbits = nbits + AIWA_RC_T501_PRE_BITS + - AIWA_RC_T501_POST_BITS; + uint16_t expected_nbits = nbits + kAiwaRcT501PreBits + kAiwaRcT501PostBits; uint64_t new_data; if (expected_nbits > sizeof(new_data) * 8) return false; // We can't possibly match something that big. @@ -88,24 +86,23 @@ bool IRrecv::decodeAiwaRCT501(decode_results *results, uint16_t nbits, new_data = results->value; if (actual_bits < expected_nbits) return false; // The data we caught was undersized. Throw it back. - if ((new_data & 0x1ULL) != AIWA_RC_T501_POST_DATA) + if ((new_data & 0x1ULL) != kAiwaRcT501PostData) return false; // The post data doesn't match, so it can't be this protocol. // Trim off the post data bit. - new_data >>= AIWA_RC_T501_POST_BITS; - actual_bits -= AIWA_RC_T501_POST_BITS; + new_data >>= kAiwaRcT501PostBits; + actual_bits -= kAiwaRcT501PostBits; // Extract out our likely new value and put it back in the results. - actual_bits -= AIWA_RC_T501_PRE_BITS; + actual_bits -= kAiwaRcT501PreBits; results->value = new_data & ((1ULL << actual_bits) - 1); // Check the prefix data matches. new_data >>= actual_bits; // Trim off the new data to expose the prefix. - if (new_data != AIWA_RC_T501_PRE_DATA) // Check the prefix. + if (new_data != kAiwaRcT501PreData) // Check the prefix. return false; // Compliance - if (strict && results->bits != expected_nbits) - return false; + if (strict && results->bits != expected_nbits) return false; // Success results->decode_type = AIWA_RC_T501; diff --git a/lib/IRremoteESP8266/src/ir_Argo.cpp b/lib/IRremoteESP8266/src/ir_Argo.cpp index eaa1c51..8246b26 100644 --- a/lib/IRremoteESP8266/src/ir_Argo.cpp +++ b/lib/IRremoteESP8266/src/ir_Argo.cpp @@ -11,44 +11,38 @@ Copyright 2017 Schmolders // Constants // using SPACE modulation. MARK is always const 400u -#define ARGO_HDR_MARK 6400U // Mark -#define ARGO_HDR_SPACE 3300U // Space -#define ARGO_BIT_MARK 400U -#define ARGO_ONE_SPACE 2200U -#define ARGO_ZERO_SPACE 900U +const uint16_t kArgoHdrMark = 6400; +const uint16_t kArgoHdrSpace = 3300; +const uint16_t kArgoBitMark = 400; +const uint16_t kArgoOneSpace = 2200; +const uint16_t kArgoZeroSpace = 900; #if SEND_ARGO // Send an Argo A/C message. // // Args: -// data: An array of ARGO_COMMAND_LENGTH bytes containing the IR command. +// data: An array of kArgoStateLength bytes containing the IR command. // // Status: ALPHA / Untested. void IRsend::sendArgo(unsigned char data[], uint16_t nbytes, uint16_t repeat) { // Check if we have enough bytes to send a proper message. - if (nbytes < ARGO_COMMAND_LENGTH) return; + if (nbytes < kArgoStateLength) return; // TODO(kaschmo): validate - sendGeneric(ARGO_HDR_MARK, ARGO_HDR_SPACE, - ARGO_BIT_MARK, ARGO_ONE_SPACE, - ARGO_BIT_MARK, ARGO_ZERO_SPACE, - 0, 0, // No Footer. - data, nbytes, 38, false, repeat, 50); + sendGeneric(kArgoHdrMark, kArgoHdrSpace, kArgoBitMark, kArgoOneSpace, + kArgoBitMark, kArgoZeroSpace, 0, 0, // No Footer. + data, nbytes, 38, false, repeat, kDutyDefault); } #endif // SEND_ARGO -IRArgoAC::IRArgoAC(uint16_t pin) : _irsend(pin) { - stateReset(); -} +IRArgoAC::IRArgoAC(uint16_t pin) : _irsend(pin) { stateReset(); } -void IRArgoAC::begin() { - _irsend.begin(); -} +void IRArgoAC::begin() { _irsend.begin(); } #if SEND_ARGO -void IRArgoAC::send() { +void IRArgoAC::send(const uint16_t repeat) { checksum(); // Create valid checksum before sending - _irsend.sendArgo(argo); + _irsend.sendArgo(argo, kArgoStateLength, repeat); } #endif // SEND_ARGO @@ -58,20 +52,18 @@ void IRArgoAC::checksum() { // Only add up bytes to 9. byte 10 is 0b01 constant anyway. // Assume that argo array is MSB first (left) - for (i = 0; i < 10; i++) - sum += argo[i]; + for (i = 0; i < 10; i++) sum += argo[i]; sum = sum % 256; // modulo 256 // Append sum to end of array // Set const part of checksum bit 10 argo[10] = 0b00000010; argo[10] += sum << 2; // Shift up 2 bits and append to byte 10 - argo[11] = sum >> 6; // Shift down 6 bits and add in two LSBs of bit 11 + argo[11] = sum >> 6; // Shift down 6 bits and add in two LSBs of bit 11 } void IRArgoAC::stateReset() { - for (uint8_t i = 0; i < ARGO_COMMAND_LENGTH; i++) - argo[i] = 0x0; + for (uint8_t i = 0; i < kArgoStateLength; i++) argo[i] = 0x0; // Argo Message. Store MSB left. // Default message: @@ -84,8 +76,8 @@ void IRArgoAC::stateReset() { this->off(); this->setTemp(20); this->setRoomTemp(25); - this->setCoolMode(ARGO_COOL_AUTO); - this->setFan(ARGO_FAN_AUTO); + this->setCoolMode(kArgoCoolAuto); + this->setFan(kArgoFanAuto); } uint8_t* IRArgoAC::getRaw() { @@ -116,9 +108,7 @@ void IRArgoAC::setPower(bool state) { off(); } -uint8_t IRArgoAC::getPower() { - return ac_state; -} +uint8_t IRArgoAC::getPower() { return ac_state; } void IRArgoAC::setMax(bool state) { max_mode = state; @@ -128,17 +118,15 @@ void IRArgoAC::setMax(bool state) { argo[9] &= 0b11110111; } -bool IRArgoAC::getMax() { - return max_mode; -} +bool IRArgoAC::getMax() { return max_mode; } // Set the temp in deg C // Sending 0 equals +4 void IRArgoAC::setTemp(uint8_t temp) { - if (temp < ARGO_MIN_TEMP) - temp = ARGO_MIN_TEMP; - else if (temp > ARGO_MAX_TEMP) - temp = ARGO_MAX_TEMP; + if (temp < kArgoMinTemp) + temp = kArgoMinTemp; + else if (temp > kArgoMaxTemp) + temp = kArgoMaxTemp; // Store in attributes set_temp = temp; @@ -154,9 +142,7 @@ void IRArgoAC::setTemp(uint8_t temp) { argo[3] += temp >> 2; // remove lowest to bits and append in 0-2 } -uint8_t IRArgoAC::getTemp() { - return set_temp; -} +uint8_t IRArgoAC::getTemp() { return set_temp; } // Set the speed of the fan void IRArgoAC::setFan(uint8_t fan) { @@ -168,18 +154,14 @@ void IRArgoAC::setFan(uint8_t fan) { argo[3] += fan << 3; } -uint8_t IRArgoAC::getFan() { - return fan_mode; -} +uint8_t IRArgoAC::getFan() { return fan_mode; } void IRArgoAC::setFlap(uint8_t flap) { flap_mode = flap; // TODO(kaschmo): set correct bits for flap mode } -uint8_t IRArgoAC::getFlap() { - return flap_mode; -} +uint8_t IRArgoAC::getFlap() { return flap_mode; } uint8_t IRArgoAC::getMode() { // return cooling 0, heating 1 @@ -196,9 +178,7 @@ void IRArgoAC::setCoolMode(uint8_t mode) { argo[2] += mode << 3; } -uint8_t IRArgoAC::getCoolMode() { - return cool_mode; -} +uint8_t IRArgoAC::getCoolMode() { return cool_mode; } void IRArgoAC::setHeatMode(uint8_t mode) { ac_mode = 1; // Set ac mode to heating @@ -211,9 +191,7 @@ void IRArgoAC::setHeatMode(uint8_t mode) { argo[2] += mode << 3; } -uint8_t IRArgoAC::getHeatMode() { - return heat_mode; -} +uint8_t IRArgoAC::getHeatMode() { return heat_mode; } void IRArgoAC::setNight(bool state) { night_mode = state; @@ -224,9 +202,7 @@ void IRArgoAC::setNight(bool state) { argo[9] &= 0b11111011; } -bool IRArgoAC::getNight() { - return night_mode; -} +bool IRArgoAC::getNight() { return night_mode; } void IRArgoAC::setiFeel(bool state) { ifeel_mode = state; @@ -237,9 +213,7 @@ void IRArgoAC::setiFeel(bool state) { argo[9] &= 0b01111111; } -bool IRArgoAC::getiFeel() { - return ifeel_mode; -} +bool IRArgoAC::getiFeel() { return ifeel_mode; } void IRArgoAC::setTime() { // TODO(kaschmo): use function call from checksum to set time first diff --git a/lib/IRremoteESP8266/src/ir_Argo.h b/lib/IRremoteESP8266/src/ir_Argo.h index d59fb77..0174d61 100644 --- a/lib/IRremoteESP8266/src/ir_Argo.h +++ b/lib/IRremoteESP8266/src/ir_Argo.h @@ -29,32 +29,50 @@ // Constants. Store MSB left. -#define ARGO_COOL_ON 0U // 0b000 -#define ARGO_COOL_OFF 3U // 0b110 -#define ARGO_COOL_AUTO 2U // 0b010 -#define ARGO_COOl_HUM 1U // 0b100 +const uint8_t kArgoCoolOn = 0; // 0b000 +const uint8_t kArgoCoolOff = 3; // 0b110 +const uint8_t kArgoCoolAuto = 2; // 0b010 +const uint8_t kArgoCoolHum = 1; // 0b100 +const uint8_t kArgoHeatOn = 0; // 0b001 +const uint8_t kArgoHeatAuto = 1; // 0b101 +const uint8_t kArgoHeatBlink = 2; // 0b011 // ??no idea what mode that is +const uint8_t kArgoMinTemp = 10; // Celsius offset +4 +const uint8_t kArgoMaxTemp = 32; // Celsius +const uint8_t kArgoFanAuto = 0; // 0b00 +const uint8_t kArgoFan3 = 3; // 0b11 +const uint8_t kArgoFan2 = 2; // 0b01 +const uint8_t kArgoFan1 = 1; // 0b10 +const uint8_t kArgoFlapAuto = 0; // 0b000 +const uint8_t kArgoFlap1 = 1; // 0b100 +const uint8_t kArgoFlap2 = 2; // 0b010 +const uint8_t kArgoFlap3 = 3; // 0b110 +const uint8_t kArgoFlap4 = 4; // 0b001 +const uint8_t kArgoFlap5 = 5; // 0b101 +const uint8_t kArgoFlap6 = 6; // 0b011 +const uint8_t kArgoFlapFull = 7; // 0b111 -#define ARGO_HEAT_ON 0U // 0b001 -#define ARGO_HEAT_AUTO 1U // 0b101 -#define ARGO_HEAT_BLINK 2U // 0b011 // ??no idea what mode that is - - -#define ARGO_MIN_TEMP 10U // Celsius offset +4 -#define ARGO_MAX_TEMP 32U // Celsius - -#define ARGO_FAN_AUTO 0U // 0b00 -#define ARGO_FAN_3 3U // 0b11 -#define ARGO_FAN_2 2U // 0b01 -#define ARGO_FAN_1 1U // 0b10 - -#define ARGO_FLAP_AUTO 0U // 0b000 -#define ARGO_FLAP_1 1U // 0b100 -#define ARGO_FLAP_2 2U // 0b010 -#define ARGO_FLAP_3 3U // 0b110 -#define ARGO_FLAP_4 4U // 0b001 -#define ARGO_FLAP_5 5U // 0b101 -#define ARGO_FLAP_6 6U // 0b011 -#define ARGO_FLAP_FULL 7U // 0b111 +// Legacy defines. (Deperecated) +#define ARGO_COOL_ON kArgoCoolOn +#define ARGO_COOL_OFF kArgoCoolOff +#define ARGO_COOL_AUTO kArgoCoolAuto +#define ARGO_COOl_HUM kArgoCoolHum +#define ARGO_HEAT_ON kArgoHeatOn +#define ARGO_HEAT_AUTO kArgoHeatAuto +#define ARGO_HEAT_BLINK kArgoHeatBlink +#define ARGO_MIN_TEMP kArgoMinTemp +#define ARGO_MAX_TEMP kArgoMaxTemp +#define ARGO_FAN_AUTO kArgoFanAuto +#define ARGO_FAN_3 kArgoFan3 +#define ARGO_FAN_2 kArgoFan2 +#define ARGO_FAN_1 kArgoFan1 +#define ARGO_FLAP_AUTO kArgoFlapAuto +#define ARGO_FLAP_1 kArgoFlap1 +#define ARGO_FLAP_2 kArgoFlap2 +#define ARGO_FLAP_3 kArgoFlap3 +#define ARGO_FLAP_4 kArgoFlap4 +#define ARGO_FLAP_5 kArgoFlap5 +#define ARGO_FLAP_6 kArgoFlap6 +#define ARGO_FLAP_FULL kArgoFlapFull class IRArgoAC { @@ -62,7 +80,7 @@ class IRArgoAC { explicit IRArgoAC(uint16_t pin); #if SEND_ARGO - void send(); + void send(const uint16_t repeat = kArgoDefaultRepeat); #endif // SEND_ARGO void begin(); void on(); @@ -103,7 +121,7 @@ class IRArgoAC { private: // # of bytes per command - uint8_t argo[ARGO_COMMAND_LENGTH]; // Defined in IRremoteESP8266.h + uint8_t argo[kArgoStateLength]; // Defined in IRremoteESP8266.h void stateReset(); void checksum(); IRsend _irsend; // instance of the IR send class diff --git a/lib/IRremoteESP8266/src/ir_Carrier.cpp b/lib/IRremoteESP8266/src/ir_Carrier.cpp index 968c2f5..350d61c 100644 --- a/lib/IRremoteESP8266/src/ir_Carrier.cpp +++ b/lib/IRremoteESP8266/src/ir_Carrier.cpp @@ -18,19 +18,19 @@ // Constants // Ref: // https://github.com/markszabo/IRremoteESP8266/issues/385 -#define CARRIER_AC_HDR_MARK 8532U -#define CARRIER_AC_HDR_SPACE 4228U -#define CARRIER_AC_BIT_MARK 628U -#define CARRIER_AC_ONE_SPACE 1320U -#define CARRIER_AC_ZERO_SPACE 532U -#define CARRIER_AC_GAP 20000U +const uint16_t kCarrierAcHdrMark = 8532; +const uint16_t kCarrierAcHdrSpace = 4228; +const uint16_t kCarrierAcBitMark = 628; +const uint16_t kCarrierAcOneSpace = 1320; +const uint16_t kCarrierAcZeroSpace = 532; +const uint16_t kCarrierAcGap = 20000; #if SEND_CARRIER_AC // Send a Carrier HVAC formatted message. // // Args: // data: The message to be sent. -// nbits: The bit size of the message being sent. typically CARRIER_AC_BITS. +// nbits: The bit size of the message being sent. typically kCarrierAcBits. // repeat: The number of times the message is to be repeated. // // Status: BETA / Appears to work on real devices. @@ -40,11 +40,10 @@ void IRsend::sendCarrierAC(uint64_t data, uint16_t nbits, uint16_t repeat) { uint64_t temp_data = data; // Carrier sends the data block three times. normal + inverted + normal. for (uint16_t i = 0; i < 3; i++) { - sendGeneric(CARRIER_AC_HDR_MARK, CARRIER_AC_HDR_SPACE, - CARRIER_AC_BIT_MARK, CARRIER_AC_ONE_SPACE, - CARRIER_AC_BIT_MARK, CARRIER_AC_ZERO_SPACE, - CARRIER_AC_BIT_MARK, CARRIER_AC_GAP, - temp_data, nbits, 38, true, 0, 50); + sendGeneric(kCarrierAcHdrMark, kCarrierAcHdrSpace, kCarrierAcBitMark, + kCarrierAcOneSpace, kCarrierAcBitMark, kCarrierAcZeroSpace, + kCarrierAcBitMark, kCarrierAcGap, temp_data, nbits, 38, true, + 0, kDutyDefault); temp_data = invertBits(temp_data, nbits); } } @@ -58,7 +57,7 @@ void IRsend::sendCarrierAC(uint64_t data, uint16_t nbits, uint16_t repeat) { // Args: // results: Ptr to the data to decode and where to store the decode result. // nbits: Nr. of bits to expect in the data portion. -// Typically CARRIER_AC_BITS. +// Typically kCarrierAcBits. // strict: Flag to indicate if we strictly adhere to the specification. // Returns: // boolean: True if it can decode it, false if it can't. @@ -66,42 +65,38 @@ void IRsend::sendCarrierAC(uint64_t data, uint16_t nbits, uint16_t repeat) { // Status: ALPHA / Untested. // bool IRrecv::decodeCarrierAC(decode_results *results, uint16_t nbits, - bool strict) { - if (results->rawlen < ((2 * nbits + HEADER + FOOTER) * 3) - 1) + bool strict) { + if (results->rawlen < ((2 * nbits + kHeader + kFooter) * 3) - 1) return false; // Can't possibly be a valid Carrier message. - if (strict && nbits != CARRIER_AC_BITS) + if (strict && nbits != kCarrierAcBits) return false; // We expect Carrier to be 32 bits of message. uint64_t data = 0; uint64_t prev_data = 0; - uint16_t offset = OFFSET_START; + uint16_t offset = kStartOffset; for (uint8_t i = 0; i < 3; i++) { prev_data = data; // Header - if (!matchMark(results->rawbuf[offset++], CARRIER_AC_HDR_MARK)) - return false; - if (!matchSpace(results->rawbuf[offset++], CARRIER_AC_HDR_SPACE)) + if (!matchMark(results->rawbuf[offset++], kCarrierAcHdrMark)) return false; + if (!matchSpace(results->rawbuf[offset++], kCarrierAcHdrSpace)) return false; // Data - match_result_t data_result = matchData(&(results->rawbuf[offset]), nbits, - CARRIER_AC_BIT_MARK, - CARRIER_AC_ONE_SPACE, - CARRIER_AC_BIT_MARK, - CARRIER_AC_ZERO_SPACE); + match_result_t data_result = + matchData(&(results->rawbuf[offset]), nbits, kCarrierAcBitMark, + kCarrierAcOneSpace, kCarrierAcBitMark, kCarrierAcZeroSpace); if (data_result.success == false) return false; data = data_result.data; offset += data_result.used; // Footer - if (!matchMark(results->rawbuf[offset++], CARRIER_AC_BIT_MARK)) - return false; + if (!matchMark(results->rawbuf[offset++], kCarrierAcBitMark)) return false; if (offset < results->rawlen && - !matchAtLeast(results->rawbuf[offset++], CARRIER_AC_GAP)) + !matchAtLeast(results->rawbuf[offset++], kCarrierAcGap)) return false; // Compliance. if (strict) { // Check if the data is an inverted copy of the previous data. - if (i > 0 && prev_data != invertBits(data, nbits)) return false; + if (i > 0 && prev_data != invertBits(data, nbits)) return false; } } diff --git a/lib/IRremoteESP8266/src/ir_Coolix.cpp b/lib/IRremoteESP8266/src/ir_Coolix.cpp index 82d59de..b0cb0e2 100644 --- a/lib/IRremoteESP8266/src/ir_Coolix.cpp +++ b/lib/IRremoteESP8266/src/ir_Coolix.cpp @@ -1,6 +1,11 @@ // Copyright bakrus // Copyright 2017 David Conran +#include "ir_Coolix.h" +#include +#ifndef ARDUINO +#include +#endif #include "IRrecv.h" #include "IRsend.h" #include "IRutils.h" @@ -12,32 +17,36 @@ // CCCCC OOOO0 OOOO0 LLLLLLL IIIII XX XX // Coolix A/C / heatpump added by (send) bakrus & (decode) crankyoldgit +// +// Supports: +// RG57K7(B)/BGEF remote control for Beko BINR 070/071 split-type aircon. +// Ref: +// https://github.com/markszabo/IRremoteESP8266/issues/484 // Constants // Pulse parms are *50-100 for the Mark and *50+100 for the space // First MARK is the one after the long gap // pulse parameters in usec -#define COOLIX_TICK 560U // Approximately 21 cycles at 38kHz -#define COOLIX_BIT_MARK_TICKS 1U -#define COOLIX_BIT_MARK (COOLIX_BIT_MARK_TICKS * COOLIX_TICK) -#define COOLIX_ONE_SPACE_TICKS 3U -#define COOLIX_ONE_SPACE (COOLIX_ONE_SPACE_TICKS * COOLIX_TICK) -#define COOLIX_ZERO_SPACE_TICKS 1U -#define COOLIX_ZERO_SPACE (COOLIX_ZERO_SPACE_TICKS * COOLIX_TICK) -#define COOLIX_HDR_MARK_TICKS 8U -#define COOLIX_HDR_MARK (COOLIX_HDR_MARK_TICKS * COOLIX_TICK) -#define COOLIX_HDR_SPACE_TICKS 8U -#define COOLIX_HDR_SPACE (COOLIX_HDR_SPACE_TICKS * COOLIX_TICK) -#define COOLIX_MIN_GAP_TICKS (COOLIX_HDR_MARK_TICKS + \ - COOLIX_ZERO_SPACE_TICKS) -#define COOLIX_MIN_GAP (COOLIX_MIN_GAP_TICKS * COOLIX_TICK) +const uint16_t kCoolixTick = 560; // Approximately 21 cycles at 38kHz +const uint16_t kCoolixBitMarkTicks = 1; +const uint16_t kCoolixBitMark = kCoolixBitMarkTicks * kCoolixTick; +const uint16_t kCoolixOneSpaceTicks = 3; +const uint16_t kCoolixOneSpace = kCoolixOneSpaceTicks * kCoolixTick; +const uint16_t kCoolixZeroSpaceTicks = 1; +const uint16_t kCoolixZeroSpace = kCoolixZeroSpaceTicks * kCoolixTick; +const uint16_t kCoolixHdrMarkTicks = 8; +const uint16_t kCoolixHdrMark = kCoolixHdrMarkTicks * kCoolixTick; +const uint16_t kCoolixHdrSpaceTicks = 8; +const uint16_t kCoolixHdrSpace = kCoolixHdrSpaceTicks * kCoolixTick; +const uint16_t kCoolixMinGapTicks = kCoolixHdrMarkTicks + kCoolixZeroSpaceTicks; +const uint16_t kCoolixMinGap = kCoolixMinGapTicks * kCoolixTick; #if SEND_COOLIX // Send a Coolix message // // Args: // data: Contents of the message to be sent. -// nbits: Nr. of bits of data to be sent. Typically COOLIX_BITS. +// nbits: Nr. of bits of data to be sent. Typically kCoolixBits. // repeat: Nr. of additional times the message is to be sent. // // Status: BETA / Probably works. @@ -46,16 +55,15 @@ // https://github.com/z3t0/Arduino-IRremote/blob/master/ir_COOLIX.cpp // TODO(anyone): Verify repeat functionality against a real unit. void IRsend::sendCOOLIX(uint64_t data, uint16_t nbits, uint16_t repeat) { - if (nbits % 8 != 0) - return; // nbits is required to be a multiple of 8. + if (nbits % 8 != 0) return; // nbits is required to be a multiple of 8. // Set IR carrier frequency enableIROut(38); for (uint16_t r = 0; r <= repeat; r++) { // Header - mark(COOLIX_HDR_MARK); - space(COOLIX_HDR_SPACE); + mark(kCoolixHdrMark); + space(kCoolixHdrSpace); // Data // Break data into byte segments, starting at the Most Significant @@ -64,28 +72,285 @@ void IRsend::sendCOOLIX(uint64_t data, uint16_t nbits, uint16_t repeat) { // Grab a bytes worth of data. uint8_t segment = (data >> (nbits - i)) & 0xFF; // Normal - sendData(COOLIX_BIT_MARK, COOLIX_ONE_SPACE, - COOLIX_BIT_MARK, COOLIX_ZERO_SPACE, - segment, 8, true); + sendData(kCoolixBitMark, kCoolixOneSpace, kCoolixBitMark, + kCoolixZeroSpace, segment, 8, true); // Inverted. - sendData(COOLIX_BIT_MARK, COOLIX_ONE_SPACE, - COOLIX_BIT_MARK, COOLIX_ZERO_SPACE, - segment ^ 0xFF, 8, true); + sendData(kCoolixBitMark, kCoolixOneSpace, kCoolixBitMark, + kCoolixZeroSpace, segment ^ 0xFF, 8, true); } // Footer - mark(COOLIX_BIT_MARK); - space(COOLIX_MIN_GAP); // Pause before repeating + mark(kCoolixBitMark); + space(kCoolixMinGap); // Pause before repeating } } #endif +// IRCoolixAC class +// Supports: +// RG57K7(B)/BGEF remote control for Beko BINR 070/071 split-type aircon. +// Ref: +// https://github.com/markszabo/IRremoteESP8266/issues/484 +IRCoolixAC::IRCoolixAC(uint16_t pin) : _irsend(pin) { stateReset(); } + +void IRCoolixAC::stateReset() { remote_state = kCoolixDefaultState; } + +void IRCoolixAC::begin() { _irsend.begin(); } + +#if SEND_COOLIX +void IRCoolixAC::send(const uint16_t repeat) { + _irsend.sendCOOLIX(remote_state, kCoolixBits, repeat); +} +#endif // SEND_COOLIX + +uint32_t IRCoolixAC::getRaw() { return remote_state; } + +void IRCoolixAC::setRaw(const uint32_t new_code) { remote_state = new_code; } + +void IRCoolixAC::setTempRaw(const uint8_t code) { + remote_state &= ~kCoolixTempMask; // Clear the old temp. + remote_state |= (code << 4); +} + +uint8_t IRCoolixAC::getTempRaw() { + return (remote_state & kCoolixTempMask) >> 4; +} + +void IRCoolixAC::setTemp(const uint8_t desired) { + // Range check. + uint8_t temp = std::min(desired, kCoolixTempMax); + temp = std::max(temp, kCoolixTempMin); + setTempRaw(kCoolixTempMap[temp - kCoolixTempMin]); +} + +uint8_t IRCoolixAC::getTemp() { + uint8_t code = getTempRaw(); + uint8_t i; + for (i = 0; i < kCoolixTempRange; i++) + if (kCoolixTempMap[i] == code) return kCoolixTempMin + i; + return kCoolixUnknown; // Not a temp we expected. +} + +void IRCoolixAC::setSensorTempRaw(const uint8_t code) { + remote_state &= ~kCoolixSensorTempMask; // Clear previous sensor temp. + remote_state |= ((code & 0xF) << 8); +} + +void IRCoolixAC::setSensorTemp(const uint8_t desired) { + uint8_t temp = desired; + temp = std::min(temp, kCoolixSensorTempMax); + temp = std::max(temp, kCoolixSensorTempMin); + setSensorTempRaw(temp - kCoolixSensorTempMin); + setZoneFollow(true); // Setting a Sensor temp means you want to Zone Follow. +} + +uint8_t IRCoolixAC::getSensorTemp() { + return ((remote_state & kCoolixSensorTempMask) >> 8) + kCoolixSensorTempMin; +} + +bool IRCoolixAC::getPower() { + // There is only an off state. Everything else is "on". + return remote_state != kCoolixOff; +} + +void IRCoolixAC::setPower(const bool power) { + if (!power) remote_state = kCoolixOff; + // There really is no distinct "on" setting, so do nothing. +} + +bool IRCoolixAC::getSwing() { return remote_state == kCoolixSwing; } + +void IRCoolixAC::setSwing() { + // Assumes that repeated sending "swing" toggles the action on the device. + remote_state = kCoolixSwing; +} + +bool IRCoolixAC::getSleep() { return remote_state == kCoolixSleep; } + +void IRCoolixAC::setSleep() { remote_state = kCoolixSleep; } + +bool IRCoolixAC::getTurbo() { return remote_state == kCoolixTurbo; } + +void IRCoolixAC::setTurbo() { + // Assumes that repeated sending "turbo" toggles the action on the device. + remote_state = kCoolixTurbo; +} + +bool IRCoolixAC::getLed() { return remote_state == kCoolixLed; } + +void IRCoolixAC::setLed() { + // Assumes that repeated sending "Led" toggles the action on the device. + remote_state = kCoolixLed; +} + +bool IRCoolixAC::getClean() { return remote_state == kCoolixClean; } + +void IRCoolixAC::setClean() { remote_state = kCoolixClean; } + +bool IRCoolixAC::getZoneFollow() { + return remote_state & kCoolixZoneFollowMask; +} + +// Internal use only. +void IRCoolixAC::setZoneFollow(bool state) { + if (state) { + remote_state |= kCoolixZoneFollowMask; + } else { + remote_state &= ~kCoolixZoneFollowMask; + } +} + +void IRCoolixAC::clearSensorTemp() { + setZoneFollow(false); + setSensorTempRaw(kCoolixSensorTempIgnoreCode); +} + +void IRCoolixAC::setMode(const uint8_t mode) { + uint32_t actualmode = mode; + // Fan mode is a special case of Dry. + if (mode == kCoolixFan) actualmode = kCoolixDry; + switch (actualmode) { + case kCoolixCool: + case kCoolixAuto: + case kCoolixHeat: + case kCoolixDry: + remote_state = (remote_state & ~kCoolixModeMask) | (actualmode << 2); + // Force the temp into a known-good state. + setTemp(getTemp()); + } + if (mode == kCoolixFan) setTempRaw(kCoolixFanTempCode); +} + +uint8_t IRCoolixAC::getMode() { + uint8_t mode = (remote_state & kCoolixModeMask) >> 2; + if (mode == kCoolixDry) + if (getTempRaw() == kCoolixFanTempCode) return kCoolixFan; + return mode; +} + +uint8_t IRCoolixAC::getFan() { return (remote_state & kCoolixFanMask) >> 13; } + +void IRCoolixAC::setFan(const uint8_t speed) { + uint8_t newspeed = speed; + switch (speed) { + case kCoolixFanMin: + case kCoolixFanMed: + case kCoolixFanMax: + case kCoolixFanAuto: + case kCoolixFanAuto0: + case kCoolixFanZoneFollow: + case kCoolixFanFixed: + break; + default: // Unknown speed requested. + newspeed = kCoolixFanAuto; + } + remote_state &= ~kCoolixFanMask; + remote_state |= ((newspeed << 13) & kCoolixFanMask); +} + +// Convert the internal state into a human readable string. +#ifdef ARDUINO +String IRCoolixAC::toString() { + String result = ""; +#else +std::string IRCoolixAC::toString() { + std::string result = ""; +#endif // ARDUINO + result += "Power: "; + if (getPower()) { + result += "On"; + } else { + result += "Off"; + return result; // If it's off, there is no other info. + } + result += ", Fan: " + uint64ToString(getFan()); + switch (getFan()) { + case kCoolixFanAuto: + result += " (AUTO)"; + break; + case kCoolixFanAuto0: + result += " (AUTO0)"; + break; + case kCoolixFanMax: + result += " (MAX)"; + break; + case kCoolixFanMin: + result += " (MIN)"; + break; + case kCoolixFanMed: + result += " (MED)"; + break; + case kCoolixFanZoneFollow: + result += " (ZONEFOLLOW)"; + break; + case kCoolixFanFixed: + result += " (FIXED)"; + break; + default: + result += " (UNKNOWN)"; + } + // Special modes. + if (getSwing()) { + result += ", Swing: Toggle"; + return result; + } + if (getSleep()) { + result += ", Sleep: Toggle"; + return result; + } + if (getTurbo()) { + result += ", Turbo: Toggle"; + return result; + } + if (getLed()) { + result += ", Led: Toggle"; + return result; + } + if (getClean()) { + result += ", Mode: Self clean"; + return result; + } + result += ", Mode: " + uint64ToString(getMode()); + switch (getMode()) { + case kCoolixAuto: + result += " (AUTO)"; + break; + case kCoolixCool: + result += " (COOL)"; + break; + case kCoolixHeat: + result += " (HEAT)"; + break; + case kCoolixDry: + result += " (DRY)"; + break; + case kCoolixFan: + result += " (FAN)"; + break; + default: + result += " (UNKNOWN)"; + } + if (getMode() != kCoolixFan) // Fan mode doesn't have a temperature. + result += ", Temp: " + uint64ToString(getTemp()) + "C"; + result += ", Zone Follow: "; + if (getZoneFollow()) + result += "On"; + else + result += "Off"; + result += ", Sensor Temp: "; + if (getSensorTemp() > kCoolixSensorTempMax) + result += "Ignored"; + else + result += uint64ToString(getSensorTemp()) + "C"; + return result; +} + #if DECODE_COOLIX // Decode the supplied Coolix message. // // Args: // results: Ptr to the data to decode and where to store the decode result. -// nbits: The number of data bits to expect. Typically COOLIX_BITS. +// nbits: The number of data bits to expect. Typically kCoolixBits. // strict: Flag indicating if we should perform strict matching. // Returns: // boolean: True if it can decode it, false if it can't. @@ -95,42 +360,41 @@ bool IRrecv::decodeCOOLIX(decode_results *results, uint16_t nbits, bool strict) { // The protocol sends the data normal + inverted, alternating on // each byte. Hence twice the number of expected data bits. - if (results->rawlen < 2 * 2 * nbits + HEADER + FOOTER - 1) + if (results->rawlen < 2 * 2 * nbits + kHeader + kFooter - 1) return false; // Can't possibly be a valid COOLIX message. - if (strict && nbits != COOLIX_BITS) - return false; // Not strictly a COOLIX message. + if (strict && nbits != kCoolixBits) + return false; // Not strictly a COOLIX message. if (nbits % 8 != 0) // nbits has to be a multiple of nr. of bits in a byte. return false; uint64_t data = 0; uint64_t inverted = 0; - uint16_t offset = OFFSET_START; + uint16_t offset = kStartOffset; if (nbits > sizeof(data) * 8) return false; // We can't possibly capture a Coolix packet that big. // Header - if (!matchMark(results->rawbuf[offset], COOLIX_HDR_MARK)) return false; + if (!matchMark(results->rawbuf[offset], kCoolixHdrMark)) return false; // Calculate how long the common tick time is based on the header mark. - uint32_t m_tick = results->rawbuf[offset++] * RAWTICK / COOLIX_HDR_MARK_TICKS; - if (!matchSpace(results->rawbuf[offset], COOLIX_HDR_SPACE)) return false; + uint32_t m_tick = results->rawbuf[offset++] * kRawTick / kCoolixHdrMarkTicks; + if (!matchSpace(results->rawbuf[offset], kCoolixHdrSpace)) return false; // Calculate how long the common tick time is based on the header space. - uint32_t s_tick = results->rawbuf[offset++] * RAWTICK / - COOLIX_HDR_SPACE_TICKS; + uint32_t s_tick = results->rawbuf[offset++] * kRawTick / kCoolixHdrSpaceTicks; // Data // Twice as many bits as there are normal plus inverted bits. for (uint16_t i = 0; i < nbits * 2; i++, offset++) { bool flip = (i / 8) % 2; - if (!matchMark(results->rawbuf[offset++], COOLIX_BIT_MARK_TICKS * m_tick)) + if (!matchMark(results->rawbuf[offset++], kCoolixBitMarkTicks * m_tick)) return false; - if (matchSpace(results->rawbuf[offset], COOLIX_ONE_SPACE_TICKS * s_tick)) { + if (matchSpace(results->rawbuf[offset], kCoolixOneSpaceTicks * s_tick)) { if (flip) inverted = (inverted << 1) | 1; else data = (data << 1) | 1; } else if (matchSpace(results->rawbuf[offset], - COOLIX_ZERO_SPACE_TICKS * s_tick)) { + kCoolixZeroSpaceTicks * s_tick)) { if (flip) inverted <<= 1; else @@ -141,18 +405,17 @@ bool IRrecv::decodeCOOLIX(decode_results *results, uint16_t nbits, } // Footer - if (!matchMark(results->rawbuf[offset++], COOLIX_BIT_MARK_TICKS * m_tick)) + if (!matchMark(results->rawbuf[offset++], kCoolixBitMarkTicks * m_tick)) return false; if (offset < results->rawlen && - !matchAtLeast(results->rawbuf[offset], COOLIX_MIN_GAP_TICKS * s_tick)) + !matchAtLeast(results->rawbuf[offset], kCoolixMinGapTicks * s_tick)) return false; // Compliance uint64_t orig = data; // Save a copy of the data. if (strict) { for (uint16_t i = 0; i < nbits; i += 8, data >>= 8, inverted >>= 8) - if ((data & 0xFF) != ((inverted & 0xFF) ^ 0xFF)) - return false; + if ((data & 0xFF) != ((inverted & 0xFF) ^ 0xFF)) return false; } // Success diff --git a/lib/IRremoteESP8266/src/ir_Coolix.h b/lib/IRremoteESP8266/src/ir_Coolix.h new file mode 100644 index 0000000..fa61437 --- /dev/null +++ b/lib/IRremoteESP8266/src/ir_Coolix.h @@ -0,0 +1,140 @@ +// Coolix A/C +// +// Copyright 2018 David Conran + +#ifndef IR_COOLIX_H_ +#define IR_COOLIX_H_ + +#define __STDC_LIMIT_MACROS +#include +#ifndef UNIT_TEST +#include +#else +#include +#endif +#include "IRremoteESP8266.h" +#include "IRsend.h" + +// CCCCC OOOOO OOOOO LL IIIII XX XX +// CC C OO OO OO OO LL III XX XX +// CC OO OO OO OO LL III XXXX +// CC C OO OO OO OO LL III XX XX +// CCCCC OOOO0 OOOO0 LLLLLLL IIIII XX XX + +// Supports: +// RG57K7(B)/BGEF remote control for Beko BINR 070/071 split-type aircon. +// Ref: +// https://github.com/markszabo/IRremoteESP8266/issues/484 +// Kudos: +// Hamper: For the breakdown and mapping of the bit values. + +// Constants +// Modes +const uint8_t kCoolixCool = 0b00; +const uint8_t kCoolixDry = 0b01; +const uint8_t kCoolixAuto = 0b10; +const uint8_t kCoolixHeat = 0b11; +const uint8_t kCoolixFan = 4; // Synthetic. +const uint32_t kCoolixModeMask = 0b000000000000000000001100; // 0xC +const uint32_t kCoolixZoneFollowMask = 0b000010000000000000000000; // 0x80000 +// Fan Control +const uint8_t kCoolixFanMin = 0b100; +const uint8_t kCoolixFanMed = 0b010; +const uint8_t kCoolixFanMax = 0b001; +const uint8_t kCoolixFanAuto = 0b101; +const uint8_t kCoolixFanAuto0 = 0b000; +const uint8_t kCoolixFanZoneFollow = 0b110; +const uint8_t kCoolixFanFixed = 0b111; +const uint32_t kCoolixFanMask = 0b000000001110000000000000; // 0x00E000 +// Temperature +const uint8_t kCoolixTempMin = 17; // Celsius +const uint8_t kCoolixTempMax = 30; // Celsius +const uint8_t kCoolixTempRange = kCoolixTempMax - kCoolixTempMin + 1; +const uint8_t kCoolixFanTempCode = 0b1110; // Part of Fan Mode. +const uint32_t kCoolixTempMask = 0b11110000; +const uint8_t kCoolixTempMap[kCoolixTempRange] = { + 0b0000, // 17C + 0b0001, // 18c + 0b0011, // 19C + 0b0010, // 20C + 0b0110, // 21C + 0b0111, // 22C + 0b0101, // 23C + 0b0100, // 24C + 0b1100, // 25C + 0b1101, // 26C + 0b1001, // 27C + 0b1000, // 28C + 0b1010, // 29C + 0b1011 // 30C +}; +const uint8_t kCoolixSensorTempMin = 16; // Celsius +const uint8_t kCoolixSensorTempMax = 30; // Celsius +const uint8_t kCoolixSensorTempIgnoreCode = 0b1111; +const uint32_t kCoolixSensorTempMask = 0b000000000000111100000000; // 0xF00 +// Fixed states/messages. +const uint8_t kCoolixPrefix = 0b1011; // 0xB +const uint8_t kCoolixUnknown = 0xFF; +const uint32_t kCoolixOff = 0b101100100111101111100000; // 0xB27BE0 +const uint32_t kCoolixSwing = 0b101100100110101111100000; // 0xB26BE0 +const uint32_t kCoolixSleep = 0b101100101110000000000011; // 0xB2E003 +const uint32_t kCoolixTurbo = 0b101101011111010110100010; // 0xB5F5A2 +const uint32_t kCoolixLed = 0b101101011111010110100101; // 0xB5F5A5 +const uint32_t kCoolixClean = 0b101101011111010110101010; // 0xB5F5AA +// On, 25C, Mode: Auto, Fan: Auto, Zone Follow: Off, Sensor Temp: Ignore. +const uint32_t kCoolixDefaultState = 0b101100101011111111001000; // 0xB2BFC8 + +// Classes +class IRCoolixAC { + public: + explicit IRCoolixAC(uint16_t pin); + + void stateReset(); +#if SEND_COOLIX + void send(const uint16_t repeat = kCoolixDefaultRepeat); +#endif // SEND_COOLIX + void begin(); + void on(); + void off(); + void setPower(const bool state); + bool getPower(); + void setTemp(const uint8_t temp); + uint8_t getTemp(); + void setSensorTemp(const uint8_t desired); + uint8_t getSensorTemp(); + void clearSensorTemp(); + void setFan(const uint8_t fan); + uint8_t getFan(); + void setMode(const uint8_t mode); + uint8_t getMode(); + void setSwing(); + bool getSwing(); + void setSleep(); + bool getSleep(); + void setTurbo(); + bool getTurbo(); + void setLed(); + bool getLed(); + void setClean(); + bool getClean(); + bool getZoneFollow(); + uint32_t getRaw(); + void setRaw(const uint32_t new_code); + +#ifdef ARDUINO + String toString(); +#else + std::string toString(); +#endif + + private: + // The state of the IR remote in IR code form. + uint32_t remote_state; + IRsend _irsend; + void setTempRaw(const uint8_t code); + uint8_t getTempRaw(); + void setSensorTempRaw(const uint8_t code); + void setZoneFollow(const bool state); +}; + +#endif // IR_COOLIX_H_ diff --git a/lib/IRremoteESP8266/src/ir_Daikin.cpp b/lib/IRremoteESP8266/src/ir_Daikin.cpp index caf0359..a6e8d9e 100644 --- a/lib/IRremoteESP8266/src/ir_Daikin.cpp +++ b/lib/IRremoteESP8266/src/ir_Daikin.cpp @@ -1,10 +1,11 @@ /* -An Arduino sketch to emulate IR Daikin ARC433** remote control unit +An Arduino sketch to emulate IR Daikin ARC433** & ARC477A1 remote control unit Read more at: http://harizanov.com/2012/02/control-daikin-air-conditioner-over-the-internet/ Copyright 2016 sillyfrog Copyright 2017 sillyfrog, crankyoldgit +Copyright 2018-2019 crankyoldgit */ #include "ir_Daikin.h" @@ -12,10 +13,10 @@ Copyright 2017 sillyfrog, crankyoldgit #ifndef ARDUINO #include #endif -#include "IRremoteESP8266.h" -#include "IRutils.h" #include "IRrecv.h" +#include "IRremoteESP8266.h" #include "IRsend.h" +#include "IRutils.h" // DDDDD AAA IIIII KK KK IIIII NN NN // DD DD AAAAA III KK KK III NNN NN @@ -27,6 +28,7 @@ Copyright 2017 sillyfrog, crankyoldgit // Ref: // https://github.com/mharizanov/Daikin-AC-remote-control-over-the-Internet/tree/master/IRremote // http://rdlab.cdmt.vn/project-2013/daikin-ir-protocol +// https://github.com/markszabo/IRremoteESP8266/issues/582 #if SEND_DAIKIN // Original header @@ -43,7 +45,7 @@ Copyright 2017 sillyfrog, crankyoldgit // Send a Daikin A/C message. // // Args: -// data: An array of DAIKIN_COMMAND_LENGTH bytes containing the IR command. +// data: An array of kDaikinStateLength bytes containing the IR command. // // Status: STABLE // @@ -52,94 +54,68 @@ Copyright 2017 sillyfrog, crankyoldgit // https://github.com/mharizanov/Daikin-AC-remote-control-over-the-Internet/tree/master/IRremote void IRsend::sendDaikin(unsigned char data[], uint16_t nbytes, uint16_t repeat) { - if (nbytes < DAIKIN_COMMAND_LENGTH) + if (nbytes < kDaikinStateLength) return; // Not enough bytes to send a proper message. for (uint16_t r = 0; r <= repeat; r++) { // Send the header, 0b00000 sendGeneric(0, 0, // No header for the header - DAIKIN_BIT_MARK, DAIKIN_ONE_SPACE, - DAIKIN_BIT_MARK, DAIKIN_ZERO_SPACE, - DAIKIN_BIT_MARK, DAIKIN_ZERO_SPACE + DAIKIN_GAP, - (uint64_t) 0b00000, 5, 38, false, 0, 50); + kDaikinBitMark, kDaikinOneSpace, kDaikinBitMark, + kDaikinZeroSpace, kDaikinBitMark, kDaikinZeroSpace + kDaikinGap, + (uint64_t)0b00000, 5, 38, false, 0, 50); // Leading header // Do this as a constant to save RAM and keep in flash memory - sendGeneric(DAIKIN_HDR_MARK, DAIKIN_HDR_SPACE, - DAIKIN_BIT_MARK, DAIKIN_ONE_SPACE, - DAIKIN_BIT_MARK, DAIKIN_ZERO_SPACE, - DAIKIN_BIT_MARK, DAIKIN_ZERO_SPACE + DAIKIN_GAP, - DAIKIN_FIRST_HEADER64, 64, 38, false, 0, 50); + sendGeneric(kDaikinHdrMark, kDaikinHdrSpace, kDaikinBitMark, + kDaikinOneSpace, kDaikinBitMark, kDaikinZeroSpace, + kDaikinBitMark, kDaikinZeroSpace + kDaikinGap, + kDaikinFirstHeader64, 64, 38, false, 0, 50); // Data #1 - sendGeneric(DAIKIN_HDR_MARK, DAIKIN_HDR_SPACE, - DAIKIN_BIT_MARK, DAIKIN_ONE_SPACE, - DAIKIN_BIT_MARK, DAIKIN_ZERO_SPACE, - DAIKIN_BIT_MARK, DAIKIN_ZERO_SPACE + DAIKIN_GAP, - data, 8, 38, false, 0, 50); + sendGeneric(kDaikinHdrMark, kDaikinHdrSpace, kDaikinBitMark, + kDaikinOneSpace, kDaikinBitMark, kDaikinZeroSpace, + kDaikinBitMark, kDaikinZeroSpace + kDaikinGap, data, 8, 38, + false, 0, 50); // Data #2 - sendGeneric(DAIKIN_HDR_MARK, DAIKIN_HDR_SPACE, - DAIKIN_BIT_MARK, DAIKIN_ONE_SPACE, - DAIKIN_BIT_MARK, DAIKIN_ZERO_SPACE, - DAIKIN_BIT_MARK, DAIKIN_ZERO_SPACE + DAIKIN_GAP, - data + 8, nbytes - 8, 38, false, 0, 50); + sendGeneric(kDaikinHdrMark, kDaikinHdrSpace, kDaikinBitMark, + kDaikinOneSpace, kDaikinBitMark, kDaikinZeroSpace, + kDaikinBitMark, kDaikinZeroSpace + kDaikinGap, data + 8, + nbytes - 8, 38, false, 0, 50); } } #endif // SEND_DAIKIN -IRDaikinESP::IRDaikinESP(uint16_t pin) : _irsend(pin) { - stateReset(); -} +IRDaikinESP::IRDaikinESP(uint16_t pin) : _irsend(pin) { stateReset(); } -void IRDaikinESP::begin() { - _irsend.begin(); -} +void IRDaikinESP::begin() { _irsend.begin(); } #if SEND_DAIKIN -void IRDaikinESP::send() { +void IRDaikinESP::send(const uint16_t repeat) { checksum(); - _irsend.sendDaikin(daikin); + _irsend.sendDaikin(daikin, kDaikinStateLength, repeat); } #endif // SEND_DAIKIN -// Calculate the checksum for a given data block. -// Args: -// block: Ptr to the start of the data block. -// length: Nr. of bytes to checksum. -// Returns: -// A byte containing the calculated checksum. -uint8_t IRDaikinESP::calcBlockChecksum(const uint8_t *block, - const uint16_t length) { - uint8_t sum = 0; - // Daikin checksum is just the addition of all the data bytes - // in the block but capped to 8 bits. - for (uint16_t i = 0; i < length; i++, block++) - sum += *block; - return sum & 0xFFU; -} - // Verify the checksum is valid for a given state. // Args: // state: The array to verify the checksum of. // length: The size of the state. // Returns: // A boolean. -bool IRDaikinESP::validChecksum(const uint8_t state[], - const uint16_t length) { - if (length < 8 || state[7] != calcBlockChecksum(state, 7)) return false; +bool IRDaikinESP::validChecksum(uint8_t state[], const uint16_t length) { + if (length < 8 || state[7] != sumBytes(state, 7)) return false; if (length < 10 || - state[length - 1] != calcBlockChecksum(state + 8, length - 9)) + state[length - 1] != sumBytes(state + 8, length - 9)) return false; return true; } // Calculate and set the checksum values for the internal state. void IRDaikinESP::checksum() { - daikin[7] = calcBlockChecksum(daikin, 7); - daikin[26] = calcBlockChecksum(daikin + 8, 17); + daikin[7] = sumBytes(daikin, 7); + daikin[26] = sumBytes(daikin + 8, 17); } void IRDaikinESP::stateReset() { - for (uint8_t i = 0; i < DAIKIN_COMMAND_LENGTH; i++) - daikin[i] = 0x0; + for (uint8_t i = 0; i < kDaikinStateLength; i++) daikin[i] = 0x0; daikin[0] = 0x11; daikin[1] = 0xDA; @@ -159,24 +135,23 @@ void IRDaikinESP::stateReset() { checksum(); } -uint8_t* IRDaikinESP::getRaw() { - checksum(); // Ensure correct settings before sending. +uint8_t *IRDaikinESP::getRaw() { + checksum(); // Ensure correct settings before sending. return daikin; } void IRDaikinESP::setRaw(uint8_t new_code[]) { - for (uint8_t i = 0; i < DAIKIN_COMMAND_LENGTH; i++) - daikin[i] = new_code[i]; + for (uint8_t i = 0; i < kDaikinStateLength; i++) daikin[i] = new_code[i]; } void IRDaikinESP::on() { // state = ON; - setBit(DAIKIN_BYTE_POWER, DAIKIN_BIT_POWER); + setBit(kDaikinBytePower, kDaikinBitPower); } void IRDaikinESP::off() { // state = OFF; - clearBit(DAIKIN_BYTE_POWER, DAIKIN_BIT_POWER); + clearBit(kDaikinBytePower, kDaikinBitPower); } void IRDaikinESP::setPower(bool state) { @@ -187,30 +162,28 @@ void IRDaikinESP::setPower(bool state) { } bool IRDaikinESP::getPower() { - return (getBit(DAIKIN_BYTE_POWER, DAIKIN_BIT_POWER) > 0); + return (getBit(kDaikinBytePower, kDaikinBitPower) > 0); } // Set the temp in deg C void IRDaikinESP::setTemp(uint8_t temp) { - if (temp < DAIKIN_MIN_TEMP) - temp = DAIKIN_MIN_TEMP; - else if (temp > DAIKIN_MAX_TEMP) - temp = DAIKIN_MAX_TEMP; + if (temp < kDaikinMinTemp) + temp = kDaikinMinTemp; + else if (temp > kDaikinMaxTemp) + temp = kDaikinMaxTemp; daikin[14] = temp * 2; } -uint8_t IRDaikinESP::getTemp() { - return daikin[14] / 2; -} +uint8_t IRDaikinESP::getTemp() { return daikin[14] / 2; } -// Set the speed of the fan, 1-5 or DAIKIN_FAN_AUTO or DAIKIN_FAN_QUIET +// Set the speed of the fan, 1-5 or kDaikinFanAuto or kDaikinFanQuiet void IRDaikinESP::setFan(uint8_t fan) { // Set the fan speed bits, leave low 4 bits alone uint8_t fanset; - if (fan == DAIKIN_FAN_QUIET || fan == DAIKIN_FAN_AUTO) + if (fan == kDaikinFanQuiet || fan == kDaikinFanAuto) fanset = fan; - else if (fan < DAIKIN_FAN_MIN || fan > DAIKIN_FAN_MAX) - fanset = DAIKIN_FAN_AUTO; + else if (fan < kDaikinFanMin || fan > kDaikinFanMax) + fanset = kDaikinFanAuto; else fanset = 2 + fan; daikin[16] &= 0x0F; @@ -219,31 +192,30 @@ void IRDaikinESP::setFan(uint8_t fan) { uint8_t IRDaikinESP::getFan() { uint8_t fan = daikin[16] >> 4; - if (fan != DAIKIN_FAN_QUIET && fan != DAIKIN_FAN_AUTO) - fan -= 2; + if (fan != kDaikinFanQuiet && fan != kDaikinFanAuto) fan -= 2; return fan; } uint8_t IRDaikinESP::getMode() { /* - DAIKIN_COOL - DAIKIN_HEAT - DAIKIN_FAN - DAIKIN_AUTO - DAIKIN_DRY + kDaikinCool + kDaikinHeat + kDaikinFan + kDaikinAuto + kDaikinDry */ return daikin[13] >> 4; } void IRDaikinESP::setMode(uint8_t mode) { switch (mode) { - case DAIKIN_COOL: - case DAIKIN_HEAT: - case DAIKIN_FAN: - case DAIKIN_DRY: + case kDaikinCool: + case kDaikinHeat: + case kDaikinFan: + case kDaikinDry: break; default: - mode = DAIKIN_AUTO; + mode = kDaikinAuto; } mode <<= 4; daikin[13] &= 0b10001111; @@ -257,9 +229,7 @@ void IRDaikinESP::setSwingVertical(bool state) { daikin[16] &= 0xF0; } -bool IRDaikinESP::getSwingVertical() { - return daikin[16] & 0x01; -} +bool IRDaikinESP::getSwingVertical() { return daikin[16] & 0x01; } void IRDaikinESP::setSwingHorizontal(bool state) { if (state) @@ -268,84 +238,82 @@ void IRDaikinESP::setSwingHorizontal(bool state) { daikin[17] &= 0xF0; } -bool IRDaikinESP::getSwingHorizontal() { - return daikin[17] & 0x01; -} +bool IRDaikinESP::getSwingHorizontal() { return daikin[17] & 0x01; } void IRDaikinESP::setQuiet(bool state) { if (state) { - setBit(DAIKIN_BYTE_SILENT, DAIKIN_BIT_SILENT); + setBit(kDaikinByteSilent, kDaikinBitSilent); // Powerful & Quiet mode being on are mutually exclusive. setPowerful(false); } else { - clearBit(DAIKIN_BYTE_SILENT, DAIKIN_BIT_SILENT); + clearBit(kDaikinByteSilent, kDaikinBitSilent); } } bool IRDaikinESP::getQuiet() { - return (getBit(DAIKIN_BYTE_SILENT, DAIKIN_BIT_SILENT) > 0); + return (getBit(kDaikinByteSilent, kDaikinBitSilent) > 0); } void IRDaikinESP::setPowerful(bool state) { if (state) { - setBit(DAIKIN_BYTE_POWERFUL, DAIKIN_BIT_POWERFUL); + setBit(kDaikinBytePowerful, kDaikinBitPowerful); // Powerful, Quiet, & Econo mode being on are mutually exclusive. setQuiet(false); setEcono(false); } else { - clearBit(DAIKIN_BYTE_POWERFUL, DAIKIN_BIT_POWERFUL); + clearBit(kDaikinBytePowerful, kDaikinBitPowerful); } } bool IRDaikinESP::getPowerful() { - return (getBit(DAIKIN_BYTE_POWERFUL, DAIKIN_BIT_POWERFUL) > 0); + return (getBit(kDaikinBytePowerful, kDaikinBitPowerful) > 0); } void IRDaikinESP::setSensor(bool state) { if (state) - setBit(DAIKIN_BYTE_SENSOR, DAIKIN_BIT_SENSOR); + setBit(kDaikinByteSensor, kDaikinBitSensor); else - clearBit(DAIKIN_BYTE_SENSOR, DAIKIN_BIT_SENSOR); + clearBit(kDaikinByteSensor, kDaikinBitSensor); } bool IRDaikinESP::getSensor() { - return (getBit(DAIKIN_BYTE_SENSOR, DAIKIN_BIT_SENSOR) > 0); + return (getBit(kDaikinByteSensor, kDaikinBitSensor) > 0); } void IRDaikinESP::setEcono(bool state) { if (state) { - setBit(DAIKIN_BYTE_ECONO, DAIKIN_BIT_ECONO); + setBit(kDaikinByteEcono, kDaikinBitEcono); // Powerful & Econo mode being on are mutually exclusive. setPowerful(false); } else { - clearBit(DAIKIN_BYTE_ECONO, DAIKIN_BIT_ECONO); + clearBit(kDaikinByteEcono, kDaikinBitEcono); } } bool IRDaikinESP::getEcono() { - return (getBit(DAIKIN_BYTE_ECONO, DAIKIN_BIT_ECONO) > 0); + return (getBit(kDaikinByteEcono, kDaikinBitEcono) > 0); } void IRDaikinESP::setEye(bool state) { if (state) - setBit(DAIKIN_BYTE_EYE, DAIKIN_BIT_EYE); + setBit(kDaikinByteEye, kDaikinBitEye); else - clearBit(DAIKIN_BYTE_EYE, DAIKIN_BIT_EYE); + clearBit(kDaikinByteEye, kDaikinBitEye); } bool IRDaikinESP::getEye() { - return (getBit(DAIKIN_BYTE_EYE, DAIKIN_BIT_EYE) > 0); + return (getBit(kDaikinByteEye, kDaikinBitEye) > 0); } void IRDaikinESP::setMold(bool state) { if (state) - setBit(DAIKIN_BYTE_MOLD, DAIKIN_BIT_MOLD); + setBit(kDaikinByteMold, kDaikinBitMold); else - clearBit(DAIKIN_BYTE_MOLD, DAIKIN_BIT_MOLD); + clearBit(kDaikinByteMold, kDaikinBitMold); } bool IRDaikinESP::getMold() { - return (getBit(DAIKIN_BYTE_MOLD, DAIKIN_BIT_MOLD) > 0); + return (getBit(kDaikinByteMold, kDaikinBitMold) > 0); } void IRDaikinESP::setBit(uint8_t byte, uint8_t bitmask) { @@ -361,18 +329,18 @@ uint8_t IRDaikinESP::getBit(uint8_t byte, uint8_t bitmask) { return daikin[byte] & bitmask; } -// starttime: Number of minutes after midnight, in 10 minutes increments +// starttime: Number of minutes after midnight. void IRDaikinESP::enableOnTimer(uint16_t starttime) { - setBit(DAIKIN_BYTE_ON_TIMER, DAIKIN_BIT_ON_TIMER); - daikin[18] = (uint8_t) (starttime & 0x00FF); + setBit(kDaikinByteOnTimer, kDaikinBitOnTimer); + daikin[18] = (uint8_t)(starttime & 0x00FF); // only keep 4 bits daikin[19] &= 0xF0; - daikin[19] |= (uint8_t) ((starttime >> 8) & 0x0F); + daikin[19] |= (uint8_t)((starttime >> 8) & 0x0F); } void IRDaikinESP::disableOnTimer() { - enableOnTimer(0x600); - clearBit(DAIKIN_BYTE_ON_TIMER, DAIKIN_BIT_ON_TIMER); + enableOnTimer(kDaikinUnusedTime); + clearBit(kDaikinByteOnTimer, kDaikinBitOnTimer); } uint16_t IRDaikinESP::getOnTime() { @@ -384,20 +352,20 @@ uint16_t IRDaikinESP::getOnTime() { } bool IRDaikinESP::getOnTimerEnabled() { - return getBit(DAIKIN_BYTE_ON_TIMER, DAIKIN_BIT_ON_TIMER); + return getBit(kDaikinByteOnTimer, kDaikinBitOnTimer); } -// endtime: Number of minutes after midnight, in 10 minutes increments +// endtime: Number of minutes after midnight. void IRDaikinESP::enableOffTimer(uint16_t endtime) { - setBit(DAIKIN_BYTE_OFF_TIMER, DAIKIN_BIT_OFF_TIMER); + setBit(kDaikinByteOffTimer, kDaikinBitOffTimer); daikin[20] = (uint8_t)((endtime >> 4) & 0xFF); daikin[19] &= 0x0F; - daikin[19] |= (uint8_t) ((endtime & 0x000F) << 4); + daikin[19] |= (uint8_t)((endtime & 0x000F) << 4); } void IRDaikinESP::disableOffTimer() { - enableOffTimer(0x600); - clearBit(DAIKIN_BYTE_OFF_TIMER, DAIKIN_BIT_OFF_TIMER); + enableOffTimer(kDaikinUnusedTime); + clearBit(kDaikinByteOffTimer, kDaikinBitOffTimer); } uint16_t IRDaikinESP::getOffTime() { @@ -411,15 +379,15 @@ uint16_t IRDaikinESP::getOffTime() { } bool IRDaikinESP::getOffTimerEnabled() { - return getBit(DAIKIN_BYTE_OFF_TIMER, DAIKIN_BIT_OFF_TIMER); + return getBit(kDaikinByteOffTimer, kDaikinBitOffTimer); } void IRDaikinESP::setCurrentTime(uint16_t numMins) { if (numMins > 24 * 60) numMins = 0; // If > 23:59, set to 00:00 - daikin[5] = (uint8_t) (numMins & 0x00FF); + daikin[5] = (uint8_t)(numMins & 0x00FF); // only keep 4 bits daikin[6] &= 0xF0; - daikin[6] |= (uint8_t) ((numMins >> 8) & 0x0F); + daikin[6] |= (uint8_t)((numMins >> 8) & 0x0F); } uint16_t IRDaikinESP::getCurrentTime() { @@ -433,7 +401,7 @@ uint16_t IRDaikinESP::getCurrentTime() { #ifdef ARDUINO String IRDaikinESP::renderTime(uint16_t timemins) { String ret; -#else // ARDUINO +#else // ARDUINO std::string IRDaikinESP::renderTime(uint16_t timemins) { std::string ret; #endif // ARDUINO @@ -441,8 +409,7 @@ std::string IRDaikinESP::renderTime(uint16_t timemins) { hours = timemins / 60; ret = uint64ToString(hours) + ":"; mins = timemins - (hours * 60); - if (mins < 10) - ret += "0"; + if (mins < 10) ret += "0"; ret += uint64ToString(mins); return ret; } @@ -451,7 +418,7 @@ std::string IRDaikinESP::renderTime(uint16_t timemins) { #ifdef ARDUINO String IRDaikinESP::toString() { String result = ""; -#else // ARDUINO +#else // ARDUINO std::string IRDaikinESP::toString() { std::string result = ""; #endif // ARDUINO @@ -462,19 +429,19 @@ std::string IRDaikinESP::toString() { result += "Off"; result += ", Mode: " + uint64ToString(getMode()); switch (getMode()) { - case DAIKIN_AUTO: + case kDaikinAuto: result += " (AUTO)"; break; - case DAIKIN_COOL: + case kDaikinCool: result += " (COOL)"; break; - case DAIKIN_HEAT: + case kDaikinHeat: result += " (HEAT)"; break; - case DAIKIN_DRY: + case kDaikinDry: result += " (DRY)"; break; - case DAIKIN_FAN: + case kDaikinFan: result += " (FAN)"; break; default: @@ -483,16 +450,16 @@ std::string IRDaikinESP::toString() { result += ", Temp: " + uint64ToString(getTemp()) + "C"; result += ", Fan: " + uint64ToString(getFan()); switch (getFan()) { - case DAIKIN_FAN_AUTO: + case kDaikinFanAuto: result += " (AUTO)"; break; - case DAIKIN_FAN_QUIET: + case kDaikinFanQuiet: result += " (QUIET)"; break; - case DAIKIN_FAN_MIN: + case kDaikinFanMin: result += " (MIN)"; break; - case DAIKIN_FAN_MAX: + case kDaikinFanMax: result += " (MAX)"; break; } @@ -551,14 +518,13 @@ std::string IRDaikinESP::toString() { void IRDaikinESP::printState() { #ifdef ARDUINO String strbits; -#else // ARDUINO +#else // ARDUINO std::string strbits; #endif // ARDUINO DPRINTLN("Raw Bits:"); - for (uint8_t i = 0; i < DAIKIN_COMMAND_LENGTH; i++) { + for (uint8_t i = 0; i < kDaikinStateLength; i++) { strbits = uint64ToString(daikin[i], BIN); - while (strbits.length() < 8) - strbits = "0" + strbits; + while (strbits.length() < 8) strbits = "0" + strbits; DPRINT(strbits); DPRINT(" "); } @@ -584,8 +550,7 @@ void IRDaikinESP::printState() { uint32_t IRDaikinESP::getCommand() { uint32_t ret = 0; uint32_t tmp = 0; - if (getPower()) - ret |= 0b00000000000000000000000000000001; + if (getPower()) ret |= 0b00000000000000000000000000000001; tmp = getMode(); tmp = tmp << 1; ret |= tmp; @@ -598,24 +563,18 @@ uint32_t IRDaikinESP::getCommand() { tmp <<= 8; ret |= tmp; - if (getEcono()) - ret |= 0b00000000000000001000000000000000; - if (getPowerful()) - ret |= 0b00000000000000010000000000000000; - if (getQuiet()) - ret |= 0b00000000000000100000000000000000; - if (getSensor()) - ret |= 0b00000000000001000000000000000000; - if (getSwingVertical()) - ret |= 0b00000000000010000000000000000000; + if (getEcono()) ret |= 0b00000000000000001000000000000000; + if (getPowerful()) ret |= 0b00000000000000010000000000000000; + if (getQuiet()) ret |= 0b00000000000000100000000000000000; + if (getSensor()) ret |= 0b00000000000001000000000000000000; + if (getSwingVertical()) ret |= 0b00000000000010000000000000000000; ret |= (getCurrentTime() << 20); return ret; } void IRDaikinESP::setCommand(uint32_t value) { uint32_t tmp = 0; - if (value & 0b00000000000000000000000000000001) - setPower(true); + if (value & 0b00000000000000000000000000000001) setPower(true); tmp = value & 0b00000000000000000000000000001110; tmp >>= 1; setMode(tmp); @@ -628,16 +587,11 @@ void IRDaikinESP::setCommand(uint32_t value) { tmp >>= 8; setTemp(tmp); - if (value & 0b00000000000000001000000000000000) - setEcono(true); - if (value & 0b00000000000000010000000000000000) - setPowerful(true); - if (value & 0b00000000000000100000000000000000) - setQuiet(true); - if (value & 0b00000000000001000000000000000000) - setSensor(true); - if (value & 0b00000000000010000000000000000000) - setSwingVertical(true); + if (value & 0b00000000000000001000000000000000) setEcono(true); + if (value & 0b00000000000000010000000000000000) setPowerful(true); + if (value & 0b00000000000000100000000000000000) setQuiet(true); + if (value & 0b00000000000001000000000000000000) setSensor(true); + if (value & 0b00000000000010000000000000000000) setSwingVertical(true); value >>= 20; setCurrentTime(value); @@ -646,8 +600,8 @@ void IRDaikinESP::setCommand(uint32_t value) { #if DECODE_DAIKIN void addbit(bool val, unsigned char data[]) { - uint8_t curbit = data[DAIKIN_CURBIT]; - uint8_t curindex = data[DAIKIN_CURINDEX]; + uint8_t curbit = data[kDaikinCurBit]; + uint8_t curindex = data[kDaikinCurIndex]; if (val) { unsigned char bit = 1; bit = bit << curbit; @@ -658,23 +612,23 @@ void addbit(bool val, unsigned char data[]) { curbit = 0; curindex++; } - data[DAIKIN_CURBIT] = curbit; - data[DAIKIN_CURINDEX] = curindex; + data[kDaikinCurBit] = curbit; + data[kDaikinCurIndex] = curindex; } -bool checkheader(decode_results *results, uint16_t* offset) { - if (!IRrecv::matchMark(results->rawbuf[(*offset)++], DAIKIN_BIT_MARK, - DAIKIN_TOLERANCE, DAIKIN_MARK_EXCESS)) +bool checkheader(decode_results *results, uint16_t *offset) { + if (!IRrecv::matchMark(results->rawbuf[(*offset)++], kDaikinBitMark, + kDaikinTolerance, kDaikinMarkExcess)) return false; if (!IRrecv::matchSpace(results->rawbuf[(*offset)++], - DAIKIN_ZERO_SPACE + DAIKIN_GAP, - DAIKIN_TOLERANCE, DAIKIN_MARK_EXCESS)) + kDaikinZeroSpace + kDaikinGap, kDaikinTolerance, + kDaikinMarkExcess)) return false; - if (!IRrecv::matchMark(results->rawbuf[(*offset)++], DAIKIN_HDR_MARK, - DAIKIN_TOLERANCE, DAIKIN_MARK_EXCESS)) + if (!IRrecv::matchMark(results->rawbuf[(*offset)++], kDaikinHdrMark, + kDaikinTolerance, kDaikinMarkExcess)) return false; - if (!IRrecv::matchSpace(results->rawbuf[(*offset)++], DAIKIN_HDR_SPACE, - DAIKIN_TOLERANCE, DAIKIN_MARK_EXCESS)) + if (!IRrecv::matchSpace(results->rawbuf[(*offset)++], kDaikinHdrSpace, + kDaikinTolerance, kDaikinMarkExcess)) return false; return true; @@ -684,14 +638,14 @@ bool readbits(decode_results *results, uint16_t *offset, unsigned char daikin_code[], uint16_t countbits) { for (uint16_t i = 0; i < countbits && *offset < results->rawlen - 1; i++, (*offset)++) { - if (!IRrecv::matchMark(results->rawbuf[(*offset)++], DAIKIN_BIT_MARK, - DAIKIN_TOLERANCE, DAIKIN_MARK_EXCESS)) + if (!IRrecv::matchMark(results->rawbuf[(*offset)++], kDaikinBitMark, + kDaikinTolerance, kDaikinMarkExcess)) return false; - if (IRrecv::matchSpace(results->rawbuf[*offset], DAIKIN_ONE_SPACE, - DAIKIN_TOLERANCE, DAIKIN_MARK_EXCESS)) + if (IRrecv::matchSpace(results->rawbuf[*offset], kDaikinOneSpace, + kDaikinTolerance, kDaikinMarkExcess)) addbit(1, daikin_code); - else if (IRrecv::matchSpace(results->rawbuf[*offset], DAIKIN_ZERO_SPACE, - DAIKIN_TOLERANCE, DAIKIN_MARK_EXCESS)) + else if (IRrecv::matchSpace(results->rawbuf[*offset], kDaikinZeroSpace, + kDaikinTolerance, kDaikinMarkExcess)) addbit(0, daikin_code); else return false; @@ -702,7 +656,7 @@ bool readbits(decode_results *results, uint16_t *offset, // Decode the supplied Daikin A/C message. // Args: // results: Ptr to the data to decode and where to store the decode result. -// nbits: Nr. of bits to expect in the data portion. (DAIKIN_RAW_BITS) +// nbits: Nr. of bits to expect in the data portion. (kDaikinRawBits) // strict: Flag to indicate if we strictly adhere to the specification. // Returns: // boolean: True if it can decode it, false if it can't. @@ -716,22 +670,18 @@ bool readbits(decode_results *results, uint16_t *offset, // https://github.com/mharizanov/Daikin-AC-remote-control-over-the-Internet/tree/master/IRremote bool IRrecv::decodeDaikin(decode_results *results, uint16_t nbits, bool strict) { - if (results->rawlen < DAIKIN_RAW_BITS) - return false; + if (results->rawlen < kDaikinRawBits) return false; // Compliance - if (strict && nbits != DAIKIN_RAW_BITS) - return false; + if (strict && nbits != kDaikinRawBits) return false; - uint16_t offset = OFFSET_START; - unsigned char daikin_code[DAIKIN_COMMAND_LENGTH + 2]; - for (uint8_t i = 0; i < DAIKIN_COMMAND_LENGTH+2; i++) - daikin_code[i] = 0; + uint16_t offset = kStartOffset; + unsigned char daikin_code[kDaikinStateLength + 2]; + for (uint8_t i = 0; i < kDaikinStateLength + 2; i++) daikin_code[i] = 0; // Header (#1) for (uint8_t i = 0; i < 10; i++) { - if (!matchMark(results->rawbuf[offset++], DAIKIN_BIT_MARK)) - return false; + if (!matchMark(results->rawbuf[offset++], kDaikinBitMark)) return false; } if (!checkheader(results, &offset)) return false; @@ -741,8 +691,7 @@ bool IRrecv::decodeDaikin(decode_results *results, uint16_t nbits, // Ignore everything that has just been captured as it is not needed. // Some remotes may not send this portion, my remote did, but it's not // required. - for (uint8_t i = 0; i < DAIKIN_COMMAND_LENGTH + 2; i++) - daikin_code[i] = 0; + for (uint8_t i = 0; i < kDaikinStateLength + 2; i++) daikin_code[i] = 0; // Header (#2) if (!checkheader(results, &offset)) return false; @@ -754,14 +703,13 @@ bool IRrecv::decodeDaikin(decode_results *results, uint16_t nbits, if (!checkheader(results, &offset)) return false; // Data (#3), read up everything else - if (!readbits(results, &offset, daikin_code, DAIKIN_BITS - (8 * 8))) + if (!readbits(results, &offset, daikin_code, kDaikinBits - (8 * 8))) return false; // Footer - if (!matchMark(results->rawbuf[offset++], DAIKIN_BIT_MARK)) - return false; - if (offset < results->rawlen && !matchAtLeast(results->rawbuf[offset], - DAIKIN_GAP)) + if (!matchMark(results->rawbuf[offset++], kDaikinBitMark)) return false; + if (offset < results->rawlen && + !matchAtLeast(results->rawbuf[offset], kDaikinGap)) return false; // Compliance @@ -780,10 +728,682 @@ bool IRrecv::decodeDaikin(decode_results *results, uint16_t nbits, #endif // DAIKIN_DEBUG // Copy across the bits to state - for (uint8_t i = 0; i < DAIKIN_COMMAND_LENGTH; i++) + for (uint8_t i = 0; i < kDaikinStateLength; i++) results->state[i] = daikin_code[i]; - results->bits = DAIKIN_COMMAND_LENGTH * 8; + results->bits = kDaikinStateLength * 8; results->decode_type = DAIKIN; return true; } #endif // DECODE_DAIKIN + +#if SEND_DAIKIN2 +// Send a Daikin2 A/C message. +// +// Args: +// data: An array of kDaikin2StateLength bytes containing the IR command. +// +// Status: Alpha/Untested. +// +// Ref: +// https://github.com/markszabo/IRremoteESP8266/issues/582 +void IRsend::sendDaikin2(unsigned char data[], uint16_t nbytes, + uint16_t repeat) { + if (nbytes < kDaikin2Section1Length) + return; // Not enough bytes to send a partial message. + + for (uint16_t r = 0; r <= repeat; r++) { + // Leader + sendGeneric(kDaikin2LeaderMark, kDaikin2LeaderSpace, + 0, 0, 0, 0, 0, 0, (uint64_t) 0, // No data payload. + 0, 38000, false, 0, 50); + // Section #1 + sendGeneric(kDaikin2HdrMark, kDaikin2HdrSpace, kDaikin2BitMark, + kDaikin2OneSpace, kDaikin2BitMark, kDaikin2ZeroSpace, + kDaikin2BitMark, kDaikin2Gap, data, kDaikin2Section1Length, + 38000, false, 0, 50); + // Section #2 + sendGeneric(kDaikin2HdrMark, kDaikin2HdrSpace, kDaikin2BitMark, + kDaikin2OneSpace, kDaikin2BitMark, kDaikin2ZeroSpace, + kDaikin2BitMark, kDaikin2Gap, data + kDaikin2Section1Length, + nbytes - kDaikin2Section1Length, + 38000, false, 0, 50); + } +} +#endif // SEND_DAIKIN2 + +// Class for handling Daikin2 A/C messages. +// +// Code by crankyoldgit, Reverse engineering analysis by sheppy99 +// +// Supported Remotes: Daikin ARC477A1 remote +// +// Ref: +// https://github.com/markszabo/IRremoteESP8266/issues/582 +// https://docs.google.com/spreadsheets/d/1f8EGfIbBUo2B-CzUFdrgKQprWakoYNKM80IKZN4KXQE/edit?usp=sharing +// https://www.daikin.co.nz/sites/default/files/daikin-split-system-US7-FTXZ25-50NV1B.pdf +IRDaikin2::IRDaikin2(uint16_t pin) : _irsend(pin) { stateReset(); } + +void IRDaikin2::begin() { _irsend.begin(); } + +#if SEND_DAIKIN2 +void IRDaikin2::send(const uint16_t repeat) { + checksum(); + _irsend.sendDaikin2(remote_state, kDaikin2StateLength, repeat); +} +#endif // SEND_DAIKIN2 + +// Verify the checksum is valid for a given state. +// Args: +// state: The array to verify the checksum of. +// length: The size of the state. +// Returns: +// A boolean. +bool IRDaikin2::validChecksum(uint8_t state[], const uint16_t length) { + // Validate the checksum of section #1. + if (length <= kDaikin2Section1Length - 1 || + state[kDaikin2Section1Length - 1] != sumBytes(state, + kDaikin2Section1Length - 1)) + return false; + // Validate the checksum of section #2 (a.k.a. the rest) + if (length <= kDaikin2Section1Length + 1 || + state[length - 1] != sumBytes(state + kDaikin2Section1Length, + length - kDaikin2Section1Length - 1)) + return false; + return true; +} + +// Calculate and set the checksum values for the internal state. +void IRDaikin2::checksum() { + remote_state[kDaikin2Section1Length - 1] = sumBytes( + remote_state, kDaikin2Section1Length - 1); + remote_state[kDaikin2StateLength -1 ] = sumBytes( + remote_state + kDaikin2Section1Length, kDaikin2Section2Length - 1); +} + +void IRDaikin2::stateReset() { + for (uint8_t i = 0; i < kDaikin2StateLength; i++) remote_state[i] = 0x0; + + remote_state[0] = 0x11; + remote_state[1] = 0xDA; + remote_state[2] = 0x27; + remote_state[4] = 0x01; + remote_state[6] = 0xC0; + remote_state[7] = 0x70; + remote_state[8] = 0x08; + remote_state[9] = 0x0C; + remote_state[10] = 0x80; + remote_state[11] = 0x04; + remote_state[12] = 0xB0; + remote_state[13] = 0x16; + remote_state[14] = 0x24; + remote_state[17] = 0xBE; + remote_state[18] = 0xD0; + // remote_state[19] is a checksum byte, it will be set by checksum(). + remote_state[20] = 0x11; + remote_state[21] = 0xDA; + remote_state[22] = 0x27; + remote_state[25] = 0x08; + remote_state[28] = 0xA0; + remote_state[35] = 0xC1; + remote_state[36] = 0x80; + remote_state[37] = 0x60; + // remote_state[38] is a checksum byte, it will be set by checksum(). + disableOnTimer(); + disableOffTimer(); + disableSleepTimer(); + checksum(); +} + +uint8_t *IRDaikin2::getRaw() { + checksum(); // Ensure correct settings before sending. + return remote_state; +} + +void IRDaikin2::setRaw(const uint8_t new_code[]) { + for (uint8_t i = 0; i < kDaikin2StateLength; i++) + remote_state[i] = new_code[i]; +} + +void IRDaikin2::on() { + remote_state[25] |= kDaikinBitPower; +} + +void IRDaikin2::off() { + remote_state[25] &= ~kDaikinBitPower; +} + +void IRDaikin2::setPower(const bool state) { + if (state) + on(); + else + off(); +} + +bool IRDaikin2::getPower() { + return (remote_state[25] & kDaikinBitPower); +} + +uint8_t IRDaikin2::getMode() { return remote_state[25] >> 4; } + +void IRDaikin2::setMode(const uint8_t desired_mode) { + uint8_t mode = desired_mode; + switch (mode) { + case kDaikinCool: + case kDaikinHeat: + case kDaikinFan: + case kDaikinDry: + break; + default: + mode = kDaikinAuto; + } + remote_state[25] &= 0b10001111; + remote_state[25] |= (mode << 4); +} + +// Set the temp in deg C +void IRDaikin2::setTemp(const uint8_t desired) { + uint8_t temp = std::max(kDaikinMinTemp, desired); + temp = std::min(kDaikinMaxTemp, temp); + remote_state[26] = temp * 2; +} + +// Set the speed of the fan, 1-5 or kDaikinFanAuto or kDaikinFanQuiet +void IRDaikin2::setFan(const uint8_t fan) { + // Set the fan speed bits, leave low 4 bits alone + uint8_t fanset; + if (fan == kDaikinFanQuiet || fan == kDaikinFanAuto) + fanset = fan; + else if (fan < kDaikinFanMin || fan > kDaikinFanMax) + fanset = kDaikinFanAuto; + else + fanset = 2 + fan; + remote_state[28] &= 0x0F; + remote_state[28] |= (fanset << 4); +} + +uint8_t IRDaikin2::getFan() { + uint8_t fan = remote_state[28] >> 4; + if (fan != kDaikinFanQuiet && fan != kDaikinFanAuto) fan -= 2; + return fan; +} + +uint8_t IRDaikin2::getTemp() { return remote_state[26] / 2; } + +void IRDaikin2::setSwingVertical(const uint8_t position) { + switch (position) { + case kDaikin2SwingVHigh: + case 2: + case 3: + case 4: + case 5: + case kDaikin2SwingVLow: + case kDaikin2SwingVBreeze: + case kDaikin2SwingVCirculate: + case kDaikin2SwingVAuto: + remote_state[18] &= 0xF0; + remote_state[18] |= (position & 0x0F); + } +} + +uint8_t IRDaikin2::getSwingVertical() { return remote_state[18] & 0x0F; } + +void IRDaikin2::setSwingHorizontal(const uint8_t position) { + remote_state[17] = position; +} + +uint8_t IRDaikin2::getSwingHorizontal() { return remote_state[17]; } + +void IRDaikin2::setCurrentTime(const uint16_t numMins) { + uint16_t mins = numMins; + if (numMins > 24 * 60) mins = 0; // If > 23:59, set to 00:00 + remote_state[5] = (uint8_t)(mins & 0xFF); + // only keep 4 bits + remote_state[6] &= 0xF0; + remote_state[6] |= (uint8_t)((mins >> 8) & 0x0F); +} + +uint16_t IRDaikin2::getCurrentTime() { + return ((remote_state[6] & 0x0F) << 8) + remote_state[5]; +} + +// starttime: Number of minutes after midnight. +// Note: Timer location is shared with sleep timer. +void IRDaikin2::enableOnTimer(const uint16_t starttime) { + clearSleepTimerFlag(); + remote_state[25] |= kDaikinBitOnTimer; // Set the On Timer flag. + remote_state[30] = (uint8_t)(starttime & 0xFF); + // only keep 4 bits + remote_state[31] &= 0xF0; + remote_state[31] |= (uint8_t)((starttime >> 8) & 0x0F); +} + +void IRDaikin2::clearOnTimerFlag() { + remote_state[25] &= ~kDaikinBitOnTimer; +} + +void IRDaikin2::disableOnTimer() { + enableOnTimer(kDaikinUnusedTime); + clearOnTimerFlag(); + clearSleepTimerFlag(); +} + +uint16_t IRDaikin2::getOnTime() { + return ((remote_state[31] & 0x0F) << 8) + remote_state[30]; +} + +bool IRDaikin2::getOnTimerEnabled() { + return remote_state[25] & kDaikinBitOnTimer; +} + +// endtime: Number of minutes after midnight. +void IRDaikin2::enableOffTimer(const uint16_t endtime) { + remote_state[25] |= kDaikinBitOffTimer; // Set the Off Timer flag. + remote_state[32] = (uint8_t)((endtime >> 4) & 0xFF); + remote_state[31] &= 0x0F; + remote_state[31] |= (uint8_t)((endtime & 0xF) << 4); +} + +void IRDaikin2::disableOffTimer() { + enableOffTimer(kDaikinUnusedTime); + remote_state[25] &= ~kDaikinBitOffTimer; // Clear the Off Timer flag. +} + +uint16_t IRDaikin2::getOffTime() { + return (remote_state[32] << 4) + (remote_state[31] >> 4); +} + +bool IRDaikin2::getOffTimerEnabled() { + return remote_state[25] & kDaikinBitOffTimer; +} + +uint8_t IRDaikin2::getBeep() { + return remote_state[7] >> 6; +} + +void IRDaikin2::setBeep(const uint8_t beep) { + remote_state[7] &= ~kDaikin2BeepMask; + remote_state[7] |= ((beep << 6) & kDaikin2BeepMask); +} + +uint8_t IRDaikin2::getLight() { + return (remote_state[7] & kDaikin2LightMask) >> 4; +} + +void IRDaikin2::setLight(const uint8_t light) { + remote_state[7] &= ~kDaikin2LightMask; + remote_state[7] |= ((light << 4) & kDaikin2LightMask); +} + +void IRDaikin2::setMold(const bool on) { + if (on) + remote_state[8] |= kDaikin2BitMold; + else + remote_state[8] &= ~kDaikin2BitMold; +} + +bool IRDaikin2::getMold() { + return remote_state[8] & kDaikin2BitMold; +} + +// Auto clean setting. +void IRDaikin2::setClean(const bool on) { + if (on) + remote_state[8] |= kDaikin2BitClean; + else + remote_state[8] &= ~kDaikin2BitClean; +} + +bool IRDaikin2::getClean() { + return remote_state[8] & kDaikin2BitClean; +} + +// Fresh Air settings. +void IRDaikin2::setFreshAir(const bool on) { + if (on) + remote_state[8] |= kDaikin2BitFreshAir; + else + remote_state[8] &= ~kDaikin2BitFreshAir; +} + +bool IRDaikin2::getFreshAir() { + return remote_state[8] & kDaikin2BitFreshAir; +} + +void IRDaikin2::setFreshAirHigh(const bool on) { + if (on) + remote_state[8] |= kDaikin2BitFreshAirHigh; + else + remote_state[8] &= ~kDaikin2BitFreshAirHigh; +} + +bool IRDaikin2::getFreshAirHigh() { + return remote_state[8] & kDaikin2BitFreshAirHigh; +} + +void IRDaikin2::setEyeAuto(bool on) { + if (on) + remote_state[13] |= kDaikin2BitEyeAuto; + else + remote_state[13] &= ~kDaikin2BitEyeAuto; +} + +bool IRDaikin2::getEyeAuto() { + return remote_state[13] & kDaikin2BitEyeAuto; +} + +void IRDaikin2::setEye(bool on) { + if (on) + remote_state[36] |= kDaikin2BitEye; + else + remote_state[36] &= ~kDaikin2BitEye; +} + +bool IRDaikin2::getEye() { + return remote_state[36] & kDaikin2BitEye; +} + +void IRDaikin2::setEcono(bool on) { + if (on) + remote_state[36] |= kDaikinBitEcono; + else + remote_state[36] &= ~kDaikinBitEcono; +} + +bool IRDaikin2::getEcono() { + return remote_state[36] & kDaikinBitEcono; +} + +// sleeptime: Number of minutes. +// Note: Timer location is shared with On Timer. +void IRDaikin2::enableSleepTimer(const uint16_t sleeptime) { + enableOnTimer(sleeptime); + clearOnTimerFlag(); + remote_state[36] |= kDaikin2BitSleepTimer; // Set the Sleep Timer flag. +} + +void IRDaikin2::clearSleepTimerFlag() { + remote_state[36] &= ~kDaikin2BitSleepTimer; +} + +void IRDaikin2::disableSleepTimer() { + disableOnTimer(); +} + +uint16_t IRDaikin2::getSleepTime() { + return getOnTime(); +} + +bool IRDaikin2::getSleepTimerEnabled() { + return remote_state[36] & kDaikin2BitSleepTimer; +} + +void IRDaikin2::setQuiet(const bool on) { + if (on) { + remote_state[33] |= kDaikinBitSilent; + // Powerful & Quiet mode being on are mutually exclusive. + setPowerful(false); + } else { + remote_state[33] &= ~kDaikinBitSilent; + } +} + +bool IRDaikin2::getQuiet() { return remote_state[33] & kDaikinBitSilent; } + +void IRDaikin2::setPowerful(const bool on) { + if (on) { + remote_state[33] |= kDaikinBitPowerful; + // Powerful & Quiet mode being on are mutually exclusive. + setQuiet(false); + } else { + remote_state[33] &= ~kDaikinBitPowerful; + } +} + +bool IRDaikin2::getPowerful() { return remote_state[33] & kDaikinBitPowerful; } + +void IRDaikin2::setPurify(const bool on) { + if (on) + remote_state[36] |= kDaikin2BitPurify; + else + remote_state[36] &= ~kDaikin2BitPurify; +} + +bool IRDaikin2::getPurify() { return remote_state[36] & kDaikin2BitPurify; } + +// Convert the internal state into a human readable string. +#ifdef ARDUINO +String IRDaikin2::toString() { + String result = ""; +#else // ARDUINO +std::string IRDaikin2::toString() { + std::string result = ""; +#endif // ARDUINO + result += "Power: "; + if (getPower()) + result += "On"; + else + result += "Off"; + result += ", Mode: " + uint64ToString(getMode()); + switch (getMode()) { + case kDaikinAuto: + result += " (AUTO)"; + break; + case kDaikinCool: + result += " (COOL)"; + break; + case kDaikinHeat: + result += " (HEAT)"; + break; + case kDaikinDry: + result += " (DRY)"; + break; + case kDaikinFan: + result += " (FAN)"; + break; + default: + result += " (UNKNOWN)"; + } + result += ", Temp: " + uint64ToString(getTemp()) + "C"; + result += ", Fan: " + uint64ToString(getFan()); + switch (getFan()) { + case kDaikinFanAuto: + result += " (Auto)"; + break; + case kDaikinFanQuiet: + result += " (Quiet)"; + break; + case kDaikinFanMin: + result += " (Min)"; + break; + case kDaikinFanMax: + result += " (Max)"; + break; + } + result += ", Swing (V): " + uint64ToString(getSwingVertical()); + switch (getSwingVertical()) { + case kDaikin2SwingVHigh: + result += " (Highest)"; + break; + case 2: + case 3: + case 4: + case 5: + break; + case kDaikin2SwingVLow: + result += " (Lowest)"; + break; + case kDaikin2SwingVBreeze: + result += " (Breeze)"; + break; + case kDaikin2SwingVCirculate: + result += " (Circulate)"; + break; + case kDaikin2SwingVAuto: + result += " (Auto)"; + break; + default: + result += " (Unknown)"; + } + result += ", Swing (H): " + uint64ToString(getSwingHorizontal()); + switch (getSwingHorizontal()) { + case kDaikin2SwingHAuto: + result += " (Auto)"; + break; + case kDaikin2SwingHSwing: + result += " (Swing)"; + break; + } + result += ", Clock: " + IRDaikinESP::renderTime(getCurrentTime()); + result += ", On Time: "; + if (getOnTimerEnabled()) + result += IRDaikinESP::renderTime(getOnTime()); + else + result += "Off"; + result += ", Off Time: "; + if (getOffTimerEnabled()) + result += IRDaikinESP::renderTime(getOffTime()); + else + result += "Off"; + result += ", Sleep Time: "; + if (getSleepTimerEnabled()) + result += IRDaikinESP::renderTime(getSleepTime()); + else + result += "Off"; + result += ", Beep: " + uint64ToString(getBeep()); + switch (getBeep()) { + case kDaikinBeepLoud: + result += " (Loud)"; + break; + case kDaikinBeepQuiet: + result += " (Quiet)"; + break; + case kDaikinBeepOff: + result += " (Off)"; + break; + default: + result += " (UNKNOWN)"; + } + result += ", Light: " + uint64ToString(getLight()); + switch (getLight()) { + case kDaikinLightBright: + result += " (Bright)"; + break; + case kDaikinLightDim: + result += " (Dim)"; + break; + case kDaikinLightOff: + result += " (Off)"; + break; + default: + result += " (UNKNOWN)"; + } + result += ", Mold: "; + result += (getMold() ? "On" : "Off"); + result += ", Clean: "; + result += (getClean() ? "On" : "Off"); + result += ", Fresh Air: "; + if (getFreshAir()) + result += (getFreshAirHigh() ? "High" : "On"); + else + result += "Off"; + result += ", Eye: "; + result += (getEye() ? "On" : "Off"); + result += ", Eye Auto: "; + result += (getEyeAuto() ? "On" : "Off"); + result += ", Quiet: "; + result += (getQuiet() ? "On" : "Off"); + result += ", Powerful: "; + result += (getPowerful() ? "On" : "Off"); + result += ", Purify: "; + result += (getPurify() ? "On" : "Off"); + result += ", Econo: "; + result += (getEcono() ? "On" : "Off"); + return result; +} + +#if DECODE_DAIKIN2 +// Decode the supplied Daikin2 A/C message. +// Args: +// results: Ptr to the data to decode and where to store the decode result. +// nbits: Nr. of bits to expect in the data portion. (kDaikin2Bits) +// strict: Flag to indicate if we strictly adhere to the specification. +// Returns: +// boolean: True if it can decode it, false if it can't. +// +// Supported devices: +// - Daikin FTXZ25NV1B, FTXZ35NV1B, FTXZ50NV1B Aircon +// - Daikin ARC477A1 remote +// +// Status: BETA / Work as expected. +// +// Ref: +// https://github.com/mharizanov/Daikin-AC-remote-control-over-the-Internet/tree/master/IRremote +bool IRrecv::decodeDaikin2(decode_results *results, uint16_t nbits, + bool strict) { + if (results->rawlen < 2 * (nbits + kHeader + kFooter) + kHeader - 1) + return false; + + // Compliance + if (strict && nbits != kDaikin2Bits) return false; + + uint16_t offset = kStartOffset; + uint16_t dataBitsSoFar = 0; + uint16_t i = 0; + match_result_t data_result; + uint8_t sectionSize[kDaikin2Sections] = {kDaikin2Section1Length, + kDaikin2Section2Length}; + + // Leader + if (!matchMark(results->rawbuf[offset++], kDaikin2LeaderMark)) return false; + if (!matchSpace(results->rawbuf[offset++], kDaikin2LeaderSpace)) + return false; + + // Sections + // Keep reading bytes until we either run out of section or state to fill. + for (uint8_t section = 0, pos = 0; section < kDaikin2Sections; + section++) { + pos += sectionSize[section]; + + // Section Header + if (!matchMark(results->rawbuf[offset++], kDaikin2HdrMark)) return false; + if (!matchSpace(results->rawbuf[offset++], kDaikin2HdrSpace)) return false; + + // Section Data + for (; offset <= results->rawlen - 16 && i < pos; + i++, dataBitsSoFar += 8, offset += data_result.used) { + // Read in a byte at a time. + data_result = + matchData(&(results->rawbuf[offset]), 8, kDaikin2BitMark, + kDaikin2OneSpace, kDaikin2BitMark, + kDaikin2ZeroSpace, kTolerance, kMarkExcess, false); + if (data_result.success == false) break; // Fail + results->state[i] = (uint8_t)data_result.data; + } + + // Section Footer + if (!matchMark(results->rawbuf[offset++], kDaikin2BitMark)) return false; + if (section < kDaikin2Sections - 1) { // Inter-section gaps. + if (!matchSpace(results->rawbuf[offset++], kDaikin2Gap)) return false; + } else { // Last section / End of message gap. + if (offset <= results->rawlen && + !matchAtLeast(results->rawbuf[offset++], kDaikin2Gap)) return false; + } + } + + // Compliance + if (strict) { + // Re-check we got the correct size/length due to the way we read the data. + if (dataBitsSoFar != kDaikin2Bits) return false; + // Validate the checksum. + if (!IRDaikin2::validChecksum(results->state)) return false; + } + + // Success + results->decode_type = DAIKIN2; + results->bits = dataBitsSoFar; + // No need to record the state as we stored it as we decoded it. + // As we use result->state, we don't record value, address, or command as it + // is a union data type. + return true; +} +#endif // DECODE_DAIKIN2 diff --git a/lib/IRremoteESP8266/src/ir_Daikin.h b/lib/IRremoteESP8266/src/ir_Daikin.h index 9ad9323..c72c80e 100644 --- a/lib/IRremoteESP8266/src/ir_Daikin.h +++ b/lib/IRremoteESP8266/src/ir_Daikin.h @@ -1,5 +1,6 @@ // Copyright 2016 sillyfrog // Copyright 2017 sillyfrog, crankyoldgit +// Copyright 2018-2019 crankyoldgit #ifndef IR_DAIKIN_H_ #define IR_DAIKIN_H_ @@ -8,8 +9,8 @@ #else #include #endif -#include "IRremoteESP8266.h" #include "IRrecv.h" +#include "IRremoteESP8266.h" #include "IRsend.h" // Option to disable the additional Daikin debug info to conserve memory @@ -22,118 +23,161 @@ // DDDDDD AA AA IIIII KK KK IIIII NN NN /* - Daikin AC map - byte 5=Current time, mins past midnight, low bits - byte 6 + Daikin AC map + byte 5=Current time, mins past midnight, low bits + byte 6 b0-b3=Current time, mins past midnight, high bits - byte 7= checksum of the first part (and last byte before a 29ms pause) - byte 13=mode - b7 = 0 - b6+b5+b4 = Mode - Modes: b6+b5+b4 - 011 = Cool - 100 = Heat (temp 23) - 110 = FAN (temp not shown, but 25) - 000 = Fully Automatic (temp 25) - 010 = DRY (temp 0xc0 = 96 degrees c) - b3 = 1 - b2 = OFF timer set - b1 = ON timer set - b0 = Air Conditioner ON - byte 14=temp*2 (Temp should be between 10 - 32) - byte 16=Fan - FAN control - b7+b6+b5+b4 = Fan speed - Fan: b7+b6+b5+b4 - 0×3 = 1 bar - 0×4 = 2 bar - 0×5 = 3 bar - 0×6 = 4 bar - 0×7 = 5 bar - 0xa = Auto - 0xb = Quite - b3+b2+b1+b0 = Swing control up/down - Swing control up/down: - 0000 = Swing up/down off - 1111 = Swing up/down on - byte 17 - Swing control left/right: - 0000 = Swing left/right off - 1111 = Swing left/right on - byte 18=On timer mins past midnight, low bits - byte 19 + byte 7= checksum of the first part (and last byte before a 29ms pause) + byte 13=mode + b7 = 0 + b6+b5+b4 = Mode + Modes: b6+b5+b4 + 011 = Cool + 100 = Heat (temp 23) + 110 = FAN (temp not shown, but 25) + 000 = Fully Automatic (temp 25) + 010 = DRY (temp 0xc0 = 96 degrees c) + b3 = 1 + b2 = OFF timer set + b1 = ON timer set + b0 = Air Conditioner ON + byte 14=temp*2 (Temp should be between 10 - 32) + byte 16=Fan + FAN control + b7+b6+b5+b4 = Fan speed + Fan: b7+b6+b5+b4 + 0×3 = 1 bar + 0×4 = 2 bar + 0×5 = 3 bar + 0×6 = 4 bar + 0×7 = 5 bar + 0xa = Auto + 0xb = Quite + b3+b2+b1+b0 = Swing control up/down + Swing control up/down: + 0000 = Swing up/down off + 1111 = Swing up/down on + byte 17 + Swing control left/right: + 0000 = Swing left/right off + 1111 = Swing left/right on + byte 18=On timer mins past midnight, low bits + byte 19 b0-b3=On timer mins past midnight, high bits b4-b7=Off timer mins past midnight, low bits - byte 20=Off timer mins past midnight, high bits - byte 21=Aux -> Powerful (bit 1), Silent (bit 5) - byte 24=Aux2 + byte 20=Off timer mins past midnight, high bits + byte 21=Aux -> Powerful (bit 1), Silent (bit 5) + byte 24=Aux2 b1: Sensor b2: Econo mode b7: Intelligent eye on - byte 25=Aux3 + byte 25=Aux3 b1: Mold Proof - byte 26= checksum of the second part + byte 26= checksum of the second part */ // Constants -#define DAIKIN_COOL 0b011 -#define DAIKIN_HEAT 0b100 -#define DAIKIN_FAN 0b110 -#define DAIKIN_AUTO 0b000 -#define DAIKIN_DRY 0b010 -#define DAIKIN_MIN_TEMP 10U // Celsius -#define DAIKIN_MAX_TEMP 32U // Celsius -#define DAIKIN_FAN_MIN (uint8_t) 1U -#define DAIKIN_FAN_MAX (uint8_t) 5U -#define DAIKIN_FAN_AUTO (uint8_t) 0b1010 -#define DAIKIN_FAN_QUIET (uint8_t) 0b1011 - -#define DAIKIN_BYTE_POWER 13 -#define DAIKIN_BIT_POWER 0b00000001 - -#define DAIKIN_BYTE_POWERFUL 21 -#define DAIKIN_BIT_POWERFUL 0b00000001 -#define DAIKIN_BYTE_SILENT 21 -#define DAIKIN_BIT_SILENT 0b00100000 - -#define DAIKIN_BYTE_SENSOR 24 -#define DAIKIN_BIT_SENSOR 0b00000010 -#define DAIKIN_BYTE_ECONO 24 -#define DAIKIN_BIT_ECONO 0b00000100 -#define DAIKIN_BYTE_EYE 24 -#define DAIKIN_BIT_EYE 0b10000000 -#define DAIKIN_BYTE_MOLD 25 -#define DAIKIN_BIT_MOLD 0b00000010 - -#define DAIKIN_BYTE_OFF_TIMER 13 -#define DAIKIN_BIT_OFF_TIMER 0b00000100 -#define DAIKIN_BYTE_ON_TIMER 13 -#define DAIKIN_BIT_ON_TIMER 0b00000010 - -#define DAIKIN_CURBIT DAIKIN_COMMAND_LENGTH -#define DAIKIN_CURINDEX (DAIKIN_COMMAND_LENGTH + 1) -#define OFFSET_ERR 65432 - -#define DAIKIN_TOLERANCE 35 -#define DAIKIN_MARK_EXCESS MARK_EXCESS - -#define DAIKIN_HDR_MARK 3650U // DAIKIN_BIT_MARK * 8 -#define DAIKIN_HDR_SPACE 1623U // DAIKIN_BIT_MARK * 4 -#define DAIKIN_BIT_MARK 428U -#define DAIKIN_ZERO_SPACE 428U -#define DAIKIN_ONE_SPACE 1280U -#define DAIKIN_GAP 29000U - +const uint8_t kDaikinAuto = 0b000; +const uint8_t kDaikinDry = 0b010; +const uint8_t kDaikinCool = 0b011; +const uint8_t kDaikinHeat = 0b100; +const uint8_t kDaikinFan = 0b110; +const uint8_t kDaikinMinTemp = 10; // Celsius +const uint8_t kDaikinMaxTemp = 32; // Celsius +const uint8_t kDaikinFanMin = 1; +const uint8_t kDaikinFanMax = 5; +const uint8_t kDaikinFanAuto = 0b1010; +const uint8_t kDaikinFanQuiet = 0b1011; +const uint8_t kDaikinBytePower = 13; +const uint8_t kDaikinBitPower = 0b00000001; +const uint8_t kDaikinBytePowerful = 21; +const uint8_t kDaikinBitPowerful = 0b00000001; +const uint8_t kDaikinByteSilent = 21; +const uint8_t kDaikinBitSilent = 0b00100000; +const uint8_t kDaikinByteSensor = 24; +const uint8_t kDaikinBitSensor = 0b00000010; +const uint8_t kDaikinByteEcono = 24; +const uint8_t kDaikinBitEcono = 0b00000100; +const uint8_t kDaikinByteEye = 24; +const uint8_t kDaikinBitEye = 0b10000000; +const uint8_t kDaikinByteMold = 25; +const uint8_t kDaikinBitMold = 0b00000010; +const uint8_t kDaikinByteOffTimer = 13; +const uint8_t kDaikinBitOffTimer = 0b00000100; +const uint8_t kDaikinByteOnTimer = 13; +const uint8_t kDaikinBitOnTimer = 0b00000010; +const uint16_t kDaikinUnusedTime = 0x600; +const uint8_t kDaikinBeepQuiet = 1; +const uint8_t kDaikinBeepLoud = 2; +const uint8_t kDaikinBeepOff = 3; +const uint8_t kDaikinLightBright = 1; +const uint8_t kDaikinLightDim = 2; +const uint8_t kDaikinLightOff = 3; +const uint8_t kDaikinCurBit = kDaikinStateLength; +const uint8_t kDaikinCurIndex = kDaikinStateLength + 1; +const uint8_t kDaikinTolerance = 35; +const uint16_t kDaikinMarkExcess = kMarkExcess; +const uint16_t kDaikinHdrMark = 3650; // kDaikinBitMark * 8 +const uint16_t kDaikinHdrSpace = 1623; // kDaikinBitMark * 4 +const uint16_t kDaikinBitMark = 428; +const uint16_t kDaikinZeroSpace = 428; +const uint16_t kDaikinOneSpace = 1280; +const uint16_t kDaikinGap = 29000; // Note bits in each octet swapped so can be sent as a single value -#define DAIKIN_FIRST_HEADER64 \ - 0b1101011100000000000000001100010100000000001001111101101000010001 +const uint64_t kDaikinFirstHeader64 = + 0b1101011100000000000000001100010100000000001001111101101000010001; + +// Another variant of the protocol for the Daikin ARC477A1 remote. +const uint16_t kDaikin2LeaderMark = 10024; +const uint16_t kDaikin2LeaderSpace = 25180; +const uint16_t kDaikin2Gap = kDaikin2LeaderMark + kDaikin2LeaderSpace; +const uint16_t kDaikin2HdrMark = 3500; +const uint16_t kDaikin2HdrSpace = 1728; +const uint16_t kDaikin2BitMark = 418; +const uint16_t kDaikin2OneSpace = 1315; +const uint16_t kDaikin2ZeroSpace = 451; +const uint16_t kDaikin2Sections = 2; +const uint16_t kDaikin2Section1Length = 20; +const uint16_t kDaikin2Section2Length = 19; + +const uint8_t kDaikin2BitSleepTimer = 0b00100000; +const uint8_t kDaikin2BitPurify = 0b00010000; +const uint8_t kDaikin2BitEye = 0b00000010; +const uint8_t kDaikin2BitEyeAuto = 0b10000000; +const uint8_t kDaikin2BitMold = 0b00001000; +const uint8_t kDaikin2BitClean = 0b00100000; +const uint8_t kDaikin2BitFreshAir = 0b00000001; +const uint8_t kDaikin2BitFreshAirHigh = 0b10000000; +const uint8_t kDaikin2LightMask = 0b00110000; +const uint8_t kDaikin2BeepMask = 0b11000000; +const uint8_t kDaikin2SwingVHigh = 0x1; +const uint8_t kDaikin2SwingVLow = 0x6; +const uint8_t kDaikin2SwingVBreeze = 0xC; +const uint8_t kDaikin2SwingVCirculate = 0xD; +const uint8_t kDaikin2SwingVAuto = 0xE; +const uint8_t kDaikin2SwingHAuto = 0xBE; +const uint8_t kDaikin2SwingHSwing = 0xBF; + + +// Legacy defines. +#define DAIKIN_COOL kDaikinCool +#define DAIKIN_HEAT kDaikinHeat +#define DAIKIN_FAN kDaikinFan +#define DAIKIN_AUTO kDaikinAuto +#define DAIKIN_DRY kDaikinDry +#define DAIKIN_MIN_TEMP kDaikinMinTemp +#define DAIKIN_MAX_TEMP kDaikinMaxTemp +#define DAIKIN_FAN_MIN kDaikinFanMin +#define DAIKIN_FAN_MAX kDaikinFanMax +#define DAIKIN_FAN_AUTO kDaikinFanAuto +#define DAIKIN_FAN_QUIET kDaikinFanQuiet class IRDaikinESP { public: explicit IRDaikinESP(uint16_t pin); #if SEND_DAIKIN - void send(); + void send(const uint16_t repeat = kDaikinDefaultRepeat); #endif void begin(); void on(); @@ -179,8 +223,8 @@ class IRDaikinESP { #endif // DAIKIN_DEBUG uint32_t getCommand(); void setCommand(uint32_t value); - static bool validChecksum(const uint8_t state[], - const uint16_t length = DAIKIN_COMMAND_LENGTH); + static bool validChecksum(uint8_t state[], + const uint16_t length = kDaikinStateLength); #ifdef ARDUINO String toString(); static String renderTime(uint16_t timemins); @@ -191,9 +235,8 @@ class IRDaikinESP { private: // # of bytes per command - uint8_t daikin[DAIKIN_COMMAND_LENGTH]; + uint8_t daikin[kDaikinStateLength]; void stateReset(); - static uint8_t calcBlockChecksum(const uint8_t *block, const uint16_t length); void checksum(); void setBit(uint8_t byte, uint8_t bitmask); void clearBit(uint8_t byte, uint8_t bitmask); @@ -201,4 +244,91 @@ class IRDaikinESP { IRsend _irsend; }; +// Class to emulate a Daikin ARC477A1 remote. +class IRDaikin2 { + public: + explicit IRDaikin2(uint16_t pin); + +#if SEND_DAIKIN2 + void send(const uint16_t repeat = kDaikin2DefaultRepeat); +#endif + void begin(); + void on(); + void off(); + void setPower(const bool state); + bool getPower(); + void setTemp(const uint8_t temp); + uint8_t getTemp(); + void setFan(const uint8_t fan); + uint8_t getFan(); + uint8_t getMode(); + void setMode(const uint8_t mode); + void setSwingVertical(const uint8_t position); + uint8_t getSwingVertical(); + void setSwingHorizontal(const uint8_t position); + uint8_t getSwingHorizontal(); + bool getQuiet(); + void setQuiet(const bool on); + bool getPowerful(); + void setPowerful(const bool on); + void setSensor(const bool on); + bool getSensor(); + void setEcono(const bool on); + bool getEcono(); + void setEye(const bool on); + bool getEye(); + void setEyeAuto(const bool on); + bool getEyeAuto(); + void setPurify(const bool on); + bool getPurify(); + void setMold(const bool on); + bool getMold(); + void enableOnTimer(const uint16_t starttime); + void disableOnTimer(); + uint16_t getOnTime(); + bool getOnTimerEnabled(); + void enableSleepTimer(const uint16_t sleeptime); + void disableSleepTimer(); + uint16_t getSleepTime(); + bool getSleepTimerEnabled(); + void enableOffTimer(const uint16_t endtime); + void disableOffTimer(); + uint16_t getOffTime(); + bool getOffTimerEnabled(); + void setCurrentTime(const uint16_t time); + uint16_t getCurrentTime(); + void setBeep(const uint8_t beep); + uint8_t getBeep(); + void setLight(const uint8_t light); + uint8_t getLight(); + void setClean(const bool on); + bool getClean(); + void setFreshAir(const bool on); + bool getFreshAir(); + void setFreshAirHigh(const bool on); + bool getFreshAirHigh(); + uint8_t* getRaw(); + void setRaw(const uint8_t new_code[]); + uint32_t getCommand(); + void setCommand(uint32_t value); + static bool validChecksum(uint8_t state[], + const uint16_t length = kDaikin2StateLength); +#ifdef ARDUINO + String toString(); + static String renderTime(uint16_t timemins); +#else + std::string toString(); + static std::string renderTime(uint16_t timemins); +#endif + + private: + // # of bytes per command + uint8_t remote_state[kDaikin2StateLength]; + void stateReset(); + void checksum(); + void clearOnTimerFlag(); + void clearSleepTimerFlag(); + IRsend _irsend; +}; + #endif // IR_DAIKIN_H_ diff --git a/lib/IRremoteESP8266/src/ir_Denon.cpp b/lib/IRremoteESP8266/src/ir_Denon.cpp index a4feb55..6798e02 100644 --- a/lib/IRremoteESP8266/src/ir_Denon.cpp +++ b/lib/IRremoteESP8266/src/ir_Denon.cpp @@ -18,25 +18,25 @@ // Constants // Ref: // https://github.com/z3t0/Arduino-IRremote/blob/master/ir_Denon.cpp -#define DENON_TICK 263U -#define DENON_HDR_MARK_TICKS 1U -#define DENON_HDR_MARK (DENON_HDR_MARK_TICKS * DENON_TICK) -#define DENON_HDR_SPACE_TICKS 3U -#define DENON_HDR_SPACE (DENON_HDR_SPACE_TICKS * DENON_TICK) -#define DENON_BIT_MARK_TICKS 1U -#define DENON_BIT_MARK (DENON_BIT_MARK_TICKS * DENON_TICK) -#define DENON_ONE_SPACE_TICKS 7U -#define DENON_ONE_SPACE (DENON_ONE_SPACE_TICKS * DENON_TICK) -#define DENON_ZERO_SPACE_TICKS 3U -#define DENON_ZERO_SPACE (DENON_ZERO_SPACE_TICKS * DENON_TICK) -#define DENON_MIN_COMMAND_LENGTH_TICKS 510U -#define DENON_MIN_COMMAND_LENGTH (DENON_MIN_COMMAND_LENGTH_TICKS * DENON_TICK) -#define DENON_MIN_GAP_TICKS (DENON_MIN_COMMAND_LENGTH_TICKS - \ - (DENON_HDR_MARK_TICKS + DENON_HDR_SPACE_TICKS + \ - DENON_BITS * (DENON_BIT_MARK_TICKS + DENON_ONE_SPACE_TICKS) + \ - DENON_BIT_MARK_TICKS)) -#define DENON_MIN_GAP (DENON_MIN_GAP_TICKS * DENON_TICK) -#define DENON_MANUFACTURER 0x2A4CULL +const uint16_t kDenonTick = 263; +const uint16_t kDenonHdrMarkTicks = 1; +const uint16_t kDenonHdrMark = kDenonHdrMarkTicks * kDenonTick; +const uint16_t kDenonHdrSpaceTicks = 3; +const uint16_t kDenonHdrSpace = kDenonHdrSpaceTicks * kDenonTick; +const uint16_t kDenonBitMarkTicks = 1; +const uint16_t kDenonBitMark = kDenonBitMarkTicks * kDenonTick; +const uint16_t kDenonOneSpaceTicks = 7; +const uint16_t kDenonOneSpace = kDenonOneSpaceTicks * kDenonTick; +const uint16_t kDenonZeroSpaceTicks = 3; +const uint16_t kDenonZeroSpace = kDenonZeroSpaceTicks * kDenonTick; +const uint16_t kDenonMinCommandLengthTicks = 510; +const uint16_t kDenonMinGapTicks = + kDenonMinCommandLengthTicks - + (kDenonHdrMarkTicks + kDenonHdrSpaceTicks + + kDenonBits * (kDenonBitMarkTicks + kDenonOneSpaceTicks) + + kDenonBitMarkTicks); +const uint32_t kDenonMinGap = kDenonMinGapTicks * kDenonTick; +const uint64_t kDenonManufacturer = 0x2A4CULL; #if SEND_DENON // Send a Denon message @@ -55,9 +55,9 @@ // https://github.com/z3t0/Arduino-IRremote/blob/master/ir_Denon.cpp // http://assets.denon.com/documentmaster/us/denon%20master%20ir%20hex.xls void IRsend::sendDenon(uint64_t data, uint16_t nbits, uint16_t repeat) { - if (nbits >= PANASONIC_BITS) // Is this really Panasonic? + if (nbits >= kPanasonicBits) // Is this really Panasonic? sendPanasonic64(data, nbits, repeat); - else if (nbits == DENON_LEGACY_BITS) + else if (nbits == kDenonLegacyBits) // Support legacy (broken) calls of sendDenon(). sendSharpRaw(data & (~0x2000ULL), nbits + 1, repeat); else @@ -84,7 +84,7 @@ bool IRrecv::decodeDenon(decode_results *results, uint16_t nbits, bool strict) { switch (nbits) { case DENON_BITS: case DENON_48_BITS: - case DENON_LEGACY_BITS: + case kDenonLegacyBits: break; default: return false; @@ -99,40 +99,36 @@ bool IRrecv::decodeDenon(decode_results *results, uint16_t nbits, bool strict) { // manufacturer code. if (!decodeSharp(results, nbits, true, false) && - !decodePanasonic(results, nbits, true, DENON_MANUFACTURER)) { + !decodePanasonic(results, nbits, true, kDenonManufacturer)) { // We couldn't decode it as expected, so try the old legacy method. // NOTE: I don't think this following protocol actually exists. // Looks like a partial version of the Sharp protocol. // Check we have enough data - if (results->rawlen < 2 * nbits + HEADER + FOOTER - 1) - return false; - if (strict && nbits != DENON_LEGACY_BITS) - return false; + if (results->rawlen < 2 * nbits + kHeader + kFooter - 1) return false; + if (strict && nbits != kDenonLegacyBits) return false; uint64_t data = 0; - uint16_t offset = OFFSET_START; + uint16_t offset = kStartOffset; // Header - if (!matchMark(results->rawbuf[offset], DENON_HDR_MARK)) return false; + if (!matchMark(results->rawbuf[offset], kDenonHdrMark)) return false; // Calculate how long the common tick time is based on the header mark. - uint32_t m_tick = results->rawbuf[offset++] * RAWTICK / - DENON_HDR_MARK_TICKS; - if (!matchSpace(results->rawbuf[offset], DENON_HDR_SPACE)) return false; - uint32_t s_tick = results->rawbuf[offset++] * RAWTICK / - DENON_HDR_SPACE_TICKS; + uint32_t m_tick = results->rawbuf[offset++] * kRawTick / kDenonHdrMarkTicks; + if (!matchSpace(results->rawbuf[offset], kDenonHdrSpace)) return false; + uint32_t s_tick = + results->rawbuf[offset++] * kRawTick / kDenonHdrSpaceTicks; // Data - match_result_t data_result = matchData(&(results->rawbuf[offset]), nbits, - DENON_BIT_MARK_TICKS * m_tick, - DENON_ONE_SPACE_TICKS * s_tick, - DENON_BIT_MARK_TICKS * m_tick, - DENON_ZERO_SPACE_TICKS * s_tick); + match_result_t data_result = + matchData(&(results->rawbuf[offset]), nbits, + kDenonBitMarkTicks * m_tick, kDenonOneSpaceTicks * s_tick, + kDenonBitMarkTicks * m_tick, kDenonZeroSpaceTicks * s_tick); if (data_result.success == false) return false; data = data_result.data; offset += data_result.used; // Footer - if (!matchMark(results->rawbuf[offset++], DENON_BIT_MARK_TICKS * m_tick)) + if (!matchMark(results->rawbuf[offset++], kDenonBitMarkTicks * m_tick)) return false; // Success diff --git a/lib/IRremoteESP8266/src/ir_Dish.cpp b/lib/IRremoteESP8266/src/ir_Dish.cpp index f5daf21..040aa3b 100644 --- a/lib/IRremoteESP8266/src/ir_Dish.cpp +++ b/lib/IRremoteESP8266/src/ir_Dish.cpp @@ -18,19 +18,19 @@ // Ref: // https://github.com/marcosamarinho/IRremoteESP8266/blob/master/ir_Dish.cpp // http://www.hifi-remote.com/wiki/index.php?title=Dish -#define DISH_TICK 100U -#define DISH_HDR_MARK_TICKS 4U -#define DISH_HDR_MARK (DISH_HDR_MARK_TICKS * DISH_TICK) -#define DISH_HDR_SPACE_TICKS 61U -#define DISH_HDR_SPACE (DISH_HDR_SPACE_TICKS * DISH_TICK) -#define DISH_BIT_MARK_TICKS 4U -#define DISH_BIT_MARK (DISH_BIT_MARK_TICKS * DISH_TICK) -#define DISH_ONE_SPACE_TICKS 17U -#define DISH_ONE_SPACE (DISH_ONE_SPACE_TICKS * DISH_TICK) -#define DISH_ZERO_SPACE_TICKS 28U -#define DISH_ZERO_SPACE (DISH_ZERO_SPACE_TICKS * DISH_TICK) -#define DISH_RPT_SPACE_TICKS DISH_HDR_SPACE_TICKS -#define DISH_RPT_SPACE (DISH_RPT_SPACE_TICKS * DISH_TICK) +const uint16_t kDishTick = 100; +const uint16_t kDishHdrMarkTicks = 4; +const uint16_t kDishHdrMark = kDishHdrMarkTicks * kDishTick; +const uint16_t kDishHdrSpaceTicks = 61; +const uint16_t kDishHdrSpace = kDishHdrSpaceTicks * kDishTick; +const uint16_t kDishBitMarkTicks = 4; +const uint16_t kDishBitMark = kDishBitMarkTicks * kDishTick; +const uint16_t kDishOneSpaceTicks = 17; +const uint16_t kDishOneSpace = kDishOneSpaceTicks * kDishTick; +const uint16_t kDishZeroSpaceTicks = 28; +const uint16_t kDishZeroSpace = kDishZeroSpaceTicks * kDishTick; +const uint16_t kDishRptSpaceTicks = kDishHdrSpaceTicks; +const uint16_t kDishRptSpace = kDishRptSpaceTicks * kDishTick; #if SEND_DISH // Send an IR command to a DISH NETWORK device. @@ -57,14 +57,13 @@ void IRsend::sendDISH(uint64_t data, uint16_t nbits, uint16_t repeat) { enableIROut(57600); // Set modulation freq. to 57.6kHz. // Header is only ever sent once. - mark(DISH_HDR_MARK); - space(DISH_HDR_SPACE); + mark(kDishHdrMark); + space(kDishHdrSpace); sendGeneric(0, 0, // No headers from here on in. - DISH_BIT_MARK, DISH_ONE_SPACE, - DISH_BIT_MARK, DISH_ZERO_SPACE, - DISH_BIT_MARK, DISH_RPT_SPACE, - data, nbits, 57600, true, repeat, 50); + kDishBitMark, kDishOneSpace, kDishBitMark, kDishZeroSpace, + kDishBitMark, kDishRptSpace, data, nbits, 57600, true, repeat, + 50); } #endif @@ -73,7 +72,7 @@ void IRsend::sendDISH(uint64_t data, uint16_t nbits, uint16_t repeat) { // // Args: // results: Ptr to the data to decode and where to store the decode result. -// nbits: Nr. of bits to expect in the data portion. Typically DISH_BITS. +// nbits: Nr. of bits to expect in the data portion. Typically kDishBits. // strict: Flag to indicate if we strictly adhere to the specification. // Returns: // boolean: True if it can decode it, false if it can't. @@ -89,34 +88,32 @@ void IRsend::sendDISH(uint64_t data, uint16_t nbits, uint16_t repeat) { // http://lirc.sourceforge.net/remotes/echostar/301_501_3100_5100_58xx_59xx // https://github.com/marcosamarinho/IRremoteESP8266/blob/master/ir_Dish.cpp bool IRrecv::decodeDISH(decode_results *results, uint16_t nbits, bool strict) { - if (results->rawlen < 2 * nbits + HEADER + FOOTER - 1) + if (results->rawlen < 2 * nbits + kHeader + kFooter - 1) return false; // Not enough entries to be valid. - if (strict && nbits != DISH_BITS) - return false; // Not strictly compliant. + if (strict && nbits != kDishBits) return false; // Not strictly compliant. uint64_t data = 0; - uint16_t offset = OFFSET_START; + uint16_t offset = kStartOffset; // Header - if (!match(results->rawbuf[offset], DISH_HDR_MARK)) return false; + if (!match(results->rawbuf[offset], kDishHdrMark)) return false; // Calculate how long the common tick time is based on the header mark. - uint32_t m_tick = results->rawbuf[offset++] * RAWTICK / DISH_HDR_MARK_TICKS; - if (!matchSpace(results->rawbuf[offset], DISH_HDR_SPACE)) return false; + uint32_t m_tick = results->rawbuf[offset++] * kRawTick / kDishHdrMarkTicks; + if (!matchSpace(results->rawbuf[offset], kDishHdrSpace)) return false; // Calculate how long the common tick time is based on the header space. - uint32_t s_tick = results->rawbuf[offset++] * RAWTICK / DISH_HDR_SPACE_TICKS; + uint32_t s_tick = results->rawbuf[offset++] * kRawTick / kDishHdrSpaceTicks; // Data - match_result_t data_result = matchData(&(results->rawbuf[offset]), nbits, - DISH_BIT_MARK_TICKS * m_tick, - DISH_ONE_SPACE_TICKS * s_tick, - DISH_BIT_MARK_TICKS * m_tick, - DISH_ZERO_SPACE_TICKS * s_tick); + match_result_t data_result = + matchData(&(results->rawbuf[offset]), nbits, kDishBitMarkTicks * m_tick, + kDishOneSpaceTicks * s_tick, kDishBitMarkTicks * m_tick, + kDishZeroSpaceTicks * s_tick); if (data_result.success == false) return false; data = data_result.data; offset += data_result.used; // Footer - if (!matchMark(results->rawbuf[offset++], DISH_BIT_MARK_TICKS * m_tick)) + if (!matchMark(results->rawbuf[offset++], kDishBitMarkTicks * m_tick)) return false; // Compliance @@ -124,7 +121,7 @@ bool IRrecv::decodeDISH(decode_results *results, uint16_t nbits, bool strict) { // The DISH protocol calls for a repeated message, so strictly speaking // there should be a code following this. Only require it if we are set to // strict matching. - if (!matchSpace(results->rawbuf[offset], DISH_RPT_SPACE_TICKS * s_tick)) + if (!matchSpace(results->rawbuf[offset], kDishRptSpaceTicks * s_tick)) return false; } diff --git a/lib/IRremoteESP8266/src/ir_Electra.cpp b/lib/IRremoteESP8266/src/ir_Electra.cpp new file mode 100644 index 0000000..df69be7 --- /dev/null +++ b/lib/IRremoteESP8266/src/ir_Electra.cpp @@ -0,0 +1,112 @@ +// Copyright 2018 David Conran + +#include "IRrecv.h" +#include "IRsend.h" +#include "IRutils.h" + +// EEEEEEE LL EEEEEEE CCCCC TTTTTTT RRRRRR AAA +// EE LL EE CC C TTT RR RR AAAAA +// EEEEE LL EEEEE CC TTT RRRRRR AA AA +// EE LL EE CC C TTT RR RR AAAAAAA +// EEEEEEE LLLLLLL EEEEEEE CCCCC TTT RR RR AA AA + +// Electra A/C added by crankyoldgit +// +// Equipment it seems compatible with: +// * + +// Ref: +// https://github.com/markszabo/IRremoteESP8266/issues/527 + +// Constants +const uint16_t kElectraAcHdrMark = 9166; +const uint16_t kElectraAcBitMark = 646; +const uint16_t kElectraAcHdrSpace = 4470; +const uint16_t kElectraAcOneSpace = 1647; +const uint16_t kElectraAcZeroSpace = 547; +const uint32_t kElectraAcMessageGap = 100000; // Completely made-up guess. + +#if SEND_ELECTRA_AC +// Send a Electra message +// +// Args: +// data: Contents of the message to be sent. (Guessing MSBF order) +// nbits: Nr. of bits of data to be sent. Typically kElectraAcBits. +// repeat: Nr. of additional times the message is to be sent. +// +// Status: Alpha / Needs testing against a real device. +// +void IRsend::sendElectraAC(uint8_t data[], uint16_t nbytes, uint16_t repeat) { + for (uint16_t r = 0; r <= repeat; r++) + sendGeneric(kElectraAcHdrMark, kElectraAcHdrSpace, kElectraAcBitMark, + kElectraAcOneSpace, kElectraAcBitMark, kElectraAcZeroSpace, + kElectraAcBitMark, kElectraAcMessageGap, data, nbytes, + 38000, // Complete guess of the modulation frequency. + true, 0, 50); +} +#endif + +#if DECODE_ELECTRA_AC +// Decode the supplied Electra A/C message. +// +// Args: +// results: Ptr to the data to decode and where to store the decode result. +// nbits: The number of data bits to expect. Typically kElectraAcBits. +// strict: Flag indicating if we should perform strict matching. +// Returns: +// boolean: True if it can decode it, false if it can't. +// +// Status: Alpha / Needs testing against a real device. +// +bool IRrecv::decodeElectraAC(decode_results *results, uint16_t nbits, + bool strict) { + if (nbits % 8 != 0) // nbits has to be a multiple of nr. of bits in a byte. + return false; + + if (strict) { + if (nbits != kElectraAcBits) + return false; // Not strictly a ELECTRA_AC message. + } + + // The protocol sends the data normal + inverted, alternating on + // each byte. Hence twice the number of expected data bits. + if (results->rawlen < 2 * nbits + kHeader + kFooter - 1) + return false; // Can't possibly be a valid ELECTRA_AC message. + + uint16_t offset = kStartOffset; + + // Message Header + if (!matchMark(results->rawbuf[offset++], kElectraAcHdrMark)) return false; + if (!matchSpace(results->rawbuf[offset++], kElectraAcHdrSpace)) return false; + + // Data Section + match_result_t data_result; + uint16_t dataBitsSoFar = 0; + // Keep reading bytes until we either run out of section or state to fill. + for (uint16_t i = 0; offset <= results->rawlen - 16 && i < nbits / 8; + i++, dataBitsSoFar += 8, offset += data_result.used) { + data_result = matchData(&(results->rawbuf[offset]), 8, kElectraAcBitMark, + kElectraAcOneSpace, kElectraAcBitMark, + kElectraAcZeroSpace, kTolerance, 0, true); + if (data_result.success == false) return false; // Fail + results->state[i] = data_result.data; + } + + // Message Footer + if (!matchMark(results->rawbuf[offset++], kElectraAcBitMark)) return false; + if (offset <= results->rawlen && + !matchAtLeast(results->rawbuf[offset++], kElectraAcMessageGap)) + return false; + + // Compliance + if (strict && dataBitsSoFar != nbits) return false; + + // Success + results->decode_type = ELECTRA_AC; + results->bits = dataBitsSoFar; + // No need to record the state as we stored it as we decoded it. + // As we use result->state, we don't record value, address, or command as it + // is a union data type. + return true; +} +#endif // DECODE_ELECTRA_AC diff --git a/lib/IRremoteESP8266/src/ir_Fujitsu.cpp b/lib/IRremoteESP8266/src/ir_Fujitsu.cpp index 70e786b..60bb96e 100644 --- a/lib/IRremoteESP8266/src/ir_Fujitsu.cpp +++ b/lib/IRremoteESP8266/src/ir_Fujitsu.cpp @@ -7,7 +7,6 @@ #include "IRsend.h" #include "IRutils.h" - // Fujitsu A/C support added by Jonny Graham & David Conran // Equipment it seems compatible with: @@ -17,12 +16,12 @@ // Ref: // These values are based on averages of measurements -#define FUJITSU_AC_HDR_MARK 3324U -#define FUJITSU_AC_HDR_SPACE 1574U -#define FUJITSU_AC_BIT_MARK 448U -#define FUJITSU_AC_ONE_SPACE 1182U -#define FUJITSU_AC_ZERO_SPACE 390U -#define FUJITSU_AC_MIN_GAP 8100U +const uint16_t kFujitsuAcHdrMark = 3324; +const uint16_t kFujitsuAcHdrSpace = 1574; +const uint16_t kFujitsuAcBitMark = 448; +const uint16_t kFujitsuAcOneSpace = 1182; +const uint16_t kFujitsuAcZeroSpace = 390; +const uint16_t kFujitsuAcMinGap = 8100; #if SEND_FUJITSU_AC // Send a Fujitsu A/C message. @@ -30,22 +29,21 @@ // Args: // data: An array of bytes containing the IR command. // nbytes: Nr. of bytes of data in the array. Typically one of: -// FUJITSU_AC_STATE_LENGTH -// FUJITSU_AC_STATE_LENGTH - 1 -// FUJITSU_AC_STATE_LENGTH_SHORT -// FUJITSU_AC_STATE_LENGTH_SHORT - 1 +// kFujitsuAcStateLength +// kFujitsuAcStateLength - 1 +// kFujitsuAcStateLengthShort +// kFujitsuAcStateLengthShort - 1 // repeat: Nr. of times the message is to be repeated. -// (Default = FUJITSU_AC_MIN_REPEAT). +// (Default = kFujitsuAcMinRepeat). // // Status: BETA / Appears to be working. // void IRsend::sendFujitsuAC(unsigned char data[], uint16_t nbytes, uint16_t repeat) { - sendGeneric(FUJITSU_AC_HDR_MARK, FUJITSU_AC_HDR_SPACE, - FUJITSU_AC_BIT_MARK, FUJITSU_AC_ONE_SPACE, - FUJITSU_AC_BIT_MARK, FUJITSU_AC_ZERO_SPACE, - FUJITSU_AC_BIT_MARK, FUJITSU_AC_MIN_GAP, - data, nbytes, 38, false, repeat, 50); + sendGeneric(kFujitsuAcHdrMark, kFujitsuAcHdrSpace, kFujitsuAcBitMark, + kFujitsuAcOneSpace, kFujitsuAcBitMark, kFujitsuAcZeroSpace, + kFujitsuAcBitMark, kFujitsuAcMinGap, data, nbytes, 38, false, + repeat, 50); } #endif // SEND_FUJITSU_AC @@ -62,35 +60,33 @@ void IRFujitsuAC::setModel(fujitsu_ac_remote_model_t model) { _model = model; switch (model) { case ARDB1: - _state_length = FUJITSU_AC_STATE_LENGTH - 1; - _state_length_short = FUJITSU_AC_STATE_LENGTH_SHORT - 1; + _state_length = kFujitsuAcStateLength - 1; + _state_length_short = kFujitsuAcStateLengthShort - 1; break; default: - _state_length = FUJITSU_AC_STATE_LENGTH; - _state_length_short = FUJITSU_AC_STATE_LENGTH_SHORT; + _state_length = kFujitsuAcStateLength; + _state_length_short = kFujitsuAcStateLengthShort; } } // Reset the state of the remote to a known good state/sequence. void IRFujitsuAC::stateReset() { _temp = 24; - _fanSpeed = FUJITSU_AC_FAN_HIGH; - _mode = FUJITSU_AC_MODE_COOL; - _swingMode = FUJITSU_AC_SWING_BOTH; - _cmd = FUJITSU_AC_CMD_TURN_ON; + _fanSpeed = kFujitsuAcFanHigh; + _mode = kFujitsuAcModeCool; + _swingMode = kFujitsuAcSwingBoth; + _cmd = kFujitsuAcCmdTurnOn; buildState(); } // Configure the pin for output. -void IRFujitsuAC::begin() { - _irsend.begin(); -} +void IRFujitsuAC::begin() { _irsend.begin(); } #if SEND_FUJITSU_AC // Send the current desired state to the IR LED. -void IRFujitsuAC::send() { +void IRFujitsuAC::send(const uint16_t repeat) { getRaw(); - _irsend.sendFujitsuAC(remote_state, getStateLength()); + _irsend.sendFujitsuAC(remote_state, getStateLength(), repeat); } #endif // SEND_FUJITSU_AC @@ -102,13 +98,13 @@ void IRFujitsuAC::buildState() { remote_state[4] = 0x10; bool fullCmd = false; switch (_cmd) { - case FUJITSU_AC_CMD_TURN_OFF: + case kFujitsuAcCmdTurnOff: remote_state[5] = 0x02; break; - case FUJITSU_AC_CMD_STEP_HORIZ: + case kFujitsuAcCmdStepHoriz: remote_state[5] = 0x79; break; - case FUJITSU_AC_CMD_STEP_VERT: + case kFujitsuAcCmdStepVert: remote_state[5] = 0x6C; break; default: @@ -124,12 +120,12 @@ void IRFujitsuAC::buildState() { break; } if (fullCmd) { // long codes - uint8_t tempByte = _temp - FUJITSU_AC_MIN_TEMP; + uint8_t tempByte = _temp - kFujitsuAcMinTemp; // Nr. of bytes in the message after this byte. remote_state[6] = _state_length - 7; remote_state[7] = 0x30; - remote_state[8] = (_cmd == FUJITSU_AC_CMD_TURN_ON) | (tempByte << 4); + remote_state[8] = (_cmd == kFujitsuAcCmdTurnOn) | (tempByte << 4); remote_state[9] = _mode | 0 << 4; // timer off remote_state[10] = _fanSpeed | _swingMode << 4; remote_state[11] = 0; // timerOff values @@ -154,12 +150,10 @@ void IRFujitsuAC::buildState() { } else { // short codes if (_model == ARRAH2E) // The last byte is the inverse of penultimate byte - remote_state[_state_length_short - 1] = ~remote_state[_state_length_short - - 2]; + remote_state[_state_length_short - 1] = + ~remote_state[_state_length_short - 2]; // Zero the rest of the state. - for (uint8_t i = _state_length_short; - i < FUJITSU_AC_STATE_LENGTH; - i++) + for (uint8_t i = _state_length_short; i < kFujitsuAcStateLength; i++) remote_state[i] = 0; } } @@ -181,8 +175,8 @@ uint8_t* IRFujitsuAC::getRaw() { void IRFujitsuAC::buildFromState(const uint16_t length) { switch (length) { - case FUJITSU_AC_STATE_LENGTH - 1: - case FUJITSU_AC_STATE_LENGTH_SHORT - 1: + case kFujitsuAcStateLength - 1: + case kFujitsuAcStateLengthShort - 1: setModel(ARDB1); break; default: @@ -196,26 +190,26 @@ void IRFujitsuAC::buildFromState(const uint16_t length) { setModel(ARRAH2E); break; } - setTemp((remote_state[8] >> 4) + FUJITSU_AC_MIN_TEMP); + setTemp((remote_state[8] >> 4) + kFujitsuAcMinTemp); if (remote_state[8] & 0x1) - setCmd(FUJITSU_AC_CMD_TURN_ON); + setCmd(kFujitsuAcCmdTurnOn); else - setCmd(FUJITSU_AC_CMD_STAY_ON); + setCmd(kFujitsuAcCmdStayOn); setMode(remote_state[9] & 0b111); setFanSpeed(remote_state[10] & 0b111); setSwing(remote_state[10] >> 4); switch (remote_state[5]) { - case FUJITSU_AC_CMD_TURN_OFF: - case FUJITSU_AC_CMD_STEP_HORIZ: - case FUJITSU_AC_CMD_STEP_VERT: + case kFujitsuAcCmdTurnOff: + case kFujitsuAcCmdStepHoriz: + case kFujitsuAcCmdStepVert: setCmd(remote_state[5]); break; } } bool IRFujitsuAC::setRaw(const uint8_t newState[], const uint16_t length) { - if (length > FUJITSU_AC_STATE_LENGTH) return false; - for (uint16_t i = 0; i < FUJITSU_AC_STATE_LENGTH; i++) { + if (length > kFujitsuAcStateLength) return false; + for (uint16_t i = 0; i < kFujitsuAcStateLength; i++) { if (i < length) remote_state[i] = newState[i]; else @@ -226,119 +220,103 @@ bool IRFujitsuAC::setRaw(const uint8_t newState[], const uint16_t length) { } // Set the requested power state of the A/C to off. -void IRFujitsuAC::off() { - _cmd = FUJITSU_AC_CMD_TURN_OFF; -} +void IRFujitsuAC::off() { _cmd = kFujitsuAcCmdTurnOff; } void IRFujitsuAC::stepHoriz() { switch (_model) { - case ARDB1: break; // This remote doesn't have a horizontal option. + case ARDB1: + break; // This remote doesn't have a horizontal option. default: - _cmd = FUJITSU_AC_CMD_STEP_HORIZ; + _cmd = kFujitsuAcCmdStepHoriz; } } -void IRFujitsuAC::stepVert() { - _cmd = FUJITSU_AC_CMD_STEP_VERT; -} +void IRFujitsuAC::stepVert() { _cmd = kFujitsuAcCmdStepVert; } // Set the requested command of the A/C. void IRFujitsuAC::setCmd(uint8_t cmd) { switch (cmd) { - case FUJITSU_AC_CMD_TURN_OFF: - case FUJITSU_AC_CMD_TURN_ON: - case FUJITSU_AC_CMD_STAY_ON: - case FUJITSU_AC_CMD_STEP_VERT: + case kFujitsuAcCmdTurnOff: + case kFujitsuAcCmdTurnOn: + case kFujitsuAcCmdStayOn: + case kFujitsuAcCmdStepVert: _cmd = cmd; break; - case FUJITSU_AC_CMD_STEP_HORIZ: + case kFujitsuAcCmdStepHoriz: if (_model != ARDB1) // AR-DB1 remote doesn't have step horizontal. _cmd = cmd; + // FALLTHRU default: - _cmd = FUJITSU_AC_CMD_STAY_ON; + _cmd = kFujitsuAcCmdStayOn; break; } } -uint8_t IRFujitsuAC::getCmd() { - return _cmd; -} +uint8_t IRFujitsuAC::getCmd() { return _cmd; } -bool IRFujitsuAC::getPower() { - return _cmd != FUJITSU_AC_CMD_TURN_OFF; -} +bool IRFujitsuAC::getPower() { return _cmd != kFujitsuAcCmdTurnOff; } // Set the temp. in deg C void IRFujitsuAC::setTemp(uint8_t temp) { - temp = std::max((uint8_t) FUJITSU_AC_MIN_TEMP, temp); - temp = std::min((uint8_t) FUJITSU_AC_MAX_TEMP, temp); + temp = std::max((uint8_t)kFujitsuAcMinTemp, temp); + temp = std::min((uint8_t)kFujitsuAcMaxTemp, temp); _temp = temp; } -uint8_t IRFujitsuAC::getTemp() { - return _temp; -} +uint8_t IRFujitsuAC::getTemp() { return _temp; } // Set the speed of the fan void IRFujitsuAC::setFanSpeed(uint8_t fanSpeed) { - if (fanSpeed > FUJITSU_AC_FAN_QUIET) - fanSpeed = FUJITSU_AC_FAN_HIGH; // Set the fan to maximum if out of range. + if (fanSpeed > kFujitsuAcFanQuiet) + fanSpeed = kFujitsuAcFanHigh; // Set the fan to maximum if out of range. _fanSpeed = fanSpeed; } -uint8_t IRFujitsuAC::getFanSpeed() { - return _fanSpeed; -} +uint8_t IRFujitsuAC::getFanSpeed() { return _fanSpeed; } // Set the requested climate operation mode of the a/c unit. void IRFujitsuAC::setMode(uint8_t mode) { - if (mode > FUJITSU_AC_MODE_HEAT) - mode = FUJITSU_AC_MODE_HEAT; // Set the mode to maximum if out of range. + if (mode > kFujitsuAcModeHeat) + mode = kFujitsuAcModeHeat; // Set the mode to maximum if out of range. _mode = mode; } -uint8_t IRFujitsuAC::getMode() { - return _mode; -} +uint8_t IRFujitsuAC::getMode() { return _mode; } // Set the requested swing operation mode of the a/c unit. void IRFujitsuAC::setSwing(uint8_t swingMode) { switch (_model) { case ARDB1: // Set the mode to max if out of range - if (swingMode > FUJITSU_AC_SWING_VERT) - swingMode = FUJITSU_AC_SWING_VERT; + if (swingMode > kFujitsuAcSwingVert) swingMode = kFujitsuAcSwingVert; break; case ARRAH2E: default: // Set the mode to max if out of range - if (swingMode > FUJITSU_AC_SWING_BOTH) - swingMode = FUJITSU_AC_SWING_BOTH; + if (swingMode > kFujitsuAcSwingBoth) swingMode = kFujitsuAcSwingBoth; } _swingMode = swingMode; } -uint8_t IRFujitsuAC::getSwing() { - return _swingMode; -} +uint8_t IRFujitsuAC::getSwing() { return _swingMode; } bool IRFujitsuAC::validChecksum(uint8_t state[], uint16_t length) { uint8_t sum = 0; uint8_t sum_complement = 0; - uint8_t checksum = 0; + uint8_t checksum = state[length - 1]; switch (length) { - case FUJITSU_AC_STATE_LENGTH_SHORT: // ARRAH2E - return state[length - 1] == (uint8_t) ~state[length - 2]; - case FUJITSU_AC_STATE_LENGTH - 1: // ARDB1 + case kFujitsuAcStateLengthShort: // ARRAH2E + return state[length - 1] == (uint8_t)~state[length - 2]; + case kFujitsuAcStateLength - 1: // ARDB1 sum = sumBytes(state, length - 1); sum_complement = 0x9B; - checksum = state[length - 1]; break; - case FUJITSU_AC_STATE_LENGTH: // ARRAH2E - sum = sumBytes(state + FUJITSU_AC_STATE_LENGTH_SHORT, - length - 1 - FUJITSU_AC_STATE_LENGTH_SHORT); - default: // Includes ARDB1 short. + case kFujitsuAcStateLength: // ARRAH2E + sum = sumBytes(state + kFujitsuAcStateLengthShort, + length - 1 - kFujitsuAcStateLengthShort); + break; + default: // Includes ARDB1 short. return true; // Assume the checksum is valid for other lengths. } - return checksum == (uint8_t) (sum_complement - sum); // Does it match? + return checksum == (uint8_t)(sum_complement - sum); // Does it match? } // Convert the internal state into a human readable string. @@ -356,19 +334,19 @@ std::string IRFujitsuAC::toString() { result += "Off"; result += ", Mode: " + uint64ToString(getMode()); switch (getMode()) { - case FUJITSU_AC_MODE_AUTO: + case kFujitsuAcModeAuto: result += " (AUTO)"; break; - case FUJITSU_AC_MODE_COOL: + case kFujitsuAcModeCool: result += " (COOL)"; break; - case FUJITSU_AC_MODE_HEAT: + case kFujitsuAcModeHeat: result += " (HEAT)"; break; - case FUJITSU_AC_MODE_DRY: + case kFujitsuAcModeDry: result += " (DRY)"; break; - case FUJITSU_AC_MODE_FAN: + case kFujitsuAcModeFan: result += " (FAN)"; break; default: @@ -377,34 +355,34 @@ std::string IRFujitsuAC::toString() { result += ", Temp: " + uint64ToString(getTemp()) + "C"; result += ", Fan: " + uint64ToString(getFanSpeed()); switch (getFanSpeed()) { - case FUJITSU_AC_FAN_AUTO: + case kFujitsuAcFanAuto: result += " (AUTO)"; break; - case FUJITSU_AC_FAN_HIGH: + case kFujitsuAcFanHigh: result += " (HIGH)"; break; - case FUJITSU_AC_FAN_MED: + case kFujitsuAcFanMed: result += " (MED)"; break; - case FUJITSU_AC_FAN_LOW: + case kFujitsuAcFanLow: result += " (LOW)"; break; - case FUJITSU_AC_FAN_QUIET: + case kFujitsuAcFanQuiet: result += " (QUIET)"; break; } result += ", Swing: "; switch (getSwing()) { - case FUJITSU_AC_SWING_OFF: + case kFujitsuAcSwingOff: result += "Off"; break; - case FUJITSU_AC_SWING_VERT: + case kFujitsuAcSwingVert: result += "Vert"; break; - case FUJITSU_AC_SWING_HORIZ: + case kFujitsuAcSwingHoriz: result += "Horiz"; break; - case FUJITSU_AC_SWING_BOTH: + case kFujitsuAcSwingBoth: result += "Vert + Horiz"; break; default: @@ -412,14 +390,14 @@ std::string IRFujitsuAC::toString() { } result += ", Command: "; switch (getCmd()) { - case FUJITSU_AC_CMD_STEP_HORIZ: + case kFujitsuAcCmdStepHoriz: result += "Step vane horizontally"; break; - case FUJITSU_AC_CMD_STEP_VERT: + case kFujitsuAcCmdStepVert: result += "Step vane vertically"; break; default: - result += "N/A"; + result += "N/A"; } return result; } @@ -429,7 +407,7 @@ std::string IRFujitsuAC::toString() { // Places successful decode information in the results pointer. // Args: // results: Ptr to the data to decode and where to store the decode result. -// nbits: The number of data bits to expect. Typically FUJITSU_AC_BITS. +// nbits: The number of data bits to expect. Typically kFujitsuAcBits. // strict: Flag to indicate if we strictly adhere to the specification. // Returns: // boolean: True if it can decode it, false if it can't. @@ -438,23 +416,22 @@ std::string IRFujitsuAC::toString() { // // Ref: // -bool IRrecv::decodeFujitsuAC(decode_results *results, uint16_t nbits, +bool IRrecv::decodeFujitsuAC(decode_results* results, uint16_t nbits, bool strict) { - uint16_t offset = OFFSET_START; + uint16_t offset = kStartOffset; uint16_t dataBitsSoFar = 0; // Have we got enough data to successfully decode? - if (results->rawlen < (2 * FUJITSU_AC_MIN_BITS) + HEADER + FOOTER - 1) + if (results->rawlen < (2 * kFujitsuAcMinBits) + kHeader + kFooter - 1) return false; // Can't possibly be a valid message. - // Compliance if (strict) { switch (nbits) { - case FUJITSU_AC_BITS: - case FUJITSU_AC_BITS - 8: - case FUJITSU_AC_MIN_BITS: - case FUJITSU_AC_MIN_BITS + 8: + case kFujitsuAcBits: + case kFujitsuAcBits - 8: + case kFujitsuAcMinBits: + case kFujitsuAcMinBits + 8: break; default: return false; // Must be called with the correct nr. of bits. @@ -462,22 +439,17 @@ bool IRrecv::decodeFujitsuAC(decode_results *results, uint16_t nbits, } // Header - if (!matchMark(results->rawbuf[offset++], FUJITSU_AC_HDR_MARK)) - return false; - if (!matchSpace(results->rawbuf[offset++], FUJITSU_AC_HDR_SPACE)) - return false; + if (!matchMark(results->rawbuf[offset++], kFujitsuAcHdrMark)) return false; + if (!matchSpace(results->rawbuf[offset++], kFujitsuAcHdrSpace)) return false; // Data (Fixed signature) - match_result_t data_result = matchData(&(results->rawbuf[offset]), - FUJITSU_AC_MIN_BITS - 8, - FUJITSU_AC_BIT_MARK, - FUJITSU_AC_ONE_SPACE, - FUJITSU_AC_BIT_MARK, - FUJITSU_AC_ZERO_SPACE); - if (data_result.success == false) return false; // Fail - if (reverseBits(data_result.data, FUJITSU_AC_MIN_BITS - 8) != 0x1010006314) - return false; // Signature failed. - dataBitsSoFar += FUJITSU_AC_MIN_BITS - 8; + match_result_t data_result = + matchData(&(results->rawbuf[offset]), kFujitsuAcMinBits - 8, + kFujitsuAcBitMark, kFujitsuAcOneSpace, kFujitsuAcBitMark, + kFujitsuAcZeroSpace, kTolerance, kMarkExcess, false); + if (data_result.success == false) return false; // Fail + if (data_result.data != 0x1010006314) return false; // Signature failed. + dataBitsSoFar += kFujitsuAcMinBits - 8; offset += data_result.used; results->state[0] = 0x14; results->state[1] = 0x63; @@ -487,27 +459,27 @@ bool IRrecv::decodeFujitsuAC(decode_results *results, uint16_t nbits, // Keep reading bytes until we either run out of message or state to fill. for (uint16_t i = 5; - offset <= results->rawlen - 16 && i < FUJITSU_AC_STATE_LENGTH; - i++, dataBitsSoFar += 8, offset += data_result.used) { - data_result = matchData(&(results->rawbuf[offset]), 8, - FUJITSU_AC_BIT_MARK, - FUJITSU_AC_ONE_SPACE, - FUJITSU_AC_BIT_MARK, - FUJITSU_AC_ZERO_SPACE); - if (data_result.success == false) break; // Fail - results->state[i] = (uint8_t) reverseBits(data_result.data, 8); + offset <= results->rawlen - 16 && i < kFujitsuAcStateLength; + i++, dataBitsSoFar += 8, offset += data_result.used) { + data_result = matchData( + &(results->rawbuf[offset]), 8, kFujitsuAcBitMark, kFujitsuAcOneSpace, + kFujitsuAcBitMark, kFujitsuAcZeroSpace, kTolerance, kMarkExcess, false); + if (data_result.success == false) break; // Fail + results->state[i] = data_result.data; } // Footer if (offset > results->rawlen || - !matchMark(results->rawbuf[offset++], FUJITSU_AC_BIT_MARK)) return false; + !matchMark(results->rawbuf[offset++], kFujitsuAcBitMark)) + return false; // The space is optional if we are out of capture. if (offset < results->rawlen && - !matchAtLeast(results->rawbuf[offset], FUJITSU_AC_MIN_GAP)) return false; + !matchAtLeast(results->rawbuf[offset], kFujitsuAcMinGap)) + return false; // Compliance if (strict) { - if (dataBitsSoFar != nbits) return false; + if (dataBitsSoFar != nbits) return false; } results->decode_type = FUJITSU_AC; @@ -515,25 +487,25 @@ bool IRrecv::decodeFujitsuAC(decode_results *results, uint16_t nbits, // Compliance switch (dataBitsSoFar) { - case FUJITSU_AC_MIN_BITS: + case kFujitsuAcMinBits: // Check if this values indicate that this should have been a long state // message. - if (results->state[5] == 0xFC) return false; + if (results->state[5] == 0xFC) return false; return true; // Success - case FUJITSU_AC_MIN_BITS + 8: + case kFujitsuAcMinBits + 8: // Check if this values indicate that this should have been a long state // message. - if (results->state[5] == 0xFE) return false; + if (results->state[5] == 0xFE) return false; // The last byte needs to be the inverse of the penultimate byte. - if (results->state[5] != (uint8_t) ~results->state[6]) return false; + if (results->state[5] != (uint8_t)~results->state[6]) return false; return true; // Success - case FUJITSU_AC_BITS - 8: + case kFujitsuAcBits - 8: // Long messages of this size require this byte be correct. - if (results->state[5] != 0xFC) return false; + if (results->state[5] != 0xFC) return false; break; - case FUJITSU_AC_BITS: + case kFujitsuAcBits: // Long messages of this size require this byte be correct. - if (results->state[5] != 0xFE) return false; + if (results->state[5] != 0xFE) return false; break; default: return false; // Unexpected size. diff --git a/lib/IRremoteESP8266/src/ir_Fujitsu.h b/lib/IRremoteESP8266/src/ir_Fujitsu.h index ed6317d..d5dc837 100644 --- a/lib/IRremoteESP8266/src/ir_Fujitsu.h +++ b/lib/IRremoteESP8266/src/ir_Fujitsu.h @@ -1,4 +1,5 @@ // Copyright 2017 Jonny Graham +// Copyright 2018 David Conran #ifndef IR_FUJITSU_H_ #define IR_FUJITSU_H_ @@ -9,41 +10,61 @@ #else #include #endif -#include "IRremoteESP8266.h" #include "IRrecv.h" +#include "IRremoteESP8266.h" #include "IRsend.h" - // FUJITSU A/C support added by Jonny Graham // Constants +const uint8_t kFujitsuAcModeAuto = 0x00; +const uint8_t kFujitsuAcModeCool = 0x01; +const uint8_t kFujitsuAcModeDry = 0x02; +const uint8_t kFujitsuAcModeFan = 0x03; +const uint8_t kFujitsuAcModeHeat = 0x04; -#define FUJITSU_AC_MODE_AUTO 0x00U -#define FUJITSU_AC_MODE_COOL 0x01U -#define FUJITSU_AC_MODE_DRY 0x02U -#define FUJITSU_AC_MODE_FAN 0x03U -#define FUJITSU_AC_MODE_HEAT 0x04U +const uint8_t kFujitsuAcCmdStayOn = 0x00; +const uint8_t kFujitsuAcCmdTurnOn = 0x01; +const uint8_t kFujitsuAcCmdTurnOff = 0x02; +const uint8_t kFujitsuAcCmdStepHoriz = 0x79; +const uint8_t kFujitsuAcCmdStepVert = 0x6C; -#define FUJITSU_AC_CMD_STAY_ON 0x00U -#define FUJITSU_AC_CMD_TURN_ON 0x01U -#define FUJITSU_AC_CMD_TURN_OFF 0x02U -#define FUJITSU_AC_CMD_STEP_HORIZ 0x79U -#define FUJITSU_AC_CMD_STEP_VERT 0x6CU +const uint8_t kFujitsuAcFanAuto = 0x00; +const uint8_t kFujitsuAcFanHigh = 0x01; +const uint8_t kFujitsuAcFanMed = 0x02; +const uint8_t kFujitsuAcFanLow = 0x03; +const uint8_t kFujitsuAcFanQuiet = 0x04; -#define FUJITSU_AC_FAN_AUTO 0x00U -#define FUJITSU_AC_FAN_HIGH 0x01U -#define FUJITSU_AC_FAN_MED 0x02U -#define FUJITSU_AC_FAN_LOW 0x03U -#define FUJITSU_AC_FAN_QUIET 0x04U +const uint8_t kFujitsuAcMinTemp = 16; // 16C +const uint8_t kFujitsuAcMaxTemp = 30; // 30C -#define FUJITSU_AC_MIN_TEMP 16U // 16C -#define FUJITSU_AC_MAX_TEMP 30U // 30C - -#define FUJITSU_AC_SWING_OFF 0x00U -#define FUJITSU_AC_SWING_VERT 0x01U -#define FUJITSU_AC_SWING_HORIZ 0x02U -#define FUJITSU_AC_SWING_BOTH 0x03U +const uint8_t kFujitsuAcSwingOff = 0x00; +const uint8_t kFujitsuAcSwingVert = 0x01; +const uint8_t kFujitsuAcSwingHoriz = 0x02; +const uint8_t kFujitsuAcSwingBoth = 0x03; +// Legacy defines. +#define FUJITSU_AC_MODE_AUTO kFujitsuAcModeAuto +#define FUJITSU_AC_MODE_COOL kFujitsuAcModeCool +#define FUJITSU_AC_MODE_DRY kFujitsuAcModeDry +#define FUJITSU_AC_MODE_FAN kFujitsuAcModeFan +#define FUJITSU_AC_MODE_HEAT kFujitsuAcModeHeat +#define FUJITSU_AC_CMD_STAY_ON kFujitsuAcCmdStayOn +#define FUJITSU_AC_CMD_TURN_ON kFujitsuAcCmdTurnOn +#define FUJITSU_AC_CMD_TURN_OFF kFujitsuAcCmdTurnOff +#define FUJITSU_AC_CMD_STEP_HORIZ kFujitsuAcCmdStepHoriz +#define FUJITSU_AC_CMD_STEP_VERT kFujitsuAcCmdStepVert +#define FUJITSU_AC_FAN_AUTO kFujitsuAcFanAuto +#define FUJITSU_AC_FAN_HIGH kFujitsuAcFanHigh +#define FUJITSU_AC_FAN_MED kFujitsuAcFanMed +#define FUJITSU_AC_FAN_LOW kFujitsuAcFanLow +#define FUJITSU_AC_FAN_QUIET kFujitsuAcFanQuiet +#define FUJITSU_AC_MIN_TEMP kFujitsuAcMinTemp +#define FUJITSU_AC_MAX_TEMP kFujitsuAcMaxTemp +#define FUJITSU_AC_SWING_OFF kFujitsuAcSwingOff +#define FUJITSU_AC_SWING_VERT kFujitsuAcSwingVert +#define FUJITSU_AC_SWING_HORIZ kFujitsuAcSwingHoriz +#define FUJITSU_AC_SWING_BOTH kFujitsuAcSwingBoth enum fujitsu_ac_remote_model_t { ARRAH2E = 1, @@ -57,7 +78,7 @@ class IRFujitsuAC { void setModel(fujitsu_ac_remote_model_t model); void stateReset(); #if SEND_FUJITSU_AC - void send(); + void send(const uint16_t repeat = kFujitsuAcMinRepeat); #endif // SEND_FUJITSU_AC void begin(); void off(); @@ -76,16 +97,16 @@ class IRFujitsuAC { uint8_t* getRaw(); bool setRaw(const uint8_t newState[], const uint16_t length); uint8_t getStateLength(); - static bool validChecksum(uint8_t *state, uint16_t length); + static bool validChecksum(uint8_t* state, uint16_t length); bool getPower(); - #ifdef ARDUINO - String toString(); - #else - std::string toString(); - #endif +#ifdef ARDUINO + String toString(); +#else + std::string toString(); +#endif private: - uint8_t remote_state[FUJITSU_AC_STATE_LENGTH]; + uint8_t remote_state[kFujitsuAcStateLength]; IRsend _irsend; uint8_t _temp; uint8_t _fanSpeed; diff --git a/lib/IRremoteESP8266/src/ir_GICable.cpp b/lib/IRremoteESP8266/src/ir_GICable.cpp index 2359acc..229e4e5 100644 --- a/lib/IRremoteESP8266/src/ir_GICable.cpp +++ b/lib/IRremoteESP8266/src/ir_GICable.cpp @@ -18,17 +18,17 @@ // https://github.com/markszabo/IRremoteESP8266/issues/447 // Constants -#define GICABLE_HDR_MARK 9000U -#define GICABLE_HDR_SPACE 4400U -#define GICABLE_BIT_MARK 550U -#define GICABLE_ONE_SPACE 4400U -#define GICABLE_ZERO_SPACE 2200U -#define GICABLE_RPT_SPACE 2200U -#define GICABLE_MIN_COMMAND_LENGTH 99600U -#define GICABLE_MIN_GAP (GICABLE_MIN_COMMAND_LENGTH - \ - (GICABLE_HDR_MARK + GICABLE_HDR_SPACE + \ - GICABLE_BITS * (GICABLE_BIT_MARK + GICABLE_ONE_SPACE) + GICABLE_BIT_MARK)) - +const uint16_t kGicableHdrMark = 9000; +const uint16_t kGicableHdrSpace = 4400; +const uint16_t kGicableBitMark = 550; +const uint16_t kGicableOneSpace = 4400; +const uint16_t kGicableZeroSpace = 2200; +const uint16_t kGicableRptSpace = 2200; +const uint32_t kGicableMinCommandLength = 99600; +const uint32_t kGicableMinGap = + kGicableMinCommandLength - + (kGicableHdrMark + kGicableHdrSpace + + kGicableBits * (kGicableBitMark + kGicableOneSpace) + kGicableBitMark); #if SEND_GICABLE // Send a raw G.I. Cable formatted message. @@ -36,25 +36,24 @@ // Args: // data: The message to be sent. // nbits: The number of bits of the message to be sent. -// Typically GICABLE_BITS. +// Typically kGicableBits. // repeat: The number of times the command is to be repeated. // // Status: Alpha / Untested. // // Ref: void IRsend::sendGICable(uint64_t data, uint16_t nbits, uint16_t repeat) { - sendGeneric(GICABLE_HDR_MARK, GICABLE_HDR_SPACE, - GICABLE_BIT_MARK, GICABLE_ONE_SPACE, - GICABLE_BIT_MARK, GICABLE_ZERO_SPACE, - GICABLE_BIT_MARK, GICABLE_MIN_GAP, GICABLE_MIN_COMMAND_LENGTH, - data, nbits, 39, true, 0, // Repeats are handled later. + sendGeneric(kGicableHdrMark, kGicableHdrSpace, kGicableBitMark, + kGicableOneSpace, kGicableBitMark, kGicableZeroSpace, + kGicableBitMark, kGicableMinGap, kGicableMinCommandLength, data, + nbits, 39, true, 0, // Repeats are handled later. 50); // Message repeat sequence. if (repeat) - sendGeneric(GICABLE_HDR_MARK, GICABLE_RPT_SPACE, - 0, 0, 0, 0, // No actual data sent. - GICABLE_BIT_MARK, GICABLE_MIN_GAP, GICABLE_MIN_COMMAND_LENGTH, - 0, 0, // No data to be sent. + sendGeneric(kGicableHdrMark, kGicableRptSpace, 0, 0, 0, + 0, // No actual data sent. + kGicableBitMark, kGicableMinGap, kGicableMinCommandLength, 0, + 0, // No data to be sent. 39, true, repeat - 1, 50); } #endif // SEND_GICABLE @@ -64,7 +63,7 @@ void IRsend::sendGICable(uint64_t data, uint16_t nbits, uint16_t repeat) { // // Args: // results: Ptr to the data to decode and where to store the decode result. -// nbits: The number of data bits to expect. Typically GICABLE_BITS. +// nbits: The number of data bits to expect. Typically kGicableBits. // strict: Flag indicating if we should perform strict matching. // Returns: // boolean: True if it can decode it, false if it can't. @@ -72,40 +71,38 @@ void IRsend::sendGICable(uint64_t data, uint16_t nbits, uint16_t repeat) { // Status: Alpha / Not tested against a real device. bool IRrecv::decodeGICable(decode_results *results, uint16_t nbits, bool strict) { - if (results->rawlen < 2 * (nbits + HEADER + FOOTER) - 1) + if (results->rawlen < 2 * (nbits + kHeader + kFooter) - 1) return false; // Can't possibly be a valid GICABLE message. - if (strict && nbits != GICABLE_BITS) + if (strict && nbits != kGicableBits) return false; // Not strictly an GICABLE message. uint64_t data = 0; - uint16_t offset = OFFSET_START; + uint16_t offset = kStartOffset; // Header - if (!matchMark(results->rawbuf[offset++], GICABLE_HDR_MARK)) return false; - if (!matchSpace(results->rawbuf[offset++], GICABLE_HDR_SPACE)) return false; + if (!matchMark(results->rawbuf[offset++], kGicableHdrMark)) return false; + if (!matchSpace(results->rawbuf[offset++], kGicableHdrSpace)) return false; // Data - match_result_t data_result = matchData(&(results->rawbuf[offset]), nbits, - GICABLE_BIT_MARK, - GICABLE_ONE_SPACE, - GICABLE_BIT_MARK, - GICABLE_ZERO_SPACE); + match_result_t data_result = + matchData(&(results->rawbuf[offset]), nbits, kGicableBitMark, + kGicableOneSpace, kGicableBitMark, kGicableZeroSpace); if (data_result.success == false) return false; data = data_result.data; offset += data_result.used; // Footer - if (!matchMark(results->rawbuf[offset++], GICABLE_BIT_MARK)) return false; + if (!matchMark(results->rawbuf[offset++], kGicableBitMark)) return false; if (offset < results->rawlen && - !matchAtLeast(results->rawbuf[offset++], GICABLE_MIN_GAP)) + !matchAtLeast(results->rawbuf[offset++], kGicableMinGap)) return false; // Compliance if (strict) { // We expect a repeat frame. - if (!matchMark(results->rawbuf[offset++], GICABLE_HDR_MARK)) return false; - if (!matchSpace(results->rawbuf[offset++], GICABLE_RPT_SPACE)) return false; - if (!matchMark(results->rawbuf[offset++], GICABLE_BIT_MARK)) return false; + if (!matchMark(results->rawbuf[offset++], kGicableHdrMark)) return false; + if (!matchSpace(results->rawbuf[offset++], kGicableRptSpace)) return false; + if (!matchMark(results->rawbuf[offset++], kGicableBitMark)) return false; } // Success diff --git a/lib/IRremoteESP8266/src/ir_GlobalCache.cpp b/lib/IRremoteESP8266/src/ir_GlobalCache.cpp index bf0a82a..daa9dd2 100644 --- a/lib/IRremoteESP8266/src/ir_GlobalCache.cpp +++ b/lib/IRremoteESP8266/src/ir_GlobalCache.cpp @@ -14,12 +14,12 @@ // (http://www.hishamkhalifa.com) // Constants -#define GLOBALCACHE_MAX_REPEAT 50U -#define GLOBALCACHE_MIN_USEC 80U -#define GLOBALCACHE_FREQ_INDEX 0U -#define GLOBALCACHE_RPT_INDEX GLOBALCACHE_FREQ_INDEX + 1U -#define GLOBALCACHE_RPT_START_INDEX GLOBALCACHE_RPT_INDEX + 1U -#define GLOBALCACHE_START_INDEX GLOBALCACHE_RPT_START_INDEX + 1U +const uint16_t kGlobalCacheMaxRepeat = 50; +const uint32_t kGlobalCacheMinUsec = 80; +const uint8_t kGlobalCacheFreqIndex = 0; +const uint8_t kGlobalCacheRptIndex = kGlobalCacheFreqIndex + 1; +const uint8_t kGlobalCacheRptStartIndex = kGlobalCacheRptIndex + 1; +const uint8_t kGlobalCacheStartIndex = kGlobalCacheRptStartIndex + 1; #if SEND_GLOBALCACHE // Send a shortened GlobalCache (GC) IRdb/control tower formatted message. @@ -40,24 +40,23 @@ // Ref: // https://irdb.globalcache.com/Home/Database void IRsend::sendGC(uint16_t buf[], uint16_t len) { - uint16_t hz = buf[GLOBALCACHE_FREQ_INDEX]; // GC frequency is in Hz. + uint16_t hz = buf[kGlobalCacheFreqIndex]; // GC frequency is in Hz. enableIROut(hz); uint32_t periodic_time = calcUSecPeriod(hz, false); - uint8_t emits = std::min(buf[GLOBALCACHE_RPT_INDEX], - (uint16_t) GLOBALCACHE_MAX_REPEAT); + uint8_t emits = + std::min(buf[kGlobalCacheRptIndex], (uint16_t)kGlobalCacheMaxRepeat); // Repeat for (uint8_t repeat = 0; repeat < emits; repeat++) { - // First time through, start at the beginning (GLOBALCACHE_START_INDEX), + // First time through, start at the beginning (kGlobalCacheStartIndex), // otherwise for repeats, we start a specified offset from that. - uint16_t offset = GLOBALCACHE_START_INDEX; - if (repeat) - offset += buf[GLOBALCACHE_RPT_START_INDEX] - 1; + uint16_t offset = kGlobalCacheStartIndex; + if (repeat) offset += buf[kGlobalCacheRptStartIndex] - 1; // Data for (; offset < len; offset++) { // Convert periodic units to microseconds. - // Minimum is GLOBALCACHE_MIN_USEC for actual GC units. - uint32_t microseconds = std::max(buf[offset] * periodic_time, - GLOBALCACHE_MIN_USEC); + // Minimum is kGlobalCacheMinUsec for actual GC units. + uint32_t microseconds = + std::max(buf[offset] * periodic_time, kGlobalCacheMinUsec); // These codes start at an odd index (not even as with sendRaw). if (offset & 1) // Odd bit. mark(microseconds); diff --git a/lib/IRremoteESP8266/src/ir_Gree.cpp b/lib/IRremoteESP8266/src/ir_Gree.cpp index 885b06a..0740d5f 100644 --- a/lib/IRremoteESP8266/src/ir_Gree.cpp +++ b/lib/IRremoteESP8266/src/ir_Gree.cpp @@ -12,8 +12,8 @@ #ifndef ARDUINO #include #endif -#include "IRremoteESP8266.h" #include "IRrecv.h" +#include "IRremoteESP8266.h" #include "IRsend.h" #include "IRutils.h" #include "ir_Kelvinator.h" @@ -26,21 +26,21 @@ // Constants // Ref: https://github.com/ToniA/arduino-heatpumpir/blob/master/GreeHeatpumpIR.h -#define GREE_HDR_MARK 9000U -#define GREE_HDR_SPACE 4000U -#define GREE_BIT_MARK 620U -#define GREE_ONE_SPACE 1600U -#define GREE_ZERO_SPACE 540U -#define GREE_MSG_SPACE 19000U -#define GREE_BLOCK_FOOTER 0b010U -#define GREE_BLOCK_FOOTER_BITS 3U +const uint16_t kGreeHdrMark = 9000; +const uint16_t kGreeHdrSpace = 4000; +const uint16_t kGreeBitMark = 620; +const uint16_t kGreeOneSpace = 1600; +const uint16_t kGreeZeroSpace = 540; +const uint16_t kGreeMsgSpace = 19000; +const uint8_t kGreeBlockFooter = 0b010; +const uint8_t kGreeBlockFooterBits = 3; #if SEND_GREE // Send a Gree Heat Pump message. // // Args: // data: An array of bytes containing the IR command. -// nbytes: Nr. of bytes of data in the array. (>=GREE_STATE_LENGTH) +// nbytes: Nr. of bytes of data in the array. (>=kGreeStateLength) // repeat: Nr. of times the message is to be repeated. (Default = 0). // // Status: ALPHA / Untested. @@ -48,29 +48,24 @@ // Ref: // https://github.com/ToniA/arduino-heatpumpir/blob/master/GreeHeatpumpIR.cpp void IRsend::sendGree(unsigned char data[], uint16_t nbytes, uint16_t repeat) { - if (nbytes < GREE_STATE_LENGTH) + if (nbytes < kGreeStateLength) return; // Not enough bytes to send a proper message. for (uint16_t r = 0; r <= repeat; r++) { // Block #1 - sendGeneric(GREE_HDR_MARK, GREE_HDR_SPACE, - GREE_BIT_MARK, GREE_ONE_SPACE, - GREE_BIT_MARK, GREE_ZERO_SPACE, - 0, 0, // No Footer. + sendGeneric(kGreeHdrMark, kGreeHdrSpace, kGreeBitMark, kGreeOneSpace, + kGreeBitMark, kGreeZeroSpace, 0, 0, // No Footer. data, 4, 38, false, 0, 50); // Footer #1 sendGeneric(0, 0, // No Header - GREE_BIT_MARK, GREE_ONE_SPACE, - GREE_BIT_MARK, GREE_ZERO_SPACE, - GREE_BIT_MARK, GREE_MSG_SPACE, - 0b010, 3, 38, true, 0, false); + kGreeBitMark, kGreeOneSpace, kGreeBitMark, kGreeZeroSpace, + kGreeBitMark, kGreeMsgSpace, 0b010, 3, 38, true, 0, false); // Block #2 sendGeneric(0, 0, // No Header for Block #2 - GREE_BIT_MARK, GREE_ONE_SPACE, - GREE_BIT_MARK, GREE_ZERO_SPACE, - GREE_BIT_MARK, GREE_MSG_SPACE, - data + 4, nbytes - 4, 38, false, 0, 50); + kGreeBitMark, kGreeOneSpace, kGreeBitMark, kGreeZeroSpace, + kGreeBitMark, kGreeMsgSpace, data + 4, nbytes - 4, 38, false, 0, + 50); } } @@ -78,7 +73,7 @@ void IRsend::sendGree(unsigned char data[], uint16_t nbytes, uint16_t repeat) { // // Args: // data: The raw message to be sent. -// nbits: Nr. of bits of data in the message. (Default is GREE_BITS) +// nbits: Nr. of bits of data in the message. (Default is kGreeBits) // repeat: Nr. of times the message is to be repeated. (Default = 0). // // Status: ALPHA / Untested. @@ -86,43 +81,40 @@ void IRsend::sendGree(unsigned char data[], uint16_t nbytes, uint16_t repeat) { // Ref: // https://github.com/ToniA/arduino-heatpumpir/blob/master/GreeHeatpumpIR.cpp void IRsend::sendGree(uint64_t data, uint16_t nbits, uint16_t repeat) { - if (nbits != GREE_BITS) + if (nbits != kGreeBits) return; // Wrong nr. of bits to send a proper message. // Set IR carrier frequency enableIROut(38); for (uint16_t r = 0; r <= repeat; r++) { // Header - mark(GREE_HDR_MARK); - space(GREE_HDR_SPACE); + mark(kGreeHdrMark); + space(kGreeHdrSpace); // Data for (int16_t i = 8; i <= nbits; i += 8) { - sendData(GREE_BIT_MARK, GREE_ONE_SPACE, GREE_BIT_MARK, GREE_ZERO_SPACE, + sendData(kGreeBitMark, kGreeOneSpace, kGreeBitMark, kGreeZeroSpace, (data >> (nbits - i)) & 0xFF, 8, false); if (i == nbits / 2) { // Send the mid-message Footer. - sendData(GREE_BIT_MARK, GREE_ONE_SPACE, GREE_BIT_MARK, GREE_ZERO_SPACE, + sendData(kGreeBitMark, kGreeOneSpace, kGreeBitMark, kGreeZeroSpace, 0b010, 3); - mark(GREE_BIT_MARK); - space(GREE_MSG_SPACE); + mark(kGreeBitMark); + space(kGreeMsgSpace); } } // Footer - mark(GREE_BIT_MARK); - space(GREE_MSG_SPACE); + mark(kGreeBitMark); + space(kGreeMsgSpace); } } #endif // SEND_GREE -IRGreeAC::IRGreeAC(uint16_t pin) : _irsend(pin) { - stateReset(); -} +IRGreeAC::IRGreeAC(uint16_t pin) : _irsend(pin) { stateReset(); } void IRGreeAC::stateReset() { // This resets to a known-good state to Power Off, Fan Auto, Mode Auto, 25C. - for (uint8_t i = 0; i < GREE_STATE_LENGTH; i++) - remote_state[i] = 0x0; + for (uint8_t i = 0; i < kGreeStateLength; i++) remote_state[i] = 0x0; remote_state[1] = 0x09; remote_state[2] = 0x20; remote_state[3] = 0x50; @@ -134,24 +126,22 @@ void IRGreeAC::fixup() { checksum(); // Calculate the checksums } -void IRGreeAC::begin() { - _irsend.begin(); -} +void IRGreeAC::begin() { _irsend.begin(); } #if SEND_GREE -void IRGreeAC::send() { - fixup(); // Ensure correct settings before sending. - _irsend.sendGree(remote_state); +void IRGreeAC::send(const uint16_t repeat) { + fixup(); // Ensure correct settings before sending. + _irsend.sendGree(remote_state, kGreeStateLength, repeat); } #endif // SEND_GREE uint8_t* IRGreeAC::getRaw() { - fixup(); // Ensure correct settings before sending. + fixup(); // Ensure correct settings before sending. return remote_state; } void IRGreeAC::setRaw(uint8_t new_code[]) { - for (uint8_t i = 0; i < GREE_STATE_LENGTH; i++) { + for (uint8_t i = 0; i < kGreeStateLength; i++) { remote_state[i] = new_code[i]; } } @@ -170,21 +160,21 @@ void IRGreeAC::checksum(const uint16_t length) { // A boolean. bool IRGreeAC::validChecksum(const uint8_t state[], const uint16_t length) { // Top 4 bits of the last byte in the state is the state's checksum. - if (state[length - 1] >> 4 == IRKelvinatorAC::calcBlockChecksum(state, - length)) + if (state[length - 1] >> 4 == + IRKelvinatorAC::calcBlockChecksum(state, length)) return true; else return false; } void IRGreeAC::on() { - remote_state[0] |= GREE_POWER1_MASK; - remote_state[2] |= GREE_POWER2_MASK; + remote_state[0] |= kGreePower1Mask; + remote_state[2] |= kGreePower2Mask; } void IRGreeAC::off() { - remote_state[0] &= ~GREE_POWER1_MASK; - remote_state[2] &= ~GREE_POWER2_MASK; + remote_state[0] &= ~kGreePower1Mask; + remote_state[2] &= ~kGreePower2Mask; } void IRGreeAC::setPower(const bool state) { @@ -195,136 +185,124 @@ void IRGreeAC::setPower(const bool state) { } bool IRGreeAC::getPower() { - return (remote_state[0] & GREE_POWER1_MASK) && - (remote_state[2] & GREE_POWER2_MASK); + return (remote_state[0] & kGreePower1Mask) && + (remote_state[2] & kGreePower2Mask); } // Set the temp. in deg C void IRGreeAC::setTemp(const uint8_t temp) { - uint8_t new_temp = std::max((uint8_t) GREE_MIN_TEMP, temp); - new_temp = std::min((uint8_t) GREE_MAX_TEMP, new_temp); - if (getMode() == GREE_AUTO) new_temp = 25; - remote_state[1] = (remote_state[1] & 0xF0U) | (new_temp - GREE_MIN_TEMP); + uint8_t new_temp = std::max((uint8_t)kGreeMinTemp, temp); + new_temp = std::min((uint8_t)kGreeMaxTemp, new_temp); + if (getMode() == kGreeAuto) new_temp = 25; + remote_state[1] = (remote_state[1] & 0xF0U) | (new_temp - kGreeMinTemp); } // Return the set temp. in deg C uint8_t IRGreeAC::getTemp() { - return ((remote_state[1] & 0xFU) + GREE_MIN_TEMP); + return ((remote_state[1] & 0xFU) + kGreeMinTemp); } // Set the speed of the fan, 0-3, 0 is auto, 1-3 is the speed void IRGreeAC::setFan(const uint8_t speed) { - uint8_t fan = std::min((uint8_t) GREE_FAN_MAX, speed); // Bounds check + uint8_t fan = std::min((uint8_t)kGreeFanMax, speed); // Bounds check - if (getMode() == GREE_DRY) fan = 1; // DRY mode is always locked to fan 1. + if (getMode() == kGreeDry) fan = 1; // DRY mode is always locked to fan 1. // Set the basic fan values. - remote_state[0] &= ~GREE_FAN_MASK; + remote_state[0] &= ~kGreeFanMask; remote_state[0] |= (fan << 4); } -uint8_t IRGreeAC::getFan() { - return ((remote_state[0] & GREE_FAN_MASK) >> 4); -} +uint8_t IRGreeAC::getFan() { return ((remote_state[0] & kGreeFanMask) >> 4); } void IRGreeAC::setMode(const uint8_t new_mode) { uint8_t mode = new_mode; switch (mode) { - case GREE_AUTO: + case kGreeAuto: // AUTO is locked to 25C setTemp(25); break; - case GREE_DRY: + case kGreeDry: // DRY always sets the fan to 1. setFan(1); break; - case GREE_COOL: - case GREE_FAN: - case GREE_HEAT: + case kGreeCool: + case kGreeFan: + case kGreeHeat: break; default: // If we get an unexpected mode, default to AUTO. - mode = GREE_AUTO; + mode = kGreeAuto; } - remote_state[0] &= ~GREE_MODE_MASK; + remote_state[0] &= ~kGreeModeMask; remote_state[0] |= mode; } -uint8_t IRGreeAC::getMode() { - return (remote_state[0] & GREE_MODE_MASK); -} +uint8_t IRGreeAC::getMode() { return (remote_state[0] & kGreeModeMask); } void IRGreeAC::setLight(const bool state) { - remote_state[2] &= ~GREE_LIGHT_MASK; + remote_state[2] &= ~kGreeLightMask; remote_state[2] |= (state << 5); } -bool IRGreeAC::getLight() { - return remote_state[2] & GREE_LIGHT_MASK; -} +bool IRGreeAC::getLight() { return remote_state[2] & kGreeLightMask; } void IRGreeAC::setXFan(const bool state) { - remote_state[2] &= ~GREE_XFAN_MASK; + remote_state[2] &= ~kGreeXfanMask; remote_state[2] |= (state << 7); } -bool IRGreeAC::getXFan() { - return remote_state[2] & GREE_XFAN_MASK; -} +bool IRGreeAC::getXFan() { return remote_state[2] & kGreeXfanMask; } void IRGreeAC::setSleep(const bool state) { - remote_state[0] &= ~GREE_SLEEP_MASK; + remote_state[0] &= ~kGreeSleepMask; remote_state[0] |= (state << 7); } -bool IRGreeAC::getSleep() { - return remote_state[0] & GREE_SLEEP_MASK; -} +bool IRGreeAC::getSleep() { return remote_state[0] & kGreeSleepMask; } void IRGreeAC::setTurbo(const bool state) { - remote_state[2] &= ~GREE_TURBO_MASK; + remote_state[2] &= ~kGreeTurboMask; remote_state[2] |= (state << 4); } -bool IRGreeAC::getTurbo() { - return remote_state[2] & GREE_TURBO_MASK; -} +bool IRGreeAC::getTurbo() { return remote_state[2] & kGreeTurboMask; } void IRGreeAC::setSwingVertical(const bool automatic, const uint8_t position) { - remote_state[0] &= ~GREE_SWING_AUTO_MASK; + remote_state[0] &= ~kGreeSwingAutoMask; remote_state[0] |= (automatic << 6); uint8_t new_position = position; if (!automatic) { switch (position) { - case GREE_SWING_UP: - case GREE_SWING_MIDDLE_UP: - case GREE_SWING_MIDDLE: - case GREE_SWING_MIDDLE_DOWN: - case GREE_SWING_DOWN: + case kGreeSwingUp: + case kGreeSwingMiddleUp: + case kGreeSwingMiddle: + case kGreeSwingMiddleDown: + case kGreeSwingDown: break; default: - new_position = GREE_SWING_LAST_POS; + new_position = kGreeSwingLastPos; } } else { switch (position) { - case GREE_SWING_AUTO: - case GREE_SWING_DOWN_AUTO: - case GREE_SWING_MIDDLE_AUTO: - case GREE_SWING_UP_AUTO: + case kGreeSwingAuto: + case kGreeSwingDownAuto: + case kGreeSwingMiddleAuto: + case kGreeSwingUpAuto: break; default: - new_position = GREE_SWING_AUTO; + new_position = kGreeSwingAuto; } } - remote_state[4] &= ~GREE_SWING_POS_MASK; + remote_state[4] &= ~kGreeSwingPosMask; remote_state[4] |= new_position; } bool IRGreeAC::getSwingVerticalAuto() { - return remote_state[0] & GREE_SWING_AUTO_MASK; + return remote_state[0] & kGreeSwingAutoMask; } uint8_t IRGreeAC::getSwingVerticalPosition() { - return remote_state[4] & GREE_SWING_POS_MASK; + return remote_state[4] & kGreeSwingPosMask; } // Convert the internal state into a human readable string. @@ -342,19 +320,19 @@ std::string IRGreeAC::toString() { result += "Off"; result += ", Mode: " + uint64ToString(getMode()); switch (getMode()) { - case GREE_AUTO: + case kGreeAuto: result += " (AUTO)"; break; - case GREE_COOL: + case kGreeCool: result += " (COOL)"; break; - case GREE_HEAT: + case kGreeHeat: result += " (HEAT)"; break; - case GREE_DRY: + case kGreeDry: result += " (DRY)"; break; - case GREE_FAN: + case kGreeFan: result += " (FAN)"; break; default: @@ -366,7 +344,7 @@ std::string IRGreeAC::toString() { case 0: result += " (AUTO)"; break; - case GREE_FAN_MAX: + case kGreeFanMax: result += " (MAX)"; break; } @@ -395,13 +373,13 @@ std::string IRGreeAC::toString() { result += "Auto"; else result += "Manual"; - result += ", Swing Vertical Pos: " + - uint64ToString(getSwingVerticalPosition()); + result += + ", Swing Vertical Pos: " + uint64ToString(getSwingVerticalPosition()); switch (getSwingVerticalPosition()) { - case GREE_SWING_LAST_POS: + case kGreeSwingLastPos: result += " (Last Pos)"; break; - case GREE_SWING_AUTO: + case kGreeSwingAuto: result += " (Auto)"; break; } @@ -413,21 +391,21 @@ std::string IRGreeAC::toString() { // // Args: // results: Ptr to the data to decode and where to store the decode result. -// nbits: The number of data bits to expect. Typically GREE_BITS. +// nbits: The number of data bits to expect. Typically kGreeBits. // strict: Flag indicating if we should perform strict matching. // Returns: // boolean: True if it can decode it, false if it can't. // // Status: ALPHA / Untested. -bool IRrecv::decodeGree(decode_results *results, uint16_t nbits, bool strict) { - if (results->rawlen < 2 * (nbits + GREE_BLOCK_FOOTER_BITS) + - (HEADER + FOOTER + 1)) +bool IRrecv::decodeGree(decode_results* results, uint16_t nbits, bool strict) { + if (results->rawlen < + 2 * (nbits + kGreeBlockFooterBits) + (kHeader + kFooter + 1)) return false; // Can't possibly be a valid Gree message. - if (strict && nbits != GREE_BITS) + if (strict && nbits != kGreeBits) return false; // Not strictly a Gree message. uint32_t data; - uint16_t offset = OFFSET_START; + uint16_t offset = kStartOffset; // There are two blocks back-to-back in a full Gree IR message // sequence. @@ -435,54 +413,56 @@ bool IRrecv::decodeGree(decode_results *results, uint16_t nbits, bool strict) { match_result_t data_result; // Header - if (!matchMark(results->rawbuf[offset++], GREE_HDR_MARK)) return false; - if (!matchSpace(results->rawbuf[offset++], GREE_HDR_SPACE)) return false; + if (!matchMark(results->rawbuf[offset++], kGreeHdrMark)) return false; + if (!matchSpace(results->rawbuf[offset++], kGreeHdrSpace)) return false; // Data Block #1 (32 bits) - data_result = matchData(&(results->rawbuf[offset]), 32, GREE_BIT_MARK, - GREE_ONE_SPACE, GREE_BIT_MARK, GREE_ZERO_SPACE); + data_result = + matchData(&(results->rawbuf[offset]), 32, kGreeBitMark, kGreeOneSpace, + kGreeBitMark, kGreeZeroSpace, kTolerance, kMarkExcess, false); if (data_result.success == false) return false; data = data_result.data; offset += data_result.used; // Record Data Block #1 in the state. - for (int i = state_pos + 3; i >= state_pos; i--, data >>= 8) - results->state[i] = reverseBits(data & 0xFF, 8); + for (uint16_t i = 0; i < 4; i++, data >>= 8) + results->state[state_pos + i] = data & 0xFF; state_pos += 4; // Block #1 footer (3 bits, B010) - data_result = matchData(&(results->rawbuf[offset]), GREE_BLOCK_FOOTER_BITS, - GREE_BIT_MARK, GREE_ONE_SPACE, GREE_BIT_MARK, - GREE_ZERO_SPACE); + data_result = matchData(&(results->rawbuf[offset]), kGreeBlockFooterBits, + kGreeBitMark, kGreeOneSpace, kGreeBitMark, + kGreeZeroSpace, kTolerance, kMarkExcess, false); if (data_result.success == false) return false; - if (data_result.data != GREE_BLOCK_FOOTER) return false; + if (data_result.data != kGreeBlockFooter) return false; offset += data_result.used; // Inter-block gap. - if (!matchMark(results->rawbuf[offset++], GREE_BIT_MARK)) return false; - if (!matchSpace(results->rawbuf[offset++], GREE_MSG_SPACE)) return false; + if (!matchMark(results->rawbuf[offset++], kGreeBitMark)) return false; + if (!matchSpace(results->rawbuf[offset++], kGreeMsgSpace)) return false; // Data Block #2 (32 bits) - data_result = matchData(&(results->rawbuf[offset]), 32, GREE_BIT_MARK, - GREE_ONE_SPACE, GREE_BIT_MARK, GREE_ZERO_SPACE); + data_result = + matchData(&(results->rawbuf[offset]), 32, kGreeBitMark, kGreeOneSpace, + kGreeBitMark, kGreeZeroSpace, kTolerance, kMarkExcess, false); if (data_result.success == false) return false; data = data_result.data; offset += data_result.used; // Record Data Block #2 in the state. - for (int i = state_pos + 3; i >= state_pos; i--, data >>= 8) - results->state[i] = reverseBits(data & 0xFF, 8); + for (uint16_t i = 0; i < 4; i++, data >>= 8) + results->state[state_pos + i] = data & 0xFF; state_pos += 4; // Footer. - if (!matchMark(results->rawbuf[offset++], GREE_BIT_MARK)) return false; + if (!matchMark(results->rawbuf[offset++], kGreeBitMark)) return false; if (offset <= results->rawlen && - !matchAtLeast(results->rawbuf[offset], GREE_MSG_SPACE)) + !matchAtLeast(results->rawbuf[offset], kGreeMsgSpace)) return false; // Compliance if (strict) { // Correct size/length) - if (state_pos != GREE_STATE_LENGTH) return false; + if (state_pos != kGreeStateLength) return false; // Verify the message's checksum is correct. if (!IRGreeAC::validChecksum(results->state)) return false; } diff --git a/lib/IRremoteESP8266/src/ir_Gree.h b/lib/IRremoteESP8266/src/ir_Gree.h index e44c97b..489cefb 100644 --- a/lib/IRremoteESP8266/src/ir_Gree.h +++ b/lib/IRremoteESP8266/src/ir_Gree.h @@ -22,36 +22,60 @@ // GGGGGG RR RR EEEEEEE EEEEEEE // Constants -#define GREE_AUTO 0U -#define GREE_COOL 1U -#define GREE_DRY 2U -#define GREE_FAN 3U -#define GREE_HEAT 4U +const uint8_t kGreeAuto = 0; +const uint8_t kGreeCool = 1; +const uint8_t kGreeDry = 2; +const uint8_t kGreeFan = 3; +const uint8_t kGreeHeat = 4; -#define GREE_POWER1_MASK 0b00001000U -#define GREE_POWER2_MASK 0b01000000U -#define GREE_MIN_TEMP 16U // Celsius -#define GREE_MAX_TEMP 30U // Celsius -#define GREE_FAN_MAX 3U -#define GREE_FAN_MASK 0b00110000U -#define GREE_MODE_MASK 0b00000111U -#define GREE_TURBO_MASK 0b00010000U -#define GREE_LIGHT_MASK 0b00100000U -#define GREE_XFAN_MASK 0b10000000U -#define GREE_SLEEP_MASK 0b10000000U +// Byte 0 +const uint8_t kGreeModeMask = 0b00000111; +const uint8_t kGreePower1Mask = 0b00001000; +const uint8_t kGreeFanMask = 0b00110000; +const uint8_t kGreeSwingAutoMask = 0b01000000; +const uint8_t kGreeSleepMask = 0b10000000; +// Byte 2 +const uint8_t kGreeTurboMask = 0b00010000; +const uint8_t kGreeLightMask = 0b00100000; +const uint8_t kGreePower2Mask = 0b01000000; +const uint8_t kGreeXfanMask = 0b10000000; +// Byte 4 +const uint8_t kGreeSwingPosMask = 0b00001111; -#define GREE_SWING_AUTO_MASK 0b01000000U -#define GREE_SWING_POS_MASK 0b00001111U -#define GREE_SWING_LAST_POS 0b00000000U -#define GREE_SWING_AUTO 0b00000001U -#define GREE_SWING_UP 0b00000010U -#define GREE_SWING_MIDDLE_UP 0b00000011U -#define GREE_SWING_MIDDLE 0b00000100U -#define GREE_SWING_MIDDLE_DOWN 0b00000101U -#define GREE_SWING_DOWN 0b00000110U -#define GREE_SWING_DOWN_AUTO 0b00000111U -#define GREE_SWING_MIDDLE_AUTO 0b00001001U -#define GREE_SWING_UP_AUTO 0b00001011U +const uint8_t kGreeMinTemp = 16; // Celsius +const uint8_t kGreeMaxTemp = 30; // Celsius +const uint8_t kGreeFanMax = 3; + +const uint8_t kGreeSwingLastPos = 0b00000000; +const uint8_t kGreeSwingAuto = 0b00000001; +const uint8_t kGreeSwingUp = 0b00000010; +const uint8_t kGreeSwingMiddleUp = 0b00000011; +const uint8_t kGreeSwingMiddle = 0b00000100; +const uint8_t kGreeSwingMiddleDown = 0b00000101; +const uint8_t kGreeSwingDown = 0b00000110; +const uint8_t kGreeSwingDownAuto = 0b00000111; +const uint8_t kGreeSwingMiddleAuto = 0b00001001; +const uint8_t kGreeSwingUpAuto = 0b00001011; + +// Legacy defines. +#define GREE_AUTO kGreeAuto +#define GREE_COOL kGreeCool +#define GREE_DRY kGreeDry +#define GREE_FAN kGreeFan +#define GREE_HEAT kGreeHeat +#define GREE_MIN_TEMP kGreeMinTemp +#define GREE_MAX_TEMP kGreeMaxTemp +#define GREE_FAN_MAX kGreeFanMax +#define GREE_SWING_LAST_POS kGreeSwingLastPos +#define GREE_SWING_AUTO kGreeSwingAuto +#define GREE_SWING_UP kGreeSwingUp +#define GREE_SWING_MIDDLE_UP kGreeSwingMiddleUp +#define GREE_SWING_MIDDLE kGreeSwingMiddle +#define GREE_SWING_MIDDLE_DOWN kGreeSwingMiddleDown +#define GREE_SWING_DOWN kGreeSwingDown +#define GREE_SWING_DOWN_AUTO kGreeSwingDownAuto +#define GREE_SWING_MIDDLE_AUTO kGreeSwingMiddleAuto +#define GREE_SWING_UP_AUTO kGreeSwingUpAuto // Classes class IRGreeAC { @@ -60,7 +84,7 @@ class IRGreeAC { void stateReset(); #if SEND_GREE - void send(); + void send(const uint16_t repeat = kGreeDefaultRepeat); #endif // SEND_GREE void begin(); void on(); @@ -88,7 +112,7 @@ class IRGreeAC { uint8_t* getRaw(); void setRaw(uint8_t new_code[]); static bool validChecksum(const uint8_t state[], - const uint16_t length = GREE_STATE_LENGTH); + const uint16_t length = kGreeStateLength); #ifdef ARDUINO String toString(); #else @@ -97,8 +121,8 @@ class IRGreeAC { private: // The state of the IR remote in IR code form. - uint8_t remote_state[GREE_STATE_LENGTH]; - void checksum(const uint16_t length = GREE_STATE_LENGTH); + uint8_t remote_state[kGreeStateLength]; + void checksum(const uint16_t length = kGreeStateLength); void fixup(); IRsend _irsend; }; diff --git a/lib/IRremoteESP8266/src/ir_Haier.cpp b/lib/IRremoteESP8266/src/ir_Haier.cpp index ae5a44a..719e8c5 100644 --- a/lib/IRremoteESP8266/src/ir_Haier.cpp +++ b/lib/IRremoteESP8266/src/ir_Haier.cpp @@ -1,5 +1,7 @@ // Copyright 2018 crankyoldgit -// The specifics of reverse engineering the protocol details by kuzin2006 +// The specifics of reverse engineering the protocols details: +// * HSU07-HEA03 by kuzin2006. +// * YR-W02/HSU-09HMC203 by non7top. #include "ir_Haier.h" #ifndef UNIT_TEST @@ -18,83 +20,96 @@ // Supported devices: // * Haier HSU07-HEA03 Remote control. +// * Haier YR-W02 Remote control +// * Haier HSU-09HMC203 A/C unit. // Ref: // https://github.com/markszabo/IRremoteESP8266/issues/404 // https://www.dropbox.com/s/mecyib3lhdxc8c6/IR%20data%20reverse%20engineering.xlsx?dl=0 +// https://github.com/markszabo/IRremoteESP8266/issues/485 +// https://www.dropbox.com/sh/w0bt7egp0fjger5/AADRFV6Wg4wZskJVdFvzb8Z0a?dl=0&preview=haer2.ods // Constants -#define HAIER_AC_HDR 3000U -#define HAIER_AC_HDR_GAP 4300U +const uint16_t kHaierAcHdr = 3000; +const uint16_t kHaierAcHdrGap = 4300; +const uint16_t kHaierAcBitMark = 520; +const uint16_t kHaierAcOneSpace = 1650; +const uint16_t kHaierAcZeroSpace = 650; +const uint32_t kHaierAcMinGap = 150000; // Completely made up value. -#define HAIER_AC_BIT_MARK 520U -#define HAIER_AC_ONE_SPACE 1650U -#define HAIER_AC_ZERO_SPACE 650U -#define HAIER_AC_MIN_GAP 150000U // Completely made up value. - -#if SEND_HAIER_AC -// Send a Haier A/C message. +#if (SEND_HAIER_AC || SEND_HAIER_AC_YRW02) +// Send a Haier A/C message. (HSU07-HEA03 remote) // // Args: // data: An array of bytes containing the IR command. -// nbytes: Nr. of bytes of data in the array. (>=HAIER_AC_STATE_LENGTH) +// nbytes: Nr. of bytes of data in the array. (>=kHaierACStateLength) // repeat: Nr. of times the message is to be repeated. (Default = 0). // // Status: Beta / Probably working. // void IRsend::sendHaierAC(unsigned char data[], uint16_t nbytes, uint16_t repeat) { - if (nbytes < HAIER_AC_STATE_LENGTH) - return; + if (nbytes < kHaierACStateLength) return; for (uint16_t r = 0; r <= repeat; r++) { enableIROut(38000); - mark(HAIER_AC_HDR); - space(HAIER_AC_HDR); - sendGeneric(HAIER_AC_HDR, HAIER_AC_HDR_GAP, - HAIER_AC_BIT_MARK, HAIER_AC_ONE_SPACE, - HAIER_AC_BIT_MARK, HAIER_AC_ZERO_SPACE, - HAIER_AC_BIT_MARK, HAIER_AC_MIN_GAP, - data, nbytes, 38, true, 0, // Repeats handled elsewhere + mark(kHaierAcHdr); + space(kHaierAcHdr); + sendGeneric(kHaierAcHdr, kHaierAcHdrGap, kHaierAcBitMark, kHaierAcOneSpace, + kHaierAcBitMark, kHaierAcZeroSpace, kHaierAcBitMark, + kHaierAcMinGap, data, nbytes, 38, true, + 0, // Repeats handled elsewhere 50); } } -#endif // SEND_HAIER_AC +#endif // (SEND_HAIER_AC || SEND_HAIER_AC_YRW02) -IRHaierAC::IRHaierAC(uint16_t pin) : _irsend(pin) { - stateReset(); +#if SEND_HAIER_AC_YRW02 +// Send a Haier YR-W02 remote A/C message. +// +// Args: +// data: An array of bytes containing the IR command. +// nbytes: Nr. of bytes of data in the array. (>=kHaierACYRW02StateLength) +// repeat: Nr. of times the message is to be repeated. (Default = 0). +// +// Status: Alpha / Untested on a real device. +// +void IRsend::sendHaierACYRW02(unsigned char data[], uint16_t nbytes, + uint16_t repeat) { + if (nbytes >= kHaierACYRW02StateLength) sendHaierAC(data, nbytes, repeat); } +#endif // SEND_HAIER_AC_YRW02 -void IRHaierAC::begin() { - _irsend.begin(); -} +// Class for emulating a Haier HSU07-HEA03 remote +IRHaierAC::IRHaierAC(uint16_t pin) : _irsend(pin) { stateReset(); } + +void IRHaierAC::begin() { _irsend.begin(); } #if SEND_HAIER_AC -void IRHaierAC::send() { +void IRHaierAC::send(const uint16_t repeat) { checksum(); - _irsend.sendHaierAC(remote_state); + _irsend.sendHaierAC(remote_state, kHaierACStateLength, repeat); } #endif // SEND_HAIER_AC void IRHaierAC::checksum() { - remote_state[8] = sumBytes(remote_state, HAIER_AC_STATE_LENGTH - 1); + remote_state[8] = sumBytes(remote_state, kHaierACStateLength - 1); } bool IRHaierAC::validChecksum(uint8_t state[], const uint16_t length) { - if (length < 2) return false; // 1 byte of data can't have a checksum. + if (length < 2) return false; // 1 byte of data can't have a checksum. return (state[length - 1] == sumBytes(state, length - 1)); } void IRHaierAC::stateReset() { - for (uint8_t i = 1; i < HAIER_AC_STATE_LENGTH; i++) - remote_state[i] = 0x0; - remote_state[0] = HAIER_AC_PREFIX; + for (uint8_t i = 1; i < kHaierACStateLength; i++) remote_state[i] = 0x0; + remote_state[0] = kHaierAcPrefix; remote_state[2] = 0b00100000; - setTemp(HAIER_AC_DEF_TEMP); - setFan(HAIER_AC_FAN_AUTO); - setMode(HAIER_AC_AUTO); - setCommand(HAIER_AC_CMD_ON); + setTemp(kHaierAcDefTemp); + setFan(kHaierAcFanAuto); + setMode(kHaierAcAuto); + setCommand(kHaierAcCmdOn); } uint8_t* IRHaierAC::getRaw() { @@ -103,7 +118,7 @@ uint8_t* IRHaierAC::getRaw() { } void IRHaierAC::setRaw(uint8_t new_code[]) { - for (uint8_t i = 0; i < HAIER_AC_STATE_LENGTH; i++) { + for (uint8_t i = 0; i < kHaierACStateLength; i++) { remote_state[i] = new_code[i]; } } @@ -111,42 +126,40 @@ void IRHaierAC::setRaw(uint8_t new_code[]) { void IRHaierAC::setCommand(uint8_t state) { remote_state[1] &= 0b11110000; switch (state) { - case HAIER_AC_CMD_OFF: - case HAIER_AC_CMD_ON: - case HAIER_AC_CMD_MODE: - case HAIER_AC_CMD_FAN: - case HAIER_AC_CMD_TEMP_UP: - case HAIER_AC_CMD_TEMP_DOWN: - case HAIER_AC_CMD_SLEEP: - case HAIER_AC_CMD_TIMER_SET: - case HAIER_AC_CMD_TIMER_CANCEL: - case HAIER_AC_CMD_HEALTH: - case HAIER_AC_CMD_SWING: + case kHaierAcCmdOff: + case kHaierAcCmdOn: + case kHaierAcCmdMode: + case kHaierAcCmdFan: + case kHaierAcCmdTempUp: + case kHaierAcCmdTempDown: + case kHaierAcCmdSleep: + case kHaierAcCmdTimerSet: + case kHaierAcCmdTimerCancel: + case kHaierAcCmdHealth: + case kHaierAcCmdSwing: remote_state[1] |= (state & 0b00001111); } } -uint8_t IRHaierAC::getCommand() { - return remote_state[1] & (0b00001111); -} +uint8_t IRHaierAC::getCommand() { return remote_state[1] & (0b00001111); } void IRHaierAC::setFan(uint8_t speed) { - uint8_t new_speed = HAIER_AC_FAN_AUTO; + uint8_t new_speed = kHaierAcFanAuto; switch (speed) { - case HAIER_AC_FAN_LOW: + case kHaierAcFanLow: new_speed = 3; break; - case HAIER_AC_FAN_MED: + case kHaierAcFanMed: new_speed = 1; break; - case HAIER_AC_FAN_HIGH: + case kHaierAcFanHigh: new_speed = 2; break; default: - new_speed = HAIER_AC_FAN_AUTO; // Default to auto for anything else. + new_speed = kHaierAcFanAuto; // Default to auto for anything else. } - if (speed != getFan()) setCommand(HAIER_AC_CMD_FAN); + if (speed != getFan()) setCommand(kHaierAcCmdFan); remote_state[5] &= 0b11111100; remote_state[5] |= new_speed; } @@ -154,70 +167,64 @@ void IRHaierAC::setFan(uint8_t speed) { uint8_t IRHaierAC::getFan() { switch (remote_state[5] & 0b00000011) { case 1: - return HAIER_AC_FAN_MED; + return kHaierAcFanMed; case 2: - return HAIER_AC_FAN_HIGH; + return kHaierAcFanHigh; case 3: - return HAIER_AC_FAN_LOW; + return kHaierAcFanLow; default: - return HAIER_AC_FAN_AUTO; + return kHaierAcFanAuto; } } void IRHaierAC::setMode(uint8_t mode) { uint8_t new_mode = mode; - setCommand(HAIER_AC_CMD_MODE); - if (mode > HAIER_AC_FAN) // If out of range, default to auto mode. - new_mode = HAIER_AC_AUTO; + setCommand(kHaierAcCmdMode); + if (mode > kHaierAcFan) // If out of range, default to auto mode. + new_mode = kHaierAcAuto; remote_state[7] &= 0b00011111; remote_state[7] |= (new_mode << 5); } -uint8_t IRHaierAC::getMode() { - return (remote_state[7] & 0b11100000) >> 5; -} +uint8_t IRHaierAC::getMode() { return (remote_state[7] & 0b11100000) >> 5; } -void IRHaierAC::setTemp(const uint8_t celcius ) { - uint8_t temp = celcius; - if (temp < HAIER_AC_MIN_TEMP) - temp = HAIER_AC_MIN_TEMP; - else if (temp > HAIER_AC_MAX_TEMP) - temp = HAIER_AC_MAX_TEMP; +void IRHaierAC::setTemp(const uint8_t celsius) { + uint8_t temp = celsius; + if (temp < kHaierAcMinTemp) + temp = kHaierAcMinTemp; + else if (temp > kHaierAcMaxTemp) + temp = kHaierAcMaxTemp; uint8_t old_temp = getTemp(); - if (old_temp == temp) return; + if (old_temp == temp) return; if (old_temp > temp) - setCommand(HAIER_AC_CMD_TEMP_DOWN); + setCommand(kHaierAcCmdTempDown); else - setCommand(HAIER_AC_CMD_TEMP_UP); + setCommand(kHaierAcCmdTempUp); remote_state[1] &= 0b00001111; // Clear the previous temp. - remote_state[1] |= ((temp - HAIER_AC_MIN_TEMP) << 4); + remote_state[1] |= ((temp - kHaierAcMinTemp) << 4); } uint8_t IRHaierAC::getTemp() { - return ((remote_state[1] & 0b11110000) >> 4) + HAIER_AC_MIN_TEMP; + return ((remote_state[1] & 0b11110000) >> 4) + kHaierAcMinTemp; } void IRHaierAC::setHealth(bool state) { - setCommand(HAIER_AC_CMD_HEALTH); + setCommand(kHaierAcCmdHealth); remote_state[4] &= 0b11011111; remote_state[4] |= (state << 5); } -bool IRHaierAC::getHealth(void) { - return remote_state[4] & (1 << 5); -} +bool IRHaierAC::getHealth(void) { return remote_state[4] & (1 << 5); } void IRHaierAC::setSleep(bool state) { - setCommand(HAIER_AC_CMD_SLEEP); + setCommand(kHaierAcCmdSleep); remote_state[7] &= 0b10111111; remote_state[7] |= (state << 6); } -bool IRHaierAC::getSleep(void) { - return remote_state[7] & 0b01000000; -} +bool IRHaierAC::getSleep(void) { return remote_state[7] & 0b01000000; } uint16_t IRHaierAC::getTime(const uint8_t ptr[]) { return (ptr[0] & 0b00011111) * 60 + (ptr[1] & 0b00111111); @@ -237,16 +244,13 @@ int16_t IRHaierAC::getOffTimer() { return -1; } -uint16_t IRHaierAC::getCurrTime() { - return getTime(remote_state + 2); -} +uint16_t IRHaierAC::getCurrTime() { return getTime(remote_state + 2); } void IRHaierAC::setTime(uint8_t ptr[], const uint16_t nr_mins) { uint16_t mins = nr_mins; - if (nr_mins > HAIER_AC_MAX_TIME) - mins = HAIER_AC_MAX_TIME; + if (nr_mins > kHaierAcMaxTime) mins = kHaierAcMaxTime; - // Hours + // Hours ptr[0] &= 0b11100000; ptr[0] |= (mins / 60); // Minutes @@ -255,19 +259,19 @@ void IRHaierAC::setTime(uint8_t ptr[], const uint16_t nr_mins) { } void IRHaierAC::setOnTimer(const uint16_t nr_mins) { - setCommand(HAIER_AC_CMD_TIMER_SET); + setCommand(kHaierAcCmdTimerSet); remote_state[3] |= 0b10000000; setTime(remote_state + 6, nr_mins); } void IRHaierAC::setOffTimer(const uint16_t nr_mins) { - setCommand(HAIER_AC_CMD_TIMER_SET); + setCommand(kHaierAcCmdTimerSet); remote_state[3] |= 0b01000000; setTime(remote_state + 4, nr_mins); } void IRHaierAC::cancelTimers() { - setCommand(HAIER_AC_CMD_TIMER_CANCEL); + setCommand(kHaierAcCmdTimerCancel); remote_state[3] &= 0b00111111; } @@ -275,18 +279,16 @@ void IRHaierAC::setCurrTime(const uint16_t nr_mins) { setTime(remote_state + 2, nr_mins); } -uint8_t IRHaierAC::getSwing() { - return (remote_state[2] & 0b11000000) >> 6; -} +uint8_t IRHaierAC::getSwing() { return (remote_state[2] & 0b11000000) >> 6; } void IRHaierAC::setSwing(const uint8_t state) { - if (state == getSwing()) return; // Nothing to do. - setCommand(HAIER_AC_CMD_SWING); + if (state == getSwing()) return; // Nothing to do. + setCommand(kHaierAcCmdSwing); switch (state) { - case HAIER_AC_SWING_OFF: - case HAIER_AC_SWING_UP: - case HAIER_AC_SWING_DOWN: - case HAIER_AC_SWING_CHG: + case kHaierAcSwingOff: + case kHaierAcSwingUp: + case kHaierAcSwingDown: + case kHaierAcSwingChg: remote_state[2] &= 0b00111111; remote_state[2] |= (state << 6); break; @@ -302,10 +304,10 @@ std::string IRHaierAC::timeToString(const uint16_t nr_mins) { std::string result = ""; #endif // ARDUINO - if (nr_mins / 24 < 10) result += "0"; // Zero pad. + if (nr_mins / 24 < 10) result += "0"; // Zero pad. result += uint64ToString(nr_mins / 60); result += ":"; - if (nr_mins % 60 < 10) result += "0"; // Zero pad. + if (nr_mins % 60 < 10) result += "0"; // Zero pad. result += uint64ToString(nr_mins % 60); return result; } @@ -319,39 +321,39 @@ std::string IRHaierAC::toString() { std::string result = ""; #endif // ARDUINO uint8_t cmd = getCommand(); - result += "Command: " + uint64ToString(cmd) +" ("; + result += "Command: " + uint64ToString(cmd) + " ("; switch (cmd) { - case HAIER_AC_CMD_OFF: + case kHaierAcCmdOff: result += "Off"; break; - case HAIER_AC_CMD_ON: + case kHaierAcCmdOn: result += "On"; break; - case HAIER_AC_CMD_MODE: + case kHaierAcCmdMode: result += "Mode"; break; - case HAIER_AC_CMD_FAN: + case kHaierAcCmdFan: result += "Fan"; break; - case HAIER_AC_CMD_TEMP_UP: + case kHaierAcCmdTempUp: result += "Temp Up"; break; - case HAIER_AC_CMD_TEMP_DOWN: + case kHaierAcCmdTempDown: result += "Temp Down"; break; - case HAIER_AC_CMD_SLEEP: + case kHaierAcCmdSleep: result += "Sleep"; break; - case HAIER_AC_CMD_TIMER_SET: + case kHaierAcCmdTimerSet: result += "Timer Set"; break; - case HAIER_AC_CMD_TIMER_CANCEL: + case kHaierAcCmdTimerCancel: result += "Timer Cancel"; break; - case HAIER_AC_CMD_HEALTH: + case kHaierAcCmdHealth: result += "Health"; break; - case HAIER_AC_CMD_SWING: + case kHaierAcCmdSwing: result += "Swing"; break; default: @@ -360,19 +362,19 @@ std::string IRHaierAC::toString() { result += ")"; result += ", Mode: " + uint64ToString(getMode()); switch (getMode()) { - case HAIER_AC_AUTO: + case kHaierAcAuto: result += " (AUTO)"; break; - case HAIER_AC_COOL: + case kHaierAcCool: result += " (COOL)"; break; - case HAIER_AC_HEAT: + case kHaierAcHeat: result += " (HEAT)"; break; - case HAIER_AC_DRY: + case kHaierAcDry: result += " (DRY)"; break; - case HAIER_AC_FAN: + case kHaierAcFan: result += " (FAN)"; break; default: @@ -381,25 +383,25 @@ std::string IRHaierAC::toString() { result += ", Temp: " + uint64ToString(getTemp()) + "C"; result += ", Fan: " + uint64ToString(getFan()); switch (getFan()) { - case HAIER_AC_FAN_AUTO: + case kHaierAcFanAuto: result += " (AUTO)"; break; - case HAIER_AC_FAN_HIGH: + case kHaierAcFanHigh: result += " (MAX)"; break; } result += ", Swing: " + uint64ToString(getSwing()) + " ("; switch (getSwing()) { - case HAIER_AC_SWING_OFF: + case kHaierAcSwingOff: result += "Off"; break; - case HAIER_AC_SWING_UP: + case kHaierAcSwingUp: result += "Up"; break; - case HAIER_AC_SWING_DOWN: + case kHaierAcSwingDown: result += "Down"; break; - case HAIER_AC_SWING_CHG: + case kHaierAcSwingChg: result += "Chg"; break; default: @@ -430,63 +432,394 @@ std::string IRHaierAC::toString() { return result; } +// End of IRHaierAC class. -#if DECODE_HAIER_AC -// Decode the supplied Haier message. +// Class for emulating a Haier YRW02 remote +IRHaierACYRW02::IRHaierACYRW02(uint16_t pin) : _irsend(pin) { stateReset(); } + +void IRHaierACYRW02::begin() { _irsend.begin(); } + +#if SEND_HAIER_AC_YRW02 +void IRHaierACYRW02::send(const uint16_t repeat) { + checksum(); + _irsend.sendHaierACYRW02(remote_state, kHaierACYRW02StateLength, repeat); +} +#endif // SEND_HAIER_AC_YRW02 + +void IRHaierACYRW02::checksum() { + remote_state[kHaierACYRW02StateLength - 1] = + sumBytes(remote_state, kHaierACYRW02StateLength - 1); +} + +bool IRHaierACYRW02::validChecksum(uint8_t state[], const uint16_t length) { + if (length < 2) return false; // 1 byte of data can't have a checksum. + return (state[length - 1] == sumBytes(state, length - 1)); +} + +void IRHaierACYRW02::stateReset() { + for (uint8_t i = 1; i < kHaierACYRW02StateLength; i++) remote_state[i] = 0x0; + remote_state[0] = kHaierAcYrw02Prefix; + + setTemp(kHaierAcDefTemp); + setHealth(true); + setTurbo(kHaierAcYrw02TurboOff); + setSleep(false); + setFan(kHaierAcYrw02FanAuto); + setSwing(kHaierAcYrw02SwingOff); + setMode(kHaierAcYrw02Auto); + setPower(true); +} + +uint8_t* IRHaierACYRW02::getRaw() { + checksum(); + return remote_state; +} + +void IRHaierACYRW02::setRaw(uint8_t new_code[]) { + for (uint8_t i = 0; i < kHaierACYRW02StateLength; i++) { + remote_state[i] = new_code[i]; + } +} + +void IRHaierACYRW02::setButton(uint8_t button) { + switch (button) { + case kHaierAcYrw02ButtonTempUp: + case kHaierAcYrw02ButtonTempDown: + case kHaierAcYrw02ButtonSwing: + case kHaierAcYrw02ButtonFan: + case kHaierAcYrw02ButtonPower: + case kHaierAcYrw02ButtonMode: + case kHaierAcYrw02ButtonHealth: + case kHaierAcYrw02ButtonTurbo: + case kHaierAcYrw02ButtonSleep: + remote_state[12] &= 0b11110000; + remote_state[12] |= (button & 0b00001111); + } +} + +uint8_t IRHaierACYRW02::getButton() { return remote_state[12] & (0b00001111); } + +void IRHaierACYRW02::setMode(uint8_t mode) { + uint8_t new_mode = mode; + setButton(kHaierAcYrw02ButtonMode); + switch (mode) { + case kHaierAcYrw02Auto: + case kHaierAcYrw02Cool: + case kHaierAcYrw02Dry: + case kHaierAcYrw02Heat: + case kHaierAcYrw02Fan: + break; + default: // If unexpected, default to auto mode. + new_mode = kHaierAcYrw02Auto; + } + remote_state[7] &= 0b0001111; + remote_state[7] |= (new_mode << 4); +} + +uint8_t IRHaierACYRW02::getMode() { return remote_state[7] >> 4; } + +void IRHaierACYRW02::setTemp(const uint8_t celcius) { + uint8_t temp = celcius; + if (temp < kHaierAcMinTemp) + temp = kHaierAcMinTemp; + else if (temp > kHaierAcMaxTemp) + temp = kHaierAcMaxTemp; + + uint8_t old_temp = getTemp(); + if (old_temp == temp) return; + if (old_temp > temp) + setButton(kHaierAcYrw02ButtonTempDown); + else + setButton(kHaierAcYrw02ButtonTempUp); + + remote_state[1] &= 0b00001111; // Clear the previous temp. + remote_state[1] |= ((temp - kHaierAcMinTemp) << 4); +} + +uint8_t IRHaierACYRW02::getTemp() { + return ((remote_state[1] & 0b11110000) >> 4) + kHaierAcMinTemp; +} + +void IRHaierACYRW02::setHealth(bool state) { + setButton(kHaierAcYrw02ButtonHealth); + remote_state[3] &= 0b11111101; + remote_state[3] |= (state << 1); +} + +bool IRHaierACYRW02::getHealth(void) { return remote_state[3] & 0b00000010; } + +bool IRHaierACYRW02::getPower() { return remote_state[4] & kHaierAcYrw02Power; } + +void IRHaierACYRW02::setPower(bool state) { + setButton(kHaierAcYrw02ButtonPower); + if (state) + remote_state[4] |= kHaierAcYrw02Power; + else + remote_state[4] &= ~kHaierAcYrw02Power; +} + +void IRHaierACYRW02::on() { setPower(true); } + +void IRHaierACYRW02::off() { setPower(false); } + +bool IRHaierACYRW02::getSleep() { return remote_state[8] & kHaierAcYrw02Sleep; } + +void IRHaierACYRW02::setSleep(bool state) { + setButton(kHaierAcYrw02ButtonSleep); + if (state) + remote_state[8] |= kHaierAcYrw02Sleep; + else + remote_state[8] &= ~kHaierAcYrw02Sleep; +} + +uint8_t IRHaierACYRW02::getTurbo() { return remote_state[6] >> 6; } + +void IRHaierACYRW02::setTurbo(uint8_t speed) { + switch (speed) { + case kHaierAcYrw02TurboOff: + case kHaierAcYrw02TurboLow: + case kHaierAcYrw02TurboHigh: + remote_state[6] &= 0b00111111; + remote_state[6] |= (speed << 6); + setButton(kHaierAcYrw02ButtonTurbo); + } +} + +uint8_t IRHaierACYRW02::getFan() { return remote_state[5] >> 4; } + +void IRHaierACYRW02::setFan(uint8_t speed) { + switch (speed) { + case kHaierAcYrw02FanLow: + case kHaierAcYrw02FanMed: + case kHaierAcYrw02FanHigh: + case kHaierAcYrw02FanAuto: + remote_state[5] &= 0b00001111; + remote_state[5] |= (speed << 4); + setButton(kHaierAcYrw02ButtonFan); + } +} + +uint8_t IRHaierACYRW02::getSwing() { return remote_state[1] & 0b00001111; } + +void IRHaierACYRW02::setSwing(uint8_t state) { + uint8_t newstate = state; + switch (state) { + case kHaierAcYrw02SwingOff: + case kHaierAcYrw02SwingAuto: + case kHaierAcYrw02SwingTop: + case kHaierAcYrw02SwingMiddle: + case kHaierAcYrw02SwingBottom: + case kHaierAcYrw02SwingDown: + setButton(kHaierAcYrw02ButtonSwing); + break; + default: + return; // Unexpected value so don't do anything. + } + + // Heat mode has no MIDDLE setting, use BOTTOM instead. + if (state == kHaierAcYrw02SwingMiddle && getMode() == kHaierAcYrw02Heat) + newstate = kHaierAcYrw02SwingBottom; + + // BOTTOM is only allowed if we are in Heat mode, otherwise MIDDLE. + if (state == kHaierAcYrw02SwingBottom && getMode() != kHaierAcYrw02Heat) + newstate = kHaierAcYrw02SwingMiddle; + + remote_state[1] &= 0b11110000; + remote_state[1] |= newstate; +} + +// Convert the internal state into a human readable string. +#ifdef ARDUINO +String IRHaierACYRW02::toString() { + String result = ""; +#else +std::string IRHaierACYRW02::toString() { + std::string result = ""; +#endif // ARDUINO + result += "Power: "; + if (getPower()) + result += "On"; + else + result += "Off"; + uint8_t cmd = getButton(); + result += ", Button: " + uint64ToString(cmd) + " ("; + switch (cmd) { + case kHaierAcYrw02ButtonPower: + result += "Power"; + break; + case kHaierAcYrw02ButtonMode: + result += "Mode"; + break; + case kHaierAcYrw02ButtonFan: + result += "Fan"; + break; + case kHaierAcYrw02ButtonTempUp: + result += "Temp Up"; + break; + case kHaierAcYrw02ButtonTempDown: + result += "Temp Down"; + break; + case kHaierAcYrw02ButtonSleep: + result += "Sleep"; + break; + case kHaierAcYrw02ButtonHealth: + result += "Health"; + break; + case kHaierAcYrw02ButtonSwing: + result += "Swing"; + break; + case kHaierAcYrw02ButtonTurbo: + result += "Turbo"; + break; + default: + result += "Unknown"; + } + result += ")"; + result += ", Mode: " + uint64ToString(getMode()); + switch (getMode()) { + case kHaierAcYrw02Auto: + result += " (Auto)"; + break; + case kHaierAcYrw02Cool: + result += " (Cool)"; + break; + case kHaierAcYrw02Heat: + result += " (Heat)"; + break; + case kHaierAcYrw02Dry: + result += " (Dry)"; + break; + case kHaierAcYrw02Fan: + result += " (Fan)"; + break; + default: + result += " (UNKNOWN)"; + } + result += ", Temp: " + uint64ToString(getTemp()) + "C"; + result += ", Fan: " + uint64ToString(getFan()); + switch (getFan()) { + case kHaierAcYrw02FanAuto: + result += " (Auto)"; + break; + case kHaierAcYrw02FanHigh: + result += " (High)"; + break; + case kHaierAcYrw02FanLow: + result += " (Low)"; + break; + case kHaierAcYrw02FanMed: + result += " (Med)"; + break; + default: + result += " (Unknown)"; + } + result += ", Turbo: " + uint64ToString(getTurbo()) + " ("; + switch (getTurbo()) { + case kHaierAcYrw02TurboOff: + result += "Off"; + break; + case kHaierAcYrw02TurboLow: + result += "Low"; + break; + case kHaierAcYrw02TurboHigh: + result += "High"; + break; + default: + result += "Unknown"; + } + result += ")"; + result += ", Swing: " + uint64ToString(getSwing()) + " ("; + switch (getSwing()) { + case kHaierAcYrw02SwingOff: + result += "Off"; + break; + case kHaierAcYrw02SwingAuto: + result += "Auto"; + break; + case kHaierAcYrw02SwingBottom: + result += "Bottom"; + break; + case kHaierAcYrw02SwingDown: + result += "Down"; + break; + case kHaierAcYrw02SwingTop: + result += "Top"; + break; + case kHaierAcYrw02SwingMiddle: + result += "Middle"; + break; + default: + result += "Unknown"; + } + result += ")"; + result += ", Sleep: "; + if (getSleep()) + result += "On"; + else + result += "Off"; + result += ", Health: "; + if (getHealth()) + result += "On"; + else + result += "Off"; + + return result; +} +// End of IRHaierACYRW02 class. + +#if (DECODE_HAIER_AC || DECODE_HAIER_AC_YRW02) +// Decode the supplied Haier HSU07-HEA03 remote message. // // Args: // results: Ptr to the data to decode and where to store the decode result. -// nbits: The number of data bits to expect. Typically HAIER_AC_BITS. +// nbits: The number of data bits to expect. Typically kHaierACBits. // 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. // -bool IRrecv::decodeHaierAC(decode_results *results, uint16_t nbits, +bool IRrecv::decodeHaierAC(decode_results* results, uint16_t nbits, bool strict) { if (nbits % 8 != 0) // nbits has to be a multiple of nr. of bits in a byte. return false; if (strict) { - if (nbits != HAIER_AC_BITS) + if (nbits != kHaierACBits) return false; // Not strictly a HAIER_AC message. } - if (results->rawlen < (2 * nbits + HEADER) + FOOTER - 1) + if (results->rawlen < (2 * nbits + kHeader) + kFooter - 1) return false; // Can't possibly be a valid HAIER_AC message. - uint16_t offset = OFFSET_START; - + uint16_t offset = kStartOffset; // Header - if (!matchMark(results->rawbuf[offset++], HAIER_AC_HDR)) return false; - if (!matchSpace(results->rawbuf[offset++], HAIER_AC_HDR)) return false; - if (!matchMark(results->rawbuf[offset++], HAIER_AC_HDR)) return false; - if (!matchSpace(results->rawbuf[offset++], HAIER_AC_HDR_GAP)) return false; + if (!matchMark(results->rawbuf[offset++], kHaierAcHdr)) return false; + if (!matchSpace(results->rawbuf[offset++], kHaierAcHdr)) return false; + if (!matchMark(results->rawbuf[offset++], kHaierAcHdr)) return false; + if (!matchSpace(results->rawbuf[offset++], kHaierAcHdrGap)) return false; // Data for (uint16_t i = 0; i < nbits / 8; i++) { - match_result_t data_result = matchData(&(results->rawbuf[offset]), 8, - HAIER_AC_BIT_MARK, - HAIER_AC_ONE_SPACE, - HAIER_AC_BIT_MARK, - HAIER_AC_ZERO_SPACE); + match_result_t data_result = + matchData(&(results->rawbuf[offset]), 8, kHaierAcBitMark, + kHaierAcOneSpace, kHaierAcBitMark, kHaierAcZeroSpace); if (data_result.success == false) return false; offset += data_result.used; - results->state[i] = (uint8_t) data_result.data; + results->state[i] = (uint8_t)data_result.data; } // Footer - if (!matchMark(results->rawbuf[offset++], HAIER_AC_BIT_MARK)) return false; + if (!matchMark(results->rawbuf[offset++], kHaierAcBitMark)) return false; if (offset < results->rawlen && - !matchAtLeast(results->rawbuf[offset++], HAIER_AC_MIN_GAP)) + !matchAtLeast(results->rawbuf[offset++], kHaierAcMinGap)) return false; // Compliance if (strict) { - if (results->state[0] != HAIER_AC_PREFIX) return false; - if (!IRHaierAC::validChecksum(results->state, nbits / 8)) return false; + if (results->state[0] != kHaierAcPrefix) return false; + if (!IRHaierAC::validChecksum(results->state, nbits / 8)) return false; } // Success @@ -494,4 +827,39 @@ bool IRrecv::decodeHaierAC(decode_results *results, uint16_t nbits, results->bits = nbits; return true; } -#endif // DECODE_HAIER_AC +#endif // (DECODE_HAIER_AC || DECODE_HAIER_AC_YRW02) + +#if DECODE_HAIER_AC_YRW02 +// Decode the supplied Haier YR-W02 remote A/C message. +// +// Args: +// results: Ptr to the data to decode and where to store the decode result. +// nbits: The number of data bits to expect. Typically kHaierACYRW02Bits. +// 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. +// +bool IRrecv::decodeHaierACYRW02(decode_results* results, uint16_t nbits, + bool strict) { + if (strict) { + if (nbits != kHaierACYRW02Bits) + return false; // Not strictly a HAIER_AC_YRW02 message. + } + + // The protocol is almost exactly the same as HAIER_AC + if (!decodeHaierAC(results, nbits, false)) return false; + + // Compliance + if (strict) { + if (results->state[0] != kHaierAcYrw02Prefix) return false; + if (!IRHaierACYRW02::validChecksum(results->state, nbits / 8)) return false; + } + + // Success + // It looks correct, but we haven't check the checksum etc. + results->decode_type = HAIER_AC_YRW02; + return true; +} +#endif // DECODE_HAIER_AC_YRW02 diff --git a/lib/IRremoteESP8266/src/ir_Haier.h b/lib/IRremoteESP8266/src/ir_Haier.h index ac0f022..f4a0d32 100644 --- a/lib/IRremoteESP8266/src/ir_Haier.h +++ b/lib/IRremoteESP8266/src/ir_Haier.h @@ -21,55 +21,172 @@ // Ref: // https://github.com/markszabo/IRremoteESP8266/issues/404 // https://www.dropbox.com/s/mecyib3lhdxc8c6/IR%20data%20reverse%20engineering.xlsx?dl=0 +// https://github.com/markszabo/IRremoteESP8266/issues/485 +// https://www.dropbox.com/sh/w0bt7egp0fjger5/AADRFV6Wg4wZskJVdFvzb8Z0a?dl=0&preview=haer2.ods // Constants + +// Haier HSU07-HEA03 remote // Byte 0 -#define HAIER_AC_PREFIX 0b10100101 +const uint8_t kHaierAcPrefix = 0b10100101; // Byte 1 -#define HAIER_AC_MIN_TEMP 16 -#define HAIER_AC_MAX_TEMP 30 -#define HAIER_AC_DEF_TEMP 25 - -#define HAIER_AC_CMD_OFF 0b00000000 -#define HAIER_AC_CMD_ON 0b00000001 -#define HAIER_AC_CMD_MODE 0b00000010 -#define HAIER_AC_CMD_FAN 0b00000011 -#define HAIER_AC_CMD_TEMP_UP 0b00000110 -#define HAIER_AC_CMD_TEMP_DOWN 0b00000111 -#define HAIER_AC_CMD_SLEEP 0b00001000 -#define HAIER_AC_CMD_TIMER_SET 0b00001001 -#define HAIER_AC_CMD_TIMER_CANCEL 0b00001010 -#define HAIER_AC_CMD_HEALTH 0b00001100 -#define HAIER_AC_CMD_SWING 0b00001101 +const uint8_t kHaierAcMinTemp = 16; +const uint8_t kHaierAcDefTemp = 25; +const uint8_t kHaierAcMaxTemp = 30; +const uint8_t kHaierAcCmdOff = 0b00000000; +const uint8_t kHaierAcCmdOn = 0b00000001; +const uint8_t kHaierAcCmdMode = 0b00000010; +const uint8_t kHaierAcCmdFan = 0b00000011; +const uint8_t kHaierAcCmdTempUp = 0b00000110; +const uint8_t kHaierAcCmdTempDown = 0b00000111; +const uint8_t kHaierAcCmdSleep = 0b00001000; +const uint8_t kHaierAcCmdTimerSet = 0b00001001; +const uint8_t kHaierAcCmdTimerCancel = 0b00001010; +const uint8_t kHaierAcCmdHealth = 0b00001100; +const uint8_t kHaierAcCmdSwing = 0b00001101; // Byte 2 -#define HAIER_AC_SWING_OFF 0b00000000 -#define HAIER_AC_SWING_UP 0b00000001 -#define HAIER_AC_SWING_DOWN 0b00000010 -#define HAIER_AC_SWING_CHG 0b00000011 +const uint8_t kHaierAcSwingOff = 0b00000000; +const uint8_t kHaierAcSwingUp = 0b00000001; +const uint8_t kHaierAcSwingDown = 0b00000010; +const uint8_t kHaierAcSwingChg = 0b00000011; // Byte 6 -#define HAIER_AC_AUTO 0 -#define HAIER_AC_COOL 1 -#define HAIER_AC_DRY 2 -#define HAIER_AC_HEAT 3 -#define HAIER_AC_FAN 4 +const uint8_t kHaierAcAuto = 0; +const uint8_t kHaierAcCool = 1; +const uint8_t kHaierAcDry = 2; +const uint8_t kHaierAcHeat = 3; +const uint8_t kHaierAcFan = 4; -#define HAIER_AC_FAN_AUTO 0 -#define HAIER_AC_FAN_LOW 1 -#define HAIER_AC_FAN_MED 2 -#define HAIER_AC_FAN_HIGH 3 +const uint8_t kHaierAcFanAuto = 0; +const uint8_t kHaierAcFanLow = 1; +const uint8_t kHaierAcFanMed = 2; +const uint8_t kHaierAcFanHigh = 3; -#define HAIER_AC_MAX_TIME (23 * 60 + 59) +const uint16_t kHaierAcMaxTime = (23 * 60) + 59; +// Legacy Haier AC defines. +#define HAIER_AC_MIN_TEMP kHaierAcMinTemp +#define HAIER_AC_DEF_TEMP kHaierAcDefTemp +#define HAIER_AC_MAX_TEMP kHaierAcMaxTemp +#define HAIER_AC_CMD_OFF kHaierAcCmdOff +#define HAIER_AC_CMD_ON kHaierAcCmdOn +#define HAIER_AC_CMD_MODE kHaierAcCmdMode +#define HAIER_AC_CMD_FAN kHaierAcCmdFan +#define HAIER_AC_CMD_TEMP_UP kHaierAcCmdTempUp +#define HAIER_AC_CMD_TEMP_DOWN kHaierAcCmdTempDown +#define HAIER_AC_CMD_SLEEP kHaierAcCmdSleep +#define HAIER_AC_CMD_TIMER_SET kHaierAcCmdTimerSet +#define HAIER_AC_CMD_TIMER_CANCEL kHaierAcCmdTimerCancel +#define HAIER_AC_CMD_HEALTH kHaierAcCmdHealth +#define HAIER_AC_CMD_SWING kHaierAcCmdSwing +#define HAIER_AC_SWING_OFF kHaierAcSwingOff +#define HAIER_AC_SWING_UP kHaierAcSwingUp +#define HAIER_AC_SWING_DOWN kHaierAcSwingDown +#define HAIER_AC_SWING_CHG kHaierAcSwingChg +#define HAIER_AC_AUTO kHaierAcAuto +#define HAIER_AC_COOL kHaierAcCool +#define HAIER_AC_DRY kHaierAcDry +#define HAIER_AC_HEAT kHaierAcHeat +#define HAIER_AC_FAN kHaierAcFan +#define HAIER_AC_FAN_AUTO kHaierAcFanAuto +#define HAIER_AC_FAN_LOW kHaierAcFanLow +#define HAIER_AC_FAN_MED kHaierAcFanMed +#define HAIER_AC_FAN_HIGH kHaierAcFanHigh + +// Haier YRW02 remote +// Byte 0 +const uint8_t kHaierAcYrw02Prefix = 0xA6; + +// Byte 1 +// Bits 0-3 +// 0x0 = 16DegC, ... 0xE = 30DegC +// Bits 4-7 - Swing +const uint8_t kHaierAcYrw02SwingOff = 0x0; +const uint8_t kHaierAcYrw02SwingTop = 0x1; +const uint8_t kHaierAcYrw02SwingMiddle = 0x2; // Not available in heat mode. +const uint8_t kHaierAcYrw02SwingBottom = 0x3; // Only available in heat mode. +const uint8_t kHaierAcYrw02SwingDown = 0xA; +const uint8_t kHaierAcYrw02SwingAuto = 0xC; // Airflow + +// Byte 3 +// Bit 7 - Health mode + +// Byte 4 +const uint8_t kHaierAcYrw02Power = 0b01000000; + +// Byte 5 +// Bits 0-3 +const uint8_t kHaierAcYrw02FanHigh = 0x2; +const uint8_t kHaierAcYrw02FanMed = 0x4; +const uint8_t kHaierAcYrw02FanLow = 0x6; +const uint8_t kHaierAcYrw02FanAuto = 0xA; + +// Byte 6 +// Bits 0-1 +const uint8_t kHaierAcYrw02TurboOff = 0x0; +const uint8_t kHaierAcYrw02TurboHigh = 0x1; +const uint8_t kHaierAcYrw02TurboLow = 0x2; + +// Byte 7 +// Bits 0-3 +const uint8_t kHaierAcYrw02Auto = 0x0; +const uint8_t kHaierAcYrw02Cool = 0x2; +const uint8_t kHaierAcYrw02Dry = 0x4; +const uint8_t kHaierAcYrw02Heat = 0x8; +const uint8_t kHaierAcYrw02Fan = 0xC; + +// Byte 8 +const uint8_t kHaierAcYrw02Sleep = 0b10000000; + +// Byte 12 +// Bits 4-7 +const uint8_t kHaierAcYrw02ButtonTempUp = 0x0; +const uint8_t kHaierAcYrw02ButtonTempDown = 0x1; +const uint8_t kHaierAcYrw02ButtonSwing = 0x2; +const uint8_t kHaierAcYrw02ButtonFan = 0x4; +const uint8_t kHaierAcYrw02ButtonPower = 0x5; +const uint8_t kHaierAcYrw02ButtonMode = 0x6; +const uint8_t kHaierAcYrw02ButtonHealth = 0x7; +const uint8_t kHaierAcYrw02ButtonTurbo = 0x8; +const uint8_t kHaierAcYrw02ButtonSleep = 0xB; + +// Legacy Haier YRW02 remote defines. +#define HAIER_AC_YRW02_SWING_OFF kHaierAcYrw02SwingOff +#define HAIER_AC_YRW02_SWING_TOP kHaierAcYrw02SwingTop +#define HAIER_AC_YRW02_SWING_MIDDLE kHaierAcYrw02SwingMiddle +#define HAIER_AC_YRW02_SWING_BOTTOM kHaierAcYrw02SwingBottom +#define HAIER_AC_YRW02_SWING_DOWN kHaierAcYrw02SwingDown +#define HAIER_AC_YRW02_SWING_AUTO kHaierAcYrw02SwingAuto +#define HAIER_AC_YRW02_FAN_HIGH kHaierAcYrw02FanHigh +#define HAIER_AC_YRW02_FAN_MED kHaierAcYrw02FanMed +#define HAIER_AC_YRW02_FAN_LOW kHaierAcYrw02FanLow +#define HAIER_AC_YRW02_FAN_AUTO kHaierAcYrw02FanAuto +#define HAIER_AC_YRW02_TURBO_OFF kHaierAcYrw02TurboOff +#define HAIER_AC_YRW02_TURBO_HIGH kHaierAcYrw02TurboHigh +#define HAIER_AC_YRW02_TURBO_LOW kHaierAcYrw02TurboLow +#define HAIER_AC_YRW02_AUTO kHaierAcYrw02Auto +#define HAIER_AC_YRW02_COOL kHaierAcYrw02Cool +#define HAIER_AC_YRW02_DRY kHaierAcYrw02Dry +#define HAIER_AC_YRW02_HEAT kHaierAcYrw02Heat +#define HAIER_AC_YRW02_FAN kHaierAcYrw02Fan +#define HAIER_AC_YRW02_BUTTON_TEMP_UP kHaierAcYrw02ButtonTempUp +#define HAIER_AC_YRW02_BUTTON_TEMP_DOWN kHaierAcYrw02ButtonTempDown +#define HAIER_AC_YRW02_BUTTON_SWING kHaierAcYrw02ButtonSwing +#define HAIER_AC_YRW02_BUTTON_FAN kHaierAcYrw02ButtonFan +#define HAIER_AC_YRW02_BUTTON_POWER kHaierAcYrw02ButtonPower +#define HAIER_AC_YRW02_BUTTON_MODE kHaierAcYrw02ButtonMode +#define HAIER_AC_YRW02_BUTTON_HEALTH kHaierAcYrw02ButtonHealth +#define HAIER_AC_YRW02_BUTTON_TURBO kHaierAcYrw02ButtonTurbo +#define HAIER_AC_YRW02_BUTTON_SLEEP kHaierAcYrw02ButtonSleep class IRHaierAC { public: explicit IRHaierAC(uint16_t pin); #if SEND_HAIER_AC - void send(); + void send(const uint16_t repeat = kHaierAcDefaultRepeat); #endif // SEND_HAIER_AC void begin(); @@ -105,17 +222,17 @@ class IRHaierAC { uint8_t* getRaw(); void setRaw(uint8_t new_code[]); static bool validChecksum(uint8_t state[], - const uint16_t length = HAIER_AC_STATE_LENGTH); - #ifdef ARDUINO - String toString(); - static String timeToString(const uint16_t nr_mins); - #else - std::string toString(); - static std::string timeToString(const uint16_t nr_mins); - #endif + const uint16_t length = kHaierACStateLength); +#ifdef ARDUINO + String toString(); + static String timeToString(const uint16_t nr_mins); +#else + std::string toString(); + static std::string timeToString(const uint16_t nr_mins); +#endif private: - uint8_t remote_state[HAIER_AC_STATE_LENGTH]; + uint8_t remote_state[kHaierACStateLength]; void stateReset(); void checksum(); static uint16_t getTime(const uint8_t ptr[]); @@ -123,4 +240,58 @@ class IRHaierAC { IRsend _irsend; }; +class IRHaierACYRW02 { + public: + explicit IRHaierACYRW02(uint16_t pin); + +#if SEND_HAIER_AC_YRW02 + void send(const uint16_t repeat = kHaierAcYrw02DefaultRepeat); +#endif // SEND_HAIER_AC_YRW02 + void begin(); + + void setButton(const uint8_t button); + uint8_t getButton(); + + void setTemp(const uint8_t temp); + uint8_t getTemp(); + + void setFan(const uint8_t speed); + uint8_t getFan(); + + uint8_t getMode(); + void setMode(const uint8_t mode); + + bool getPower(); + void setPower(const bool state); + void on(); + void off(); + + bool getSleep(); + void setSleep(const bool state); + bool getHealth(); + void setHealth(const bool state); + + uint8_t getTurbo(); + void setTurbo(const uint8_t speed); + + uint8_t getSwing(); + void setSwing(const uint8_t state); + + uint8_t* getRaw(); + void setRaw(uint8_t new_code[]); + static bool validChecksum(uint8_t state[], + const uint16_t length = kHaierACYRW02StateLength); +#ifdef ARDUINO + String toString(); +#else + std::string toString(); +#endif + + private: + uint8_t remote_state[kHaierACYRW02StateLength]; + void stateReset(); + void checksum(); + IRsend _irsend; +}; + #endif // IR_HAIER_H_ diff --git a/lib/IRremoteESP8266/src/ir_Hitachi.cpp b/lib/IRremoteESP8266/src/ir_Hitachi.cpp index f7bd849..248f2d5 100644 --- a/lib/IRremoteESP8266/src/ir_Hitachi.cpp +++ b/lib/IRremoteESP8266/src/ir_Hitachi.cpp @@ -5,12 +5,13 @@ // * Hitachi RAS-35THA6 remote // +#include "ir_Hitachi.h" #include #ifndef ARDUINO #include #endif -#include "IRremoteESP8266.h" #include "IRrecv.h" +#include "IRremoteESP8266.h" #include "IRsend.h" #include "IRutils.h" @@ -22,21 +23,21 @@ // Constants // Ref: https://github.com/markszabo/IRremoteESP8266/issues/417 -#define HITACHI_AC_HDR_MARK 3300U -#define HITACHI_AC_HDR_SPACE 1700U -#define HITACHI_AC1_HDR_MARK 3400U -#define HITACHI_AC1_HDR_SPACE 3400U -#define HITACHI_AC_BIT_MARK 400U -#define HITACHI_AC_ONE_SPACE 1250U -#define HITACHI_AC_ZERO_SPACE 500U -#define HITACHI_AC_MIN_GAP 100000U // Completely made up value. +const uint16_t kHitachiAcHdrMark = 3300; +const uint16_t kHitachiAcHdrSpace = 1700; +const uint16_t kHitachiAc1HdrMark = 3400; +const uint16_t kHitachiAc1HdrSpace = 3400; +const uint16_t kHitachiAcBitMark = 400; +const uint16_t kHitachiAcOneSpace = 1250; +const uint16_t kHitachiAcZeroSpace = 500; +const uint32_t kHitachiAcMinGap = 100000; // Completely made up value. #if (SEND_HITACHI_AC || SEND_HITACHI_AC2) // Send a Hitachi A/C message. // // Args: // data: An array of bytes containing the IR command. -// nbytes: Nr. of bytes of data in the array. (>=HITACHI_AC_STATE_LENGTH) +// nbytes: Nr. of bytes of data in the array. (>=kHitachiAcStateLength) // repeat: Nr. of times the message is to be repeated. (Default = 0). // // Status: ALPHA / Untested. @@ -45,13 +46,12 @@ // https://github.com/markszabo/IRremoteESP8266/issues/417 void IRsend::sendHitachiAC(unsigned char data[], uint16_t nbytes, uint16_t repeat) { - if (nbytes < HITACHI_AC_STATE_LENGTH) + if (nbytes < kHitachiAcStateLength) return; // Not enough bytes to send a proper message. - sendGeneric(HITACHI_AC_HDR_MARK, HITACHI_AC_HDR_SPACE, - HITACHI_AC_BIT_MARK, HITACHI_AC_ONE_SPACE, - HITACHI_AC_BIT_MARK, HITACHI_AC_ZERO_SPACE, - HITACHI_AC_BIT_MARK, HITACHI_AC_MIN_GAP, - data, nbytes, 38, true, repeat, 50); + sendGeneric(kHitachiAcHdrMark, kHitachiAcHdrSpace, kHitachiAcBitMark, + kHitachiAcOneSpace, kHitachiAcBitMark, kHitachiAcZeroSpace, + kHitachiAcBitMark, kHitachiAcMinGap, data, nbytes, 38, true, + repeat, 50); } #endif // (SEND_HITACHI_AC || SEND_HITACHI_AC2) @@ -63,7 +63,7 @@ void IRsend::sendHitachiAC(unsigned char data[], uint16_t nbytes, // // Args: // data: An array of bytes containing the IR command. -// nbytes: Nr. of bytes of data in the array. (>=HITACHI_AC1_STATE_LENGTH) +// nbytes: Nr. of bytes of data in the array. (>=kHitachiAc1StateLength) // repeat: Nr. of times the message is to be repeated. (Default = 0). // // Status: BETA / Appears to work. @@ -73,13 +73,12 @@ void IRsend::sendHitachiAC(unsigned char data[], uint16_t nbytes, // Basically the same as sendHitatchiAC() except different size and header. void IRsend::sendHitachiAC1(unsigned char data[], uint16_t nbytes, uint16_t repeat) { - if (nbytes < HITACHI_AC1_STATE_LENGTH) + if (nbytes < kHitachiAc1StateLength) return; // Not enough bytes to send a proper message. - sendGeneric(HITACHI_AC1_HDR_MARK, HITACHI_AC1_HDR_SPACE, - HITACHI_AC_BIT_MARK, HITACHI_AC_ONE_SPACE, - HITACHI_AC_BIT_MARK, HITACHI_AC_ZERO_SPACE, - HITACHI_AC_BIT_MARK, HITACHI_AC_MIN_GAP, - data, nbytes, 38, true, repeat, 50); + sendGeneric(kHitachiAc1HdrMark, kHitachiAc1HdrSpace, kHitachiAcBitMark, + kHitachiAcOneSpace, kHitachiAcBitMark, kHitachiAcZeroSpace, + kHitachiAcBitMark, kHitachiAcMinGap, data, nbytes, 38, true, + repeat, 50); } #endif // SEND_HITACHI_AC1 @@ -91,7 +90,7 @@ void IRsend::sendHitachiAC1(unsigned char data[], uint16_t nbytes, // // Args: // data: An array of bytes containing the IR command. -// nbytes: Nr. of bytes of data in the array. (>=HITACHI_AC2_STATE_LENGTH) +// nbytes: Nr. of bytes of data in the array. (>=kHitachiAc2StateLength) // repeat: Nr. of times the message is to be repeated. (Default = 0). // // Status: BETA / Appears to work. @@ -101,19 +100,232 @@ void IRsend::sendHitachiAC1(unsigned char data[], uint16_t nbytes, // Basically the same as sendHitatchiAC() except different size. void IRsend::sendHitachiAC2(unsigned char data[], uint16_t nbytes, uint16_t repeat) { - if (nbytes < HITACHI_AC2_STATE_LENGTH) + if (nbytes < kHitachiAc2StateLength) return; // Not enough bytes to send a proper message. sendHitachiAC(data, nbytes, repeat); } #endif // SEND_HITACHI_AC2 +// Class for handling the remote control oh a Hitachi 28 byte A/C message. +// Inspired by: +// https://github.com/ToniA/arduino-heatpumpir/blob/master/HitachiHeatpumpIR.cpp + +IRHitachiAc::IRHitachiAc(uint16_t pin) : _irsend(pin) { stateReset(); } + +void IRHitachiAc::stateReset() { + remote_state[0] = 0x80; + remote_state[1] = 0x08; + remote_state[2] = 0x0C; + remote_state[3] = 0x02; + remote_state[4] = 0xFD; + remote_state[5] = 0x80; + remote_state[6] = 0x7F; + remote_state[7] = 0x88; + remote_state[8] = 0x48; + remote_state[9] = 0x10; + for (uint8_t i = 10; i < kHitachiAcStateLength; i++) remote_state[i] = 0x00; + remote_state[14] = 0x60; + remote_state[15] = 0x60; + remote_state[24] = 0x80; + setTemp(23); +} + +void IRHitachiAc::begin() { _irsend.begin(); } + +uint8_t IRHitachiAc::calcChecksum(const uint8_t state[], + const uint16_t length) { + int8_t sum = 62; + for (uint16_t i = 0; i < length - 1; i++) sum -= reverseBits(state[i], 8); + return reverseBits((uint8_t)sum, 8); +} + +void IRHitachiAc::checksum(const uint16_t length) { + remote_state[length - 1] = calcChecksum(remote_state, length); +} + +bool IRHitachiAc::validChecksum(const uint8_t state[], const uint16_t length) { + if (length < 2) return true; // Assume true for lengths that are too short. + return (state[length - 1] == calcChecksum(state, length)); +} + +uint8_t *IRHitachiAc::getRaw() { + checksum(); + return remote_state; +} + +void IRHitachiAc::setRaw(const uint8_t new_code[], const uint16_t length) { + for (uint8_t i = 0; i < length && i < kHitachiAcStateLength; i++) + remote_state[i] = new_code[i]; +} + +#if SEND_HITACHI_AC +void IRHitachiAc::send(const uint16_t repeat) { + checksum(); + _irsend.sendHitachiAC(remote_state, kHitachiAcStateLength, repeat); +} +#endif // SEND_HITACHI_AC + +bool IRHitachiAc::getPower() { return (remote_state[17] & 0x01); } + +void IRHitachiAc::setPower(const bool on) { + if (on) + remote_state[17] |= 0x01; + else + remote_state[17] &= 0xFE; +} + +void IRHitachiAc::on() { setPower(true); } + +void IRHitachiAc::off() { setPower(false); } + +uint8_t IRHitachiAc::getMode() { return reverseBits(remote_state[10], 8); } + +void IRHitachiAc::setMode(const uint8_t mode) { + uint8_t newmode = mode; + switch (mode) { + case kHitachiAcFan: + // Fan mode sets a special temp. + setTemp(64); + break; + case kHitachiAcAuto: + case kHitachiAcHeat: + case kHitachiAcCool: + case kHitachiAcDry: + break; + default: + newmode = kHitachiAcAuto; + } + remote_state[10] = reverseBits(newmode, 8); + if (mode != kHitachiAcFan) setTemp(_previoustemp); + setFan(getFan()); // Reset the fan speed after the mode change. +} + +uint8_t IRHitachiAc::getTemp() { return reverseBits(remote_state[11], 8) >> 1; } + +void IRHitachiAc::setTemp(const uint8_t celsius) { + uint8_t temp; + if (celsius != 64) _previoustemp = celsius; + switch (celsius) { + case 64: + temp = celsius; + break; + default: + temp = std::min(celsius, kHitachiAcMaxTemp); + temp = std::max(temp, kHitachiAcMinTemp); + } + remote_state[11] = reverseBits(temp << 1, 8); + if (temp == kHitachiAcMinTemp) + remote_state[9] = 0x90; + else + remote_state[9] = 0x10; +} + +uint8_t IRHitachiAc::getFan() { return reverseBits(remote_state[13], 8); } + +void IRHitachiAc::setFan(const uint8_t speed) { + uint8_t fanmin = kHitachiAcFanAuto; + uint8_t fanmax = kHitachiAcFanHigh; + switch (getMode()) { + case kHitachiAcDry: // Only 2 x low speeds in Dry mode. + fanmin = kHitachiAcFanLow; + fanmax = kHitachiAcFanLow + 1; + break; + case kHitachiAcFan: + fanmin = kHitachiAcFanLow; // No Auto in Fan mode. + break; + } + uint8_t newspeed = std::max(speed, fanmin); + newspeed = std::min(newspeed, fanmax); + remote_state[13] = reverseBits(newspeed, 8); +} + +bool IRHitachiAc::getSwingVertical() { return remote_state[14] & 0x80; } + +void IRHitachiAc::setSwingVertical(const bool on) { + if (on) + remote_state[14] |= 0x80; + else + remote_state[14] &= 0x7F; +} + +bool IRHitachiAc::getSwingHorizontal() { return remote_state[15] & 0x80; } + +void IRHitachiAc::setSwingHorizontal(const bool on) { + if (on) + remote_state[15] |= 0x80; + else + remote_state[15] &= 0x7F; +} + +// Convert the internal state into a human readable string. +#ifdef ARDUINO +String IRHitachiAc::toString() { + String result = ""; +#else +std::string IRHitachiAc::toString() { + std::string result = ""; +#endif // ARDUINO + result += "Power: "; + if (getPower()) + result += "On"; + else + result += "Off"; + result += ", Mode: " + uint64ToString(getMode()); + switch (getMode()) { + case kHitachiAcAuto: + result += " (AUTO)"; + break; + case kHitachiAcCool: + result += " (COOL)"; + break; + case kHitachiAcHeat: + result += " (HEAT)"; + break; + case kHitachiAcDry: + result += " (DRY)"; + break; + case kHitachiAcFan: + result += " (FAN)"; + break; + default: + result += " (UNKNOWN)"; + } + result += ", Temp: " + uint64ToString(getTemp()) + "C"; + result += ", Fan: " + uint64ToString(getFan()); + switch (getFan()) { + case kHitachiAcFanAuto: + result += " (AUTO)"; + break; + case kHitachiAcFanLow: + result += " (LOW)"; + break; + case kHitachiAcFanHigh: + result += " (HIGH)"; + break; + default: + result += " (UNKNOWN)"; + break; + } + result += ", Swing (Vertical): "; + if (getSwingVertical()) + result += "On"; + else + result += "Off"; + result += ", Swing (Horizontal): "; + if (getSwingHorizontal()) + result += "On"; + else + result += "Off"; + return result; +} + #if (DECODE_HITACHI_AC || DECODE_HITACHI_AC1 || DECODE_HITACHI_AC2) // Decode the supplied Hitachi A/C message. // // Args: // results: Ptr to the data to decode and where to store the decode result. // nbits: The number of data bits to expect. -// Typically HITACHI_AC_BITS, HITACHI_AC1_BITS, HITACHI_AC2_BITS +// Typically kHitachiAcBits, kHitachiAc1Bits, kHitachiAc2Bits // strict: Flag indicating if we should perform strict matching. // Returns: // boolean: True if it can decode it, false if it can't. @@ -129,80 +341,77 @@ void IRsend::sendHitachiAC2(unsigned char data[], uint16_t nbytes, bool IRrecv::decodeHitachiAC(decode_results *results, uint16_t nbits, bool strict) { const uint8_t kTolerance = 30; - if (results->rawlen < 2 * nbits + HEADER + FOOTER - 1) + if (results->rawlen < 2 * nbits + kHeader + kFooter - 1) return false; // Can't possibly be a valid HitachiAC message. if (strict) { switch (nbits) { - case HITACHI_AC_BITS: - case HITACHI_AC1_BITS: - case HITACHI_AC2_BITS: + case kHitachiAcBits: + case kHitachiAc1Bits: + case kHitachiAc2Bits: break; // Okay to continue. default: return false; // Not strictly a Hitachi message. } } - uint16_t offset = OFFSET_START; + uint16_t offset = kStartOffset; uint16_t dataBitsSoFar = 0; match_result_t data_result; // Header - if (nbits == HITACHI_AC1_BITS) { - if (!matchMark(results->rawbuf[offset++], HITACHI_AC1_HDR_MARK, kTolerance)) + if (nbits == kHitachiAc1Bits) { + if (!matchMark(results->rawbuf[offset++], kHitachiAc1HdrMark, kTolerance)) return false; - if (!matchSpace(results->rawbuf[offset++], HITACHI_AC1_HDR_SPACE, - kTolerance)) + if (!matchSpace(results->rawbuf[offset++], kHitachiAc1HdrSpace, kTolerance)) return false; } else { // Everything else. - if (!matchMark(results->rawbuf[offset++], HITACHI_AC_HDR_MARK, kTolerance)) + if (!matchMark(results->rawbuf[offset++], kHitachiAcHdrMark, kTolerance)) return false; - if (!matchSpace(results->rawbuf[offset++], HITACHI_AC_HDR_SPACE, - kTolerance)) + if (!matchSpace(results->rawbuf[offset++], kHitachiAcHdrSpace, kTolerance)) return false; } // Data // Keep reading bytes until we either run out of message or state to fill. - for (uint16_t i = 0; - offset <= results->rawlen - 16 && i < nbits / 8; - i++, dataBitsSoFar += 8, offset += data_result.used) { - data_result = matchData(&(results->rawbuf[offset]), 8, - HITACHI_AC_BIT_MARK, - HITACHI_AC_ONE_SPACE, - HITACHI_AC_BIT_MARK, - HITACHI_AC_ZERO_SPACE, - kTolerance); - if (data_result.success == false) break; // Fail - results->state[i] = (uint8_t) data_result.data; + for (uint16_t i = 0; offset <= results->rawlen - 16 && i < nbits / 8; + i++, dataBitsSoFar += 8, offset += data_result.used) { + data_result = matchData(&(results->rawbuf[offset]), 8, kHitachiAcBitMark, + kHitachiAcOneSpace, kHitachiAcBitMark, + kHitachiAcZeroSpace, kTolerance); + if (data_result.success == false) break; // Fail + results->state[i] = (uint8_t)data_result.data; } // Footer - if (!matchMark(results->rawbuf[offset++], HITACHI_AC_BIT_MARK, kTolerance)) + if (!matchMark(results->rawbuf[offset++], kHitachiAcBitMark, kTolerance)) return false; if (offset <= results->rawlen && - !matchAtLeast(results->rawbuf[offset], HITACHI_AC_MIN_GAP, kTolerance)) + !matchAtLeast(results->rawbuf[offset], kHitachiAcMinGap, kTolerance)) return false; // Compliance if (strict) { // Re-check we got the correct size/length due to the way we read the data. switch (dataBitsSoFar / 8) { - case HITACHI_AC_STATE_LENGTH: - case HITACHI_AC1_STATE_LENGTH: - case HITACHI_AC2_STATE_LENGTH: + case kHitachiAcStateLength: + case kHitachiAc1StateLength: + case kHitachiAc2StateLength: break; // Continue default: return false; } + if (dataBitsSoFar / 8 == kHitachiAcStateLength && + !IRHitachiAc::validChecksum(results->state, kHitachiAcStateLength)) + return false; } // Success switch (dataBitsSoFar) { - case HITACHI_AC1_BITS: + case kHitachiAc1Bits: results->decode_type = HITACHI_AC1; break; - case HITACHI_AC2_BITS: + case kHitachiAc2Bits: results->decode_type = HITACHI_AC2; break; - case HITACHI_AC_BITS: + case kHitachiAcBits: default: results->decode_type = HITACHI_AC; } diff --git a/lib/IRremoteESP8266/src/ir_Hitachi.h b/lib/IRremoteESP8266/src/ir_Hitachi.h new file mode 100644 index 0000000..efc775e --- /dev/null +++ b/lib/IRremoteESP8266/src/ir_Hitachi.h @@ -0,0 +1,76 @@ +// Hitachi A/C +// +// Copyright 2018 David Conran + +#ifndef IR_HITACHI_H_ +#define IR_HITACHI_H_ + +#define __STDC_LIMIT_MACROS +#include +#ifndef UNIT_TEST +#include +#else +#include +#endif +#include "IRremoteESP8266.h" +#include "IRsend.h" + +// Constants +const uint8_t kHitachiAcAuto = 2; +const uint8_t kHitachiAcHeat = 3; +const uint8_t kHitachiAcCool = 4; +const uint8_t kHitachiAcDry = 5; +const uint8_t kHitachiAcFan = 0xC; +const uint8_t kHitachiAcFanAuto = 1; +const uint8_t kHitachiAcFanLow = 2; +const uint8_t kHitachiAcFanHigh = 5; +const uint8_t kHitachiAcMinTemp = 16; // 16C +const uint8_t kHitachiAcMaxTemp = 32; // 32C +const uint8_t kHitachiAcAutoTemp = 23; // 23C + +// Classes +class IRHitachiAc { + public: + explicit IRHitachiAc(uint16_t pin); + + void stateReset(); +#if SEND_HITACHI_AC + void send(const uint16_t repeat = kHitachiAcDefaultRepeat); +#endif // SEND_HITACHI_AC + void begin(); + void on(); + void off(); + void setPower(const bool on); + bool getPower(); + void setTemp(const uint8_t temp); + uint8_t getTemp(); + void setFan(const uint8_t speed); + uint8_t getFan(); + void setMode(const uint8_t mode); + uint8_t getMode(); + void setSwingVertical(const bool on); + bool getSwingVertical(); + void setSwingHorizontal(const bool on); + bool getSwingHorizontal(); + uint8_t* getRaw(); + void setRaw(const uint8_t new_code[], + const uint16_t length = kHitachiAcStateLength); + static bool validChecksum(const uint8_t state[], + const uint16_t length = kHitachiAcStateLength); + static uint8_t calcChecksum(const uint8_t state[], + const uint16_t length = kHitachiAcStateLength); +#ifdef ARDUINO + String toString(); +#else + std::string toString(); +#endif + + private: + // The state of the IR remote in IR code form. + uint8_t remote_state[kHitachiAcStateLength]; + void checksum(const uint16_t length = kHitachiAcStateLength); + IRsend _irsend; + uint8_t _previoustemp; +}; + +#endif // IR_HITACHI_H_ diff --git a/lib/IRremoteESP8266/src/ir_JVC.cpp b/lib/IRremoteESP8266/src/ir_JVC.cpp index 5a4017e..47df29d 100644 --- a/lib/IRremoteESP8266/src/ir_JVC.cpp +++ b/lib/IRremoteESP8266/src/ir_JVC.cpp @@ -19,31 +19,31 @@ // Constants // Ref: // http://www.sbprojects.com/knowledge/ir/jvc.php -#define JVC_TICK 75U -#define JVC_HDR_MARK_TICKS 112U -#define JVC_HDR_MARK (JVC_HDR_MARK_TICKS * JVC_TICK) -#define JVC_HDR_SPACE_TICKS 56U -#define JVC_HDR_SPACE (JVC_HDR_SPACE_TICKS * JVC_TICK) -#define JVC_BIT_MARK_TICKS 7U -#define JVC_BIT_MARK (JVC_BIT_MARK_TICKS * JVC_TICK) -#define JVC_ONE_SPACE_TICKS 23U -#define JVC_ONE_SPACE (JVC_ONE_SPACE_TICKS * JVC_TICK) -#define JVC_ZERO_SPACE_TICKS 7U -#define JVC_ZERO_SPACE (JVC_ZERO_SPACE_TICKS * JVC_TICK) -#define JVC_RPT_LENGTH_TICKS 800U -#define JVC_RPT_LENGTH (JVC_RPT_LENGTH_TICKS * JVC_TICK) -#define JVC_MIN_GAP_TICKS (JVC_RPT_LENGTH_TICKS - \ - (JVC_HDR_MARK_TICKS + JVC_HDR_SPACE_TICKS + \ - JVC_BITS * (JVC_BIT_MARK_TICKS + JVC_ONE_SPACE_TICKS) + \ - JVC_BIT_MARK_TICKS)) -#define JVC_MIN_GAP (JVC_MIN_GAP_TICKS * JVC_TICK) +const uint16_t kJvcTick = 75; +const uint16_t kJvcHdrMarkTicks = 112; +const uint16_t kJvcHdrMark = kJvcHdrMarkTicks * kJvcTick; +const uint16_t kJvcHdrSpaceTicks = 56; +const uint16_t kJvcHdrSpace = kJvcHdrSpaceTicks * kJvcTick; +const uint16_t kJvcBitMarkTicks = 7; +const uint16_t kJvcBitMark = kJvcBitMarkTicks * kJvcTick; +const uint16_t kJvcOneSpaceTicks = 23; +const uint16_t kJvcOneSpace = kJvcOneSpaceTicks * kJvcTick; +const uint16_t kJvcZeroSpaceTicks = 7; +const uint16_t kJvcZeroSpace = kJvcZeroSpaceTicks * kJvcTick; +const uint16_t kJvcRptLengthTicks = 800; +const uint16_t kJvcRptLength = kJvcRptLengthTicks * kJvcTick; +const uint16_t kJvcMinGapTicks = + kJvcRptLengthTicks - + (kJvcHdrMarkTicks + kJvcHdrSpaceTicks + + kJvcBits * (kJvcBitMarkTicks + kJvcOneSpaceTicks) + kJvcBitMarkTicks); +const uint16_t kJvcMinGap = kJvcMinGapTicks * kJvcTick; #if SEND_JVC // Send a JVC message. // // Args: // data: The contents of the command you want to send. -// nbits: The bit size of the command being sent. (JVC_BITS) +// nbits: The bit size of the command being sent. (kJvcBits) // repeat: The number of times you want the command to be repeated. // // Status: STABLE. @@ -57,23 +57,21 @@ void IRsend::sendJVC(uint64_t data, uint16_t nbits, uint16_t repeat) { IRtimer usecs = IRtimer(); // Header // Only sent for the first message. - mark(JVC_HDR_MARK); - space(JVC_HDR_SPACE); + mark(kJvcHdrMark); + space(kJvcHdrSpace); // We always send the data & footer at least once, hence '<= repeat'. for (uint16_t i = 0; i <= repeat; i++) { sendGeneric(0, 0, // No Header - JVC_BIT_MARK, JVC_ONE_SPACE, - JVC_BIT_MARK, JVC_ZERO_SPACE, - JVC_BIT_MARK, JVC_MIN_GAP, - data, nbits, 38, true, 0, // Repeats are handles elsewhere. + kJvcBitMark, kJvcOneSpace, kJvcBitMark, kJvcZeroSpace, + kJvcBitMark, kJvcMinGap, data, nbits, 38, true, + 0, // Repeats are handles elsewhere. 33); // Wait till the end of the repeat time window before we send another code. uint32_t elapsed = usecs.elapsed(); // Avoid potential unsigned integer underflow. - // e.g. when elapsed > JVC_RPT_LENGTH. - if (elapsed < JVC_RPT_LENGTH) - space(JVC_RPT_LENGTH - elapsed); + // e.g. when elapsed > kJvcRptLength. + if (elapsed < kJvcRptLength) space(kJvcRptLength - elapsed); usecs.reset(); } } @@ -100,7 +98,7 @@ uint16_t IRsend::encodeJVC(uint8_t address, uint8_t command) { // // Args: // results: Ptr to the data to decode and where to store the decode result. -// nbits: Nr. of bits of data to expect. Typically JVC_BITS. +// nbits: Nr. of bits of data to expect. Typically kJvcBits. // strict: Flag indicating if we should perform strict matching. // Returns: // boolean: True if it can decode it, false if it can't. @@ -111,50 +109,48 @@ uint16_t IRsend::encodeJVC(uint8_t address, uint8_t command) { // JVC repeat codes don't have a header. // Ref: // http://www.sbprojects.com/knowledge/ir/jvc.php -bool IRrecv::decodeJVC(decode_results *results, uint16_t nbits, bool strict) { - if (strict && nbits != JVC_BITS) +bool IRrecv::decodeJVC(decode_results *results, uint16_t nbits, bool strict) { + if (strict && nbits != kJvcBits) return false; // Must be called with the correct nr. of bits. - if (results->rawlen < 2 * nbits + FOOTER - 1) + if (results->rawlen < 2 * nbits + kFooter - 1) return false; // Can't possibly be a valid JVC message. uint64_t data = 0; - uint16_t offset = OFFSET_START; + uint16_t offset = kStartOffset; bool isRepeat = true; uint32_t m_tick; uint32_t s_tick; // Header // (Optional as repeat codes don't have the header) - if (matchMark(results->rawbuf[offset], JVC_HDR_MARK)) { + if (matchMark(results->rawbuf[offset], kJvcHdrMark)) { isRepeat = false; - m_tick = results->rawbuf[offset++] * RAWTICK / JVC_HDR_MARK_TICKS; + m_tick = results->rawbuf[offset++] * kRawTick / kJvcHdrMarkTicks; if (results->rawlen < 2 * nbits + 4) return false; // Can't possibly be a valid JVC message with a header. - if (!matchSpace(results->rawbuf[offset], JVC_HDR_SPACE)) - return false; - s_tick = results->rawbuf[offset++] * RAWTICK / JVC_HDR_SPACE_TICKS; + if (!matchSpace(results->rawbuf[offset], kJvcHdrSpace)) return false; + s_tick = results->rawbuf[offset++] * kRawTick / kJvcHdrSpaceTicks; } else { // We can't easily auto-calibrate as there is no header, so assume // the default tick time. - m_tick = JVC_TICK; - s_tick = JVC_TICK; + m_tick = kJvcTick; + s_tick = kJvcTick; } // Data - match_result_t data_result = matchData(&(results->rawbuf[offset]), nbits, - JVC_BIT_MARK_TICKS * m_tick, - JVC_ONE_SPACE_TICKS * s_tick, - JVC_BIT_MARK_TICKS * m_tick, - JVC_ZERO_SPACE_TICKS * s_tick); + match_result_t data_result = + matchData(&(results->rawbuf[offset]), nbits, kJvcBitMarkTicks * m_tick, + kJvcOneSpaceTicks * s_tick, kJvcBitMarkTicks * m_tick, + kJvcZeroSpaceTicks * s_tick); if (data_result.success == false) return false; data = data_result.data; offset += data_result.used; // Footer - if (!matchMark(results->rawbuf[offset++], JVC_BIT_MARK_TICKS * m_tick)) + if (!matchMark(results->rawbuf[offset++], kJvcBitMarkTicks * m_tick)) return false; if (offset < results->rawlen && - !matchAtLeast(results->rawbuf[offset], JVC_MIN_GAP_TICKS * s_tick)) + !matchAtLeast(results->rawbuf[offset], kJvcMinGapTicks * s_tick)) return false; // Success @@ -162,7 +158,7 @@ bool IRrecv::decodeJVC(decode_results *results, uint16_t nbits, bool strict) { results->bits = nbits; results->value = data; // command & address are transmitted LSB first, so we need to reverse them. - results->address = reverseBits(data >> 8, 8); // The first 8 bits sent. + results->address = reverseBits(data >> 8, 8); // The first 8 bits sent. results->command = reverseBits(data & 0xFF, 8); // The last 8 bits sent. results->repeat = isRepeat; return true; diff --git a/lib/IRremoteESP8266/src/ir_Kelvinator.cpp b/lib/IRremoteESP8266/src/ir_Kelvinator.cpp index 0a7f43d..e172c81 100644 --- a/lib/IRremoteESP8266/src/ir_Kelvinator.cpp +++ b/lib/IRremoteESP8266/src/ir_Kelvinator.cpp @@ -30,151 +30,142 @@ // KK KK EEEEEEE LLLLLLL VVV IIIII NN NN AA AA TTT OOOO0 RR RR // Constants -#define KELVINATOR_TICK 85U -#define KELVINATOR_HDR_MARK_TICKS 106U -#define KELVINATOR_HDR_MARK (KELVINATOR_HDR_MARK_TICKS * KELVINATOR_TICK) -#define KELVINATOR_HDR_SPACE_TICKS 53U -#define KELVINATOR_HDR_SPACE (KELVINATOR_HDR_SPACE_TICKS * KELVINATOR_TICK) -#define KELVINATOR_BIT_MARK_TICKS 8U -#define KELVINATOR_BIT_MARK (KELVINATOR_BIT_MARK_TICKS * KELVINATOR_TICK) -#define KELVINATOR_ONE_SPACE_TICKS 18U -#define KELVINATOR_ONE_SPACE (KELVINATOR_ONE_SPACE_TICKS * KELVINATOR_TICK) -#define KELVINATOR_ZERO_SPACE_TICKS 6U -#define KELVINATOR_ZERO_SPACE (KELVINATOR_ZERO_SPACE_TICKS * KELVINATOR_TICK) -#define KELVINATOR_GAP_SPACE_TICKS 235U -#define KELVINATOR_GAP_SPACE (KELVINATOR_GAP_SPACE_TICKS * KELVINATOR_TICK) -#define KELVINATOR_CMD_FOOTER 2U -#define KELVINATOR_CMD_FOOTER_BITS 3U -#define KELVINATOR_POWER 8U -#define KELVINATOR_MODE_MASK 0xF8U -#define KELVINATOR_FAN_OFFSET 4U -#define KELVINATOR_BASIC_FAN_MASK uint8_t(0xFFU ^ (3U << KELVINATOR_FAN_OFFSET)) -#define KELVINATOR_FAN_MASK uint8_t(0xFFU ^ (7U << KELVINATOR_FAN_OFFSET)) -#define KELVINATOR_CHECKSUM_START 10U -#define KELVINATOR_VENT_SWING_OFFSET 6U -#define KELVINATOR_VENT_SWING uint8_t(1U << KELVINATOR_VENT_SWING_OFFSET) -#define KELVINATOR_VENT_SWING_V uint8_t(1U) -#define KELVINATOR_VENT_SWING_H uint8_t(1U << 4) -#define KELVINATOR_SLEEP_1_AND_3 uint8_t(1U << 7) -#define KELVINATOR_QUIET_OFFSET 7U -#define KELVINATOR_QUIET uint8_t(1U << KELVINATOR_QUIET_OFFSET) -#define KELVINATOR_ION_FILTER_OFFSET 6U -#define KELVINATOR_ION_FILTER uint8_t(1U << KELVINATOR_ION_FILTER_OFFSET) -#define KELVINATOR_LIGHT_OFFSET 5U -#define KELVINATOR_LIGHT uint8_t(1U << KELVINATOR_LIGHT_OFFSET) -#define KELVINATOR_XFAN_OFFSET 7U -#define KELVINATOR_XFAN uint8_t(1U << KELVINATOR_XFAN_OFFSET) -#define KELVINATOR_TURBO_OFFSET 4U -#define KELVINATOR_TURBO uint8_t(1U << KELVINATOR_TURBO_OFFSET) +const uint16_t kKelvinatorTick = 85; +const uint16_t kKelvinatorHdrMarkTicks = 106; +const uint16_t kKelvinatorHdrMark = kKelvinatorHdrMarkTicks * kKelvinatorTick; +const uint16_t kKelvinatorHdrSpaceTicks = 53; +const uint16_t kKelvinatorHdrSpace = kKelvinatorHdrSpaceTicks * kKelvinatorTick; +const uint16_t kKelvinatorBitMarkTicks = 8; +const uint16_t kKelvinatorBitMark = kKelvinatorBitMarkTicks * kKelvinatorTick; +const uint16_t kKelvinatorOneSpaceTicks = 18; +const uint16_t kKelvinatorOneSpace = kKelvinatorOneSpaceTicks * kKelvinatorTick; +const uint16_t kKelvinatorZeroSpaceTicks = 6; +const uint16_t kKelvinatorZeroSpace = + kKelvinatorZeroSpaceTicks * kKelvinatorTick; +const uint16_t kKelvinatorGapSpaceTicks = 235; +const uint16_t kKelvinatorGapSpace = kKelvinatorGapSpaceTicks * kKelvinatorTick; + +const uint8_t kKelvinatorCmdFooter = 2; +const uint8_t kKelvinatorCmdFooterBits = 3; + +const uint8_t kKelvinatorPower = 8; +const uint8_t kKelvinatorModeMask = 0xF8; +const uint8_t kKelvinatorFanOffset = 4; +const uint8_t kKelvinatorBasicFanMask = 0xFF ^ (3U << kKelvinatorFanOffset); +const uint8_t kKelvinatorFanMask = 0xFF ^ (7U << kKelvinatorFanOffset); +const uint8_t kKelvinatorChecksumStart = 10; +const uint8_t kKelvinatorVentSwingOffset = 6; +const uint8_t kKelvinatorVentSwing = 1 << kKelvinatorVentSwingOffset; +const uint8_t kKelvinatorVentSwingV = 1; +const uint8_t kKelvinatorVentSwingH = 1 << 4; +const uint8_t kKelvinatorSleep1And3 = 1 << 7; +const uint8_t kKelvinatorQuietOffset = 7; +const uint8_t kKelvinatorQuiet = 1 << kKelvinatorQuietOffset; +const uint8_t kKelvinatorIonFilterOffset = 6; +const uint8_t kKelvinatorIonFilter = 1 << kKelvinatorIonFilterOffset; +const uint8_t kKelvinatorLightOffset = 5; +const uint8_t kKelvinatorLight = 1 << kKelvinatorLightOffset; +const uint8_t kKelvinatorXfanOffset = 7; +const uint8_t kKelvinatorXfan = 1 << kKelvinatorXfanOffset; +const uint8_t kKelvinatorTurboOffset = 4; +const uint8_t kKelvinatorTurbo = 1 << kKelvinatorTurboOffset; #if SEND_KELVINATOR // Send a Kelvinator A/C message. // // Args: // data: An array of bytes containing the IR command. -// nbytes: Nr. of bytes of data in the array. (>=KELVINATOR_STATE_LENGTH) +// nbytes: Nr. of bytes of data in the array. (>=kKelvinatorStateLength) // repeat: Nr. of times the message is to be repeated. (Default = 0). // // Status: STABLE / Known working. // void IRsend::sendKelvinator(unsigned char data[], uint16_t nbytes, uint16_t repeat) { - if (nbytes < KELVINATOR_STATE_LENGTH) + if (nbytes < kKelvinatorStateLength) return; // Not enough bytes to send a proper message. for (uint16_t r = 0; r <= repeat; r++) { // Command Block #1 (4 bytes) - sendGeneric(KELVINATOR_HDR_MARK, KELVINATOR_HDR_SPACE, - KELVINATOR_BIT_MARK, KELVINATOR_ONE_SPACE, - KELVINATOR_BIT_MARK, KELVINATOR_ZERO_SPACE, + sendGeneric(kKelvinatorHdrMark, kKelvinatorHdrSpace, kKelvinatorBitMark, + kKelvinatorOneSpace, kKelvinatorBitMark, kKelvinatorZeroSpace, 0, 0, // No Footer yet. data, 4, 38, false, 0, 50); - // Send Footer for the command block (3 bits (B010)) + // Send Footer for the command block (3 bits (b010)) sendGeneric(0, 0, // No Header - KELVINATOR_BIT_MARK, KELVINATOR_ONE_SPACE, - KELVINATOR_BIT_MARK, KELVINATOR_ZERO_SPACE, - KELVINATOR_BIT_MARK, KELVINATOR_GAP_SPACE, - KELVINATOR_CMD_FOOTER, KELVINATOR_CMD_FOOTER_BITS, - 38, false, 0, 50); + kKelvinatorBitMark, kKelvinatorOneSpace, kKelvinatorBitMark, + kKelvinatorZeroSpace, kKelvinatorBitMark, kKelvinatorGapSpace, + kKelvinatorCmdFooter, kKelvinatorCmdFooterBits, 38, false, 0, + 50); // Data Block #1 (4 bytes) sendGeneric(0, 0, // No header - KELVINATOR_BIT_MARK, KELVINATOR_ONE_SPACE, - KELVINATOR_BIT_MARK, KELVINATOR_ZERO_SPACE, - KELVINATOR_BIT_MARK, KELVINATOR_GAP_SPACE * 2, - data + 4, 4, 38, false, 0, 50); + kKelvinatorBitMark, kKelvinatorOneSpace, kKelvinatorBitMark, + kKelvinatorZeroSpace, kKelvinatorBitMark, + kKelvinatorGapSpace * 2, data + 4, 4, 38, false, 0, 50); // Command Block #2 (4 bytes) - sendGeneric(KELVINATOR_HDR_MARK, KELVINATOR_HDR_SPACE, - KELVINATOR_BIT_MARK, KELVINATOR_ONE_SPACE, - KELVINATOR_BIT_MARK, KELVINATOR_ZERO_SPACE, + sendGeneric(kKelvinatorHdrMark, kKelvinatorHdrSpace, kKelvinatorBitMark, + kKelvinatorOneSpace, kKelvinatorBitMark, kKelvinatorZeroSpace, 0, 0, // No Footer yet. data + 8, 4, 38, false, 0, 50); // Send Footer for the command block (3 bits (B010)) sendGeneric(0, 0, // No Header - KELVINATOR_BIT_MARK, KELVINATOR_ONE_SPACE, - KELVINATOR_BIT_MARK, KELVINATOR_ZERO_SPACE, - KELVINATOR_BIT_MARK, KELVINATOR_GAP_SPACE, - KELVINATOR_CMD_FOOTER, KELVINATOR_CMD_FOOTER_BITS, - 38, false, 0, 50); + kKelvinatorBitMark, kKelvinatorOneSpace, kKelvinatorBitMark, + kKelvinatorZeroSpace, kKelvinatorBitMark, kKelvinatorGapSpace, + kKelvinatorCmdFooter, kKelvinatorCmdFooterBits, 38, false, 0, + 50); // Data Block #2 (4 bytes) sendGeneric(0, 0, // No header - KELVINATOR_BIT_MARK, KELVINATOR_ONE_SPACE, - KELVINATOR_BIT_MARK, KELVINATOR_ZERO_SPACE, - KELVINATOR_BIT_MARK, KELVINATOR_GAP_SPACE * 2, - data + 12, 4, 38, false, 0, 50); + kKelvinatorBitMark, kKelvinatorOneSpace, kKelvinatorBitMark, + kKelvinatorZeroSpace, kKelvinatorBitMark, + kKelvinatorGapSpace * 2, data + 12, 4, 38, false, 0, 50); } } #endif // SEND_KELVINATOR -IRKelvinatorAC::IRKelvinatorAC(uint16_t pin) : _irsend(pin) { - stateReset(); -} +IRKelvinatorAC::IRKelvinatorAC(uint16_t pin) : _irsend(pin) { stateReset(); } void IRKelvinatorAC::stateReset() { - for (uint8_t i = 0; i < KELVINATOR_STATE_LENGTH; i++) - remote_state[i] = 0x0; + for (uint8_t i = 0; i < kKelvinatorStateLength; i++) remote_state[i] = 0x0; remote_state[3] = 0x50; remote_state[11] = 0x70; } -void IRKelvinatorAC::begin() { - _irsend.begin(); -} +void IRKelvinatorAC::begin() { _irsend.begin(); } void IRKelvinatorAC::fixup() { // X-Fan mode is only valid in COOL or DRY modes. - if (getMode() != KELVINATOR_COOL && getMode() != KELVINATOR_DRY) + if (getMode() != kKelvinatorCool && getMode() != kKelvinatorDry) setXFan(false); checksum(); // Calculate the checksums } #if SEND_KELVINATOR -void IRKelvinatorAC::send() { - fixup(); // Ensure correct settings before sending. - _irsend.sendKelvinator(remote_state); +void IRKelvinatorAC::send(const uint16_t repeat) { + fixup(); // Ensure correct settings before sending. + _irsend.sendKelvinator(remote_state, kKelvinatorStateLength, repeat); } #endif // SEND_KELVINATOR -uint8_t* IRKelvinatorAC::getRaw() { - fixup(); // Ensure correct settings before sending. +uint8_t *IRKelvinatorAC::getRaw() { + fixup(); // Ensure correct settings before sending. return remote_state; } void IRKelvinatorAC::setRaw(uint8_t new_code[]) { - for (uint8_t i = 0; i < KELVINATOR_STATE_LENGTH; i++) { + for (uint8_t i = 0; i < kKelvinatorStateLength; i++) { remote_state[i] = new_code[i]; } } uint8_t IRKelvinatorAC::calcBlockChecksum(const uint8_t *block, const uint16_t length) { - uint8_t sum = KELVINATOR_CHECKSUM_START; + uint8_t sum = kKelvinatorChecksumStart; // Sum the lower half of the first 4 bytes of this block. for (uint8_t i = 0; i < 4 && i < length - 1; i++, block++) sum += (*block & 0x0FU); - // then sum the upper half of the next 3 bytes. - for (uint8_t i = 4; i < length - 1; i++, block++) - sum += (*block >> 4); + // then sum the upper half of the next 3 bytes. + for (uint8_t i = 4; i < length - 1; i++, block++) sum += (*block >> 4); // Trim it down to fit into the 4 bits allowed. i.e. Mod 16. return sum & 0x0FU; } @@ -205,12 +196,12 @@ bool IRKelvinatorAC::validChecksum(const uint8_t state[], } void IRKelvinatorAC::on() { - remote_state[0] |= KELVINATOR_POWER; + remote_state[0] |= kKelvinatorPower; remote_state[8] = remote_state[0]; // Duplicate to the 2nd command chunk. } void IRKelvinatorAC::off() { - remote_state[0] &= ~KELVINATOR_POWER; + remote_state[0] &= ~kKelvinatorPower; remote_state[8] = remote_state[0]; // Duplicate to the 2nd command chunk. } @@ -222,140 +213,138 @@ void IRKelvinatorAC::setPower(bool state) { } bool IRKelvinatorAC::getPower() { - return ((remote_state[0] & KELVINATOR_POWER) != 0); + return ((remote_state[0] & kKelvinatorPower) != 0); } // Set the temp. in deg C void IRKelvinatorAC::setTemp(uint8_t temp) { - temp = std::max((uint8_t) KELVINATOR_MIN_TEMP, temp); - temp = std::min((uint8_t) KELVINATOR_MAX_TEMP, temp); - remote_state[1] = (remote_state[1] & 0xF0U) | (temp - KELVINATOR_MIN_TEMP); + temp = std::max(kKelvinatorMinTemp, temp); + temp = std::min(kKelvinatorMaxTemp, temp); + remote_state[1] = (remote_state[1] & 0xF0U) | (temp - kKelvinatorMinTemp); remote_state[9] = remote_state[1]; // Duplicate to the 2nd command chunk. } // Return the set temp. in deg C uint8_t IRKelvinatorAC::getTemp() { - return ((remote_state[1] & 0xFU) + KELVINATOR_MIN_TEMP); + return ((remote_state[1] & 0xFU) + kKelvinatorMinTemp); } // Set the speed of the fan, 0-5, 0 is auto, 1-5 is the speed void IRKelvinatorAC::setFan(uint8_t fan) { - fan = std::min((uint8_t) KELVINATOR_FAN_MAX, fan); // Bounds check + fan = std::min(kKelvinatorFanMax, fan); // Bounds check // Only change things if we need to. if (fan != getFan()) { // Set the basic fan values. - uint8_t fan_basic = std::min((uint8_t) KELVINATOR_BASIC_FAN_MAX, fan); - remote_state[0] = (remote_state[0] & KELVINATOR_BASIC_FAN_MASK) | - (fan_basic << KELVINATOR_FAN_OFFSET); + uint8_t fan_basic = std::min(kKelvinatorBasicFanMax, fan); + remote_state[0] = (remote_state[0] & kKelvinatorBasicFanMask) | + (fan_basic << kKelvinatorFanOffset); remote_state[8] = remote_state[0]; // Duplicate to the 2nd command chunk. // Set the advanced(?) fan value. - remote_state[14] = (remote_state[14] & KELVINATOR_FAN_MASK) | - (fan << KELVINATOR_FAN_OFFSET); + remote_state[14] = + (remote_state[14] & kKelvinatorFanMask) | (fan << kKelvinatorFanOffset); setTurbo(false); // Turbo mode is turned off if we change the fan settings. } } uint8_t IRKelvinatorAC::getFan() { - return ((remote_state[14] & ~KELVINATOR_FAN_MASK) >> KELVINATOR_FAN_OFFSET); + return ((remote_state[14] & ~kKelvinatorFanMask) >> kKelvinatorFanOffset); } uint8_t IRKelvinatorAC::getMode() { - return (remote_state[0] & ~KELVINATOR_MODE_MASK); + return (remote_state[0] & ~kKelvinatorModeMask); } void IRKelvinatorAC::setMode(uint8_t mode) { // If we get an unexpected mode, default to AUTO. - if (mode > KELVINATOR_HEAT) mode = KELVINATOR_AUTO; - remote_state[0] = (remote_state[0] & KELVINATOR_MODE_MASK) | mode; + if (mode > kKelvinatorHeat) mode = kKelvinatorAuto; + remote_state[0] = (remote_state[0] & kKelvinatorModeMask) | mode; remote_state[8] = remote_state[0]; // Duplicate to the 2nd command chunk. - if (mode == KELVINATOR_AUTO || KELVINATOR_DRY) + if (mode == kKelvinatorAuto || kKelvinatorDry) // When the remote is set to Auto or Dry, it defaults to 25C and doesn't // show it. - setTemp(KELVINATOR_AUTO_TEMP); + setTemp(kKelvinatorAutoTemp); } void IRKelvinatorAC::setSwingVertical(bool state) { if (state) { - remote_state[0] |= KELVINATOR_VENT_SWING; - remote_state[4] |= KELVINATOR_VENT_SWING_V; + remote_state[0] |= kKelvinatorVentSwing; + remote_state[4] |= kKelvinatorVentSwingV; } else { - remote_state[4] &= ~KELVINATOR_VENT_SWING_V; - if (!getSwingHorizontal()) - remote_state[0] &= ~KELVINATOR_VENT_SWING; + remote_state[4] &= ~kKelvinatorVentSwingV; + if (!getSwingHorizontal()) remote_state[0] &= ~kKelvinatorVentSwing; } remote_state[8] = remote_state[0]; // Duplicate to the 2nd command chunk. } bool IRKelvinatorAC::getSwingVertical() { - return ((remote_state[4] & KELVINATOR_VENT_SWING_V) != 0); + return ((remote_state[4] & kKelvinatorVentSwingV) != 0); } void IRKelvinatorAC::setSwingHorizontal(bool state) { if (state) { - remote_state[0] |= KELVINATOR_VENT_SWING; - remote_state[4] |= KELVINATOR_VENT_SWING_H; + remote_state[0] |= kKelvinatorVentSwing; + remote_state[4] |= kKelvinatorVentSwingH; } else { - remote_state[4] &= ~KELVINATOR_VENT_SWING_H; - if (!getSwingVertical()) - remote_state[0] &= ~KELVINATOR_VENT_SWING; + remote_state[4] &= ~kKelvinatorVentSwingH; + if (!getSwingVertical()) remote_state[0] &= ~kKelvinatorVentSwing; } remote_state[8] = remote_state[0]; // Duplicate to the 2nd command chunk. } bool IRKelvinatorAC::getSwingHorizontal() { - return ((remote_state[4] & KELVINATOR_VENT_SWING_H) != 0); + return ((remote_state[4] & kKelvinatorVentSwingH) != 0); } void IRKelvinatorAC::setQuiet(bool state) { - remote_state[12] &= ~KELVINATOR_QUIET; - remote_state[12] |= (state << KELVINATOR_QUIET_OFFSET); + remote_state[12] &= ~kKelvinatorQuiet; + remote_state[12] |= (state << kKelvinatorQuietOffset); } bool IRKelvinatorAC::getQuiet() { - return ((remote_state[12] & KELVINATOR_QUIET) != 0); + return ((remote_state[12] & kKelvinatorQuiet) != 0); } void IRKelvinatorAC::setIonFilter(bool state) { - remote_state[2] &= ~KELVINATOR_ION_FILTER; - remote_state[2] |= (state << KELVINATOR_ION_FILTER_OFFSET); + remote_state[2] &= ~kKelvinatorIonFilter; + remote_state[2] |= (state << kKelvinatorIonFilterOffset); remote_state[10] = remote_state[2]; // Duplicate to the 2nd command chunk. } bool IRKelvinatorAC::getIonFilter() { - return ((remote_state[2] & KELVINATOR_ION_FILTER) != 0); + return ((remote_state[2] & kKelvinatorIonFilter) != 0); } void IRKelvinatorAC::setLight(bool state) { - remote_state[2] &= ~KELVINATOR_LIGHT; - remote_state[2] |= (state << KELVINATOR_LIGHT_OFFSET); + remote_state[2] &= ~kKelvinatorLight; + remote_state[2] |= (state << kKelvinatorLightOffset); remote_state[10] = remote_state[2]; // Duplicate to the 2nd command chunk. } bool IRKelvinatorAC::getLight() { - return ((remote_state[2] & KELVINATOR_LIGHT) != 0); + return ((remote_state[2] & kKelvinatorLight) != 0); } // Note: XFan mode is only valid in Cool or Dry mode. void IRKelvinatorAC::setXFan(bool state) { - remote_state[2] &= ~KELVINATOR_XFAN; - remote_state[2] |= (state << KELVINATOR_XFAN_OFFSET); + remote_state[2] &= ~kKelvinatorXfan; + remote_state[2] |= (state << kKelvinatorXfanOffset); remote_state[10] = remote_state[2]; // Duplicate to the 2nd command chunk. } bool IRKelvinatorAC::getXFan() { - return ((remote_state[2] & KELVINATOR_XFAN) != 0); + return ((remote_state[2] & kKelvinatorXfan) != 0); } // Note: Turbo mode is turned off if the fan speed is changed. void IRKelvinatorAC::setTurbo(bool state) { - remote_state[2] &= ~KELVINATOR_TURBO; - remote_state[2] |= (state << KELVINATOR_TURBO_OFFSET); + remote_state[2] &= ~kKelvinatorTurbo; + remote_state[2] |= (state << kKelvinatorTurboOffset); remote_state[10] = remote_state[2]; // Duplicate to the 2nd command chunk. } bool IRKelvinatorAC::getTurbo() { - return ((remote_state[2] & KELVINATOR_TURBO) != 0); + return ((remote_state[2] & kKelvinatorTurbo) != 0); } // Convert the internal state into a human readable string. @@ -373,19 +362,19 @@ std::string IRKelvinatorAC::toString() { result += "Off"; result += ", Mode: " + uint64ToString(getMode()); switch (getMode()) { - case KELVINATOR_AUTO: + case kKelvinatorAuto: result += " (AUTO)"; break; - case KELVINATOR_COOL: + case kKelvinatorCool: result += " (COOL)"; break; - case KELVINATOR_HEAT: + case kKelvinatorHeat: result += " (HEAT)"; break; - case KELVINATOR_DRY: + case kKelvinatorDry: result += " (DRY)"; break; - case KELVINATOR_FAN: + case kKelvinatorFan: result += " (FAN)"; break; default: @@ -394,10 +383,10 @@ std::string IRKelvinatorAC::toString() { result += ", Temp: " + uint64ToString(getTemp()) + "C"; result += ", Fan: " + uint64ToString(getFan()); switch (getFan()) { - case KELVINATOR_FAN_AUTO: + case kKelvinatorFanAuto: result += " (AUTO)"; break; - case KELVINATOR_FAN_MAX: + case kKelvinatorFanMax: result += " (MAX)"; break; } @@ -444,7 +433,7 @@ std::string IRKelvinatorAC::toString() { // // Args: // results: Ptr to the data to decode and where to store the decode result. -// nbits: The number of data bits to expect. Typically KELVINATOR_BITS. +// nbits: The number of data bits to expect. Typically kKelvinatorBits. // strict: Flag indicating if we should perform strict matching. // Returns: // boolean: True if it can decode it, false if it can't. @@ -452,14 +441,14 @@ std::string IRKelvinatorAC::toString() { // Status: ALPHA / Untested. bool IRrecv::decodeKelvinator(decode_results *results, uint16_t nbits, bool strict) { - if (results->rawlen < 2 * (nbits + KELVINATOR_CMD_FOOTER_BITS) + - (HEADER + FOOTER + 1) * 2 - 1) + if (results->rawlen < + 2 * (nbits + kKelvinatorCmdFooterBits) + (kHeader + kFooter + 1) * 2 - 1) return false; // Can't possibly be a valid Kelvinator message. - if (strict && nbits != KELVINATOR_BITS) + if (strict && nbits != kKelvinatorBits) return false; // Not strictly a Kelvinator message. uint32_t data; - uint16_t offset = OFFSET_START; + uint16_t offset = kStartOffset; // There are two messages back-to-back in a full Kelvinator IR message // sequence. @@ -468,77 +457,76 @@ bool IRrecv::decodeKelvinator(decode_results *results, uint16_t nbits, match_result_t data_result; // Header - if (!matchMark(results->rawbuf[offset], KELVINATOR_HDR_MARK)) return false; + if (!matchMark(results->rawbuf[offset], kKelvinatorHdrMark)) return false; // Calculate how long the lowest tick time is based on the header mark. - uint32_t mark_tick = results->rawbuf[offset++] * RAWTICK / - KELVINATOR_HDR_MARK_TICKS; - if (!matchSpace(results->rawbuf[offset], KELVINATOR_HDR_SPACE)) - return false; + uint32_t mark_tick = + results->rawbuf[offset++] * kRawTick / kKelvinatorHdrMarkTicks; + if (!matchSpace(results->rawbuf[offset], kKelvinatorHdrSpace)) return false; // Calculate how long the common tick time is based on the header space. - uint32_t space_tick = results->rawbuf[offset++] * RAWTICK / - KELVINATOR_HDR_SPACE_TICKS; + uint32_t space_tick = + results->rawbuf[offset++] * kRawTick / kKelvinatorHdrSpaceTicks; // Data (Command) (32 bits) - data_result = matchData(&(results->rawbuf[offset]), 32, - KELVINATOR_BIT_MARK_TICKS * mark_tick, - KELVINATOR_ONE_SPACE_TICKS * space_tick, - KELVINATOR_BIT_MARK_TICKS * mark_tick, - KELVINATOR_ZERO_SPACE_TICKS * space_tick); + data_result = matchData( + &(results->rawbuf[offset]), 32, kKelvinatorBitMarkTicks * mark_tick, + kKelvinatorOneSpaceTicks * space_tick, + kKelvinatorBitMarkTicks * mark_tick, + kKelvinatorZeroSpaceTicks * space_tick, kTolerance, kMarkExcess, false); if (data_result.success == false) return false; data = data_result.data; offset += data_result.used; // Record command data in the state. - for (int i = state_pos + 3; i >= state_pos; i--, data >>= 8) - results->state[i] = reverseBits(data & 0xFF, 8); + for (uint16_t i = 0; i < 4; i++, data >>= 8) + results->state[state_pos + i] = data & 0xFF; state_pos += 4; // Command data footer (3 bits, B010) - data_result = matchData(&(results->rawbuf[offset]), - KELVINATOR_CMD_FOOTER_BITS, - KELVINATOR_BIT_MARK_TICKS * mark_tick, - KELVINATOR_ONE_SPACE_TICKS * space_tick, - KELVINATOR_BIT_MARK_TICKS * mark_tick, - KELVINATOR_ZERO_SPACE_TICKS * space_tick); + data_result = matchData( + &(results->rawbuf[offset]), kKelvinatorCmdFooterBits, + kKelvinatorBitMarkTicks * mark_tick, + kKelvinatorOneSpaceTicks * space_tick, + kKelvinatorBitMarkTicks * mark_tick, + kKelvinatorZeroSpaceTicks * space_tick, kTolerance, kMarkExcess, false); if (data_result.success == false) return false; - if (data_result.data != KELVINATOR_CMD_FOOTER) return false; + if (data_result.data != kKelvinatorCmdFooter) return false; offset += data_result.used; // Interdata gap. if (!matchMark(results->rawbuf[offset++], - KELVINATOR_BIT_MARK_TICKS * mark_tick)) + kKelvinatorBitMarkTicks * mark_tick)) return false; if (!matchSpace(results->rawbuf[offset++], - KELVINATOR_GAP_SPACE_TICKS * space_tick)) + kKelvinatorGapSpaceTicks * space_tick)) return false; // Data (Options) (32 bits) - data_result = matchData(&(results->rawbuf[offset]), 32, - KELVINATOR_BIT_MARK_TICKS * mark_tick, - KELVINATOR_ONE_SPACE_TICKS * space_tick, - KELVINATOR_BIT_MARK_TICKS * mark_tick, - KELVINATOR_ZERO_SPACE_TICKS * space_tick); + data_result = matchData( + &(results->rawbuf[offset]), 32, kKelvinatorBitMarkTicks * mark_tick, + kKelvinatorOneSpaceTicks * space_tick, + kKelvinatorBitMarkTicks * mark_tick, + kKelvinatorZeroSpaceTicks * space_tick, kTolerance, kMarkExcess, false); if (data_result.success == false) return false; data = data_result.data; offset += data_result.used; // Record option data in the state. - for (int i = state_pos + 3; i >= state_pos; i--, data >>= 8) - results->state[i] = reverseBits(data & 0xFF, 8); + for (uint16_t i = 0; i < 4; i++, data >>= 8) + results->state[state_pos + i] = data & 0xFF; state_pos += 4; // Inter-sequence gap. (Double length gap) if (!matchMark(results->rawbuf[offset++], - KELVINATOR_BIT_MARK_TICKS * mark_tick)) + kKelvinatorBitMarkTicks * mark_tick)) return false; if (s == 0) { if (!matchSpace(results->rawbuf[offset++], - KELVINATOR_GAP_SPACE_TICKS * space_tick * 2)) + kKelvinatorGapSpaceTicks * space_tick * 2)) return false; } else { if (offset <= results->rawlen && !matchAtLeast(results->rawbuf[offset], - KELVINATOR_GAP_SPACE_TICKS * 2 * space_tick)) + kKelvinatorGapSpaceTicks * 2 * space_tick)) return false; } } @@ -546,7 +534,7 @@ bool IRrecv::decodeKelvinator(decode_results *results, uint16_t nbits, // Compliance if (strict) { // Correct size/length) - if (state_pos != KELVINATOR_STATE_LENGTH) return false; + if (state_pos != kKelvinatorStateLength) return false; // Verify the message's checksum is correct. if (!IRKelvinatorAC::validChecksum(results->state)) return false; } diff --git a/lib/IRremoteESP8266/src/ir_Kelvinator.h b/lib/IRremoteESP8266/src/ir_Kelvinator.h index 6343b5a..2cc4e5a 100644 --- a/lib/IRremoteESP8266/src/ir_Kelvinator.h +++ b/lib/IRremoteESP8266/src/ir_Kelvinator.h @@ -22,20 +22,33 @@ // KK KK EEEEEEE LLLLLLL VVV IIIII NN NN AA AA TTT OOOO0 RR RR // Constants -#define KELVINATOR_AUTO 0U -#define KELVINATOR_COOL 1U -#define KELVINATOR_DRY 2U -#define KELVINATOR_FAN 3U -#define KELVINATOR_HEAT 4U -#define KELVINATOR_BASIC_FAN_MAX 3U -#define KELVINATOR_FAN_AUTO 0U -#define KELVINATOR_FAN_MAX 5U -#define KELVINATOR_MIN_TEMP 16U // 16C -#define KELVINATOR_MAX_TEMP 30U // 30C -#define KELVINATOR_AUTO_TEMP 25U // 25C +const uint8_t kKelvinatorAuto = 0; +const uint8_t kKelvinatorCool = 1; +const uint8_t kKelvinatorDry = 2; +const uint8_t kKelvinatorFan = 3; +const uint8_t kKelvinatorHeat = 4; +const uint8_t kKelvinatorBasicFanMax = 3; +const uint8_t kKelvinatorFanAuto = 0; +const uint8_t kKelvinatorFanMax = 5; +const uint8_t kKelvinatorMinTemp = 16; // 16C +const uint8_t kKelvinatorMaxTemp = 30; // 30C +const uint8_t kKelvinatorAutoTemp = 25; // 25C + +// Legacy defines (Deprecated) +#define KELVINATOR_MIN_TEMP kKelvinatorMinTemp +#define KELVINATOR_MAX_TEMP kKelvinatorMaxTemp +#define KELVINATOR_HEAT kKelvinatorHeat +#define KELVINATOR_FAN_MAX kKelvinatorFanMax +#define KELVINATOR_FAN_AUTO kKelvinatorFanAuto +#define KELVINATOR_FAN kKelvinatorFan +#define KELVINATOR_DRY kKelvinatorDry +#define KELVINATOR_COOL kKelvinatorCool +#define KELVINATOR_BASIC_FAN_MAX kKelvinatorBasicFanMax +#define KELVINATOR_AUTO_TEMP kKelvinatorAutoTemp +#define KELVINATOR_AUTO kKelvinatorAuto /* - Kelvinator AC map + Kelvinator AC map (header mark and space) byte 0 = Basic Modes @@ -117,7 +130,7 @@ class IRKelvinatorAC { void stateReset(); #if SEND_KELVINATOR - void send(); + void send(const uint16_t repeat = kKelvinatorDefaultRepeat); #endif // SEND_KELVINATOR void begin(); void on(); @@ -147,10 +160,9 @@ class IRKelvinatorAC { uint8_t* getRaw(); void setRaw(uint8_t new_code[]); static uint8_t calcBlockChecksum( - const uint8_t *block, - const uint16_t length = KELVINATOR_STATE_LENGTH / 2); + const uint8_t* block, const uint16_t length = kKelvinatorStateLength / 2); static bool validChecksum(const uint8_t state[], - const uint16_t length = KELVINATOR_STATE_LENGTH); + const uint16_t length = kKelvinatorStateLength); #ifdef ARDUINO String toString(); #else @@ -159,8 +171,8 @@ class IRKelvinatorAC { private: // The state of the IR remote in IR code form. - uint8_t remote_state[KELVINATOR_STATE_LENGTH]; - void checksum(const uint16_t length = KELVINATOR_STATE_LENGTH); + uint8_t remote_state[kKelvinatorStateLength]; + void checksum(const uint16_t length = kKelvinatorStateLength); void fixup(); IRsend _irsend; }; diff --git a/lib/IRremoteESP8266/src/ir_LG.cpp b/lib/IRremoteESP8266/src/ir_LG.cpp index f2d3d06..f9d922f 100644 --- a/lib/IRremoteESP8266/src/ir_LG.cpp +++ b/lib/IRremoteESP8266/src/ir_LG.cpp @@ -1,6 +1,6 @@ // Copyright 2015 Darryl Smith // Copyright 2015 cheaplin -// Copyright 2017 David Conran +// Copyright 2017, 2018 David Conran #include "ir_LG.h" #include @@ -16,31 +16,44 @@ // LG decode originally added by Darryl Smith (based on the JVC protocol) // LG send originally added by https://github.com/chaeplin +// +// Known supported devices: +// IR Remotes: +// 6711A20083V +// AKB74395308 // Constants -#define LG_TICK 50U -#define LG_HDR_MARK_TICKS 160U -#define LG_HDR_MARK (LG_HDR_MARK_TICKS * LG_TICK) -#define LG_HDR_SPACE_TICKS 80U -#define LG_HDR_SPACE (LG_HDR_SPACE_TICKS * LG_TICK) -#define LG_BIT_MARK_TICKS 11U -#define LG_BIT_MARK (LG_BIT_MARK_TICKS * LG_TICK) -#define LG_ONE_SPACE_TICKS 32U -#define LG_ONE_SPACE (LG_ONE_SPACE_TICKS * LG_TICK) -#define LG_ZERO_SPACE_TICKS 11U -#define LG_ZERO_SPACE (LG_ZERO_SPACE_TICKS * LG_TICK) -#define LG_RPT_SPACE_TICKS 45U -#define LG_RPT_SPACE (LG_RPT_SPACE_TICKS * LG_TICK) -#define LG_MIN_GAP_TICKS 795U -#define LG_MIN_GAP (LG_MIN_GAP_TICKS * LG_TICK) -#define LG_MIN_MESSAGE_LENGTH_TICKS 2161U -#define LG_MIN_MESSAGE_LENGTH (LG_MIN_MESSAGE_LENGTH_TICKS * LG_TICK) -#define LG32_HDR_MARK_TICKS 90U -#define LG32_HDR_MARK (LG32_HDR_MARK_TICKS * LG_TICK) -#define LG32_HDR_SPACE_TICKS 89U -#define LG32_HDR_SPACE (LG32_HDR_SPACE_TICKS * LG_TICK) -#define LG32_RPT_HDR_MARK_TICKS 179U -#define LG32_RPT_HDR_MARK (LG32_RPT_HDR_MARK_TICKS * LG_TICK) +const uint16_t kLgTick = 50; +const uint16_t kLgHdrMarkTicks = 170; +const uint16_t kLgHdrMark = kLgHdrMarkTicks * kLgTick; // 8500 +const uint16_t kLgHdrSpaceTicks = 85; +const uint16_t kLgHdrSpace = kLgHdrSpaceTicks * kLgTick; // 4250 +const uint16_t kLgBitMarkTicks = 11; +const uint16_t kLgBitMark = kLgBitMarkTicks * kLgTick; // 550 +const uint16_t kLgOneSpaceTicks = 32; +const uint16_t kLgOneSpace = kLgOneSpaceTicks * kLgTick; // 1600 +const uint16_t kLgZeroSpaceTicks = 11; +const uint16_t kLgZeroSpace = kLgZeroSpaceTicks * kLgTick; // 550 +const uint16_t kLgRptSpaceTicks = 45; +const uint16_t kLgRptSpace = kLgRptSpaceTicks * kLgTick; // 2250 +const uint16_t kLgMinGapTicks = 795; +const uint16_t kLgMinGap = kLgMinGapTicks * kLgTick; // 39750 +const uint16_t kLgMinMessageLengthTicks = 2161; +const uint32_t kLgMinMessageLength = kLgMinMessageLengthTicks * kLgTick; + +const uint16_t kLg32HdrMarkTicks = 90; +const uint16_t kLg32HdrMark = kLg32HdrMarkTicks * kLgTick; // 4500 +const uint16_t kLg32HdrSpaceTicks = 89; +const uint16_t kLg32HdrSpace = kLg32HdrSpaceTicks * kLgTick; // 4450 +const uint16_t kLg32RptHdrMarkTicks = 179; +const uint16_t kLg32RptHdrMark = kLg32RptHdrMarkTicks * kLgTick; // 8950 + +const uint16_t kLg2HdrMarkTicks = 64; +const uint16_t kLg2HdrMark = kLg2HdrMarkTicks * kLgTick; // 3200 +const uint16_t kLg2HdrSpaceTicks = 197; +const uint16_t kLg2HdrSpace = kLg2HdrSpaceTicks * kLgTick; // 9850 +const uint16_t kLg2BitMarkTicks = 10; +const uint16_t kLg2BitMark = kLg2BitMarkTicks * kLgTick; // 500 #if (SEND_LG || DECODE_LG) // Calculate the rolling 4-bit wide checksum over all of the data. @@ -49,8 +62,9 @@ // Returns: // A 4-bit checksum. uint8_t calcLGChecksum(uint16_t data) { - return(((data >> 12) + ((data >> 8) & 0xF) + ((data >> 4) & 0xF) + - (data & 0xF)) & 0xF); + return (((data >> 12) + ((data >> 8) & 0xF) + ((data >> 4) & 0xF) + + (data & 0xF)) & + 0xF); } #endif @@ -60,50 +74,83 @@ uint8_t calcLGChecksum(uint16_t data) { // Args: // data: The contents of the message you want to send. // nbits: The bit size of the message being sent. -// Typically LG_BITS or LG32_BITS. +// Typically kLgBits or kLg32Bits. // repeat: The number of times you want the message to be repeated. // // Status: Beta / Should be working. // // Notes: // LG has a separate message to indicate a repeat, like NEC does. +// Supports: +// IR Remote models: 6711A20083V void IRsend::sendLG(uint64_t data, uint16_t nbits, uint16_t repeat) { uint16_t repeatHeaderMark = 0; - if (nbits >= LG32_BITS) { + if (nbits >= kLg32Bits) { // LG 32bit protocol is near identical to Samsung except for repeats. sendSAMSUNG(data, nbits, 0); // Send it as a single Samsung message. - repeatHeaderMark = LG32_RPT_HDR_MARK; + repeatHeaderMark = kLg32RptHdrMark; repeat++; } else { // LG (28-bit) protocol. - repeatHeaderMark = LG_HDR_MARK; - sendGeneric(LG_HDR_MARK, LG_HDR_SPACE, - LG_BIT_MARK, LG_ONE_SPACE, - LG_BIT_MARK, LG_ZERO_SPACE, - LG_BIT_MARK, - LG_MIN_GAP, LG_MIN_MESSAGE_LENGTH, - data, nbits, 38, true, 0, // Repeats are handled later. + repeatHeaderMark = kLgHdrMark; + sendGeneric(kLgHdrMark, kLgHdrSpace, kLgBitMark, kLgOneSpace, kLgBitMark, + kLgZeroSpace, kLgBitMark, kLgMinGap, kLgMinMessageLength, data, + nbits, 38, true, 0, // Repeats are handled later. 50); } // Repeat // Protocol has a mandatory repeat-specific code sent after every command. if (repeat) - sendGeneric(repeatHeaderMark, LG_RPT_SPACE, - 0, 0, 0, 0, // No data is sent. - LG_BIT_MARK, LG_MIN_GAP, LG_MIN_MESSAGE_LENGTH, - 0, 0, // No data. + sendGeneric(repeatHeaderMark, kLgRptSpace, 0, 0, 0, 0, // No data is sent. + kLgBitMark, kLgMinGap, kLgMinMessageLength, 0, 0, // No data. 38, true, repeat - 1, 50); } -// Construct a raw 28-bit LG message from the supplied address & command. +// Send an LG Variant-2 formatted message. +// +// Args: +// data: The contents of the message you want to send. +// nbits: The bit size of the message being sent. +// Typically kLgBits or kLg32Bits. +// repeat: The number of times you want the message to be repeated. +// +// Status: Beta / Should be working. +// +// Notes: +// LG has a separate message to indicate a repeat, like NEC does. +// Supports: +// IR Remote models: AKB74395308 +void IRsend::sendLG2(uint64_t data, uint16_t nbits, uint16_t repeat) { + if (nbits >= kLg32Bits) { + // Let the original routine handle it. + sendLG(data, nbits, repeat); // Send it as a single Samsung message. + return; + } + + // LGv2 (28-bit) protocol. + sendGeneric(kLg2HdrMark, kLg2HdrSpace, kLgBitMark, kLgOneSpace, kLgBitMark, + kLgZeroSpace, kLgBitMark, kLgMinGap, kLgMinMessageLength, data, + nbits, 38, true, 0, // Repeats are handled later. + 50); + + // TODO(crackn): Verify the details of what repeat messages look like. + // Repeat + // Protocol has a mandatory repeat-specific code sent after every command. + if (repeat) + sendGeneric(kLg2HdrMark, kLgRptSpace, 0, 0, 0, 0, // No data is sent. + kLgBitMark, kLgMinGap, kLgMinMessageLength, 0, 0, // No data. + 38, true, repeat - 1, 50); +} + +// Construct a raw 28-bit LG message code from the supplied address & command. // // Args: // address: The address code. // command: The command code. // Returns: -// A raw 28-bit LG message suitable for sendLG(). +// A raw 28-bit LG message code suitable for sendLG() etc. // // Status: BETA / Should work. // @@ -125,7 +172,7 @@ uint32_t IRsend::encodeLG(uint16_t address, uint16_t command) { // Args: // results: Ptr to the data to decode and where to store the decode result. // nbits: Nr. of bits to expect in the data portion. -// Typically LG_BITS or LG32_BITS. +// Typically kLgBits or kLg32Bits. // strict: Flag to indicate if we strictly adhere to the specification. // Returns: // boolean: True if it can decode it, false if it can't. @@ -135,69 +182,91 @@ uint32_t IRsend::encodeLG(uint16_t address, uint16_t command) { // Note: // LG 32bit protocol appears near identical to the Samsung protocol. // They possibly differ on how they repeat and initial HDR mark. +// +// Supports: +// IR Remote models: 6711A20083V, AKB74395308 // Ref: // https://funembedded.wordpress.com/2014/11/08/ir-remote-control-for-lg-conditioner-using-stm32f302-mcu-on-mbed-platform/ bool IRrecv::decodeLG(decode_results *results, uint16_t nbits, bool strict) { - if (nbits >= LG32_BITS) { - if (results->rawlen < 2 * nbits + 2 * (HEADER + FOOTER) - 1) + if (nbits >= kLg32Bits) { + if (results->rawlen < 2 * nbits + 2 * (kHeader + kFooter) - 1) return false; // Can't possibly be a valid LG32 message. } else { - if (results->rawlen < 2 * nbits + HEADER + FOOTER - 1) + if (results->rawlen < 2 * nbits + kHeader + kFooter - 1) return false; // Can't possibly be a valid LG message. } - if (strict && nbits != LG_BITS && nbits != LG32_BITS) + if (strict && nbits != kLgBits && nbits != kLg32Bits) return false; // Doesn't comply with expected LG protocol. uint64_t data = 0; - uint16_t offset = OFFSET_START; + uint16_t offset = kStartOffset; + bool isLg2 = false; // Header - if (!matchMark(results->rawbuf[offset], LG_HDR_MARK) && - !matchMark(results->rawbuf[offset], LG32_HDR_MARK)) return false; uint32_t m_tick; - if (matchMark(results->rawbuf[offset], LG_HDR_MARK)) - m_tick = results->rawbuf[offset++] * RAWTICK / LG_HDR_MARK_TICKS; - else - m_tick = results->rawbuf[offset++] * RAWTICK / LG32_HDR_MARK_TICKS; - if (!matchSpace(results->rawbuf[offset], LG_HDR_SPACE) && - !matchSpace(results->rawbuf[offset], LG32_HDR_SPACE)) return false; + if (matchMark(results->rawbuf[offset], kLgHdrMark)) { + m_tick = results->rawbuf[offset++] * kRawTick / kLgHdrMarkTicks; + } else if (matchMark(results->rawbuf[offset], kLg2HdrMark)) { + m_tick = results->rawbuf[offset++] * kRawTick / kLg2HdrMarkTicks; + isLg2 = true; + } else if (matchMark(results->rawbuf[offset], kLg32HdrMark)) { + m_tick = results->rawbuf[offset++] * kRawTick / kLg32HdrMarkTicks; + } else { + return false; + } uint32_t s_tick; - if (matchSpace(results->rawbuf[offset], LG_HDR_SPACE)) - s_tick = results->rawbuf[offset++] * RAWTICK / LG_HDR_SPACE_TICKS; - else - s_tick = results->rawbuf[offset++] * RAWTICK / LG32_HDR_SPACE_TICKS; + if (isLg2) { + if (matchSpace(results->rawbuf[offset], kLg2HdrSpace)) + s_tick = results->rawbuf[offset++] * kRawTick / kLg2HdrSpaceTicks; + else + return false; + } else { + if (matchSpace(results->rawbuf[offset], kLgHdrSpace)) + s_tick = results->rawbuf[offset++] * kRawTick / kLgHdrSpaceTicks; + else if (matchSpace(results->rawbuf[offset], kLg2HdrSpace)) + s_tick = results->rawbuf[offset++] * kRawTick / kLg32HdrSpaceTicks; + else + return false; + } + + // Set up the expected tick sizes based on variant. + uint16_t bitmarkticks; + if (isLg2) { + bitmarkticks = kLg2BitMarkTicks; + } else { + bitmarkticks = kLgBitMarkTicks; + } // Data - match_result_t data_result = matchData(&(results->rawbuf[offset]), nbits, - LG_BIT_MARK_TICKS * m_tick, - LG_ONE_SPACE_TICKS * s_tick, - LG_BIT_MARK_TICKS * m_tick, - LG_ZERO_SPACE_TICKS * s_tick); + match_result_t data_result = + matchData(&(results->rawbuf[offset]), nbits, bitmarkticks * m_tick, + kLgOneSpaceTicks * s_tick, bitmarkticks * m_tick, + kLgZeroSpaceTicks * s_tick, kTolerance, 0); if (data_result.success == false) return false; data = data_result.data; offset += data_result.used; // Footer - if (!matchMark(results->rawbuf[offset++], LG_BIT_MARK_TICKS * m_tick)) + if (!matchMark(results->rawbuf[offset++], bitmarkticks * m_tick)) return false; if (offset < results->rawlen && - !matchAtLeast(results->rawbuf[offset], LG_MIN_GAP_TICKS * s_tick)) + !matchAtLeast(results->rawbuf[offset], kLgMinGapTicks * s_tick)) return false; // Repeat - if (nbits >= LG32_BITS) { + if (nbits >= kLg32Bits) { // If we are expecting the LG 32-bit protocol, there is always // a repeat message. So, check for it. offset++; - if (!matchMark(results->rawbuf[offset++], LG32_RPT_HDR_MARK_TICKS * m_tick)) + if (!matchMark(results->rawbuf[offset++], kLg32RptHdrMarkTicks * m_tick)) return false; - if (!matchSpace(results->rawbuf[offset++], LG_RPT_SPACE_TICKS * s_tick)) + if (!matchSpace(results->rawbuf[offset++], kLgRptSpaceTicks * s_tick)) return false; - if (!matchMark(results->rawbuf[offset++], LG_BIT_MARK_TICKS * m_tick)) + if (!matchMark(results->rawbuf[offset++], bitmarkticks * m_tick)) return false; if (offset < results->rawlen && - !matchAtLeast(results->rawbuf[offset], LG_MIN_GAP_TICKS * s_tick)) + !matchAtLeast(results->rawbuf[offset], kLgMinGapTicks * s_tick)) return false; } @@ -208,7 +277,10 @@ bool IRrecv::decodeLG(decode_results *results, uint16_t nbits, bool strict) { return false; // The last 4 bits sent are the expected checksum. // Success - results->decode_type = LG; + if (isLg2) + results->decode_type = LG2; + else + results->decode_type = LG; results->bits = nbits; results->value = data; results->command = command; diff --git a/lib/IRremoteESP8266/src/ir_Lasertag.cpp b/lib/IRremoteESP8266/src/ir_Lasertag.cpp index 2fc930b..7f0b89a 100644 --- a/lib/IRremoteESP8266/src/ir_Lasertag.cpp +++ b/lib/IRremoteESP8266/src/ir_Lasertag.cpp @@ -12,14 +12,14 @@ // LLLLLLL AA AA SSSSS EEEEEEE RR RR TTT AA AA GGGGGG // Constants -#define MIN_LASERTAG_SAMPLES 13U -#define LASERTAG_TICK 333U -#define LASERTAG_MIN_GAP 100000UL // Completely made up amount. -#define LASERTAG_TOLERANCE 0U // Percentage error margin -#define LASERTAG_EXCESS 0U // See MARK_EXCESS -#define LASERTAG_DELTA 150U // Use instead of EXCESS and TOLERANCE. -const int16_t kSPACE = 1; -const int16_t kMARK = 0; +const uint16_t kLasertagMinSamples = 13; +const uint16_t kLasertagTick = 333; +const uint32_t kLasertagMinGap = 100000; // Completely made up amount. +const uint8_t kLasertagTolerance = 0; // Percentage error margin. +const uint16_t kLasertagExcess = 0; // See kMarkExcess. +const uint16_t kLasertagDelta = 150; // Use instead of Excess and Tolerance. +const int16_t kSpace = 1; +const int16_t kMark = 0; #if SEND_LASERTAG // Send a Lasertag packet. @@ -32,10 +32,8 @@ const int16_t kMARK = 0; // // Status: STABLE / Working. // - void IRsend::sendLasertag(uint64_t data, uint16_t nbits, uint16_t repeat) { - if (nbits > sizeof(data) * 8) - return; // We can't send something that big. + if (nbits > sizeof(data) * 8) return; // We can't send something that big. // Set 36kHz IR carrier frequency & a 1/4 (25%) duty cycle. // NOTE: duty cycle is not confirmed. Just guessing based on RC5/6 protocols. @@ -44,15 +42,15 @@ void IRsend::sendLasertag(uint64_t data, uint16_t nbits, uint16_t repeat) { for (uint16_t i = 0; i <= repeat; i++) { // Data for (uint64_t mask = 1ULL << (nbits - 1); mask; mask >>= 1) - if (data & mask) { // 1 - space(LASERTAG_TICK); // 1 is space, then mark. - mark(LASERTAG_TICK); - } else { // 0 - mark(LASERTAG_TICK); // 0 is mark, then space. - space(LASERTAG_TICK); + if (data & mask) { // 1 + space(kLasertagTick); // 1 is space, then mark. + mark(kLasertagTick); + } else { // 0 + mark(kLasertagTick); // 0 is mark, then space. + space(kLasertagTick); } // Footer - space(LASERTAG_MIN_GAP); + space(kLasertagMinGap); } } #endif // SEND_LASERTAG @@ -76,12 +74,12 @@ void IRsend::sendLasertag(uint64_t data, uint16_t nbits, uint16_t repeat) { // https://en.wikipedia.org/wiki/Manchester_code bool IRrecv::decodeLasertag(decode_results *results, uint16_t nbits, bool strict) { - if (results->rawlen < MIN_LASERTAG_SAMPLES) return false; + if (results->rawlen < kLasertagMinSamples) return false; // Compliance - if (strict && nbits != LASERTAG_BITS) return false; + if (strict && nbits != kLasertagBits) return false; - uint16_t offset = OFFSET_START; + uint16_t offset = kStartOffset; uint16_t used = 0; uint64_t data = 0; uint16_t actual_bits = 0; @@ -90,19 +88,19 @@ bool IRrecv::decodeLasertag(decode_results *results, uint16_t nbits, // Data for (; offset <= results->rawlen; actual_bits++) { - int16_t levelA = getRClevel(results, &offset, &used, LASERTAG_TICK, - LASERTAG_TOLERANCE, LASERTAG_EXCESS, - LASERTAG_DELTA); - int16_t levelB = getRClevel(results, &offset, &used, LASERTAG_TICK, - LASERTAG_TOLERANCE, LASERTAG_EXCESS, - LASERTAG_DELTA); - if (levelA == kSPACE && levelB == kMARK) { + int16_t levelA = + getRClevel(results, &offset, &used, kLasertagTick, kLasertagTolerance, + kLasertagExcess, kLasertagDelta); + int16_t levelB = + getRClevel(results, &offset, &used, kLasertagTick, kLasertagTolerance, + kLasertagExcess, kLasertagDelta); + if (levelA == kSpace && levelB == kMark) { data = (data << 1) | 1; // 1 } else { - if (levelA == kMARK && levelB == kSPACE) { + if (levelA == kMark && levelB == kSpace) { data <<= 1; // 0 } else { - break; + break; } } } @@ -110,7 +108,7 @@ bool IRrecv::decodeLasertag(decode_results *results, uint16_t nbits, // Compliance if (actual_bits < nbits) return false; // Less data than we expected. - if (strict && actual_bits != LASERTAG_BITS) return false; + if (strict && actual_bits != kLasertagBits) return false; // Success results->decode_type = LASERTAG; diff --git a/lib/IRremoteESP8266/src/ir_Lutron.cpp b/lib/IRremoteESP8266/src/ir_Lutron.cpp new file mode 100644 index 0000000..00eb938 --- /dev/null +++ b/lib/IRremoteESP8266/src/ir_Lutron.cpp @@ -0,0 +1,156 @@ +// Copyright 2018 David Conran + +#define __STDC_LIMIT_MACROS +#include +#include +#include "IRrecv.h" +#include "IRsend.h" +#include "IRutils.h" + +// LL UU UU TTTTTTT RRRRRR OOOOO NN NN +// LL UU UU TTT RR RR OO OO NNN NN +// LL UU UU TTT RRRRRR OO OO NN N NN +// LL UU UU TTT RR RR OO OO NN NNN +// LLLLLLL UUUUU TTT RR RR OOOO0 NN NN + +// Notes: +// The Lutron protocol uses a sort of Run Length encoding to encode +// its data. There is no header or footer per-se. +// As a mark is the first data we will notice, we always assume the First +// bit of the technically 36-bit protocol is '1'. So it is assumed, and thus +// we only care about the 35 bits of data. + +// Constants +// Ref: +// https://github.com/markszabo/IRremoteESP8266/issues/515 +const uint16_t kLutronTick = 2288; +const uint32_t kLutronGap = 150000; // Completely made up value. +const uint16_t kLutronDelta = 400; // +/- 300 usecs. + +#if SEND_LUTRON +// Send a Lutron formatted message. +// +// Args: +// data: The message to be sent. +// nbits: The number of bits of the message to be sent. Typically kLutronBits +// repeat: The number of times the command is to be repeated. +// +// Status: Stable / Appears to be working for real devices. + +// Notes: +// Protocol is really 36 bits long, but the first bit is always a 1. +// So, assume the 1 and only have a normal payload of 35 bits. +// +// Ref: +// https://github.com/markszabo/IRremoteESP8266/issues/515 +void IRsend::sendLutron(uint64_t data, uint16_t nbits, uint16_t repeat) { + enableIROut(40000, 40); // 40Khz & 40% dutycycle. + for (uint16_t r = 0; r <= repeat; r++) { + mark(kLutronTick); // 1st bit is always '1'. + // Send the supplied data in MSB First order. + for (uint64_t mask = 1ULL << (nbits - 1); mask; mask >>= 1) + if (data & mask) + mark(kLutronTick); // Send a 1 + else + space(kLutronTick); // Send a 0 + space(kLutronGap); // Inter-message gap. + } +} +#endif // SEND_LUTRON + +#if DECODE_LUTRON +// Decode the supplied Lutron message. +// +// Args: +// results: Ptr to the data to decode and where to store the decode result. +// nbits: The number of data bits to expect. Typically kLutronBits. +// strict: Flag indicating if we should perform strict matching. +// Returns: +// boolean: True if it can decode it, false if it can't. +// +// Status: ALPHA / Untested. +// +// Notes: +// +// Ref: +// https://github.com/markszabo/IRremoteESP8266/issues/515 +bool IRrecv::decodeLutron(decode_results *results, uint16_t nbits, + bool strict) { + // Technically the smallest number of entries for the smallest message is '1'. + // i.e. All the bits set to 1, would produce a single huge mark signal. + // So no minimum length check is required. + if (strict && nbits != kLutronBits) + return false; // Not strictly an Lutron message. + + uint64_t data = 0; + int16_t bitsSoFar = -1; + + if (nbits > sizeof(data) * 8) return false; // To large to store the data. + for (uint16_t offset = kStartOffset; + bitsSoFar < nbits && offset < results->rawlen; offset++) { + uint16_t entry = results->rawbuf[offset]; + // It has to be large enough to qualify as a bit. + if (!matchAtLeast(entry, kLutronTick, 0, kLutronDelta)) { + DPRINTLN("Entry too small. Aborting."); + return false; + } + // Keep reading bits of the same value until we run out. + while (entry != 0 && matchAtLeast(entry, kLutronTick, 0, kLutronDelta)) { + bitsSoFar++; + DPRINT("Bit: "); + DPRINT(bitsSoFar); + if (offset % 2) { // Is Odd? + data = (data << 1) + 1; // Append a '1'. + DPRINTLN(" is a 1."); + } else { // Is it Even? + data <<= 1; // Append a '0'. + DPRINTLN(" is a 0."); + if (bitsSoFar == nbits && matchAtLeast(entry, kLutronGap)) + break; // We've likely reached the end of a message. + } + // Remove a bit length from the current entry. + entry = std::max(entry, (uint16_t)(kLutronTick / kRawTick)) - + kLutronTick / kRawTick; + } + if (offset % 2 && !match(entry, kLutronDelta, 0, kLutronDelta)) { + DPRINT("offset = "); + DPRINTLN(offset); + DPRINT("rawlen = "); + DPRINTLN(results->rawlen); + DPRINT("entry = "); + DPRINTLN(entry); + DPRINTLN("Odd Entry has too much left over. Aborting."); + return false; // Too much left over to be a good value. Reject it. + } + if (offset % 2 == 0 && offset <= results->rawlen - 1 && + !matchAtLeast(entry, kLutronDelta, 0, kLutronDelta)) { + DPRINT("offset = "); + DPRINTLN(offset); + DPRINT("rawlen = "); + DPRINTLN(results->rawlen); + DPRINT("entry = "); + DPRINTLN(entry); + DPRINTLN("Entry has too much left over. Aborting."); + return false; // Too much left over to be a good value. Reject it. + } + } + + // We got too many bits. + if (bitsSoFar > nbits || bitsSoFar < 0) { + DPRINTLN("Wrong number of bits found. Aborting."); + return false; + } + // If we got less bits than we were expecting, we need to pad with zeros + // until we get the correct number of bits. + if (bitsSoFar < nbits) data <<= (nbits - bitsSoFar); + + // Success + DPRINTLN("Lutron Success!"); + results->decode_type = LUTRON; + results->bits = bitsSoFar; + results->value = data ^ (1ULL << nbits); // Mask off the initial '1'. + results->address = 0; + results->command = 0; + return true; +} +#endif // DECODE_LUTRON diff --git a/lib/IRremoteESP8266/src/ir_MWM.cpp b/lib/IRremoteESP8266/src/ir_MWM.cpp new file mode 100644 index 0000000..a75e99e --- /dev/null +++ b/lib/IRremoteESP8266/src/ir_MWM.cpp @@ -0,0 +1,202 @@ +// Copyright 2018 Brett T. Warden +// derived from ir_Lasertag.cpp, Copyright 2017 David Conran + +#include +#include "IRrecv.h" +#include "IRsend.h" +#include "IRutils.h" + +// MM MM WW WW MM MM +// MMM MMM WW WW MMM MMM +// MM M MM WW W WW MM M MM +// MM MM WWW WWW MM MM +// MM MM WW WW MM MM + +// Constants +const uint16_t kMWMMinSamples = 6; // Msgs are >=3 bytes, bytes have >=2 + // samples +const uint16_t kMWMTick = 417; +const uint32_t kMWMMinGap = 30000; // Typical observed delay b/w commands +const uint8_t kMWMTolerance = 0; // Percentage error margin. +const uint16_t kMWMExcess = 0; // See kMarkExcess. +const uint16_t kMWMDelta = 150; // Use instead of Excess and Tolerance. +const uint8_t kMWMMaxWidth = 9; // Maximum number of successive bits at a + // single level - worst case +const int16_t kSpace = 1; +const int16_t kMark = 0; + +#if SEND_MWM +// Send a MWM packet. +// This protocol is 2400 bps serial, 1 start bit (mark), 1 stop bit (space), no +// parity +// +// Args: +// data: The message you wish to send. +// nbits: Bit size of the protocol you want to send. +// repeat: Nr. of extra times the data will be sent. +// +// Status: Implemented. +// +void IRsend::sendMWM(uint8_t data[], uint16_t nbytes, uint16_t repeat) { + if (nbytes < 3) return; // Shortest possible message is 3 bytes + + // Set 38kHz IR carrier frequency & a 1/4 (25%) duty cycle. + // NOTE: duty cycle is not confirmed. Just guessing based on RC5/6 protocols. + enableIROut(38, 25); + + for (uint16_t r = 0; r <= repeat; r++) { + // Data + for (uint16_t i = 0; i < nbytes; i++) { + uint8_t byte = data[i]; + + // Start bit + mark(kMWMTick); + + // LSB first, space=1 + for (uint8_t mask = 0x1; mask; mask <<= 1) { + if (byte & mask) { // 1 + space(kMWMTick); + } else { // 0 + mark(kMWMTick); + } + } + // Stop bit + space(kMWMTick); + } + // Footer + space(kMWMMinGap); + } +} +#endif // SEND_MWM + +#if DECODE_MWM +// Decode the supplied MWM message. +// This protocol is 2400 bps serial, 1 start bit (mark), 1 stop bit (space), no +// parity +// +// Args: +// results: Ptr to the data to decode and where to store the decode result. +// nbits: The number of data bits to expect. +// strict: Flag indicating if we should perform strict matching. +// Returns: +// boolean: True if it can decode it, false if it can't. +// +// Status: Implemented. +// +bool IRrecv::decodeMWM(decode_results *results, uint16_t nbits, bool strict) { + DPRINTLN("DEBUG: decodeMWM"); + + // Compliance + if (results->rawlen < kMWMMinSamples) { + DPRINTLN("DEBUG: decodeMWM: too few samples"); + return false; + } + + uint16_t offset = kStartOffset; + uint16_t used = 0; + uint64_t data = 0; + uint16_t frame_bits = 0; + uint16_t data_bits = 0; + + // No Header + + // Data + uint8_t bits_per_frame = 10; + for (; offset < results->rawlen && results->bits < 8 * kStateSizeMax; + frame_bits++) { + DPRINT("DEBUG: decodeMWM: offset = "); + DPRINTLN(uint64ToString(offset)); + int16_t level = getRClevel(results, &offset, &used, kMWMTick, kMWMTolerance, + kMWMExcess, kMWMDelta, kMWMMaxWidth); + if (level < 0) { + DPRINTLN("DEBUG: decodeMWM: getRClevel returned error"); + break; + } + switch (frame_bits % bits_per_frame) { + case 0: + // Start bit + if (level != kMark) { + DPRINTLN("DEBUG: decodeMWM: framing error - invalid start bit"); + goto done; + } + break; + case 9: + // Stop bit + if (level != kSpace) { + DPRINTLN("DEBUG: decodeMWM: framing error - invalid stop bit"); + return false; + } else { + DPRINT("DEBUG: decodeMWM: data_bits = "); + DPRINTLN(data_bits); + DPRINT("DEBUG: decodeMWM: Finished byte: "); + DPRINTLN(data); + results->state[data_bits / 8 - 1] = data & 0xFF; + results->bits = data_bits; + data = 0; + } + break; + default: + // Data bits + DPRINT("DEBUG: decodeMWM: Storing bit: "); + DPRINTLN((level == kSpace)); + // Transmission is LSB-first, space=1 + data |= ((level == kSpace)) << 8; + data >>= 1; + data_bits++; + break; + } + } + +done: + // Footer (None) + + // Compliance + DPRINT("DEBUG: decodeMWM: frame_bits = "); + DPRINTLN(frame_bits); + DPRINT("DEBUG: decodeMWM: data_bits = "); + DPRINTLN(data_bits); + if (data_bits < nbits) { + DPRINT("DEBUG: decodeMWM: too few bits; expected "); + DPRINTLN(nbits); + return false; // Less data than we expected. + } + + uint16_t payload_length = 0; + switch (results->state[0] & 0xf0) { + case 0x90: + case 0xf0: + // Normal commands + payload_length = results->state[0] & 0x0f; + DPRINT("DEBUG: decodeMWM: payload_length = "); + DPRINTLN(payload_length); + break; + default: + if (strict) { + // Show commands + if (results->state[0] != 0x55 && results->state[1] != 0xAA) { + return false; + } + } + break; + } + if (data_bits < (payload_length + 3) * 8) { + DPRINT("DEBUG: decodeMWM: too few bytes; expected "); + DPRINTLN((payload_length + 3)); + return false; + } + if (strict) { + if (payload_length && (data_bits > (payload_length + 3) * 8)) { + DPRINT("DEBUG: decodeMWM: too many bytes; expected "); + DPRINTLN((payload_length + 3)); + return false; + } + } + + // Success + results->decode_type = MWM; + results->repeat = false; + return true; +} +#endif // DECODE_MWM + +// vim: et:ts=2:sw=2 diff --git a/lib/IRremoteESP8266/src/ir_Magiquest.cpp b/lib/IRremoteESP8266/src/ir_Magiquest.cpp index dcf2174..863aa0e 100644 --- a/lib/IRremoteESP8266/src/ir_Magiquest.cpp +++ b/lib/IRremoteESP8266/src/ir_Magiquest.cpp @@ -8,8 +8,8 @@ #include "IRsend.h" #include "IRutils.h" -#define IS_ZERO(m, s) (((m) * 100 / ((m) + (s))) <= MAGIQUEST_ZERO_RATIO) -#define IS_ONE(m, s) (((m) * 100 / ((m) + (s))) >= MAGIQUEST_ONE_RATIO) +#define IS_ZERO(m, s) (((m)*100 / ((m) + (s))) <= kMagiQuestZeroRatio) +#define IS_ONE(m, s) (((m)*100 / ((m) + (s))) >= kMagiQuestOneRatio) // Strips taken from: // https://github.com/kitlaan/Arduino-IRremote/blob/master/ir_Magiquest.cpp @@ -24,7 +24,7 @@ // Args: // data: The contents of the message you want to send. // nbits: The bit size of the message being sent. -// Typically MAGIQUEST_BITS. +// Typically kMagiquestBits. // repeat: The number of times you want the message to be repeated. // // Status: Alpha / Should be working. @@ -32,11 +32,10 @@ void IRsend::sendMagiQuest(uint64_t data, uint16_t nbits, uint16_t repeat) { sendGeneric(0, 0, // No Headers - Technically it's included in the data. // i.e. 8 zeros. - MAGIQUEST_MARK_ONE, MAGIQUEST_SPACE_ONE, - MAGIQUEST_MARK_ZERO, MAGIQUEST_SPACE_ZERO, + kMagiQuestMarkOne, kMagiQuestSpaceOne, kMagiQuestMarkZero, + kMagiQuestSpaceZero, 0, // No footer mark. - MAGIQUEST_GAP, - data, nbits, 36, true, repeat, 50); + kMagiQuestGap, data, nbits, 36, true, repeat, 50); } // Encode a MagiQuest wand_id, and a magnitude into a single 64bit value. @@ -54,7 +53,8 @@ uint64_t IRsend::encodeMagiQuest(uint32_t wand_id, uint16_t magnitude) { } #endif -// Source: https://github.com/kitlaan/Arduino-IRremote/blob/master/ir_Magiquest.cpp +// Source: +// https://github.com/kitlaan/Arduino-IRremote/blob/master/ir_Magiquest.cpp #if DECODE_MAGIQUEST // Decode the supplied MagiQuest message. @@ -68,7 +68,7 @@ uint64_t IRsend::encodeMagiQuest(uint32_t wand_id, uint16_t magnitude) { // Args: // results: Ptr to the data to decode and where to store the decode result. // nbits: Nr. of bits to expect in the data portion, inc. the 8 bit header. -// Typically MAGIQUEST_BITS. +// Typically kMagiquestBits. // strict: Flag to indicate if we strictly adhere to the specification. // Returns: // boolean: True if it can decode it, false if it can't. @@ -81,18 +81,18 @@ bool IRrecv::decodeMagiQuest(decode_results *results, uint16_t nbits, bool strict) { uint16_t bits = 0; uint64_t data = 0; - uint16_t offset = OFFSET_START; + uint16_t offset = kStartOffset; - if (results->rawlen < (2 * MAGIQUEST_BITS)) { + if (results->rawlen < (2 * kMagiquestBits)) { DPRINT("Not enough bits to be Magiquest - Rawlen: "); DPRINT(results->rawlen); DPRINT(" Expected: "); - DPRINTLN((2 * MAGIQUEST_BITS)); + DPRINTLN((2 * kMagiquestBits)); return false; } // Compliance - if (strict && nbits != MAGIQUEST_BITS) return false; + if (strict && nbits != kMagiquestBits) return false; // Of six wands as datapoints, so far they all start with 8 ZEROs. // For example, here is the data from two wands @@ -101,23 +101,26 @@ bool IRrecv::decodeMagiQuest(decode_results *results, uint16_t nbits, // Decode the (MARK + SPACE) bits while (offset + 1 < results->rawlen && bits < nbits - 1) { - uint16_t mark = results->rawbuf[offset]; + uint16_t mark = results->rawbuf[offset]; uint16_t space = results->rawbuf[offset + 1]; - if (!matchMark(mark + space, MAGIQUEST_TOTAL_USEC)) { + if (!matchMark(mark + space, kMagiQuestTotalUsec)) { DPRINT("Not enough time to be Magiquest - Mark: "); DPRINT(mark); DPRINT(" Space: "); DPRINT(space); DPRINT(" Total: "); - DPRINT(mark+space); + DPRINT(mark + space); DPRINT("Expected: "); - DPRINTLN(MAGIQUEST_TOTAL_USEC); + DPRINTLN(kMagiQuestTotalUsec); return false; } - if (IS_ZERO(mark, space)) data = (data << 1) | 0; - else if (IS_ONE( mark, space)) data = (data << 1) | 1; - else return false; + if (IS_ZERO(mark, space)) + data = (data << 1) | 0; + else if (IS_ONE(mark, space)) + data = (data << 1) | 1; + else + return false; bits++; offset += 2; @@ -125,35 +128,38 @@ bool IRrecv::decodeMagiQuest(decode_results *results, uint16_t nbits, // Compliance // The first 8 bits of this protocol are supposed to all be 0. // Exit out early as it is never going to match. - if (strict && bits == 8 && data != 0) return false; + if (strict && bits == 8 && data != 0) return false; } // Last bit is special as the protocol ends with a SPACE, not a MARK. // Grab the last MARK bit, assuming a good SPACE after it if (offset < results->rawlen) { - uint16_t mark = results->rawbuf[offset]; - uint16_t space = (MAGIQUEST_TOTAL_USEC / RAWTICK) - mark; + uint16_t mark = results->rawbuf[offset]; + uint16_t space = (kMagiQuestTotalUsec / kRawTick) - mark; - if (IS_ZERO(mark, space)) data = (data << 1) | 0; - else if (IS_ONE( mark, space)) data = (data << 1) | 1; - else return false; + if (IS_ZERO(mark, space)) + data = (data << 1) | 0; + else if (IS_ONE(mark, space)) + data = (data << 1) | 1; + else + return false; bits++; } - if (bits != nbits) return false; + if (bits != nbits) return false; if (strict) { // The top 8 bits of the 56 bits needs to be 0x00 to be valid. // i.e. bits 56 to 49 are all zero. - if ((data >> (nbits - 8)) != 0) return false; + if ((data >> (nbits - 8)) != 0) return false; } // Success results->decode_type = MAGIQUEST; results->bits = bits; results->value = data; - results->address = data >> 16; // Wand ID + results->address = data >> 16; // Wand ID results->command = data & 0xFFFF; // Magnitude return true; } diff --git a/lib/IRremoteESP8266/src/ir_Magiquest.h b/lib/IRremoteESP8266/src/ir_Magiquest.h index 94cebfc..d2d82d1 100644 --- a/lib/IRremoteESP8266/src/ir_Magiquest.h +++ b/lib/IRremoteESP8266/src/ir_Magiquest.h @@ -13,25 +13,23 @@ // MagiQuest packet is both Wand ID and magnitude of swish and flick union magiquest { uint64_t llword; - uint8_t byte[8]; -// uint16_t word[4]; - uint32_t lword[2]; + uint8_t byte[8]; + // uint16_t word[4]; + uint32_t lword[2]; struct { uint16_t magnitude; uint32_t wand_id; - uint8_t padding; - uint8_t scrap; + uint8_t padding; + uint8_t scrap; } cmd; }; -#define MAGIQUEST_TOTAL_USEC 1150U -#define MAGIQUEST_ZERO_RATIO 30U // usually <= ~25% -#define MAGIQUEST_ONE_RATIO 38U // usually >= ~50% - -#define MAGIQUEST_PERIOD 1150U -#define MAGIQUEST_MARK_ZERO 280U -#define MAGIQUEST_SPACE_ZERO 850U -#define MAGIQUEST_MARK_ONE 580U -#define MAGIQUEST_SPACE_ONE 600U -#define MAGIQUEST_GAP 100000UL // A guess of the gap between messages -#endif // IR_MAGIQUEST_H_ +const uint16_t kMagiQuestTotalUsec = 1150; +const uint8_t kMagiQuestZeroRatio = 30; // usually <= ~25% +const uint8_t kMagiQuestOneRatio = 38; // usually >= ~50% +const uint16_t kMagiQuestMarkZero = 280; +const uint16_t kMagiQuestSpaceZero = 850; +const uint16_t kMagiQuestMarkOne = 580; +const uint16_t kMagiQuestSpaceOne = 600; +const uint32_t kMagiQuestGap = 100000; // A guess of the gap between messages +#endif // IR_MAGIQUEST_H_ diff --git a/lib/IRremoteESP8266/src/ir_Midea.cpp b/lib/IRremoteESP8266/src/ir_Midea.cpp index a3dd890..af40fcc 100644 --- a/lib/IRremoteESP8266/src/ir_Midea.cpp +++ b/lib/IRremoteESP8266/src/ir_Midea.cpp @@ -26,35 +26,34 @@ // https://docs.google.com/spreadsheets/d/1TZh4jWrx4h9zzpYUI9aYXMl1fYOiqu-xVuOOMqagxrs/edit?usp=sharing // Constants -#define MIDEA_TICK 80U -#define MIDEA_BIT_MARK_TICKS 7U -#define MIDEA_BIT_MARK (MIDEA_BIT_MARK_TICKS * MIDEA_TICK) -#define MIDEA_ONE_SPACE_TICKS 21U -#define MIDEA_ONE_SPACE (MIDEA_ONE_SPACE_TICKS * MIDEA_TICK) -#define MIDEA_ZERO_SPACE_TICKS 7U -#define MIDEA_ZERO_SPACE (MIDEA_ZERO_SPACE_TICKS * MIDEA_TICK) -#define MIDEA_HDR_MARK_TICKS 56U -#define MIDEA_HDR_MARK (MIDEA_HDR_MARK_TICKS * MIDEA_TICK) -#define MIDEA_HDR_SPACE_TICKS 56U -#define MIDEA_HDR_SPACE (MIDEA_HDR_SPACE_TICKS * MIDEA_TICK) -#define MIDEA_MIN_GAP_TICKS (MIDEA_HDR_MARK_TICKS + MIDEA_ZERO_SPACE_TICKS \ - + MIDEA_BIT_MARK_TICKS) -#define MIDEA_MIN_GAP (MIDEA_MIN_GAP_TICKS * MIDEA_TICK) -#define MIDEA_TOLERANCE 30U // Percent +const uint16_t kMideaTick = 80; +const uint16_t kMideaBitMarkTicks = 7; +const uint16_t kMideaBitMark = kMideaBitMarkTicks * kMideaTick; +const uint16_t kMideaOneSpaceTicks = 21; +const uint16_t kMideaOneSpace = kMideaOneSpaceTicks * kMideaTick; +const uint16_t kMideaZeroSpaceTicks = 7; +const uint16_t kMideaZeroSpace = kMideaZeroSpaceTicks * kMideaTick; +const uint16_t kMideaHdrMarkTicks = 56; +const uint16_t kMideaHdrMark = kMideaHdrMarkTicks * kMideaTick; +const uint16_t kMideaHdrSpaceTicks = 56; +const uint16_t kMideaHdrSpace = kMideaHdrSpaceTicks * kMideaTick; +const uint16_t kMideaMinGapTicks = + kMideaHdrMarkTicks + kMideaZeroSpaceTicks + kMideaBitMarkTicks; +const uint16_t kMideaMinGap = kMideaMinGapTicks * kMideaTick; +const uint8_t kMideaTolerance = 30; // Percent #if SEND_MIDEA // Send a Midea message // // Args: // data: Contents of the message to be sent. -// nbits: Nr. of bits of data to be sent. Typically MIDEA_BITS. +// nbits: Nr. of bits of data to be sent. Typically kMideaBits. // repeat: Nr. of additional times the message is to be sent. // // Status: Alpha / Needs testing against a real device. // void IRsend::sendMidea(uint64_t data, uint16_t nbits, uint16_t repeat) { - if (nbits % 8 != 0) - return; // nbits is required to be a multiple of 8. + if (nbits % 8 != 0) return; // nbits is required to be a multiple of 8. // Set IR carrier frequency enableIROut(38); @@ -64,21 +63,20 @@ void IRsend::sendMidea(uint64_t data, uint16_t nbits, uint16_t repeat) { // inverted payload. for (size_t inner_loop = 0; inner_loop < 2; inner_loop++) { // Header - mark(MIDEA_HDR_MARK); - space(MIDEA_HDR_SPACE); + mark(kMideaHdrMark); + space(kMideaHdrSpace); // Data // Break data into byte segments, starting at the Most Significant // Byte. Each byte then being sent normal, then followed inverted. for (uint16_t i = 8; i <= nbits; i += 8) { // Grab a bytes worth of data. uint8_t segment = (data >> (nbits - i)) & 0xFF; - sendData(MIDEA_BIT_MARK, MIDEA_ONE_SPACE, - MIDEA_BIT_MARK, MIDEA_ZERO_SPACE, + sendData(kMideaBitMark, kMideaOneSpace, kMideaBitMark, kMideaZeroSpace, segment, 8, true); } // Footer - mark(MIDEA_BIT_MARK); - space(MIDEA_MIN_GAP); // Pause before repeating + mark(kMideaBitMark); + space(kMideaMinGap); // Pause before repeating // Invert the data for the 2nd phase of the message. // As we get called twice in the inner loop, we will always revert @@ -93,9 +91,7 @@ void IRsend::sendMidea(uint64_t data, uint16_t nbits, uint16_t repeat) { // Warning: Consider this very alpha code. // Initialise the object. -IRMideaAC::IRMideaAC(uint16_t pin) : _irsend(pin) { - stateReset(); -} +IRMideaAC::IRMideaAC(uint16_t pin) : _irsend(pin) { stateReset(); } // Reset the state of the remote to a known good state/sequence. void IRMideaAC::stateReset() { @@ -104,38 +100,32 @@ void IRMideaAC::stateReset() { } // Configure the pin for output. -void IRMideaAC::begin() { - _irsend.begin(); -} +void IRMideaAC::begin() { _irsend.begin(); } #if SEND_MIDEA // Send the current desired state to the IR LED. -void IRMideaAC::send() { - checksum(); // Ensure correct checksum before sending. - _irsend.sendMidea(remote_state); +void IRMideaAC::send(const uint16_t repeat) { + checksum(); // Ensure correct checksum before sending. + _irsend.sendMidea(remote_state, kMideaBits, repeat); } #endif // SEND_MIDEA // Return a pointer to the internal state date of the remote. uint64_t IRMideaAC::getRaw() { checksum(); - return remote_state & MIDEA_AC_STATE_MASK; + return remote_state & kMideaACStateMask; } // Override the internal state with the new state. void IRMideaAC::setRaw(uint64_t newState) { - remote_state = newState & MIDEA_AC_STATE_MASK; + remote_state = newState & kMideaACStateMask; } // Set the requested power state of the A/C to off. -void IRMideaAC::on() { - remote_state |= MIDEA_AC_POWER; -} +void IRMideaAC::on() { remote_state |= kMideaACPower; } // Set the requested power state of the A/C to off. -void IRMideaAC::off() { - remote_state &= (MIDEA_AC_STATE_MASK ^ MIDEA_AC_POWER); -} +void IRMideaAC::off() { remote_state &= (kMideaACStateMask ^ kMideaACPower); } // Set the requested power state of the A/C. void IRMideaAC::setPower(const bool state) { @@ -146,37 +136,35 @@ void IRMideaAC::setPower(const bool state) { } // Return the requested power state of the A/C. -bool IRMideaAC::getPower() { - return (remote_state & MIDEA_AC_POWER); -} +bool IRMideaAC::getPower() { return (remote_state & kMideaACPower); } // Set the temperature. // Args: // temp: Temp. in degrees. -// useCelsius: Degree type to use. celsius (true) or fahrenheit (false) +// useCelsius: Degree type to use. Celsius (true) or Fahrenheit (false) void IRMideaAC::setTemp(const uint8_t temp, const bool useCelsius) { uint8_t new_temp = temp; if (useCelsius) { - new_temp = std::max((uint8_t) MIDEA_AC_MIN_TEMP_C, new_temp); - new_temp = std::min((uint8_t) MIDEA_AC_MAX_TEMP_C, new_temp); - new_temp = (uint8_t) ((new_temp * 1.8) + 32.5); // 0.5 so we rounding. + new_temp = std::max(kMideaACMinTempC, new_temp); + new_temp = std::min(kMideaACMaxTempC, new_temp); + new_temp = (uint8_t)((new_temp * 1.8) + 32.5); // 0.5 so we rounding. } - new_temp = std::max((uint8_t) MIDEA_AC_MIN_TEMP_F, new_temp); - new_temp = std::min((uint8_t) MIDEA_AC_MAX_TEMP_F, new_temp); - new_temp -= MIDEA_AC_MIN_TEMP_F; - remote_state &= MIDEA_AC_TEMP_MASK; - remote_state |= ((uint64_t) new_temp << 24); + new_temp = std::max(kMideaACMinTempF, new_temp); + new_temp = std::min(kMideaACMaxTempF, new_temp); + new_temp -= kMideaACMinTempF; + remote_state &= kMideaACTempMask; + remote_state |= ((uint64_t)new_temp << 24); } // Return the set temp. // Args: -// useCelsius: Flag indicating if the results are in celsius or fahrenheit. +// useCelsius: Flag indicating if the results are in Celsius or Fahrenheit. // Returns: // A uint8_t containing the temperature. uint8_t IRMideaAC::getTemp(const bool useCelsius) { - uint8_t temp = ((remote_state >> 24) & 0x1F) + MIDEA_AC_MIN_TEMP_F; + uint8_t temp = ((remote_state >> 24) & 0x1F) + kMideaACMinTempF; if (useCelsius) { - temp = (uint8_t) ((temp - 32) / 1.8); + temp = (uint8_t)((temp - 32) / 1.8); } return temp; } @@ -186,61 +174,55 @@ uint8_t IRMideaAC::getTemp(const bool useCelsius) { void IRMideaAC::setFan(const uint8_t fan) { uint64_t new_fan; switch (fan) { - case MIDEA_AC_FAN_LOW: - case MIDEA_AC_FAN_MED: - case MIDEA_AC_FAN_HI: + case kMideaACFanLow: + case kMideaACFanMed: + case kMideaACFanHigh: new_fan = fan; break; default: - new_fan = MIDEA_AC_FAN_AUTO; + new_fan = kMideaACFanAuto; } - remote_state &= MIDEA_AC_FAN_MASK; + remote_state &= kMideaACFanMask; remote_state |= (new_fan << 35); } // Return the requested state of the unit's fan. -uint8_t IRMideaAC::getFan() { - return (remote_state >> 35) & 0b111; -} +uint8_t IRMideaAC::getFan() { return (remote_state >> 35) & 0b111; } // Get the requested climate operation mode of the a/c unit. // Returns: // A uint8_t containing the A/C mode. -uint8_t IRMideaAC::getMode() { - return ((remote_state >> 32) & 0b111); -} +uint8_t IRMideaAC::getMode() { return ((remote_state >> 32) & 0b111); } // Set the requested climate operation mode of the a/c unit. void IRMideaAC::setMode(const uint8_t mode) { // If we get an unexpected mode, default to AUTO. uint64_t new_mode; switch (mode) { - case MIDEA_AC_AUTO: - case MIDEA_AC_COOL: - case MIDEA_AC_HEAT: - case MIDEA_AC_DRY: - case MIDEA_AC_FAN: + case kMideaACAuto: + case kMideaACCool: + case kMideaACHeat: + case kMideaACDry: + case kMideaACFan: new_mode = mode; break; default: - new_mode = MIDEA_AC_AUTO; + new_mode = kMideaACAuto; } - remote_state &= MIDEA_AC_MODE_MASK; + remote_state &= kMideaACModeMask; remote_state |= (new_mode << 32); } // Set the Sleep state of the A/C. void IRMideaAC::setSleep(const bool state) { if (state) - remote_state |= MIDEA_AC_SLEEP; + remote_state |= kMideaACSleep; else - remote_state &= (MIDEA_AC_STATE_MASK ^ MIDEA_AC_SLEEP); + remote_state &= (kMideaACStateMask ^ kMideaACSleep); } // Return the Sleep state of the A/C. -bool IRMideaAC::getSleep() { - return (remote_state & MIDEA_AC_SLEEP); -} +bool IRMideaAC::getSleep() { return (remote_state & kMideaACSleep); } // Calculate the checksum for a given array. // Args: @@ -271,7 +253,7 @@ bool IRMideaAC::validChecksum(const uint64_t state) { // Calculate & set the checksum for the current internal state of the remote. void IRMideaAC::checksum() { // Stored the checksum value in the last byte. - remote_state &= MIDEA_AC_CHECKSUM_MASK; + remote_state &= kMideaACChecksumMask; remote_state |= calcChecksum(remote_state); } @@ -290,38 +272,38 @@ std::string IRMideaAC::toString() { result += "Off"; result += ", Mode: " + uint64ToString(getMode()); switch (getMode()) { - case MIDEA_AC_AUTO: + case kMideaACAuto: result += " (AUTO)"; break; - case MIDEA_AC_COOL: + case kMideaACCool: result += " (COOL)"; break; - case MIDEA_AC_HEAT: + case kMideaACHeat: result += " (HEAT)"; break; - case MIDEA_AC_DRY: + case kMideaACDry: result += " (DRY)"; break; - case MIDEA_AC_FAN: + case kMideaACFan: result += " (FAN)"; break; default: result += " (UNKNOWN)"; } result += ", Temp: " + uint64ToString(getTemp(true)) + "C/" + - uint64ToString(getTemp(false)) + "F"; + uint64ToString(getTemp(false)) + "F"; result += ", Fan: " + uint64ToString(getFan()); switch (getFan()) { - case MIDEA_AC_FAN_AUTO: + case kMideaACFanAuto: result += " (AUTO)"; break; - case MIDEA_AC_FAN_LOW: + case kMideaACFanLow: result += " (LOW)"; break; - case MIDEA_AC_FAN_MED: + case kMideaACFanMed: result += " (MED)"; break; - case MIDEA_AC_FAN_HI: + case kMideaACFanHigh: result += " (HI)"; break; } @@ -338,55 +320,51 @@ std::string IRMideaAC::toString() { // // Args: // results: Ptr to the data to decode and where to store the decode result. -// nbits: The number of data bits to expect. Typically MIDEA_BITS. +// nbits: The number of data bits to expect. Typically kMideaBits. // strict: Flag indicating if we should perform strict matching. // Returns: // boolean: True if it can decode it, false if it can't. // // Status: Alpha / Needs testing against a real device. // -bool IRrecv::decodeMidea(decode_results *results, uint16_t nbits, - bool strict) { +bool IRrecv::decodeMidea(decode_results *results, uint16_t nbits, bool strict) { if (nbits % 8 != 0) // nbits has to be a multiple of nr. of bits in a byte. return false; uint8_t min_nr_of_messages = 1; if (strict) { - if (nbits != MIDEA_BITS) - return false; // Not strictly a MIDEA message. + if (nbits != kMideaBits) return false; // Not strictly a MIDEA message. min_nr_of_messages = 2; } // The protocol sends the data normal + inverted, alternating on // each byte. Hence twice the number of expected data bits. - if (results->rawlen < min_nr_of_messages * (2 * nbits + HEADER + FOOTER) - 1) + if (results->rawlen < + min_nr_of_messages * (2 * nbits + kHeader + kFooter) - 1) return false; // Can't possibly be a valid MIDEA message. uint64_t data = 0; uint64_t inverted = 0; - uint16_t offset = OFFSET_START; + uint16_t offset = kStartOffset; if (nbits > sizeof(data) * 8) return false; // We can't possibly capture a Midea packet that big. for (uint8_t i = 0; i < min_nr_of_messages; i++) { // Header - if (!matchMark(results->rawbuf[offset], MIDEA_HDR_MARK)) return false; + if (!matchMark(results->rawbuf[offset], kMideaHdrMark)) return false; // Calculate how long the common tick time is based on the header mark. - uint32_t m_tick = results->rawbuf[offset++] * RAWTICK / - MIDEA_HDR_MARK_TICKS; - if (!matchSpace(results->rawbuf[offset], MIDEA_HDR_SPACE)) return false; + uint32_t m_tick = results->rawbuf[offset++] * kRawTick / kMideaHdrMarkTicks; + if (!matchSpace(results->rawbuf[offset], kMideaHdrSpace)) return false; // Calculate how long the common tick time is based on the header space. - uint32_t s_tick = results->rawbuf[offset++] * RAWTICK / - MIDEA_HDR_SPACE_TICKS; + uint32_t s_tick = + results->rawbuf[offset++] * kRawTick / kMideaHdrSpaceTicks; // Data (Normal) - match_result_t data_result = matchData(&(results->rawbuf[offset]), nbits, - MIDEA_BIT_MARK_TICKS * m_tick, - MIDEA_ONE_SPACE_TICKS * s_tick, - MIDEA_BIT_MARK_TICKS * m_tick, - MIDEA_ZERO_SPACE_TICKS * s_tick, - MIDEA_TOLERANCE); + match_result_t data_result = matchData( + &(results->rawbuf[offset]), nbits, kMideaBitMarkTicks * m_tick, + kMideaOneSpaceTicks * s_tick, kMideaBitMarkTicks * m_tick, + kMideaZeroSpaceTicks * s_tick, kMideaTolerance); if (data_result.success == false) return false; offset += data_result.used; if (i % 2 == 0) @@ -395,24 +373,23 @@ bool IRrecv::decodeMidea(decode_results *results, uint16_t nbits, inverted = data_result.data; // Footer - if (!matchMark(results->rawbuf[offset++], MIDEA_BIT_MARK_TICKS * m_tick, - MIDEA_TOLERANCE)) + if (!matchMark(results->rawbuf[offset++], kMideaBitMarkTicks * m_tick, + kMideaTolerance)) return false; if (offset < results->rawlen && - !matchAtLeast(results->rawbuf[offset++], MIDEA_MIN_GAP_TICKS * s_tick, - MIDEA_TOLERANCE)) + !matchAtLeast(results->rawbuf[offset++], kMideaMinGapTicks * s_tick, + kMideaTolerance)) return false; } - // Compliance if (strict) { // Protocol requires a second message with all the data bits inverted. // We should have checked we got a second message in the previous loop. // Just need to check it's value is an inverted copy of the first message. - uint64_t mask = (1ULL << MIDEA_BITS) - 1; - if ((data & mask) != ((inverted ^ mask) & mask)) return false; - if (!IRMideaAC::validChecksum(data)) return false; + uint64_t mask = (1ULL << kMideaBits) - 1; + if ((data & mask) != ((inverted ^ mask) & mask)) return false; + if (!IRMideaAC::validChecksum(data)) return false; } // Success diff --git a/lib/IRremoteESP8266/src/ir_Midea.h b/lib/IRremoteESP8266/src/ir_Midea.h index 692cdf0..c749b32 100644 --- a/lib/IRremoteESP8266/src/ir_Midea.h +++ b/lib/IRremoteESP8266/src/ir_Midea.h @@ -23,26 +23,43 @@ // https://docs.google.com/spreadsheets/d/1TZh4jWrx4h9zzpYUI9aYXMl1fYOiqu-xVuOOMqagxrs/edit?usp=sharing // Constants -#define MIDEA_AC_COOL 0U // 0b000 -#define MIDEA_AC_DRY 1U // 0b001 -#define MIDEA_AC_AUTO 2U // 0b010 -#define MIDEA_AC_HEAT 3U // 0b011 -#define MIDEA_AC_FAN 4U // 0b100 -#define MIDEA_AC_POWER 1ULL << 39 -#define MIDEA_AC_SLEEP 1ULL << 38 -#define MIDEA_AC_FAN_AUTO 0U // 0b000 -#define MIDEA_AC_FAN_LOW 1U // 0b001 -#define MIDEA_AC_FAN_MED 2U // 0b010 -#define MIDEA_AC_FAN_HI 3U // 0b011 -#define MIDEA_AC_MIN_TEMP_F 62U // 62F -#define MIDEA_AC_MAX_TEMP_F 86U // 86F -#define MIDEA_AC_MIN_TEMP_C 16U // 16C -#define MIDEA_AC_MAX_TEMP_C 30U // 30C -#define MIDEA_AC_STATE_MASK 0x0000FFFFFFFFFFFFULL -#define MIDEA_AC_TEMP_MASK 0x0000FFFFE0FFFFFFULL -#define MIDEA_AC_FAN_MASK 0x0000FFC7FFFFFFFFULL -#define MIDEA_AC_MODE_MASK 0x0000FFF8FFFFFFFFULL -#define MIDEA_AC_CHECKSUM_MASK 0x0000FFFFFFFFFF00ULL +const uint8_t kMideaACCool = 0; // 0b000 +const uint8_t kMideaACDry = 1; // 0b001 +const uint8_t kMideaACAuto = 2; // 0b010 +const uint8_t kMideaACHeat = 3; // 0b011 +const uint8_t kMideaACFan = 4; // 0b100 +const uint8_t kMideaACFanAuto = 0; // 0b000 +const uint8_t kMideaACFanLow = 1; // 0b001 +const uint8_t kMideaACFanMed = 2; // 0b010 +const uint8_t kMideaACFanHigh = 3; // 0b011 +const uint64_t kMideaACPower = 1ULL << 39; +const uint64_t kMideaACSleep = 1ULL << 38; +const uint8_t kMideaACMinTempF = 62; // Fahrenheit +const uint8_t kMideaACMaxTempF = 86; // Fahrenheit +const uint8_t kMideaACMinTempC = 16; // Celsius +const uint8_t kMideaACMaxTempC = 30; // Celsius +const uint64_t kMideaACStateMask = 0x0000FFFFFFFFFFFF; +const uint64_t kMideaACTempMask = 0x0000FFFFE0FFFFFF; +const uint64_t kMideaACFanMask = 0x0000FFC7FFFFFFFF; +const uint64_t kMideaACModeMask = 0x0000FFF8FFFFFFFF; +const uint64_t kMideaACChecksumMask = 0x0000FFFFFFFFFF00; + +// Legacy defines. (Deprecated) +#define MIDEA_AC_COOL kMideaACCool +#define MIDEA_AC_DRY kMideaACDry +#define MIDEA_AC_AUTO kMideaACAuto +#define MIDEA_AC_HEAT kMideaACHeat +#define MIDEA_AC_FAN kMideaACFan +#define MIDEA_AC_FAN_AUTO kMideaACFanAuto +#define MIDEA_AC_FAN_LOW kMideaACFanLow +#define MIDEA_AC_FAN_MED kMideaACFanMed +#define MIDEA_AC_FAN_HI kMideaACFanHigh +#define MIDEA_AC_POWER kMideaACPower +#define MIDEA_AC_SLEEP kMideaACSleep +#define MIDEA_AC_MIN_TEMP_F kMideaACMinTempF +#define MIDEA_AC_MAX_TEMP_F kMideaACMaxTempF +#define MIDEA_AC_MIN_TEMP_C kMideaACMinTempC +#define MIDEA_AC_MAX_TEMP_C kMideaACMaxTempC class IRMideaAC { public: @@ -50,7 +67,7 @@ class IRMideaAC { void stateReset(); #if SEND_MIDEA - void send(); + void send(const uint16_t repeat = kMideaMinRepeat); #endif // SEND_MIDEA void begin(); void on(); @@ -83,5 +100,4 @@ class IRMideaAC { IRsend _irsend; }; - #endif // IR_MIDEA_H_ diff --git a/lib/IRremoteESP8266/src/ir_Mitsubishi.cpp b/lib/IRremoteESP8266/src/ir_Mitsubishi.cpp index ddee663..655dc5b 100644 --- a/lib/IRremoteESP8266/src/ir_Mitsubishi.cpp +++ b/lib/IRremoteESP8266/src/ir_Mitsubishi.cpp @@ -1,8 +1,12 @@ // Copyright 2009 Ken Shirriff -// Copyright 2017 David Conran +// Copyright 2017-2018 David Conran +// Copyright 2018 Denes Varga #include "ir_Mitsubishi.h" #include +#ifndef ARDUINO +#include +#endif #include "IRrecv.h" #include "IRsend.h" #include "IRutils.h" @@ -22,50 +26,49 @@ // Ref: // GlobalCache's Control Tower's Mitsubishi TV data. // https://github.com/marcosamarinho/IRremoteESP8266/blob/master/ir_Mitsubishi.cpp -#define MITSUBISHI_TICK 30U -#define MITSUBISHI_BIT_MARK_TICKS 10U -#define MITSUBISHI_BIT_MARK (MITSUBISHI_BIT_MARK_TICKS * \ - MITSUBISHI_TICK) -#define MITSUBISHI_ONE_SPACE_TICKS 70U -#define MITSUBISHI_ONE_SPACE (MITSUBISHI_ONE_SPACE_TICKS * \ - MITSUBISHI_TICK) -#define MITSUBISHI_ZERO_SPACE_TICKS 30U -#define MITSUBISHI_ZERO_SPACE (MITSUBISHI_ZERO_SPACE_TICKS * \ - MITSUBISHI_TICK) -#define MITSUBISHI_MIN_COMMAND_LENGTH_TICKS 1786U -#define MITSUBISHI_MIN_COMMAND_LENGTH (MITSUBISHI_MIN_COMMAND_LENGTH_TICKS * \ - MITSUBISHI_TICK) -#define MITSUBISHI_MIN_GAP_TICKS 936U -#define MITSUBISHI_MIN_GAP (MITSUBISHI_MIN_GAP_TICKS * \ - MITSUBISHI_TICK) +const uint16_t kMitsubishiTick = 30; +const uint16_t kMitsubishiBitMarkTicks = 10; +const uint16_t kMitsubishiBitMark = kMitsubishiBitMarkTicks * kMitsubishiTick; +const uint16_t kMitsubishiOneSpaceTicks = 70; +const uint16_t kMitsubishiOneSpace = kMitsubishiOneSpaceTicks * kMitsubishiTick; +const uint16_t kMitsubishiZeroSpaceTicks = 30; +const uint16_t kMitsubishiZeroSpace = + kMitsubishiZeroSpaceTicks * kMitsubishiTick; +const uint16_t kMitsubishiMinCommandLengthTicks = 1786; +const uint16_t kMitsubishiMinCommandLength = + kMitsubishiMinCommandLengthTicks * kMitsubishiTick; +const uint16_t kMitsubishiMinGapTicks = 936; +const uint16_t kMitsubishiMinGap = kMitsubishiMinGapTicks * kMitsubishiTick; // Mitsubishi Projector (HC3000) // Ref: // https://github.com/markszabo/IRremoteESP8266/issues/441 -#define MITSUBISHI2_HDR_MARK 8400U -#define MITSUBISHI2_HDR_SPACE (MITSUBISHI2_HDR_MARK / 2) -#define MITSUBISHI2_BIT_MARK 560U -#define MITSUBISHI2_ZERO_SPACE 520U -#define MITSUBISHI2_ONE_SPACE (MITSUBISHI2_ZERO_SPACE * 3) -#define MITSUBISHI2_MIN_GAP 28500U + +const uint16_t kMitsubishi2HdrMark = 8400; +const uint16_t kMitsubishi2HdrSpace = kMitsubishi2HdrMark / 2; +const uint16_t kMitsubishi2BitMark = 560; +const uint16_t kMitsubishi2ZeroSpace = 520; +const uint16_t kMitsubishi2OneSpace = kMitsubishi2ZeroSpace * 3; +const uint16_t kMitsubishi2MinGap = 28500; // Mitsubishi A/C // Ref: // https://github.com/r45635/HVAC-IR-Control/blob/master/HVAC_ESP8266/HVAC_ESP8266.ino#L84 -#define MITSUBISHI_AC_HDR_MARK 3400U -#define MITSUBISHI_AC_HDR_SPACE 1750U -#define MITSUBISHI_AC_BIT_MARK 450U -#define MITSUBISHI_AC_ONE_SPACE 1300U -#define MITSUBISHI_AC_ZERO_SPACE 420U -#define MITSUBISHI_AC_RPT_MARK 440U -#define MITSUBISHI_AC_RPT_SPACE 17100UL + +const uint16_t kMitsubishiAcHdrMark = 3400; +const uint16_t kMitsubishiAcHdrSpace = 1750; +const uint16_t kMitsubishiAcBitMark = 450; +const uint16_t kMitsubishiAcOneSpace = 1300; +const uint16_t kMitsubishiAcZeroSpace = 420; +const uint16_t kMitsubishiAcRptMark = 440; +const uint16_t kMitsubishiAcRptSpace = 17100; #if SEND_MITSUBISHI // Send a Mitsubishi message // // Args: // data: Contents of the message to be sent. -// nbits: Nr. of bits of data to be sent. Typically MITSUBISHI_BITS. +// nbits: Nr. of bits of data to be sent. Typically kMitsubishiBits. // repeat: Nr. of additional times the message is to be sent. // // Status: ALPHA / untested. @@ -77,13 +80,11 @@ // GlobalCache's Control Tower's Mitsubishi TV data. void IRsend::sendMitsubishi(uint64_t data, uint16_t nbits, uint16_t repeat) { sendGeneric(0, 0, // No Header - MITSUBISHI_BIT_MARK, MITSUBISHI_ONE_SPACE, - MITSUBISHI_BIT_MARK, MITSUBISHI_ZERO_SPACE, - MITSUBISHI_BIT_MARK, MITSUBISHI_MIN_GAP, - MITSUBISHI_MIN_COMMAND_LENGTH, - data, nbits, 33, true, repeat, 50); + kMitsubishiBitMark, kMitsubishiOneSpace, kMitsubishiBitMark, + kMitsubishiZeroSpace, kMitsubishiBitMark, kMitsubishiMinGap, + kMitsubishiMinCommandLength, data, nbits, 33, true, repeat, 50); } -#endif // SEND_MITSUBISHI +#endif // SEND_MITSUBISHI #if DECODE_MITSUBISHI // Decode the supplied Mitsubishi message. @@ -104,44 +105,40 @@ void IRsend::sendMitsubishi(uint64_t data, uint16_t nbits, uint16_t repeat) { // GlobalCache's Control Tower's Mitsubishi TV data. bool IRrecv::decodeMitsubishi(decode_results *results, uint16_t nbits, bool strict) { - if (results->rawlen < 2 * nbits + FOOTER - 1) + if (results->rawlen < 2 * nbits + kFooter - 1) return false; // Shorter than shortest possibly expected. - if (strict && nbits != MITSUBISHI_BITS) + if (strict && nbits != kMitsubishiBits) return false; // Request is out of spec. - uint16_t offset = OFFSET_START; + uint16_t offset = kStartOffset; uint64_t data = 0; // No Header // But try to auto-calibrate off the initial mark signal. - if (!matchMark(results->rawbuf[offset], MITSUBISHI_BIT_MARK, 30)) - return false; + if (!matchMark(results->rawbuf[offset], kMitsubishiBitMark, 30)) return false; // Calculate how long the common tick time is based on the initial mark. - uint32_t tick = results->rawbuf[offset] * RAWTICK / MITSUBISHI_BIT_MARK_TICKS; + uint32_t tick = results->rawbuf[offset] * kRawTick / kMitsubishiBitMarkTicks; // Data - match_result_t data_result = matchData(&(results->rawbuf[offset]), nbits, - MITSUBISHI_BIT_MARK_TICKS * tick, - MITSUBISHI_ONE_SPACE_TICKS * tick, - MITSUBISHI_BIT_MARK_TICKS * tick, - MITSUBISHI_ZERO_SPACE_TICKS * tick); + match_result_t data_result = matchData( + &(results->rawbuf[offset]), nbits, kMitsubishiBitMarkTicks * tick, + kMitsubishiOneSpaceTicks * tick, kMitsubishiBitMarkTicks * tick, + kMitsubishiZeroSpaceTicks * tick); if (data_result.success == false) return false; data = data_result.data; offset += data_result.used; uint16_t actualBits = data_result.used / 2; // Footer - if (!matchMark(results->rawbuf[offset++], MITSUBISHI_BIT_MARK_TICKS * tick, - 30)) return false; + if (!matchMark(results->rawbuf[offset++], kMitsubishiBitMarkTicks * tick, 30)) + return false; if (offset < results->rawlen && - !matchAtLeast(results->rawbuf[offset], MITSUBISHI_MIN_GAP_TICKS * tick)) + !matchAtLeast(results->rawbuf[offset], kMitsubishiMinGapTicks * tick)) return false; // Compliance - if (actualBits < nbits) - return false; - if (strict && actualBits != nbits) - return false; // Not as we expected. + if (actualBits < nbits) return false; + if (strict && actualBits != nbits) return false; // Not as we expected. // Success results->decode_type = MITSUBISHI; @@ -158,7 +155,7 @@ bool IRrecv::decodeMitsubishi(decode_results *results, uint16_t nbits, // // Args: // data: Contents of the message to be sent. -// nbits: Nr. of bits of data to be sent. Typically MITSUBISHI_BITS. +// nbits: Nr. of bits of data to be sent. Typically kMitsubishiBits. // repeat: Nr. of additional times the message is to be sent. // // Status: ALPHA / untested. @@ -175,17 +172,16 @@ bool IRrecv::decodeMitsubishi(decode_results *results, uint16_t nbits, void IRsend::sendMitsubishi2(uint64_t data, uint16_t nbits, uint16_t repeat) { for (uint16_t i = 0; i <= repeat; i++) { // First half of the data. - sendGeneric(MITSUBISHI2_HDR_MARK, MITSUBISHI2_HDR_SPACE, - MITSUBISHI2_BIT_MARK, MITSUBISHI2_ONE_SPACE, - MITSUBISHI2_BIT_MARK, MITSUBISHI2_ZERO_SPACE, - MITSUBISHI2_BIT_MARK, MITSUBISHI2_HDR_SPACE, - data >> (nbits / 2), nbits / 2, 33, true, 0, 50); + sendGeneric(kMitsubishi2HdrMark, kMitsubishi2HdrSpace, kMitsubishi2BitMark, + kMitsubishi2OneSpace, kMitsubishi2BitMark, + kMitsubishi2ZeroSpace, kMitsubishi2BitMark, + kMitsubishi2HdrSpace, data >> (nbits / 2), nbits / 2, 33, true, + 0, 50); // Second half of the data. sendGeneric(0, 0, // No header for the second data block - MITSUBISHI2_BIT_MARK, MITSUBISHI2_ONE_SPACE, - MITSUBISHI2_BIT_MARK, MITSUBISHI2_ZERO_SPACE, - MITSUBISHI2_BIT_MARK, MITSUBISHI2_MIN_GAP, - data & ((1 << (nbits / 2)) - 1), nbits / 2, 33, true, 0, 50); + kMitsubishi2BitMark, kMitsubishi2OneSpace, kMitsubishi2BitMark, + kMitsubishi2ZeroSpace, kMitsubishi2BitMark, kMitsubishi2MinGap, + data & ((1 << (nbits / 2)) - 1), nbits / 2, 33, true, 0, 50); } } #endif // SEND_MITSUBISHI2 @@ -210,28 +206,24 @@ void IRsend::sendMitsubishi2(uint64_t data, uint16_t nbits, uint16_t repeat) { // https://github.com/markszabo/IRremoteESP8266/issues/441 bool IRrecv::decodeMitsubishi2(decode_results *results, uint16_t nbits, bool strict) { - if (results->rawlen < 2 * nbits + HEADER + (FOOTER * 2) - 1) + if (results->rawlen < 2 * nbits + kHeader + (kFooter * 2) - 1) return false; // Shorter than shortest possibly expected. - if (strict && nbits != MITSUBISHI_BITS) + if (strict && nbits != kMitsubishiBits) return false; // Request is out of spec. - uint16_t offset = OFFSET_START; + uint16_t offset = kStartOffset; uint64_t data = 0; uint16_t actualBits = 0; // Header - if (!matchMark(results->rawbuf[offset++], MITSUBISHI2_HDR_MARK)) - return false; - if (!matchSpace(results->rawbuf[offset++], MITSUBISHI2_HDR_SPACE)) + if (!matchMark(results->rawbuf[offset++], kMitsubishi2HdrMark)) return false; + if (!matchSpace(results->rawbuf[offset++], kMitsubishi2HdrSpace)) return false; for (uint8_t i = 1; i <= 2; i++) { // Data - match_result_t data_result = matchData(&(results->rawbuf[offset]), - nbits / 2, - MITSUBISHI2_BIT_MARK, - MITSUBISHI2_ONE_SPACE, - MITSUBISHI2_BIT_MARK, - MITSUBISHI2_ZERO_SPACE); + match_result_t data_result = matchData( + &(results->rawbuf[offset]), nbits / 2, kMitsubishi2BitMark, + kMitsubishi2OneSpace, kMitsubishi2BitMark, kMitsubishi2ZeroSpace); if (data_result.success == false) return false; data <<= nbits / 2; data += data_result.data; @@ -239,24 +231,21 @@ bool IRrecv::decodeMitsubishi2(decode_results *results, uint16_t nbits, actualBits += data_result.used / 2; // Footer - if (!matchMark(results->rawbuf[offset++], MITSUBISHI2_BIT_MARK)) + if (!matchMark(results->rawbuf[offset++], kMitsubishi2BitMark)) return false; if (i % 2) { // Every odd data block, we expect a HDR space. - if (!matchSpace(results->rawbuf[offset++], MITSUBISHI2_HDR_SPACE)) + if (!matchSpace(results->rawbuf[offset++], kMitsubishi2HdrSpace)) return false; } else { // Every even data block, we expect Min Gap or end of the message. if (offset < results->rawlen && - !matchAtLeast(results->rawbuf[offset++], MITSUBISHI2_MIN_GAP)) + !matchAtLeast(results->rawbuf[offset++], kMitsubishi2MinGap)) return false; } } - // Compliance - if (actualBits < nbits) - return false; - if (strict && actualBits != nbits) - return false; // Not as we expected. + if (actualBits < nbits) return false; + if (strict && actualBits != nbits) return false; // Not as we expected. // Success results->decode_type = MITSUBISHI2; @@ -273,25 +262,155 @@ bool IRrecv::decodeMitsubishi2(decode_results *results, uint16_t nbits, // // Args: // data: An array of bytes containing the IR command. -// nbytes: Nr. of bytes of data in the array. (>=MITSUBISHI_AC_STATE_LENGTH) +// nbytes: Nr. of bytes of data in the array. (>=kMitsubishiACStateLength) // repeat: Nr. of times the message is to be repeated. -// (Default = MITSUBISHI_AC_MIN_REPEAT). +// (Default = kMitsubishiACMinRepeat). // // Status: BETA / Appears to be working. // void IRsend::sendMitsubishiAC(unsigned char data[], uint16_t nbytes, uint16_t repeat) { - if (nbytes < MITSUBISHI_AC_STATE_LENGTH) + if (nbytes < kMitsubishiACStateLength) return; // Not enough bytes to send a proper message. - sendGeneric(MITSUBISHI_AC_HDR_MARK, MITSUBISHI_AC_HDR_SPACE, - MITSUBISHI_AC_BIT_MARK, MITSUBISHI_AC_ONE_SPACE, - MITSUBISHI_AC_BIT_MARK, MITSUBISHI_AC_ZERO_SPACE, - MITSUBISHI_AC_RPT_MARK, MITSUBISHI_AC_RPT_SPACE, - data, nbytes, 38, false, repeat, 50); + sendGeneric(kMitsubishiAcHdrMark, kMitsubishiAcHdrSpace, kMitsubishiAcBitMark, + kMitsubishiAcOneSpace, kMitsubishiAcBitMark, + kMitsubishiAcZeroSpace, kMitsubishiAcRptMark, + kMitsubishiAcRptSpace, data, nbytes, 38, false, repeat, 50); } #endif // SEND_MITSUBISHI_AC +#if DECODE_MITSUBISHI_AC +// Decode the supplied Mitsubishi message. +// +// Args: +// results: Ptr to the data to decode and where to store the decode result. +// nbits: Nr. of data bits to expect. +// strict: Flag indicating if we should perform strict matching. +// Returns: +// boolean: True if it can decode it, false if it can't. +// +// Status: ALPHA / Under development +// +// Ref: +// https://www.analysir.com/blog/2015/01/06/reverse-engineering-mitsubishi-ac-infrared-protocol/ +bool IRrecv::decodeMitsubishiAC(decode_results *results, uint16_t nbits, + bool strict) { + if (results->rawlen < ((kMitsubishiACBits * 2) + 2)) { + DPRINTLN("Shorter than shortest possibly expected."); + return false; // Shorter than shortest possibly expected. + } + if (strict && nbits != kMitsubishiACBits) { + DPRINTLN("Request is out of spec."); + return false; // Request is out of spec. + } + uint16_t offset = kStartOffset; + for (uint8_t i = 0; i < kMitsubishiACStateLength; i++) { + results->state[i] = 0; + } + bool failure = false; + uint8_t rep = 0; + do { + failure = false; + // Header: + // Somtime happens that junk signals arrives before the real message + bool headerFound = false; + while (!headerFound && + offset < (results->rawlen - (kMitsubishiACBits * 2 + 2))) { + headerFound = + matchMark(results->rawbuf[offset++], kMitsubishiAcHdrMark) && + matchSpace(results->rawbuf[offset++], kMitsubishiAcHdrSpace); + } + if (!headerFound) { + DPRINTLN("Header mark not found."); + failure = true; + } + // Decode byte-by-byte: + match_result_t data_result; + for (uint8_t i = 0; i < kMitsubishiACStateLength && !failure; i++) { + results->state[i] = 0; + data_result = + matchData(&(results->rawbuf[offset]), 8, kMitsubishiAcBitMark, + kMitsubishiAcOneSpace, kMitsubishiAcBitMark, + kMitsubishiAcZeroSpace, kTolerance, kMarkExcess, false); + if (data_result.success == false) { + failure = true; + DPRINT("Byte decode failed at #"); + DPRINTLN((uint16_t)i); + } else { + results->state[i] = data_result.data; + offset += data_result.used; + DPRINT((uint16_t)results->state[i]); + DPRINT(","); + } + DPRINTLN(""); + } + // HEADER validation: + if (failure || results->state[0] != 0x23 || results->state[1] != 0xCB || + results->state[2] != 0x26 || results->state[3] != 0x01 || + results->state[4] != 0x00) { + DPRINTLN("Header mismatch."); + failure = true; + } else { + // DATA part: + + // FOOTER checksum: + if (IRMitsubishiAC::calculateChecksum(results->state) != + results->state[kMitsubishiACStateLength - 1]) { + DPRINTLN("Checksum error."); + failure = true; + } + } + if (rep != kMitsubishiACMinRepeat && failure) { + bool repeatMarkFound = false; + while (!repeatMarkFound && + offset < (results->rawlen - (kMitsubishiACBits * 2 + 4))) { + repeatMarkFound = + matchMark(results->rawbuf[offset++], kMitsubishiAcRptMark) && + matchSpace(results->rawbuf[offset++], kMitsubishiAcRptSpace); + } + if (!repeatMarkFound) { + DPRINTLN("First attempt failure and repeat mark not found."); + return false; + } + } + rep++; + // Check if the repeat is correct if we need strict decode: + if (strict && !failure) { + DPRINTLN("Strict repeat check enabled."); + // Repeat mark and space: + if (!matchMark(results->rawbuf[offset++], kMitsubishiAcRptMark) || + !matchSpace(results->rawbuf[offset++], kMitsubishiAcRptSpace)) { + DPRINTLN("Repeat mark error."); + return false; + } + // Header mark and space: + if (!matchMark(results->rawbuf[offset++], kMitsubishiAcHdrMark) || + !matchSpace(results->rawbuf[offset++], kMitsubishiAcHdrSpace)) { + DPRINTLN("Repeat header error."); + return false; + } + // Payload: + for (uint8_t i = 0; i < kMitsubishiACStateLength; i++) { + data_result = + matchData(&(results->rawbuf[offset]), 8, kMitsubishiAcBitMark, + kMitsubishiAcOneSpace, kMitsubishiAcBitMark, + kMitsubishiAcZeroSpace, kTolerance, kMarkExcess, false); + if (data_result.success == false || + data_result.data != results->state[i]) { + DPRINTLN("Repeat payload error."); + return false; + } + offset += data_result.used; + } + } // strict repeat check + } while (failure && rep <= kMitsubishiACMinRepeat); + results->decode_type = MITSUBISHI_AC; + results->bits = kMitsubishiACStateLength * 8; + return true; +} +#endif // DECODE_MITSUBISHI_AC + // Code to emulate Mitsubishi A/C IR remote control unit. // Inspired and derived from the work done at: // https://github.com/r45635/HVAC-IR-Control @@ -301,9 +420,7 @@ void IRsend::sendMitsubishiAC(unsigned char data[], uint16_t nbytes, // Equipment it seems compatible with: // * // Initialise the object. -IRMitsubishiAC::IRMitsubishiAC(uint16_t pin) : _irsend(pin) { - stateReset(); -} +IRMitsubishiAC::IRMitsubishiAC(uint16_t pin) : _irsend(pin) { stateReset(); } // Reset the state of the remote to a known good state/sequence. void IRMitsubishiAC::stateReset() { @@ -311,7 +428,7 @@ void IRMitsubishiAC::stateReset() { // Known good state obtained from: // https://github.com/r45635/HVAC-IR-Control/blob/master/HVAC_ESP8266/HVAC_ESP8266.ino#L108 // Note: Can't use the following because it requires -std=c++11 - // uint8_t known_good_state[MITSUBISHI_AC_STATE_LENGTH] = { + // uint8_t known_good_state[kMitsubishiACStateLength] = { // 0x23, 0xCB, 0x26, 0x01, 0x00, 0x20, 0x08, 0x06, 0x30, 0x45, 0x67, 0x00, // 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F}; remote_state[0] = 0x23; @@ -325,51 +442,59 @@ void IRMitsubishiAC::stateReset() { remote_state[8] = 0x30; remote_state[9] = 0x45; remote_state[10] = 0x67; - for (uint8_t i = 11; i < MITSUBISHI_AC_STATE_LENGTH - 1; i++) + for (uint8_t i = 11; i < kMitsubishiACStateLength - 1; i++) remote_state[i] = 0; - remote_state[MITSUBISHI_AC_STATE_LENGTH - 1] = 0x1F; + remote_state[kMitsubishiACStateLength - 1] = 0x1F; checksum(); // Calculate the checksum } // Configure the pin for output. -void IRMitsubishiAC::begin() { - _irsend.begin(); -} +void IRMitsubishiAC::begin() { _irsend.begin(); } #if SEND_MITSUBISHI_AC // Send the current desired state to the IR LED. -void IRMitsubishiAC::send() { - checksum(); // Ensure correct checksum before sending. - _irsend.sendMitsubishiAC(remote_state); +void IRMitsubishiAC::send(const uint16_t repeat) { + checksum(); // Ensure correct checksum before sending. + _irsend.sendMitsubishiAC(remote_state, kMitsubishiACStateLength, repeat); } #endif // SEND_MITSUBISHI_AC // Return a pointer to the internal state date of the remote. -uint8_t* IRMitsubishiAC::getRaw() { +uint8_t *IRMitsubishiAC::getRaw() { checksum(); return remote_state; } +void IRMitsubishiAC::setRaw(uint8_t *data) { + for (uint8_t i = 0; i < (kMitsubishiACStateLength - 1); i++) { + remote_state[i] = data[i]; + } + checksum(); +} + // Calculate the checksum for the current internal state of the remote. void IRMitsubishiAC::checksum() { + remote_state[17] = calculateChecksum(remote_state); +} + +uint8_t IRMitsubishiAC::calculateChecksum(uint8_t *data) { uint8_t sum = 0; // Checksum is simple addition of all previous bytes stored - // as a 8 bit value. - for (uint8_t i = 0; i < 17; i++) - sum += remote_state[i]; - remote_state[17] = sum & 0xFFU; + // as an 8 bit value. + for (uint8_t i = 0; i < 17; i++) sum += data[i]; + return sum & 0xFFU; } // Set the requested power state of the A/C to off. void IRMitsubishiAC::on() { // state = ON; - remote_state[5] |= MITSUBISHI_AC_POWER; + remote_state[5] |= kMitsubishiAcPower; } // Set the requested power state of the A/C to off. void IRMitsubishiAC::off() { // state = OFF; - remote_state[5] &= ~MITSUBISHI_AC_POWER; + remote_state[5] &= ~kMitsubishiAcPower; } // Set the requested power state of the A/C. @@ -382,31 +507,31 @@ void IRMitsubishiAC::setPower(bool state) { // Return the requested power state of the A/C. bool IRMitsubishiAC::getPower() { - return((remote_state[5] & MITSUBISHI_AC_POWER) != 0); + return ((remote_state[5] & kMitsubishiAcPower) != 0); } // Set the temp. in deg C void IRMitsubishiAC::setTemp(uint8_t temp) { - temp = std::max((uint8_t) MITSUBISHI_AC_MIN_TEMP, temp); - temp = std::min((uint8_t) MITSUBISHI_AC_MAX_TEMP, temp); - remote_state[7] = temp - MITSUBISHI_AC_MIN_TEMP; + temp = std::max((uint8_t)kMitsubishiAcMinTemp, temp); + temp = std::min((uint8_t)kMitsubishiAcMaxTemp, temp); + remote_state[7] = temp - kMitsubishiAcMinTemp; } // Return the set temp. in deg C uint8_t IRMitsubishiAC::getTemp() { - return(remote_state[7] + MITSUBISHI_AC_MIN_TEMP); + return (remote_state[7] + kMitsubishiAcMinTemp); } // Set the speed of the fan, 0-6. // 0 is auto, 1-5 is the speed, 6 is silent. void IRMitsubishiAC::setFan(uint8_t fan) { // Bounds check - if (fan > MITSUBISHI_AC_FAN_SILENT) - fan = MITSUBISHI_AC_FAN_MAX; // Set the fan to maximum if out of range. - if (fan == MITSUBISHI_AC_FAN_AUTO) { // Automatic is a special case. + if (fan > kMitsubishiAcFanSilent) + fan = kMitsubishiAcFanMax; // Set the fan to maximum if out of range. + if (fan == kMitsubishiAcFanAuto) { // Automatic is a special case. remote_state[9] = 0b10000000 | (remote_state[9] & 0b01111000); return; - } else if (fan >= MITSUBISHI_AC_FAN_MAX) { + } else if (fan >= kMitsubishiAcFanMax) { fan--; // There is no spoon^H^H^Heed 5 (max), pretend it doesn't exist. } remote_state[9] &= 0b01111000; // Clear the previous state @@ -416,32 +541,39 @@ void IRMitsubishiAC::setFan(uint8_t fan) { // Return the requested state of the unit's fan. uint8_t IRMitsubishiAC::getFan() { uint8_t fan = remote_state[9] & 0b111; - if (fan == MITSUBISHI_AC_FAN_MAX) - return MITSUBISHI_AC_FAN_SILENT; + if (fan == kMitsubishiAcFanMax) return kMitsubishiAcFanSilent; return fan; } // Return the requested climate operation mode of the a/c unit. -uint8_t IRMitsubishiAC::getMode() { - return(remote_state[6]); -} +uint8_t IRMitsubishiAC::getMode() { return (remote_state[6]); } // Set the requested climate operation mode of the a/c unit. void IRMitsubishiAC::setMode(uint8_t mode) { // If we get an unexpected mode, default to AUTO. switch (mode) { - case MITSUBISHI_AC_AUTO: break; - case MITSUBISHI_AC_COOL: break; - case MITSUBISHI_AC_DRY: break; - case MITSUBISHI_AC_HEAT: break; - default: mode = MITSUBISHI_AC_AUTO; + case kMitsubishiAcAuto: + remote_state[8] = 0b00110000; + break; + case kMitsubishiAcCool: + remote_state[8] = 0b00110110; + break; + case kMitsubishiAcDry: + remote_state[8] = 0b00110010; + break; + case kMitsubishiAcHeat: + remote_state[8] = 0b00110000; + break; + default: + mode = kMitsubishiAcAuto; + remote_state[8] = 0b00110000; } remote_state[6] = mode; } // Set the requested vane operation mode of the a/c unit. void IRMitsubishiAC::setVane(uint8_t mode) { - mode = std::min(mode, (uint8_t) 0b111); // bounds check + mode = std::min(mode, (uint8_t)0b111); // bounds check mode |= 0b1000; mode <<= 3; remote_state[9] &= 0b11000111; // Clear the previous setting. @@ -452,3 +584,131 @@ void IRMitsubishiAC::setVane(uint8_t mode) { uint8_t IRMitsubishiAC::getVane() { return ((remote_state[9] & 0b00111000) >> 3); } + +// Return the clock setting of the message. 1=1/6 hour. e.g. 4pm = 48 +uint8_t IRMitsubishiAC::getClock() { return remote_state[10]; } + +// Set the current time. 1 = 1/6 hour. e.g. 6am = 36. +void IRMitsubishiAC::setClock(uint8_t clock) { remote_state[10] = clock; } + +// Return the desired start time. 1 = 1/6 hour. e.g. 1am = 6 +uint8_t IRMitsubishiAC::getStartClock() { return remote_state[12]; } + +// Set the desired start tiem of the AC. 1 = 1/6 hour. e.g. 8pm = 120 +void IRMitsubishiAC::setStartClock(uint8_t clock) { remote_state[12] = clock; } + +// Return the desired stop time of the AC. 1 = 1/6 hour. e.g 10pm = 132 +uint8_t IRMitsubishiAC::getStopClock() { return remote_state[11]; } + +// Set the desired stop time of the AC. 1 = 1/6 hour. e.g 10pm = 132 +void IRMitsubishiAC::setStopClock(uint8_t clock) { remote_state[11] = clock; } + +// Return the timer setting. Possible values: kMitsubishiAcNoTimer, +// kMitsubishiAcStartTimer, kMitsubishiAcStopTimer, +// kMitsubishiAcStartStopTimer +uint8_t IRMitsubishiAC::getTimer() { return remote_state[13] & 0b111; } + +// Set the timer setting. Possible values: kMitsubishiAcNoTimer, +// kMitsubishiAcStartTimer, kMitsubishiAcStopTimer, +// kMitsubishiAcStartStopTimer +void IRMitsubishiAC::setTimer(uint8_t timer) { + remote_state[13] = timer & 0b111; +} + +#ifdef ARDUINO +String IRMitsubishiAC::timeToString(uint64_t time) { + String result = ""; +#else +std::string IRMitsubishiAC::timeToString(uint64_t time) { + std::string result = ""; +#endif // ARDUINO + if (time / 6 < 10) result += "0"; + result += uint64ToString(time / 6); + result += ":"; + if (time * 10 % 60 < 10) result += "0"; + result += uint64ToString(time * 10 % 60); + return result; +} + +// Convert the internal state into a human readable string. +#ifdef ARDUINO +String IRMitsubishiAC::toString() { + String result = ""; +#else +std::string IRMitsubishiAC::toString() { + std::string result = ""; +#endif // ARDUINO + result += "Power: "; + if (getPower()) + result += "On"; + else + result += "Off"; + switch (getMode()) { + case MITSUBISHI_AC_AUTO: + result += " (AUTO)"; + break; + case MITSUBISHI_AC_COOL: + result += " (COOL)"; + break; + case MITSUBISHI_AC_DRY: + result += " (DRY)"; + break; + case MITSUBISHI_AC_HEAT: + result += " (HEAT)"; + break; + default: + result += " (UNKNOWN)"; + } + result += ", Temp: " + uint64ToString(getTemp()) + "C"; + result += ", FAN: "; + switch (getFan()) { + case MITSUBISHI_AC_FAN_AUTO: + result += "AUTO"; + break; + case MITSUBISHI_AC_FAN_MAX: + result += "MAX"; + break; + case MITSUBISHI_AC_FAN_SILENT: + result += "SILENT"; + break; + default: + result += uint64ToString(getFan()); + } + result += ", VANE: "; + switch (getVane()) { + case MITSUBISHI_AC_VANE_AUTO: + result += "AUTO"; + break; + case MITSUBISHI_AC_VANE_AUTO_MOVE: + result += "AUTO MOVE"; + break; + default: + result += uint64ToString(getVane()); + } + result += ", Time: "; + result += timeToString(getClock()); + result += ", On timer: "; + result += timeToString(getStartClock()); + result += ", Off timer: "; + result += timeToString(getStopClock()); + result += ", Timer: "; + switch (getTimer()) { + case kMitsubishiAcNoTimer: + result += "-"; + break; + case kMitsubishiAcStartTimer: + result += "Start"; + break; + case kMitsubishiAcStopTimer: + result += "Stop"; + break; + case kMitsubishiAcStartStopTimer: + result += "Start+Stop"; + break; + default: + result += "? ("; + result += getTimer(); + result += ")\n"; + } + return result; +} diff --git a/lib/IRremoteESP8266/src/ir_Mitsubishi.h b/lib/IRremoteESP8266/src/ir_Mitsubishi.h index ec4c01b..0d897bc 100644 --- a/lib/IRremoteESP8266/src/ir_Mitsubishi.h +++ b/lib/IRremoteESP8266/src/ir_Mitsubishi.h @@ -5,6 +5,11 @@ #define __STDC_LIMIT_MACROS #include +#ifndef UNIT_TEST +#include +#else +#include +#endif #include "IRremoteESP8266.h" #include "IRsend.h" @@ -18,27 +23,48 @@ // Mitsubishi (TV) sending & Mitsubishi A/C support added by David Conran // Constants -#define MITSUBISHI_AC_AUTO 0x20U -#define MITSUBISHI_AC_COOL 0x18U -#define MITSUBISHI_AC_DRY 0x10U -#define MITSUBISHI_AC_HEAT 0x08U -#define MITSUBISHI_AC_POWER 0x20U -#define MITSUBISHI_AC_FAN_AUTO 0U -#define MITSUBISHI_AC_FAN_MAX 5U -#define MITSUBISHI_AC_FAN_REAL_MAX 4U -#define MITSUBISHI_AC_FAN_SILENT 6U -#define MITSUBISHI_AC_MIN_TEMP 16U // 16C -#define MITSUBISHI_AC_MAX_TEMP 31U // 31C -#define MITSUBISHI_AC_VANE_AUTO 0U -#define MITSUBISHI_AC_VANE_AUTO_MOVE 7U +const uint8_t kMitsubishiAcAuto = 0x20; +const uint8_t kMitsubishiAcCool = 0x18; +const uint8_t kMitsubishiAcDry = 0x10; +const uint8_t kMitsubishiAcHeat = 0x08; +const uint8_t kMitsubishiAcPower = 0x20; +const uint8_t kMitsubishiAcFanAuto = 0; +const uint8_t kMitsubishiAcFanMax = 5; +const uint8_t kMitsubishiAcFanRealMax = 4; +const uint8_t kMitsubishiAcFanSilent = 6; +const uint8_t kMitsubishiAcMinTemp = 16; // 16C +const uint8_t kMitsubishiAcMaxTemp = 31; // 31C +const uint8_t kMitsubishiAcVaneAuto = 0; +const uint8_t kMitsubishiAcVaneAutoMove = 7; +const uint8_t kMitsubishiAcNoTimer = 0; +const uint8_t kMitsubishiAcStartTimer = 5; +const uint8_t kMitsubishiAcStopTimer = 3; +const uint8_t kMitsubishiAcStartStopTimer = 7; + +// Legacy defines (Deprecated) +#define MITSUBISHI_AC_VANE_AUTO_MOVE kMitsubishiAcVaneAutoMove +#define MITSUBISHI_AC_VANE_AUTO kMitsubishiAcVaneAuto +#define MITSUBISHI_AC_POWER kMitsubishiAcPower +#define MITSUBISHI_AC_MIN_TEMP kMitsubishiAcMinTemp +#define MITSUBISHI_AC_MAX_TEMP kMitsubishiAcMaxTemp +#define MITSUBISHI_AC_HEAT kMitsubishiAcHeat +#define MITSUBISHI_AC_FAN_SILENT kMitsubishiAcFanSilent +#define MITSUBISHI_AC_FAN_REAL_MAX kMitsubishiAcFanRealMax +#define MITSUBISHI_AC_FAN_MAX kMitsubishiAcFanMax +#define MITSUBISHI_AC_FAN_AUTO kMitsubishiAcFanAuto +#define MITSUBISHI_AC_DRY kMitsubishiAcDry +#define MITSUBISHI_AC_COOL kMitsubishiAcCool +#define MITSUBISHI_AC_AUTO kMitsubishiAcAuto class IRMitsubishiAC { public: explicit IRMitsubishiAC(uint16_t pin); + static uint8_t calculateChecksum(uint8_t* data); + void stateReset(); #if SEND_MITSUBISHI_AC - void send(); + void send(const uint16_t repeat = kMitsubishiACMinRepeat); #endif // SEND_MITSUBISHI_AC void begin(); void on(); @@ -54,12 +80,30 @@ class IRMitsubishiAC { void setVane(uint8_t mode); uint8_t getVane(); uint8_t* getRaw(); + void setRaw(uint8_t* data); + uint8_t getClock(); + void setClock(uint8_t clock); + uint8_t getStartClock(); + void setStartClock(uint8_t clock); + uint8_t getStopClock(); + void setStopClock(uint8_t clock); + uint8_t getTimer(); + void setTimer(uint8_t timer); +#ifdef ARDUINO + String toString(); +#else + std::string toString(); +#endif private: - uint8_t remote_state[MITSUBISHI_AC_STATE_LENGTH]; +#ifdef ARDUINO + String timeToString(uint64_t time); +#else + std::string timeToString(uint64_t time); +#endif + uint8_t remote_state[kMitsubishiACStateLength]; void checksum(); IRsend _irsend; }; - #endif // IR_MITSUBISHI_H_ diff --git a/lib/IRremoteESP8266/src/ir_NEC.cpp b/lib/IRremoteESP8266/src/ir_NEC.cpp index 8c603f2..660b511 100644 --- a/lib/IRremoteESP8266/src/ir_NEC.cpp +++ b/lib/IRremoteESP8266/src/ir_NEC.cpp @@ -2,6 +2,7 @@ // Copyright 2017 David Conran #define __STDC_LIMIT_MACROS +#include "ir_NEC.h" #include #include #include "IRrecv.h" @@ -16,39 +17,13 @@ // NEC originally added from https://github.com/shirriff/Arduino-IRremote/ -// Constants -// Ref: -// http://www.sbprojects.com/knowledge/ir/nec.php -#define NEC_TICK 560U -#define NEC_HDR_MARK_TICKS 16U -#define NEC_HDR_MARK (NEC_HDR_MARK_TICKS * NEC_TICK) -#define NEC_HDR_SPACE_TICKS 8U -#define NEC_HDR_SPACE (NEC_HDR_SPACE_TICKS * NEC_TICK) -#define NEC_BIT_MARK_TICKS 1U -#define NEC_BIT_MARK (NEC_BIT_MARK_TICKS * NEC_TICK) -#define NEC_ONE_SPACE_TICKS 3U -#define NEC_ONE_SPACE (NEC_TICK * NEC_ONE_SPACE_TICKS) -#define NEC_ZERO_SPACE_TICKS 1U -#define NEC_ZERO_SPACE (NEC_TICK * NEC_ZERO_SPACE_TICKS) -#define NEC_RPT_SPACE_TICKS 4U -#define NEC_RPT_SPACE (NEC_RPT_SPACE_TICKS * NEC_TICK) -#define NEC_RPT_LENGTH 4U -#define NEC_MIN_COMMAND_LENGTH_TICKS 193U -#define NEC_MIN_COMMAND_LENGTH (NEC_MIN_COMMAND_LENGTH_TICKS * NEC_TICK) -#define NEC_MIN_GAP (NEC_MIN_COMMAND_LENGTH - \ - (NEC_HDR_MARK + NEC_HDR_SPACE + NEC_BITS * (NEC_BIT_MARK + NEC_ONE_SPACE) \ - + NEC_BIT_MARK)) -#define NEC_MIN_GAP_TICKS (NEC_MIN_COMMAND_LENGTH_TICKS - \ - (NEC_HDR_MARK_TICKS + NEC_HDR_SPACE_TICKS + \ - NEC_BITS * (NEC_BIT_MARK_TICKS + NEC_ONE_SPACE_TICKS) + \ - NEC_BIT_MARK_TICKS)) - -#if (SEND_NEC || SEND_SHERWOOD || SEND_AIWA_RC_T501 || SEND_SANYO) +#if (SEND_NEC || SEND_SHERWOOD || SEND_AIWA_RC_T501 || SEND_SANYO || \ + SEND_PIONEER) // Send a raw NEC(Renesas) formatted message. // // Args: // data: The message to be sent. -// nbits: The number of bits of the message to be sent. Typically NEC_BITS. +// nbits: The number of bits of the message to be sent. Typically kNECBits. // repeat: The number of times the command is to be repeated. // // Status: STABLE / Known working. @@ -56,18 +31,15 @@ // Ref: // http://www.sbprojects.com/knowledge/ir/nec.php void IRsend::sendNEC(uint64_t data, uint16_t nbits, uint16_t repeat) { - sendGeneric(NEC_HDR_MARK, NEC_HDR_SPACE, - NEC_BIT_MARK, NEC_ONE_SPACE, - NEC_BIT_MARK, NEC_ZERO_SPACE, - NEC_BIT_MARK, NEC_MIN_GAP, NEC_MIN_COMMAND_LENGTH, + sendGeneric(kNecHdrMark, kNecHdrSpace, kNecBitMark, kNecOneSpace, kNecBitMark, + kNecZeroSpace, kNecBitMark, kNecMinGap, kNecMinCommandLength, data, nbits, 38, true, 0, // Repeats are handled later. 33); // Optional command repeat sequence. if (repeat) - sendGeneric(NEC_HDR_MARK, NEC_RPT_SPACE, - 0, 0, 0, 0, // No actual data sent. - NEC_BIT_MARK, NEC_MIN_GAP, NEC_MIN_COMMAND_LENGTH, - 0, 0, // No data to be sent. + sendGeneric(kNecHdrMark, kNecRptSpace, 0, 0, 0, 0, // No actual data sent. + kNecBitMark, kNecMinGap, kNecMinCommandLength, 0, + 0, // No data to be sent. 38, true, repeat - 1, // We've already sent a one message. 33); } @@ -87,8 +59,8 @@ uint32_t IRsend::encodeNEC(uint16_t address, uint16_t command) { command &= 0xFF; // We only want the least significant byte of command. // sendNEC() sends MSB first, but protocol says this is LSB first. command = reverseBits(command, 8); - command = (command << 8) + (command ^ 0xFF); // Calculate the new command. - if (address > 0xFF) { // Is it Extended NEC? + command = (command << 8) + (command ^ 0xFF); // Calculate the new command. + if (address > 0xFF) { // Is it Extended NEC? address = reverseBits(address, 16); return ((address << 16) + command); // Extended. } else { @@ -103,7 +75,7 @@ uint32_t IRsend::encodeNEC(uint16_t address, uint16_t command) { // // Args: // results: Ptr to the data to decode and where to store the decode result. -// nbits: The number of data bits to expect. Typically NEC_BITS. +// nbits: The number of data bits to expect. Typically kNECBits. // strict: Flag indicating if we should perform strict matching. // Returns: // boolean: True if it can decode it, false if it can't. @@ -112,34 +84,33 @@ uint32_t IRsend::encodeNEC(uint16_t address, uint16_t command) { // // Notes: // NEC protocol has three varients/forms. -// Normal: a 8 bit address & a 8 bit command in 32 bit data form. +// Normal: an 8 bit address & an 8 bit command in 32 bit data form. // i.e. address + inverted(address) + command + inverted(command) -// Extended: a 16 bit address & a 8 bit command in 32 bit data form. +// Extended: a 16 bit address & an 8 bit command in 32 bit data form. // i.e. address + command + inverted(command) // Repeat: a 0-bit code. i.e. No data bits. Just the header + footer. // // Ref: // http://www.sbprojects.com/knowledge/ir/nec.php bool IRrecv::decodeNEC(decode_results *results, uint16_t nbits, bool strict) { - if (results->rawlen < 2 * nbits + HEADER + FOOTER - 1 && - results->rawlen != NEC_RPT_LENGTH) + if (results->rawlen < 2 * nbits + kHeader + kFooter - 1 && + results->rawlen != kNecRptLength) return false; // Can't possibly be a valid NEC message. - if (strict && nbits != NEC_BITS) + if (strict && nbits != kNECBits) return false; // Not strictly an NEC message. uint64_t data = 0; - uint16_t offset = OFFSET_START; + uint16_t offset = kStartOffset; // Header - if (!matchMark(results->rawbuf[offset], NEC_HDR_MARK)) return false; + if (!matchMark(results->rawbuf[offset], kNecHdrMark)) return false; // Calculate how long the lowest tick time is based on the header mark. - uint32_t mark_tick = results->rawbuf[offset++] * RAWTICK / - NEC_HDR_MARK_TICKS; + uint32_t mark_tick = results->rawbuf[offset++] * kRawTick / kNecHdrMarkTicks; // Check if it is a repeat code. - if (results->rawlen == NEC_RPT_LENGTH && - matchSpace(results->rawbuf[offset], NEC_RPT_SPACE) && - matchMark(results->rawbuf[offset + 1], NEC_BIT_MARK_TICKS * mark_tick)) { - results->value = REPEAT; + if (results->rawlen == kNecRptLength && + matchSpace(results->rawbuf[offset], kNecRptSpace) && + matchMark(results->rawbuf[offset + 1], kNecBitMarkTicks * mark_tick)) { + results->value = kRepeat; results->decode_type = NEC; results->bits = 0; results->address = 0; @@ -149,34 +120,32 @@ bool IRrecv::decodeNEC(decode_results *results, uint16_t nbits, bool strict) { } // Header (cont.) - if (!matchSpace(results->rawbuf[offset], NEC_HDR_SPACE)) return false; + if (!matchSpace(results->rawbuf[offset], kNecHdrSpace)) return false; // Calculate how long the common tick time is based on the header space. - uint32_t space_tick = results->rawbuf[offset++] * RAWTICK / - NEC_HDR_SPACE_TICKS; + uint32_t space_tick = + results->rawbuf[offset++] * kRawTick / kNecHdrSpaceTicks; // Data - match_result_t data_result = matchData(&(results->rawbuf[offset]), nbits, - NEC_BIT_MARK_TICKS * mark_tick, - NEC_ONE_SPACE_TICKS * space_tick, - NEC_BIT_MARK_TICKS * mark_tick, - NEC_ZERO_SPACE_TICKS * space_tick); + match_result_t data_result = + matchData(&(results->rawbuf[offset]), nbits, kNecBitMarkTicks * mark_tick, + kNecOneSpaceTicks * space_tick, kNecBitMarkTicks * mark_tick, + kNecZeroSpaceTicks * space_tick); if (data_result.success == false) return false; data = data_result.data; offset += data_result.used; // Footer - if (!matchMark(results->rawbuf[offset++], NEC_BIT_MARK_TICKS * mark_tick)) - return false; + if (!matchMark(results->rawbuf[offset++], kNecBitMarkTicks * mark_tick)) + return false; if (offset < results->rawlen && - !matchAtLeast(results->rawbuf[offset], NEC_MIN_GAP_TICKS * space_tick)) + !matchAtLeast(results->rawbuf[offset], kNecMinGapTicks * space_tick)) return false; // Compliance // Calculate command and optionally enforce integrity checking. - uint8_t command = (data & 0xFF00) >> 8; + uint8_t command = (data & 0xFF00) >> 8; // Command is sent twice, once as plain and then inverted. if ((command ^ 0xFF) != (data & 0xFF)) { - if (strict) - return false; // Command integrity failed. + if (strict) return false; // Command integrity failed. command = 0; // The command value isn't valid, so default to zero. } diff --git a/lib/IRremoteESP8266/src/ir_NEC.h b/lib/IRremoteESP8266/src/ir_NEC.h new file mode 100644 index 0000000..c274c10 --- /dev/null +++ b/lib/IRremoteESP8266/src/ir_NEC.h @@ -0,0 +1,46 @@ +// Copyright 2009 Ken Shirriff +// Copyright 2017, 2018 David Conran + +#ifndef IR_NEC_H_ +#define IR_NEC_H_ + +#include +#include "IRremoteESP8266.h" + +// N N EEEEE CCCC +// NN N E C +// N N N EEE C +// N NN E C +// N N EEEEE CCCC + +// NEC originally added from https://github.com/shirriff/Arduino-IRremote/ + +// Constants +// Ref: +// http://www.sbprojects.com/knowledge/ir/nec.php +const uint16_t kNecTick = 560; +const uint16_t kNecHdrMarkTicks = 16; +const uint16_t kNecHdrMark = kNecHdrMarkTicks * kNecTick; +const uint16_t kNecHdrSpaceTicks = 8; +const uint16_t kNecHdrSpace = kNecHdrSpaceTicks * kNecTick; +const uint16_t kNecBitMarkTicks = 1; +const uint16_t kNecBitMark = kNecBitMarkTicks * kNecTick; +const uint16_t kNecOneSpaceTicks = 3; +const uint16_t kNecOneSpace = kNecOneSpaceTicks * kNecTick; +const uint16_t kNecZeroSpaceTicks = 1; +const uint16_t kNecZeroSpace = kNecZeroSpaceTicks * kNecTick; +const uint16_t kNecRptSpaceTicks = 4; +const uint16_t kNecRptSpace = kNecRptSpaceTicks * kNecTick; +const uint16_t kNecRptLength = 4; +const uint16_t kNecMinCommandLengthTicks = 193; +const uint32_t kNecMinCommandLength = kNecMinCommandLengthTicks * kNecTick; +const uint32_t kNecMinGap = + kNecMinCommandLength - + (kNecHdrMark + kNecHdrSpace + kNECBits * (kNecBitMark + kNecOneSpace) + + kNecBitMark); +const uint16_t kNecMinGapTicks = + kNecMinCommandLengthTicks - + (kNecHdrMarkTicks + kNecHdrSpaceTicks + + kNECBits * (kNecBitMarkTicks + kNecOneSpaceTicks) + kNecBitMarkTicks); + +#endif // IR_NEC_H_ diff --git a/lib/IRremoteESP8266/src/ir_Nikai.cpp b/lib/IRremoteESP8266/src/ir_Nikai.cpp index cbb6500..9ac22a8 100644 --- a/lib/IRremoteESP8266/src/ir_Nikai.cpp +++ b/lib/IRremoteESP8266/src/ir_Nikai.cpp @@ -15,38 +15,35 @@ // Constants // Ref: // https://github.com/markszabo/IRremoteESP8266/issues/309 -#define NIKAI_TICK 500U -#define NIKAI_HDR_MARK_TICKS 8U -#define NIKAI_HDR_MARK (NIKAI_HDR_MARK_TICKS * NIKAI_TICK) -#define NIKAI_HDR_SPACE_TICKS 8U -#define NIKAI_HDR_SPACE (NIKAI_HDR_SPACE_TICKS * NIKAI_TICK) -#define NIKAI_BIT_MARK_TICKS 1U -#define NIKAI_BIT_MARK (NIKAI_BIT_MARK_TICKS * NIKAI_TICK) -#define NIKAI_ONE_SPACE_TICKS 2U -#define NIKAI_ONE_SPACE (NIKAI_ONE_SPACE_TICKS * NIKAI_TICK) -#define NIKAI_ZERO_SPACE_TICKS 4U -#define NIKAI_ZERO_SPACE (NIKAI_ZERO_SPACE_TICKS * NIKAI_TICK) -#define NIKAI_MIN_GAP_TICKS 17U -#define NIKAI_MIN_GAP (NIKAI_MIN_GAP_TICKS * NIKAI_TICK) - +const uint16_t kNikaiTick = 500; +const uint16_t kNikaiHdrMarkTicks = 8; +const uint16_t kNikaiHdrMark = kNikaiHdrMarkTicks * kNikaiTick; +const uint16_t kNikaiHdrSpaceTicks = 8; +const uint16_t kNikaiHdrSpace = kNikaiHdrSpaceTicks * kNikaiTick; +const uint16_t kNikaiBitMarkTicks = 1; +const uint16_t kNikaiBitMark = kNikaiBitMarkTicks * kNikaiTick; +const uint16_t kNikaiOneSpaceTicks = 2; +const uint16_t kNikaiOneSpace = kNikaiOneSpaceTicks * kNikaiTick; +const uint16_t kNikaiZeroSpaceTicks = 4; +const uint16_t kNikaiZeroSpace = kNikaiZeroSpaceTicks * kNikaiTick; +const uint16_t kNikaiMinGapTicks = 17; +const uint16_t kNikaiMinGap = kNikaiMinGapTicks * kNikaiTick; #if SEND_NIKAI // Send a Nikai TV formatted message. // // Args: // data: The message to be sent. -// nbits: The bit size of the message being sent. typically NIKAI_BITS. +// nbits: The bit size of the message being sent. typically kNikaiBits. // repeat: The number of times the message is to be repeated. // // Status: STABLE / Working. // // Ref: https://github.com/markszabo/IRremoteESP8266/issues/309 void IRsend::sendNikai(uint64_t data, uint16_t nbits, uint16_t repeat) { - sendGeneric(NIKAI_HDR_MARK, NIKAI_HDR_SPACE, - NIKAI_BIT_MARK, NIKAI_ONE_SPACE, - NIKAI_BIT_MARK, NIKAI_ZERO_SPACE, - NIKAI_BIT_MARK, NIKAI_MIN_GAP, - data, nbits, 38, true, repeat, 33); + sendGeneric(kNikaiHdrMark, kNikaiHdrSpace, kNikaiBitMark, kNikaiOneSpace, + kNikaiBitMark, kNikaiZeroSpace, kNikaiBitMark, kNikaiMinGap, data, + nbits, 38, true, repeat, 33); } #endif @@ -56,7 +53,7 @@ void IRsend::sendNikai(uint64_t data, uint16_t nbits, uint16_t repeat) { // Args: // results: Ptr to the data to decode and where to store the decode result. // nbits: Nr. of bits to expect in the data portion. -// Typically NIKAI_BITS. +// Typically kNikaiBits. // strict: Flag to indicate if we strictly adhere to the specification. // Returns: // boolean: True if it can decode it, false if it can't. @@ -64,37 +61,34 @@ void IRsend::sendNikai(uint64_t data, uint16_t nbits, uint16_t repeat) { // Status: STABLE / Working. // bool IRrecv::decodeNikai(decode_results *results, uint16_t nbits, bool strict) { - if (results->rawlen < 2 * nbits + HEADER + FOOTER - 1) + if (results->rawlen < 2 * nbits + kHeader + kFooter - 1) return false; // Can't possibly be a valid Nikai message. - if (strict && nbits != NIKAI_BITS) + if (strict && nbits != kNikaiBits) return false; // We expect Nikai to be a certain sized message. uint64_t data = 0; - uint16_t offset = OFFSET_START; + uint16_t offset = kStartOffset; // Header - if (!matchMark(results->rawbuf[offset], NIKAI_HDR_MARK)) return false; + if (!matchMark(results->rawbuf[offset], kNikaiHdrMark)) return false; // Calculate how long the common tick time is based on the header mark. - uint32_t m_tick = results->rawbuf[offset++] * RAWTICK / - NIKAI_HDR_MARK_TICKS; - if (!matchSpace(results->rawbuf[offset], NIKAI_HDR_SPACE)) return false; + uint32_t m_tick = results->rawbuf[offset++] * kRawTick / kNikaiHdrMarkTicks; + if (!matchSpace(results->rawbuf[offset], kNikaiHdrSpace)) return false; // Calculate how long the common tick time is based on the header space. - uint32_t s_tick = results->rawbuf[offset++] * RAWTICK / - NIKAI_HDR_SPACE_TICKS; + uint32_t s_tick = results->rawbuf[offset++] * kRawTick / kNikaiHdrSpaceTicks; // Data - match_result_t data_result = matchData(&(results->rawbuf[offset]), nbits, - NIKAI_BIT_MARK_TICKS * m_tick, - NIKAI_ONE_SPACE_TICKS * s_tick, - NIKAI_BIT_MARK_TICKS * m_tick, - NIKAI_ZERO_SPACE_TICKS * s_tick); + match_result_t data_result = + matchData(&(results->rawbuf[offset]), nbits, kNikaiBitMarkTicks * m_tick, + kNikaiOneSpaceTicks * s_tick, kNikaiBitMarkTicks * m_tick, + kNikaiZeroSpaceTicks * s_tick); if (data_result.success == false) return false; data = data_result.data; offset += data_result.used; // Footer - if (!matchMark(results->rawbuf[offset++], NIKAI_BIT_MARK_TICKS * m_tick)) + if (!matchMark(results->rawbuf[offset++], kNikaiBitMarkTicks * m_tick)) return false; if (offset < results->rawlen && - !matchAtLeast(results->rawbuf[offset], NIKAI_MIN_GAP_TICKS * s_tick)) + !matchAtLeast(results->rawbuf[offset], kNikaiMinGapTicks * s_tick)) return false; // Compliance diff --git a/lib/IRremoteESP8266/src/ir_Panasonic.cpp b/lib/IRremoteESP8266/src/ir_Panasonic.cpp index 687f73c..be96ce0 100644 --- a/lib/IRremoteESP8266/src/ir_Panasonic.cpp +++ b/lib/IRremoteESP8266/src/ir_Panasonic.cpp @@ -1,7 +1,11 @@ // Copyright 2015 Kristian Lauszus -// Copyright 2017 David Conran +// Copyright 2017, 2018 David Conran +#include "ir_Panasonic.h" #include +#ifndef ARDUINO +#include +#endif #include "IRrecv.h" #include "IRsend.h" #include "IRutils.h" @@ -15,36 +19,58 @@ // Panasonic protocol originally added by Kristian Lauszus from: // https://github.com/z3t0/Arduino-IRremote // (Thanks to zenwheel and other people at the original blog post) +// +// Panasonic A/C support add by crankyoldgit but heavily influenced by: +// https://github.com/ToniA/ESPEasy/blob/HeatpumpIR/lib/HeatpumpIR/PanasonicHeatpumpIR.cpp +// Panasonic A/C Clock & Timer support: +// Reverse Engineering by MikkelTb +// Code by crankyoldgit +// Panasonic A/C models supported: +// A/C Series/models: +// JKE, LKE, DKE, CKP, & NKE series. (In theory) +// CS-YW9MKD (confirmed) +// CS-ME14CKPG / CS-ME12CKPG / CS-ME10CKPG +// A/C Remotes: +// A75C3747 (confirmed) +// A75C3704 +// A75C2311 (CKP) // Constants // Ref: // http://www.remotecentral.com/cgi-bin/mboard/rc-pronto/thread.cgi?26152 -#define PANASONIC_TICK 432U -#define PANASONIC_HDR_MARK_TICKS 8U -#define PANASONIC_HDR_MARK (PANASONIC_HDR_MARK_TICKS * PANASONIC_TICK) -#define PANASONIC_HDR_SPACE_TICKS 4U -#define PANASONIC_HDR_SPACE (PANASONIC_HDR_SPACE_TICKS * PANASONIC_TICK) -#define PANASONIC_BIT_MARK_TICKS 1U -#define PANASONIC_BIT_MARK (PANASONIC_BIT_MARK_TICKS * PANASONIC_TICK) -#define PANASONIC_ONE_SPACE_TICKS 3U -#define PANASONIC_ONE_SPACE (PANASONIC_ONE_SPACE_TICKS * PANASONIC_TICK) -#define PANASONIC_ZERO_SPACE_TICKS 1U -#define PANASONIC_ZERO_SPACE (PANASONIC_ZERO_SPACE_TICKS * PANASONIC_TICK) -#define PANASONIC_MIN_COMMAND_LENGTH_TICKS 378UL -#define PANASONIC_MIN_COMMAND_LENGTH (PANASONIC_MIN_COMMAND_LENGTH_TICKS * \ - PANASONIC_TICK) -#define PANASONIC_END_GAP 5000U // See issue #245 -#define PANASONIC_MIN_GAP_TICKS (PANASONIC_MIN_COMMAND_LENGTH_TICKS - \ - (PANASONIC_HDR_MARK_TICKS + PANASONIC_HDR_SPACE_TICKS + \ - PANASONIC_BITS * (PANASONIC_BIT_MARK_TICKS + PANASONIC_ONE_SPACE_TICKS) + \ - PANASONIC_BIT_MARK_TICKS)) -#define PANASONIC_MIN_GAP ((uint32_t)(PANASONIC_MIN_GAP_TICKS * PANASONIC_TICK)) + +const uint16_t kPanasonicTick = 432; +const uint16_t kPanasonicHdrMarkTicks = 8; +const uint16_t kPanasonicHdrMark = kPanasonicHdrMarkTicks * kPanasonicTick; +const uint16_t kPanasonicHdrSpaceTicks = 4; +const uint16_t kPanasonicHdrSpace = kPanasonicHdrSpaceTicks * kPanasonicTick; +const uint16_t kPanasonicBitMarkTicks = 1; +const uint16_t kPanasonicBitMark = kPanasonicBitMarkTicks * kPanasonicTick; +const uint16_t kPanasonicOneSpaceTicks = 3; +const uint16_t kPanasonicOneSpace = kPanasonicOneSpaceTicks * kPanasonicTick; +const uint16_t kPanasonicZeroSpaceTicks = 1; +const uint16_t kPanasonicZeroSpace = kPanasonicZeroSpaceTicks * kPanasonicTick; +const uint16_t kPanasonicMinCommandLengthTicks = 378; +const uint32_t kPanasonicMinCommandLength = + kPanasonicMinCommandLengthTicks * kPanasonicTick; +const uint16_t kPanasonicEndGap = 5000; // See issue #245 +const uint16_t kPanasonicMinGapTicks = + kPanasonicMinCommandLengthTicks - + (kPanasonicHdrMarkTicks + kPanasonicHdrSpaceTicks + + kPanasonicBits * (kPanasonicBitMarkTicks + kPanasonicOneSpaceTicks) + + kPanasonicBitMarkTicks); +const uint32_t kPanasonicMinGap = kPanasonicMinGapTicks * kPanasonicTick; + +const uint16_t kPanasonicAcSectionGap = 10000; +const uint16_t kPanasonicAcSection1Length = 8; +const uint32_t kPanasonicAcMessageGap = 100000; // A complete guess. + #if (SEND_PANASONIC || SEND_DENON) // Send a Panasonic formatted message. // // Args: // data: The message to be sent. -// nbits: The number of bits of the message to be sent. (PANASONIC_BITS). +// nbits: The number of bits of the message to be sent. (kPanasonicBits). // repeat: The number of times the command is to be repeated. // // Status: BETA / Should be working. @@ -52,12 +78,10 @@ // Note: // This protocol is a modified version of Kaseikyo. void IRsend::sendPanasonic64(uint64_t data, uint16_t nbits, uint16_t repeat) { - sendGeneric(PANASONIC_HDR_MARK, PANASONIC_HDR_SPACE, - PANASONIC_BIT_MARK, PANASONIC_ONE_SPACE, - PANASONIC_BIT_MARK, PANASONIC_ZERO_SPACE, - PANASONIC_BIT_MARK, - PANASONIC_MIN_GAP, PANASONIC_MIN_COMMAND_LENGTH, - data, nbits, 36700U, true, repeat, 50); + sendGeneric(kPanasonicHdrMark, kPanasonicHdrSpace, kPanasonicBitMark, + kPanasonicOneSpace, kPanasonicBitMark, kPanasonicZeroSpace, + kPanasonicBitMark, kPanasonicMinGap, kPanasonicMinCommandLength, + data, nbits, kPanasonicFreq, true, repeat, 50); } // Send a Panasonic formatted message. @@ -65,7 +89,7 @@ void IRsend::sendPanasonic64(uint64_t data, uint16_t nbits, uint16_t repeat) { // Args: // address: The manufacturer code. // data: The data portion to be sent. -// nbits: The number of bits of the message to be sent. (PANASONIC_BITS). +// nbits: The number of bits of the message to be sent. (kPanasonicBits). // repeat: The number of times the command is to be repeated. // // Status: STABLE. @@ -74,7 +98,7 @@ void IRsend::sendPanasonic64(uint64_t data, uint16_t nbits, uint16_t repeat) { // This protocol is a modified version of Kaseikyo. void IRsend::sendPanasonic(uint16_t address, uint32_t data, uint16_t nbits, uint16_t repeat) { - sendPanasonic64(((uint64_t) address << 32) | (uint64_t) data, nbits, repeat); + sendPanasonic64(((uint64_t)address << 32) | (uint64_t)data, nbits, repeat); } // Calculate the raw Panasonic data based on device, subdevice, & function. @@ -93,16 +117,11 @@ void IRsend::sendPanasonic(uint16_t address, uint32_t data, uint16_t nbits, // Panasonic 48-bit protocol is a modified version of Kaseikyo. // Ref: // http://www.remotecentral.com/cgi-bin/mboard/rc-pronto/thread.cgi?2615 -uint64_t IRsend::encodePanasonic(uint16_t manufacturer, - uint8_t device, - uint8_t subdevice, - uint8_t function) { +uint64_t IRsend::encodePanasonic(uint16_t manufacturer, uint8_t device, + uint8_t subdevice, uint8_t function) { uint8_t checksum = device ^ subdevice ^ function; - return (((uint64_t) manufacturer << 32) | - ((uint64_t) device << 24) | - ((uint64_t) subdevice << 16) | - ((uint64_t) function << 8) | - checksum); + return (((uint64_t)manufacturer << 32) | ((uint64_t)device << 24) | + ((uint64_t)subdevice << 16) | ((uint64_t)function << 8) | checksum); } #endif // (SEND_PANASONIC || SEND_DENON) @@ -124,39 +143,38 @@ uint64_t IRsend::encodePanasonic(uint16_t manufacturer, // http://www.hifi-remote.com/wiki/index.php?title=Panasonic bool IRrecv::decodePanasonic(decode_results *results, uint16_t nbits, bool strict, uint32_t manufacturer) { - if (results->rawlen < 2 * nbits + HEADER + FOOTER - 1) + if (results->rawlen < 2 * nbits + kHeader + kFooter - 1) return false; // Not enough entries to be a Panasonic message. - if (strict && nbits != PANASONIC_BITS) + if (strict && nbits != kPanasonicBits) return false; // Request is out of spec. uint64_t data = 0; - uint16_t offset = OFFSET_START; + uint16_t offset = kStartOffset; // Header - if (!matchMark(results->rawbuf[offset], PANASONIC_HDR_MARK)) return false; + if (!matchMark(results->rawbuf[offset], kPanasonicHdrMark)) return false; // Calculate how long the common tick time is based on the header mark. - uint32_t m_tick = results->rawbuf[offset++] * RAWTICK / - PANASONIC_HDR_MARK_TICKS; - if (!matchSpace(results->rawbuf[offset], PANASONIC_HDR_SPACE)) return false; + uint32_t m_tick = + results->rawbuf[offset++] * kRawTick / kPanasonicHdrMarkTicks; + if (!matchSpace(results->rawbuf[offset], kPanasonicHdrSpace)) return false; // Calculate how long the common tick time is based on the header space. - uint32_t s_tick = results->rawbuf[offset++] * RAWTICK / - PANASONIC_HDR_SPACE_TICKS; + uint32_t s_tick = + results->rawbuf[offset++] * kRawTick / kPanasonicHdrSpaceTicks; // Data - match_result_t data_result = matchData(&(results->rawbuf[offset]), nbits, - PANASONIC_BIT_MARK_TICKS * m_tick, - PANASONIC_ONE_SPACE_TICKS * s_tick, - PANASONIC_BIT_MARK_TICKS * m_tick, - PANASONIC_ZERO_SPACE_TICKS * s_tick); + match_result_t data_result = matchData( + &(results->rawbuf[offset]), nbits, kPanasonicBitMarkTicks * m_tick, + kPanasonicOneSpaceTicks * s_tick, kPanasonicBitMarkTicks * m_tick, + kPanasonicZeroSpaceTicks * s_tick); if (data_result.success == false) return false; data = data_result.data; offset += data_result.used; // Footer - if (!match(results->rawbuf[offset++], PANASONIC_BIT_MARK_TICKS * m_tick)) + if (!match(results->rawbuf[offset++], kPanasonicBitMarkTicks * m_tick)) return false; if (offset < results->rawlen && - !matchAtLeast(results->rawbuf[offset], PANASONIC_END_GAP)) + !matchAtLeast(results->rawbuf[offset], kPanasonicEndGap)) return false; // Compliance @@ -168,8 +186,7 @@ bool IRrecv::decodePanasonic(decode_results *results, uint16_t nbits, // Verify the checksum. uint8_t checksumOrig = data & 0xFF; uint8_t checksumCalc = ((data >> 24) ^ (data >> 16) ^ (data >> 8)) & 0xFF; - if (checksumOrig != checksumCalc) - return false; + if (checksumOrig != checksumCalc) return false; } // Success @@ -181,3 +198,666 @@ bool IRrecv::decodePanasonic(decode_results *results, uint16_t nbits, return true; } #endif // (DECODE_PANASONIC || DECODE_DENON) + +#if SEND_PANASONIC_AC +// Send a Panasonic A/C message. +// +// Args: +// data: Contents of the message to be sent. (Guessing MSBF order) +// nbits: Nr. of bits of data to be sent. Typically kPanasonicAcBits. +// repeat: Nr. of additional times the message is to be sent. +// +// Status: Beta / Appears to work with real device(s). +//: +// Panasonic A/C models supported: +// A/C Series/models: +// JKE, LKE, DKE, & NKE series. +// CS-YW9MKD +// A/C Remotes: +// A75C3747 +// A75C3704 +// +void IRsend::sendPanasonicAC(uint8_t data[], uint16_t nbytes, uint16_t repeat) { + if (nbytes < kPanasonicAcSection1Length) return; + for (uint16_t r = 0; r <= repeat; r++) { + // First section. (8 bytes) + sendGeneric(kPanasonicHdrMark, kPanasonicHdrSpace, kPanasonicBitMark, + kPanasonicOneSpace, kPanasonicBitMark, kPanasonicZeroSpace, + kPanasonicBitMark, kPanasonicAcSectionGap, data, + kPanasonicAcSection1Length, kPanasonicFreq, false, 0, 50); + // First section. (The rest of the data bytes) + sendGeneric(kPanasonicHdrMark, kPanasonicHdrSpace, kPanasonicBitMark, + kPanasonicOneSpace, kPanasonicBitMark, kPanasonicZeroSpace, + kPanasonicBitMark, kPanasonicAcMessageGap, + data + kPanasonicAcSection1Length, + nbytes - kPanasonicAcSection1Length, kPanasonicFreq, false, 0, + 50); + } +} +#endif // SEND_PANASONIC_AC + +IRPanasonicAc::IRPanasonicAc(uint16_t pin) : _irsend(pin) { stateReset(); } + +void IRPanasonicAc::stateReset() { + for (uint8_t i = 0; i < kPanasonicAcStateLength; i++) + remote_state[i] = kPanasonicKnownGoodState[i]; + _temp = 25; // An initial saved desired temp. Completely made up. + _swingh = kPanasonicAcSwingHMiddle; // A similar made up value for H Swing. +} + +void IRPanasonicAc::begin() { _irsend.begin(); } + +// Verify the checksum is valid for a given state. +// Args: +// state: The array to verify the checksum of. +// length: The size of the state. +// Returns: +// A boolean. +bool IRPanasonicAc::validChecksum(uint8_t state[], const uint16_t length) { + if (length < 2) return false; // 1 byte of data can't have a checksum. + return (state[length - 1] == + sumBytes(state, length - 1, kPanasonicAcChecksumInit)); +} + +uint8_t IRPanasonicAc::calcChecksum(uint8_t state[], const uint16_t length) { + return sumBytes(state, length - 1, kPanasonicAcChecksumInit); +} + +void IRPanasonicAc::fixChecksum(const uint16_t length) { + remote_state[length - 1] = calcChecksum(remote_state, length); +} + +#if SEND_PANASONIC_AC +void IRPanasonicAc::send(const uint16_t repeat) { + fixChecksum(); + _irsend.sendPanasonicAC(remote_state, kPanasonicAcStateLength, repeat); +} +#endif // SEND_PANASONIC_AC + +void IRPanasonicAc::setModel(const panasonic_ac_remote_model_t model) { + switch (model) { + case kPanasonicDke: + case kPanasonicJke: + case kPanasonicLke: + case kPanasonicNke: + case kPanasonicCkp: + break; + default: // Only proceed if we know what to do. + return; + } + // clear & set the various bits and bytes. + remote_state[13] &= 0xF0; + remote_state[17] = 0x00; + remote_state[21] &= 0b11101111; + remote_state[23] = 0x81; + remote_state[25] = 0x00; + + switch (model) { + case kPanasonicLke: + remote_state[13] |= 0x02; + remote_state[17] = 0x06; + break; + case kPanasonicDke: + remote_state[23] = 0x01; + remote_state[25] = 0x06; + // Has to be done last as setSwingHorizontal has model check built-in + setSwingHorizontal(_swingh); + break; + case kPanasonicNke: + remote_state[17] = 0x06; + break; + case kPanasonicJke: + break; + case kPanasonicCkp: + remote_state[21] |= 0x10; + remote_state[23] = 0x01; + default: + break; + } +} + +panasonic_ac_remote_model_t IRPanasonicAc::getModel() { + if (remote_state[17] == 0x00) { + if ((remote_state[21] & 0x10) && (remote_state[23] & 0x01)) + return kPanasonicCkp; + if (remote_state[23] & 0x80) return kPanasonicJke; + } + if (remote_state[17] == 0x06 && (remote_state[13] & 0x0F) == 0x02) + return kPanasonicLke; + if (remote_state[23] == 0x01) return kPanasonicDke; + if (remote_state[17] == 0x06) return kPanasonicNke; + return kPanasonicUnknown; +} + +uint8_t *IRPanasonicAc::getRaw() { + fixChecksum(); + return remote_state; +} + +void IRPanasonicAc::setRaw(const uint8_t state[]) { + for (uint8_t i = 0; i < kPanasonicAcStateLength; i++) { + remote_state[i] = state[i]; + } +} + +// Control the power state of the A/C unit. +// +// For CKP models, the remote has no memory of the power state the A/C unit +// should be in. For those models setting this on/true will toggle the power +// state of the Panasonic A/C unit with the next meessage. +// e.g. If the A/C unit is already on, setPower(true) will turn it off. +// If the A/C unit is already off, setPower(true) will turn it on. +// setPower(false) will leave the A/C power state as it was. +// +// For all other models, setPower(true) should set the internal state to +// turn it on, and setPower(false) should turn it off. +void IRPanasonicAc::setPower(const bool state) { + if (state) + on(); + else + off(); +} + +// Return the A/C power state of the remote. +// Except for CKP models, where it returns if the power state will be toggled +// on the A/C unit when the next message is sent. +bool IRPanasonicAc::getPower() { + return (remote_state[13] & kPanasonicAcPower) == kPanasonicAcPower; +} + +void IRPanasonicAc::on() { remote_state[13] |= kPanasonicAcPower; } + +void IRPanasonicAc::off() { remote_state[13] &= ~kPanasonicAcPower; } + +uint8_t IRPanasonicAc::getMode() { return remote_state[13] >> 4; } + +void IRPanasonicAc::setMode(const uint8_t desired) { + uint8_t mode = kPanasonicAcAuto; // Default to Auto mode. + switch (desired) { + case kPanasonicAcFan: + // Allegedly Fan mode has a temperature of 27. + setTemp(kPanasonicAcFanModeTemp, false); + mode = desired; + break; + case kPanasonicAcAuto: + case kPanasonicAcCool: + case kPanasonicAcHeat: + case kPanasonicAcDry: + mode = desired; + // Set the temp to the saved temp, just incase our previous mode was Fan. + setTemp(_temp); + break; + } + remote_state[13] &= 0x0F; // Clear the previous mode bits. + remote_state[13] |= mode << 4; +} + +uint8_t IRPanasonicAc::getTemp() { return remote_state[14] >> 1; } + +// Set the desitred temperature in Celcius. +// Args: +// celsius: The temperature to set the A/C unit to. +// remember: A boolean flag for the class to remember the temperature. +// +// Automatically safely limits the temp to the operating range supported. +void IRPanasonicAc::setTemp(const uint8_t celsius, const bool remember) { + uint8_t temperature; + temperature = std::max(celsius, kPanasonicAcMinTemp); + temperature = std::min(temperature, kPanasonicAcMaxTemp); + remote_state[14] = temperature << 1; + if (remember) _temp = temperature; +} + +uint8_t IRPanasonicAc::getSwingVertical() { return remote_state[16] & 0x0F; } + +void IRPanasonicAc::setSwingVertical(const uint8_t desired_elevation) { + uint8_t elevation = desired_elevation; + if (elevation != kPanasonicAcSwingVAuto) { + elevation = std::max(elevation, kPanasonicAcSwingVUp); + elevation = std::min(elevation, kPanasonicAcSwingVDown); + } + remote_state[16] &= 0xF0; + remote_state[16] |= elevation; +} + +uint8_t IRPanasonicAc::getSwingHorizontal() { return remote_state[17]; } + +void IRPanasonicAc::setSwingHorizontal(const uint8_t desired_direction) { + switch (desired_direction) { + case kPanasonicAcSwingHAuto: + case kPanasonicAcSwingHMiddle: + case kPanasonicAcSwingHFullLeft: + case kPanasonicAcSwingHLeft: + case kPanasonicAcSwingHRight: + case kPanasonicAcSwingHFullRight: + break; + default: // Ignore anything that isn't valid. + return; + } + _swingh = desired_direction; // Store the direction for later. + uint8_t direction = desired_direction; + switch (getModel()) { + case kPanasonicDke: + break; + case kPanasonicNke: + case kPanasonicLke: + direction = kPanasonicAcSwingHMiddle; + break; + default: // Ignore everything else. + return; + } + remote_state[17] = direction; +} + +void IRPanasonicAc::setFan(const uint8_t speed) { + if (speed <= kPanasonicAcFanMax || speed == kPanasonicAcFanAuto) + remote_state[16] = + (remote_state[16] & 0x0F) | ((speed + kPanasonicAcFanOffset) << 4); +} + +uint8_t IRPanasonicAc::getFan() { + return (remote_state[16] >> 4) - kPanasonicAcFanOffset; +} + +bool IRPanasonicAc::getQuiet() { + if (getModel() == kPanasonicCkp) + return remote_state[21] & kPanasonicAcQuietCkp; + else + return remote_state[21] & kPanasonicAcQuiet; +} + +void IRPanasonicAc::setQuiet(const bool state) { + uint8_t quiet; + if (getModel() == kPanasonicCkp) + quiet = kPanasonicAcQuietCkp; + else + quiet = kPanasonicAcQuiet; + + if (state) { + setPowerful(false); // Powerful is mutually exclusive. + remote_state[21] |= quiet; + } else { + remote_state[21] &= ~quiet; + } +} + +bool IRPanasonicAc::getPowerful() { + if (getModel() == kPanasonicCkp) + return remote_state[21] & kPanasonicAcPowerfulCkp; + else + return remote_state[21] & kPanasonicAcPowerful; +} + +void IRPanasonicAc::setPowerful(const bool state) { + uint8_t powerful; + if (getModel() == kPanasonicCkp) + powerful = kPanasonicAcPowerfulCkp; + else + powerful = kPanasonicAcPowerful; + + if (state) { + setQuiet(false); // Quiet is mutually exclusive. + remote_state[21] |= powerful; + } else { + remote_state[21] &= ~powerful; + } +} + +uint16_t IRPanasonicAc::encodeTime(const uint8_t hours, const uint8_t mins) { + return std::min(hours, (uint8_t)23) * 60 + std::min(mins, (uint8_t)59); +} + +uint16_t IRPanasonicAc::getClock() { + uint16_t result = ((remote_state[25] & 0b00000111) << 8) + remote_state[24]; + if (result == kPanasonicAcTimeSpecial) return 0; + return result; +} + +void IRPanasonicAc::setClock(const uint16_t mins_since_midnight) { + uint16_t corrected = std::min(mins_since_midnight, kPanasonicAcTimeMax); + if (mins_since_midnight == kPanasonicAcTimeSpecial) + corrected = kPanasonicAcTimeSpecial; + remote_state[24] = corrected & 0xFF; + remote_state[25] &= 0b11111000; + remote_state[25] |= (corrected >> 8); +} + +uint16_t IRPanasonicAc::getOnTimer() { + uint16_t result = ((remote_state[19] & 0b00000111) << 8) + remote_state[18]; + if (result == kPanasonicAcTimeSpecial) return 0; + return result; +} + +void IRPanasonicAc::setOnTimer(const uint16_t mins_since_midnight, + const bool enable) { + // Ensure it's on a 10 minute boundary and no overflow. + uint16_t corrected = std::min(mins_since_midnight, kPanasonicAcTimeMax); + corrected -= corrected % 10; + if (mins_since_midnight == kPanasonicAcTimeSpecial) + corrected = kPanasonicAcTimeSpecial; + + if (enable) + remote_state[13] |= kPanasonicAcOnTimer; // Set the Ontimer flag. + else + remote_state[13] &= ~kPanasonicAcOnTimer; // Clear the Ontimer flag. + // Store the time. + remote_state[18] = corrected & 0xFF; + remote_state[19] &= 0b11111000; + remote_state[19] |= (corrected >> 8); +} + +void IRPanasonicAc::cancelOnTimer() { setOnTimer(0, false); } + +bool IRPanasonicAc::isOnTimerEnabled() { + return remote_state[13] & kPanasonicAcOnTimer; +} + +uint16_t IRPanasonicAc::getOffTimer() { + uint16_t result = + ((remote_state[20] & 0b01111111) << 4) + (remote_state[19] >> 4); + if (result == kPanasonicAcTimeSpecial) return 0; + return result; +} + +void IRPanasonicAc::setOffTimer(const uint16_t mins_since_midnight, + const bool enable) { + // Ensure its on a 10 minute boundary and no overflow. + uint16_t corrected = std::min(mins_since_midnight, kPanasonicAcTimeMax); + corrected -= corrected % 10; + if (mins_since_midnight == kPanasonicAcTimeSpecial) + corrected = kPanasonicAcTimeSpecial; + + if (enable) + remote_state[13] |= kPanasonicAcOffTimer; // Set the OffTimer flag. + else + remote_state[13] &= ~kPanasonicAcOffTimer; // Clear the OffTimer flag. + // Store the time. + remote_state[19] &= 0b00001111; + remote_state[19] |= (corrected & 0b00001111) << 4; + remote_state[20] &= 0b10000000; + remote_state[20] |= corrected >> 4; +} + +void IRPanasonicAc::cancelOffTimer() { setOffTimer(0, false); } + +bool IRPanasonicAc::isOffTimerEnabled() { + return remote_state[13] & kPanasonicAcOffTimer; +} + +#ifdef ARDUINO +String IRPanasonicAc::timeToString(const uint16_t mins_since_midnight) { + String result = ""; +#else +std::string IRPanasonicAc::timeToString(const uint16_t mins_since_midnight) { + std::string result = ""; +#endif // ARDUINO + result += uint64ToString(mins_since_midnight / 60) + ":"; + uint8_t mins = mins_since_midnight % 60; + if (mins < 10) result += "0"; // Zero pad the minutes. + return result + uint64ToString(mins); +} + +// Convert the internal state into a human readable string. +#ifdef ARDUINO +String IRPanasonicAc::toString() { + String result = ""; +#else +std::string IRPanasonicAc::toString() { + std::string result = ""; +#endif // ARDUINO + result += "Model: " + uint64ToString(getModel()); + switch (getModel()) { + case kPanasonicDke: + result += " (DKE)"; + break; + case kPanasonicJke: + result += " (JKE)"; + break; + case kPanasonicNke: + result += " (NKE)"; + break; + case kPanasonicLke: + result += " (LKE)"; + break; + case kPanasonicCkp: + result += " (CKP)"; + break; + default: + result += " (UNKNOWN)"; + } + result += ", Power: "; + if (getPower()) + result += "On"; + else + result += "Off"; + result += ", Mode: " + uint64ToString(getMode()); + switch (getMode()) { + case kPanasonicAcAuto: + result += " (AUTO)"; + break; + case kPanasonicAcCool: + result += " (COOL)"; + break; + case kPanasonicAcHeat: + result += " (HEAT)"; + break; + case kPanasonicAcDry: + result += " (DRY)"; + break; + case kPanasonicAcFan: + result += " (FAN)"; + break; + default: + result += " (UNKNOWN)"; + } + result += ", Temp: " + uint64ToString(getTemp()) + "C"; + result += ", Fan: " + uint64ToString(getFan()); + switch (getFan()) { + case kPanasonicAcFanAuto: + result += " (AUTO)"; + break; + case kPanasonicAcFanMax: + result += " (MAX)"; + break; + case kPanasonicAcFanMin: + result += " (MIN)"; + break; + default: + result += " (UNKNOWN)"; + break; + } + result += ", Swing (Vertical): " + uint64ToString(getSwingVertical()); + switch (getSwingVertical()) { + case kPanasonicAcSwingVAuto: + result += " (AUTO)"; + break; + case kPanasonicAcSwingVUp: + result += " (Full Up)"; + break; + case kPanasonicAcSwingVDown: + result += " (Full Down)"; + break; + case 2: + case 3: + case 4: + break; + default: + result += " (UNKNOWN)"; + break; + } + switch (getModel()) { + case kPanasonicJke: + case kPanasonicCkp: + break; // No Horizontal Swing support. + default: + result += ", Swing (Horizontal): " + uint64ToString(getSwingHorizontal()); + switch (getSwingHorizontal()) { + case kPanasonicAcSwingHAuto: + result += " (AUTO)"; + break; + case kPanasonicAcSwingHFullLeft: + result += " (Full Left)"; + break; + case kPanasonicAcSwingHLeft: + result += " (Left)"; + break; + case kPanasonicAcSwingHMiddle: + result += " (Middle)"; + break; + case kPanasonicAcSwingHFullRight: + result += " (Full Right)"; + break; + case kPanasonicAcSwingHRight: + result += " (Right)"; + break; + default: + result += " (UNKNOWN)"; + break; + } + } + result += ", Quiet: "; + if (getQuiet()) + result += "On"; + else + result += "Off"; + result += ", Powerful: "; + if (getPowerful()) + result += "On"; + else + result += "Off"; + result += ", Clock: " + timeToString(getClock()); + result += ", On Timer: "; + if (isOnTimerEnabled()) + result += timeToString(getOnTimer()); + else + result += "Off"; + result += ", Off Timer: "; + if (isOffTimerEnabled()) + result += timeToString(getOffTimer()); + else + result += "Off"; + return result; +} + +#if DECODE_PANASONIC_AC +// Decode the supplied Panasonic AC message. +// +// Args: +// results: Ptr to the data to decode and where to store the decode result. +// nbits: The number of data bits to expect. Typically kPanasonicAcBits. +// 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 work with real device(s). +// +// Panasonic A/C models supported: +// A/C Series/models: +// JKE, LKE, DKE, & NKE series. +// CS-YW9MKD +// A/C Remotes: +// A75C3747 (Confirmed) +// A75C3704 +bool IRrecv::decodePanasonicAC(decode_results *results, uint16_t nbits, + bool strict) { + if (nbits % 8 != 0) // nbits has to be a multiple of nr. of bits in a byte. + return false; + + uint8_t min_nr_of_messages = 1; + if (strict) { + if (nbits != kPanasonicAcBits && nbits != kPanasonicAcShortBits) + return false; // Not strictly a PANASONIC_AC message. + } + + if (results->rawlen < + min_nr_of_messages * (2 * nbits + kHeader + kFooter) - 1) + return false; // Can't possibly be a valid PANASONIC_AC message. + + uint16_t dataBitsSoFar = 0; + uint16_t offset = kStartOffset; + match_result_t data_result; + + // Header + if (!matchMark(results->rawbuf[offset], kPanasonicHdrMark, + kPanasonicAcTolerance, kPanasonicAcExcess)) + return false; + // Calculate how long the common tick time is based on the header mark. + uint32_t m_tick = + results->rawbuf[offset++] * kRawTick / kPanasonicHdrMarkTicks; + if (!matchSpace(results->rawbuf[offset], kPanasonicHdrSpace, + kPanasonicAcTolerance, kPanasonicAcExcess)) + return false; + // Calculate how long the common tick time is based on the header space. + uint32_t s_tick = + results->rawbuf[offset++] * kRawTick / kPanasonicHdrSpaceTicks; + + uint16_t i = 0; + // Data (Section #1) + // Keep reading bytes until we either run out of section or state to fill. + for (; offset <= results->rawlen - 16 && i < kPanasonicAcSection1Length; + i++, dataBitsSoFar += 8, offset += data_result.used) { + data_result = matchData( + &(results->rawbuf[offset]), 8, kPanasonicBitMarkTicks * m_tick, + kPanasonicOneSpaceTicks * s_tick, kPanasonicBitMarkTicks * m_tick, + kPanasonicZeroSpaceTicks * s_tick, kPanasonicAcTolerance, + kPanasonicAcExcess, false); + if (data_result.success == false) { + DPRINT("DEBUG: offset = "); + DPRINTLN(offset + data_result.used); + return false; // Fail + } + results->state[i] = data_result.data; + } + // Section footer. + if (!matchMark(results->rawbuf[offset++], kPanasonicBitMarkTicks * m_tick, + kPanasonicAcTolerance, kPanasonicAcExcess)) + return false; + if (!matchSpace(results->rawbuf[offset++], kPanasonicAcSectionGap, + kPanasonicAcTolerance, kPanasonicAcExcess)) + return false; + // Header. + if (!matchMark(results->rawbuf[offset++], kPanasonicHdrMarkTicks * m_tick, + kPanasonicAcTolerance, kPanasonicAcExcess)) + return false; + if (!matchSpace(results->rawbuf[offset++], kPanasonicHdrSpaceTicks * s_tick, + kPanasonicAcTolerance, kPanasonicAcExcess)) + return false; + // Data (Section #2) + // Keep reading bytes until we either run out of data. + for (; offset <= results->rawlen - 16 && i < nbits / 8; + i++, dataBitsSoFar += 8, offset += data_result.used) { + data_result = matchData( + &(results->rawbuf[offset]), 8, kPanasonicBitMarkTicks * m_tick, + kPanasonicOneSpaceTicks * s_tick, kPanasonicBitMarkTicks * m_tick, + kPanasonicZeroSpaceTicks * s_tick, kPanasonicAcTolerance, + kPanasonicAcExcess, false); + if (data_result.success == false) { + DPRINT("DEBUG: offset = "); + DPRINTLN(offset + data_result.used); + return false; // Fail + } + results->state[i] = data_result.data; + } + // Message Footer. + if (!matchMark(results->rawbuf[offset++], kPanasonicBitMarkTicks * m_tick, + kPanasonicAcTolerance, kPanasonicAcExcess)) + return false; + if (offset <= results->rawlen && + !matchAtLeast(results->rawbuf[offset++], kPanasonicAcMessageGap)) + return false; + + // Compliance + if (strict) { + // Check the signatures of the section blocks. They start with 0x02& 0x20. + if (results->state[0] != 0x02 || results->state[1] != 0x20 || + results->state[8] != 0x02 || results->state[9] != 0x20) + return false; + if (!IRPanasonicAc::validChecksum(results->state, nbits / 8)) return false; + } + + // Success + results->decode_type = PANASONIC_AC; + results->bits = nbits; + return true; +} +#endif // DECODE_PANASONIC_AC diff --git a/lib/IRremoteESP8266/src/ir_Panasonic.h b/lib/IRremoteESP8266/src/ir_Panasonic.h new file mode 100644 index 0000000..9d9da38 --- /dev/null +++ b/lib/IRremoteESP8266/src/ir_Panasonic.h @@ -0,0 +1,145 @@ +// Copyright 2018 David Conran + +#ifndef IR_PANASONIC_H_ +#define IR_PANASONIC_H_ + +#define __STDC_LIMIT_MACROS +#include +#ifdef ARDUINO +#include +#else +#include +#endif +#include "IRremoteESP8266.h" +#include "IRsend.h" + +// PPPP AAA N N AAA SSSS OOO N N IIIII CCCC +// P P A A NN N A A S O O NN N I C +// PPPP AAAAA N N N AAAAA SSS O O N N N I C +// P A A N NN A A S O O N NN I C +// P A A N N A A SSSS OOO N N IIIII CCCC + +// Panasonic A/C support heavily influenced by: +// https://github.com/ToniA/ESPEasy/blob/HeatpumpIR/lib/HeatpumpIR/PanasonicHeatpumpIR.cpp + +// Constants +const uint16_t kPanasonicFreq = 36700; +const uint16_t kPanasonicAcExcess = 0; +// Much higher than usual. See issue #540. +const uint16_t kPanasonicAcTolerance = 40; + +const uint8_t kPanasonicAcAuto = 0; // 0b0000 +const uint8_t kPanasonicAcDry = 2; // 0b0010 +const uint8_t kPanasonicAcCool = 3; // 0b0011 +const uint8_t kPanasonicAcHeat = 4; // 0b0010 +const uint8_t kPanasonicAcFan = 6; // 0b0110 +const uint8_t kPanasonicAcFanMin = 0; +const uint8_t kPanasonicAcFanMax = 4; +const uint8_t kPanasonicAcFanAuto = 7; +const uint8_t kPanasonicAcFanOffset = 3; +const uint8_t kPanasonicAcPower = 1; // 0b1 +const uint8_t kPanasonicAcMinTemp = 16; // Celsius +const uint8_t kPanasonicAcMaxTemp = 30; // Celsius +const uint8_t kPanasonicAcFanModeTemp = 27; // Celsius +const uint8_t kPanasonicAcQuiet = 1; // 0b1 +const uint8_t kPanasonicAcPowerful = 0x20; // 0b100000 +// CKP models have Powerful and Quiet bits swapped. +const uint8_t kPanasonicAcQuietCkp = 0x20; // 0b100000 +const uint8_t kPanasonicAcPowerfulCkp = 1; // 0b1 +const uint8_t kPanasonicAcSwingVAuto = 0xF; +const uint8_t kPanasonicAcSwingVUp = 0x1; +const uint8_t kPanasonicAcSwingVDown = 0x5; +const uint8_t kPanasonicAcSwingHAuto = 0xD; +const uint8_t kPanasonicAcSwingHMiddle = 0x6; +const uint8_t kPanasonicAcSwingHFullLeft = 0x9; +const uint8_t kPanasonicAcSwingHLeft = 0xA; +const uint8_t kPanasonicAcSwingHRight = 0xB; +const uint8_t kPanasonicAcSwingHFullRight = 0xC; +const uint8_t kPanasonicAcChecksumInit = 0xF4; +const uint8_t kPanasonicAcOnTimer = 0b00000010; +const uint8_t kPanasonicAcOffTimer = 0b00000100; +const uint16_t kPanasonicAcTimeMax = 23 * 60 + 59; // Mins since midnight. +const uint16_t kPanasonicAcTimeSpecial = 0x600; + +const uint8_t kPanasonicKnownGoodState[kPanasonicAcStateLength] = { + 0x02, 0x20, 0xE0, 0x04, 0x00, 0x00, 0x00, 0x06, 0x02, + 0x20, 0xE0, 0x04, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, + 0x00, 0x0E, 0xE0, 0x00, 0x00, 0x81, 0x00, 0x00, 0x00}; + +enum panasonic_ac_remote_model_t { + kPanasonicUnknown = 0, + kPanasonicLke = 1, + kPanasonicNke = 2, + kPanasonicDke = 3, + kPanasonicJke = 4, + kPanasonicCkp = 5, +}; + +class IRPanasonicAc { + public: + explicit IRPanasonicAc(uint16_t pin); + + void stateReset(); +#if SEND_PANASONIC + void send(const uint16_t repeat = kPanasonicAcDefaultRepeat); +#endif // SEND_PANASONIC + void begin(); + void on(); + void off(); + void setPower(const bool state); + bool getPower(); + void setTemp(const uint8_t temp, const bool remember = true); + uint8_t getTemp(); + void setFan(const uint8_t fan); + uint8_t getFan(); + void setMode(const uint8_t mode); + uint8_t getMode(); + void setRaw(const uint8_t state[]); + uint8_t *getRaw(); + static bool validChecksum(uint8_t *state, + const uint16_t length = kPanasonicAcStateLength); + static uint8_t calcChecksum(uint8_t *state, + const uint16_t length = kPanasonicAcStateLength); + void setQuiet(const bool state); + bool getQuiet(); + void setPowerful(const bool state); + bool getPowerful(); + void setModel(const panasonic_ac_remote_model_t model); + panasonic_ac_remote_model_t getModel(); + void setSwingVertical(const uint8_t elevation); + uint8_t getSwingVertical(); + void setSwingHorizontal(const uint8_t direction); + uint8_t getSwingHorizontal(); + static uint16_t encodeTime(const uint8_t hours, const uint8_t mins); + uint16_t getClock(); + void setClock(const uint16_t mins_since_midnight); + uint16_t getOnTimer(); + void setOnTimer(const uint16_t mins_since_midnight, const bool enable = true); + void cancelOnTimer(); + bool isOnTimerEnabled(); + uint16_t getOffTimer(); + void setOffTimer(const uint16_t mins_since_midnight, + const bool enable = true); + void cancelOffTimer(); + bool isOffTimerEnabled(); +#ifdef ARDUINO + String toString(); + static String timeToString(const uint16_t mins_since_midnight); +#else + std::string toString(); + static std::string timeToString(const uint16_t mins_since_midnight); +#endif +#ifndef UNIT_TEST + + private: +#endif + uint8_t remote_state[kPanasonicAcStateLength]; + uint8_t _swingh; + uint8_t _temp; + void fixChecksum(const uint16_t length = kPanasonicAcStateLength); + static uint8_t calcChecksum(const uint8_t *state, + const uint16_t length = kPanasonicAcStateLength); + IRsend _irsend; +}; + +#endif // IR_PANASONIC_H_ diff --git a/lib/IRremoteESP8266/src/ir_Pioneer.cpp b/lib/IRremoteESP8266/src/ir_Pioneer.cpp new file mode 100644 index 0000000..9134e36 --- /dev/null +++ b/lib/IRremoteESP8266/src/ir_Pioneer.cpp @@ -0,0 +1,143 @@ +// Copyright 2009 Ken Shirriff +// Copyright 2017, 2018 David Conran +// Copyright 2018 Kamil Palczewski + +#define __STDC_LIMIT_MACROS +#include +#include +#include "IRrecv.h" +#include "IRsend.h" +#include "IRutils.h" +#include "ir_NEC.h" + +// PPPP III OOO N N EEEE EEEE RRRR +// P P I O O NN N E E R R +// PPPP I O O N N N EEE EEE RRRR +// P I O O N NN E E R R +// P III OOO N N EEEE EEEE R RR + +// Ref: +// http://adrian-kingston.com/IRFormatPioneer.htm + +#if SEND_PIONEER +// Send a raw Pioneer formatted message. +// +// Args: +// data: The message to be sent. +// nbits: The number of bits of the message to be sent. +// Typically kPioneerBits. +// repeat: The number of times the command is to be repeated. +// +// Status: BETA / Expected to be working. +// +// Ref: +// http://adrian-kingston.com/IRFormatPioneer.htm +void IRsend::sendPioneer(const uint64_t data, const uint16_t nbits, + const uint16_t repeat) { + // If nbits is to big, or is odd, abort. + if (nbits > sizeof(data) * 8 || nbits % 2 == 1) return; + + // send 1st part of the code + sendNEC(data >> (nbits / 2), nbits / 2, 0); + // send 2nd part of the code + sendNEC(data & (((uint64_t)1 << (nbits / 2)) - 1), nbits / 2, repeat); +} + +// Calculate the raw Pioneer data code based on two NEC sub-codes +// Args: +// address A 16-bit "published" NEC value. +// command: A 16-bit "published" NEC value. +// Returns: +// A raw 64-bit Pioneer message code. +// +// Status: BETA / Expected to work. +// +// Note: +// Address & Command can be take from a decode result OR from the spreadsheets +// located at: +// https://www.pioneerelectronics.com/PUSA/Support/Home-Entertainment-Custom-Install/IR+Codes/A+V+Receivers +// where the first part is considered the address, +// and the second the command. +// e.g. +// "A556+AF20" is an Address of 0xA556 & a Command of 0xAF20. +uint64_t IRsend::encodePioneer(const uint16_t address, const uint16_t command) { + return (((uint64_t)encodeNEC(address >> 8, address & 0xFF)) << 32) | + encodeNEC(command >> 8, command & 0xFF); +} +#endif // SEND_PIONEER + +#if DECODE_PIONEER +// Decode the supplied Pioneer message. +// +// Args: +// results: Ptr to the data to decode and where to store the decode result. +// nbits: The number of data bits to expect. Typically kPioneerBits. +// strict: Flag indicating if we should perform strict matching. +// Returns: +// boolean: True if it can decode it, false if it can't. +// +// Status: BETA / Should be working. (Self decodes & real examples) +// +bool IRrecv::decodePioneer(decode_results *results, const uint16_t nbits, + const bool strict) { + if (results->rawlen < 2 * (nbits + kHeader + kFooter) - 1) + return false; // Can't possibly be a valid Pioneer message. + if (strict && nbits != kPioneerBits) + return false; // Not strictly an Pioneer message. + + uint64_t data = 0; + uint16_t offset = kStartOffset; + + for (uint16_t section = 0; section < 2; section++) { + // Header + if (!matchMark(results->rawbuf[offset], kNecHdrMark)) return false; + // Calculate how long the lowest tick time is based on the header mark. + uint32_t mark_tick = + results->rawbuf[offset++] * kRawTick / kNecHdrMarkTicks; + if (!matchSpace(results->rawbuf[offset], kNecHdrSpace)) return false; + // Calculate how long the common tick time is based on the header space. + uint32_t space_tick = + results->rawbuf[offset++] * kRawTick / kNecHdrSpaceTicks; + // + // Data + match_result_t data_result = matchData( + &(results->rawbuf[offset]), nbits / 2, kNecBitMarkTicks * mark_tick, + kNecOneSpaceTicks * space_tick, kNecBitMarkTicks * mark_tick, + kNecZeroSpaceTicks * space_tick); + if (data_result.success == false) return false; + uint8_t command = data_result.data >> 8; + uint8_t command_inverted = data_result.data; + uint8_t address = data_result.data >> 24; + uint8_t address_inverted = data_result.data >> 16; + // Compliance + if (strict) { + if (command != (command_inverted ^ 0xFF)) + return false; // Command integrity failed. + if (address != (address_inverted ^ 0xFF)) + return false; // Address integrity failed. + } + data = (data << (nbits / 2)) + data_result.data; + offset += data_result.used; + // NEC-like commands and addresses are technically in LSB first order so the + // final versions have to be reversed. + uint16_t code = reverseBits((command << 8) + address, 16); + if (section) + results->command = code; + else + results->address = code; + + // Footer + if (!matchMark(results->rawbuf[offset++], kNecBitMarkTicks * mark_tick)) + return false; + if (offset < results->rawlen && + !matchAtLeast(results->rawbuf[offset++], kNecMinGapTicks * space_tick)) + return false; + } + + // Success + results->bits = nbits; + results->value = data; + results->decode_type = PIONEER; + return true; +} +#endif // DECODE_PIONEER diff --git a/lib/IRremoteESP8266/src/ir_Pronto.cpp b/lib/IRremoteESP8266/src/ir_Pronto.cpp index 28e8083..9ab5c76 100644 --- a/lib/IRremoteESP8266/src/ir_Pronto.cpp +++ b/lib/IRremoteESP8266/src/ir_Pronto.cpp @@ -10,12 +10,12 @@ // PP rr oooo nn nn tttt oooo // Constants -#define PRONTO_FREQ_FACTOR 0.241246 -#define PRONTO_TYPE_OFFSET 0U -#define PRONTO_FREQ_OFFSET 1U -#define PRONTO_SEQ_1_LEN_OFFSET 2U -#define PRONTO_SEQ_2_LEN_OFFSET 3U -#define PRONTO_DATA_OFFSET 4U +const float kProntoFreqFactor = 0.241246; +const uint16_t kProntoTypeOffset = 0; +const uint16_t kProntoFreqOffset = 1; +const uint16_t kProntoSeq1LenOffset = 2; +const uint16_t kProntoSeq2LenOffset = 3; +const uint16_t kProntoDataOffset = 4; #if SEND_PRONTO // Send a Pronto Code formatted message. @@ -49,29 +49,29 @@ // 0x0030, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0030, 0x0018, // 0x0018, 0x03f6}; // // Send the Pronto(Sony) code. Repeat twice as Sony's require that. -// sendPronto(prontoCode, 46, SONY_MIN_REPEAT); +// sendPronto(prontoCode, 46, kSonyMinRepeat); // // Ref: // http://www.etcwiki.org/wiki/Pronto_Infrared_Format // http://www.remotecentral.com/features/irdisp2.htm void IRsend::sendPronto(uint16_t data[], uint16_t len, uint16_t repeat) { // Check we have enough data to work out what to send. - if (len < PRONTO_MIN_LENGTH) return; + if (len < kProntoMinLength) return; // We only know how to deal with 'raw' pronto codes types. Reject all others. - if (data[PRONTO_TYPE_OFFSET] != 0) return; + if (data[kProntoTypeOffset] != 0) return; // Pronto frequency is in Hz. - uint16_t hz = (uint16_t) (1000000U / (data[PRONTO_FREQ_OFFSET] * - PRONTO_FREQ_FACTOR)); + uint16_t hz = + (uint16_t)(1000000U / (data[kProntoFreqOffset] * kProntoFreqFactor)); enableIROut(hz); // Grab the length of the two sequences. - uint16_t seq_1_len = data[PRONTO_SEQ_1_LEN_OFFSET] * 2; - uint16_t seq_2_len = data[PRONTO_SEQ_2_LEN_OFFSET] * 2; + uint16_t seq_1_len = data[kProntoSeq1LenOffset] * 2; + uint16_t seq_2_len = data[kProntoSeq2LenOffset] * 2; // Calculate where each sequence starts in the buffer. - uint16_t seq_1_start = PRONTO_DATA_OFFSET; - uint16_t seq_2_start = PRONTO_DATA_OFFSET + seq_1_len; + uint16_t seq_1_start = kProntoDataOffset; + uint16_t seq_2_start = kProntoDataOffset + seq_1_len; uint32_t periodic_time = calcUSecPeriod(hz, false); diff --git a/lib/IRremoteESP8266/src/ir_RC5_RC6.cpp b/lib/IRremoteESP8266/src/ir_RC5_RC6.cpp index 8fcd097..ef1500d 100644 --- a/lib/IRremoteESP8266/src/ir_RC5_RC6.cpp +++ b/lib/IRremoteESP8266/src/ir_RC5_RC6.cpp @@ -21,29 +21,31 @@ // Ref: // https://en.wikipedia.org/wiki/RC-5 // http://www.sbprojects.com/knowledge/ir/rc5.php -#define MIN_RC5_SAMPLES 11U -#define MIN_RC6_SAMPLES 1U -#define RC5_T1 889U -#define RC5_MIN_COMMAND_LENGTH 113778UL -#define RC5_MIN_GAP (RC5_MIN_COMMAND_LENGTH - RC5_RAW_BITS * (2 * RC5_T1)) -#define RC5_TOGGLE_MASK 0x800U // (The 12th bit) + +const uint16_t kRc5T1 = 889; +const uint32_t kRc5MinCommandLength = 113778; +const uint32_t kRc5MinGap = kRc5MinCommandLength - kRC5RawBits * (2 * kRc5T1); +const uint16_t kRc5ToggleMask = 0x800; // The 12th bit. +const uint16_t kRc5SamplesMin = 11; + // RC-6 // Ref: // https://en.wikipedia.org/wiki/RC-6 // http://www.pcbheaven.com/userpages/The_Philips_RC6_Protocol/ -#define RC6_TICK 444U -#define RC6_HDR_MARK_TICKS 6U -#define RC6_HDR_MARK (RC6_HDR_MARK_TICKS * RC6_TICK) -#define RC6_HDR_SPACE_TICKS 2U -#define RC6_HDR_SPACE (RC6_HDR_SPACE_TICKS * RC6_TICK) -#define RC6_RPT_LENGTH_TICKS 187U -#define RC6_RPT_LENGTH (RC6_RPT_LENGTH_TICKS * RC6_TICK) -#define RC6_TOGGLE_MASK 0x10000UL // (The 17th bit) -#define RC6_36_TOGGLE_MASK 0x8000U // (The 16th bit) + +const uint16_t kRc6Tick = 444; +const uint16_t kRc6HdrMarkTicks = 6; +const uint16_t kRc6HdrMark = kRc6HdrMarkTicks * kRc6Tick; +const uint16_t kRc6HdrSpaceTicks = 2; +const uint16_t kRc6HdrSpace = kRc6HdrSpaceTicks * kRc6Tick; +const uint16_t kRc6RptLengthTicks = 187; +const uint32_t kRc6RptLength = kRc6RptLengthTicks * kRc6Tick; +const uint32_t kRc6ToggleMask = 0x10000UL; // The 17th bit. +const uint16_t kRc6_36ToggleMask = 0x8000; // The 16th bit. // Common (getRClevel()) -const int16_t kMARK = 0; -const int16_t kSPACE = 1; +const int16_t kMark = 0; +const int16_t kSpace = 1; #if SEND_RC5 // Send a Philips RC-5/RC-5X packet. @@ -67,14 +69,13 @@ const int16_t kSPACE = 1; // TODO(anyone): // Testing of the RC-5X components. void IRsend::sendRC5(uint64_t data, uint16_t nbits, uint16_t repeat) { - if (nbits > sizeof(data) * 8) - return; // We can't send something that big. + if (nbits > sizeof(data) * 8) return; // We can't send something that big. bool skipSpace = true; bool field_bit = true; // Set 36kHz IR carrier frequency & a 1/4 (25%) duty cycle. enableIROut(36, 25); - if (nbits >= RC5X_BITS) { // Is this a RC-5X message? + if (nbits >= kRC5XBits) { // Is this a RC-5X message? // field bit is the inverted MSB of RC-5X data. field_bit = ((data >> (nbits - 1)) ^ 1) & 1; nbits--; @@ -89,28 +90,28 @@ void IRsend::sendRC5(uint64_t data, uint16_t nbits, uint16_t repeat) { if (skipSpace) skipSpace = false; // First time through, we assume the leading space(). else - space(RC5_T1); - mark(RC5_T1); + space(kRc5T1); + mark(kRc5T1); // Field/Second start bit. if (field_bit) { // Send a 1. Normal for RC-5. - space(RC5_T1); - mark(RC5_T1); + space(kRc5T1); + mark(kRc5T1); } else { // Send a 0. Special case for RC-5X. Means 7th command bit is 1. - mark(RC5_T1); - space(RC5_T1); + mark(kRc5T1); + space(kRc5T1); } // Data for (uint64_t mask = 1ULL << (nbits - 1); mask; mask >>= 1) if (data & mask) { // 1 - space(RC5_T1); // 1 is space, then mark. - mark(RC5_T1); - } else { // 0 - mark(RC5_T1); // 0 is mark, then space. - space(RC5_T1); + space(kRc5T1); // 1 is space, then mark. + mark(kRc5T1); + } else { // 0 + mark(kRc5T1); // 0 is mark, then space. + space(kRc5T1); } // Footer - space(std::max(RC5_MIN_GAP, RC5_MIN_COMMAND_LENGTH - usecTimer.elapsed())); + space(std::max(kRc5MinGap, kRc5MinCommandLength - usecTimer.elapsed())); } } @@ -131,8 +132,7 @@ void IRsend::sendRC5(uint64_t data, uint16_t nbits, uint16_t repeat) { // https://en.wikipedia.org/wiki/RC-5 uint16_t IRsend::encodeRC5(uint8_t address, uint8_t command, bool key_released) { - return (key_released << (RC5_BITS - 1)) | - ((address & 0x1f) << 6) | + return (key_released << (kRC5Bits - 1)) | ((address & 0x1f) << 6) | (command & 0x3F); } @@ -156,8 +156,8 @@ uint16_t IRsend::encodeRC5X(uint8_t address, uint8_t command, // The 2nd start/field bit (MSB of the return value) is the value of the 7th // command bit. bool s2 = (command >> 6) & 1; - return ((uint16_t) s2 << (RC5X_BITS - 1)) | - encodeRC5(address, command, key_released); + return ((uint16_t)s2 << (kRC5XBits - 1)) | + encodeRC5(address, command, key_released); } // Flip the toggle bit of a Philips RC-5/RC-5X data message. @@ -174,9 +174,7 @@ uint16_t IRsend::encodeRC5X(uint8_t address, uint8_t command, // Ref: // http://www.sbprojects.com/knowledge/ir/rc5.php // https://en.wikipedia.org/wiki/RC-5 -uint64_t IRsend::toggleRC5(uint64_t data) { - return data ^ RC5_TOGGLE_MASK; -} +uint64_t IRsend::toggleRC5(uint64_t data) { return data ^ kRc5ToggleMask; } #endif // SEND_RC5 #if SEND_RC6 @@ -198,9 +196,8 @@ uint64_t IRsend::toggleRC5(uint64_t data) { // http://www.sbprojects.com/knowledge/ir/rc6.php // http://www.righto.com/2010/12/64-bit-rc6-codes-arduino-and-xbox.html uint64_t IRsend::toggleRC6(uint64_t data, uint16_t nbits) { - if (nbits == RC6_36_BITS) - return data ^ RC6_36_TOGGLE_MASK; - return data ^ RC6_TOGGLE_MASK; + if (nbits == kRC6_36Bits) return data ^ kRc6_36ToggleMask; + return data ^ kRc6ToggleMask; } // Encode a Philips RC-6 data message. @@ -220,13 +217,12 @@ uint64_t IRsend::toggleRC6(uint64_t data, uint16_t nbits) { // http://www.sbprojects.com/knowledge/ir/rc6.php // http://www.righto.com/2010/12/64-bit-rc6-codes-arduino-and-xbox.html // http://www.pcbheaven.com/userpages/The_Philips_RC6_Protocol/ -uint64_t IRsend::encodeRC6(uint32_t address, uint8_t command, - uint16_t mode) { +uint64_t IRsend::encodeRC6(uint32_t address, uint8_t command, uint16_t mode) { switch (mode) { - case RC6_MODE0_BITS: + case kRC6Mode0Bits: return ((address & 0xFFF) << 8) | (command & 0xFF); - case RC6_36_BITS: - return ((uint64_t) (address & 0xFFFFFFF) << 8) | (command & 0xFF); + case kRC6_36Bits: + return ((uint64_t)(address & 0xFFFFFFF) << 8) | (command & 0xFF); default: return 0; } @@ -249,25 +245,24 @@ uint64_t IRsend::encodeRC6(uint32_t address, uint8_t command, // https://en.wikipedia.org/wiki/Manchester_code void IRsend::sendRC6(uint64_t data, uint16_t nbits, uint16_t repeat) { // Check we can send the number of bits requested. - if (nbits > sizeof(data) * 8) - return; + if (nbits > sizeof(data) * 8) return; // Set 36kHz IR carrier frequency & a 1/3 (33%) duty cycle. enableIROut(36, 33); for (uint16_t r = 0; r <= repeat; r++) { // Header - mark(RC6_HDR_MARK); - space(RC6_HDR_SPACE); + mark(kRc6HdrMark); + space(kRc6HdrSpace); // Start bit. - mark(RC6_TICK); // mark, then space == 0x1. - space(RC6_TICK); + mark(kRc6Tick); // mark, then space == 0x1. + space(kRc6Tick); // Data uint16_t bitTime; for (uint64_t i = 1, mask = 1ULL << (nbits - 1); mask; i++, mask >>= 1) { if (i == 4) // The fourth bit we send is a "double width trailer bit". - bitTime = 2 * RC6_TICK; // double-wide trailer bit + bitTime = 2 * kRc6Tick; // double-wide trailer bit else - bitTime = RC6_TICK; // Normal bit - if (data & mask) { // 1 + bitTime = kRc6Tick; // Normal bit + if (data & mask) { // 1 mark(bitTime); space(bitTime); } else { // 0 @@ -276,7 +271,7 @@ void IRsend::sendRC6(uint64_t data, uint16_t nbits, uint16_t repeat) { } } // Footer - space(RC6_RPT_LENGTH); + space(kRc6RptLength); } } #endif // SEND_RC6 @@ -293,53 +288,57 @@ void IRsend::sendRC6(uint64_t data, uint16_t nbits, uint16_t repeat) { // offset: Ptr to the currect offset to the rawbuf. // used: Ptr to the current used counter. // bitTime: Time interval of single bit in microseconds. +// maxwidth: Maximum number of successive levels to find in a single level +// (default 3) // Returns: // int: MARK, SPACE, or -1 for error (The measured time interval is not a // multiple of t1.) // Ref: // https://en.wikipedia.org/wiki/Manchester_code -int16_t IRrecv::getRClevel(decode_results *results, uint16_t *offset, - uint16_t *used, uint16_t bitTime, - uint8_t tolerance, int16_t excess, uint16_t delta) { +int16_t IRrecv::getRClevel(decode_results *results, uint16_t *offset, + uint16_t *used, uint16_t bitTime, uint8_t tolerance, + int16_t excess, uint16_t delta, uint8_t maxwidth) { DPRINT("DEBUG: getRClevel: offset = "); DPRINTLN(uint64ToString(*offset)); + DPRINT("DEBUG: getRClevel: rawlen = "); + DPRINTLN(uint64ToString(results->rawlen)); if (*offset >= results->rawlen) { DPRINTLN("DEBUG: getRClevel: SPACE, past end of rawbuf"); - return kSPACE; // After end of recorded buffer, assume SPACE. + return kSpace; // After end of recorded buffer, assume SPACE. } uint16_t width = results->rawbuf[*offset]; // If the value of offset is odd, it's a MARK. Even, it's a SPACE. - uint16_t val = ((*offset) % 2) ? kMARK : kSPACE; + uint16_t val = ((*offset) % 2) ? kMark : kSpace; // Check to see if we have hit an inter-message gap (> 20ms). - if (val == kSPACE && width > 20000 - delta) { + if (val == kSpace && + (width > 20000 - delta || width > maxwidth * bitTime + delta)) { DPRINTLN("DEBUG: getRClevel: SPACE, hit end of mesg gap."); - return kSPACE; + return kSpace; } - int16_t correction = (val == kMARK) ? excess : -excess; + int16_t correction = (val == kMark) ? excess : -excess; // Calculate the look-ahead for our current position in the buffer. uint16_t avail; // Note: We want to match in greedy order as the other way leads to // mismatches due to overlaps induced by the correction and tolerance // values. - if (match(width, 3 * bitTime + correction, tolerance, delta)) { - avail = 3; - } else if (match(width, 2 * bitTime + correction, tolerance, delta)) { - avail = 2; - } else if (match(width, bitTime + correction, tolerance, delta)) { - avail = 1; - } else { + for (avail = maxwidth; avail > 0; avail--) { + if (match(width, avail * bitTime + correction, tolerance, delta)) { + break; + } + } + if (!avail) { DPRINTLN("DEBUG: getRClevel: Unexpected width. Exiting."); return -1; // The width is not what we expected. } - (*used)++; // Count another one of the avail slots as used. + (*used)++; // Count another one of the avail slots as used. if (*used >= avail) { // Are we out of look-ahead/avail slots? // Yes, so reset the used counter, and move the offset ahead. *used = 0; (*offset)++; } - if (val == kMARK) { + if (val == kMark) { DPRINTLN("DEBUG: getRClevel: MARK"); } else { DPRINTLN("DEBUG: getRClevel: SPACE"); @@ -371,28 +370,28 @@ int16_t IRrecv::getRClevel(decode_results *results, uint16_t *offset, // TODO(anyone): // Serious testing of the RC-5X and strict aspects needs to be done. bool IRrecv::decodeRC5(decode_results *results, uint16_t nbits, bool strict) { - if (results->rawlen < MIN_RC5_SAMPLES + HEADER - 1) return false; + if (results->rawlen < kRc5SamplesMin + kHeader - 1) return false; // Compliance - if (strict && nbits != RC5_BITS && nbits != RC5X_BITS) + if (strict && nbits != kRC5Bits && nbits != kRC5XBits) return false; // It's neither RC-5 or RC-5X. - uint16_t offset = OFFSET_START; + uint16_t offset = kStartOffset; uint16_t used = 0; bool is_rc5x = false; uint64_t data = 0; // Header // Get start bit #1. - if (getRClevel(results, &offset, &used, RC5_T1) != kMARK) return false; + if (getRClevel(results, &offset, &used, kRc5T1) != kMark) return false; // Get field/start bit #2 (inverted bit-7 of the command if RC-5X protocol) uint16_t actual_bits = 1; - int16_t levelA = getRClevel(results, &offset, &used, RC5_T1); - int16_t levelB = getRClevel(results, &offset, &used, RC5_T1); - if (levelA == kSPACE && levelB == kMARK) { // Matched a 1. + int16_t levelA = getRClevel(results, &offset, &used, kRc5T1); + int16_t levelB = getRClevel(results, &offset, &used, kRc5T1); + if (levelA == kSpace && levelB == kMark) { // Matched a 1. is_rc5x = false; - } else if (levelA == kMARK && levelB == kSPACE) { // Matched a 0. - if (nbits <= RC5_BITS) return false; // Field bit must be '1' for RC5. + } else if (levelA == kMark && levelB == kSpace) { // Matched a 0. + if (nbits <= kRC5Bits) return false; // Field bit must be '1' for RC5. is_rc5x = true; data = 1; } else { @@ -401,11 +400,11 @@ bool IRrecv::decodeRC5(decode_results *results, uint16_t nbits, bool strict) { // Data for (; offset < results->rawlen; actual_bits++) { - int16_t levelA = getRClevel(results, &offset, &used, RC5_T1); - int16_t levelB = getRClevel(results, &offset, &used, RC5_T1); - if (levelA == kSPACE && levelB == kMARK) + int16_t levelA = getRClevel(results, &offset, &used, kRc5T1); + int16_t levelB = getRClevel(results, &offset, &used, kRc5T1); + if (levelA == kSpace && levelB == kMark) data = (data << 1) | 1; // 1 - else if (levelA == kMARK && levelB == kSPACE) + else if (levelA == kMark && levelB == kSpace) data <<= 1; // 0 else break; @@ -414,8 +413,8 @@ bool IRrecv::decodeRC5(decode_results *results, uint16_t nbits, bool strict) { // Compliance if (actual_bits < nbits) return false; // Less data than we expected. - if (strict && actual_bits != RC5_BITS && - actual_bits != RC5X_BITS) return false; + if (strict && actual_bits != kRC5Bits && actual_bits != kRC5XBits) + return false; // Success results->value = data; @@ -424,7 +423,7 @@ bool IRrecv::decodeRC5(decode_results *results, uint16_t nbits, bool strict) { results->repeat = false; if (is_rc5x) { results->decode_type = RC5X; - results->command |= ((uint32_t) is_rc5x) << 6; + results->command |= ((uint32_t)is_rc5x) << 6; } else { results->decode_type = RC5; actual_bits--; // RC5 doesn't count the field bit as data. @@ -452,7 +451,7 @@ bool IRrecv::decodeRC5(decode_results *results, uint16_t nbits, bool strict) { // TODO(anyone): // Testing of the strict compliance aspects. bool IRrecv::decodeRC6(decode_results *results, uint16_t nbits, bool strict) { - if (results->rawlen < HEADER + 2 + 4) // Up to the double-wide T bit. + if (results->rawlen < kHeader + 2 + 4) // Up to the double-wide T bit. return false; // Smaller than absolute smallest possible RC6 message. if (strict) { // Compliance @@ -462,31 +461,31 @@ bool IRrecv::decodeRC6(decode_results *results, uint16_t nbits, bool strict) { // Also due to potential melding with the start bit, we can only count // the start bit as 1, instead of a more typical 2 value. The header still // remains as normal. - if (results->rawlen < nbits + HEADER + 1) + if (results->rawlen < nbits + kHeader + 1) return false; // Don't have enough entries/samples to be valid. switch (nbits) { - case RC6_MODE0_BITS: - case RC6_36_BITS: + case kRC6Mode0Bits: + case kRC6_36Bits: break; default: return false; // Asking for the wrong number of bits. } } - uint16_t offset = OFFSET_START; + uint16_t offset = kStartOffset; // Header - if (!matchMark(results->rawbuf[offset], RC6_HDR_MARK)) return false; + if (!matchMark(results->rawbuf[offset], kRc6HdrMark)) return false; // Calculate how long the common tick time is based on the header mark. - uint32_t tick = results->rawbuf[offset++] * RAWTICK / RC6_HDR_MARK_TICKS; - if (!matchSpace(results->rawbuf[offset++], RC6_HDR_SPACE_TICKS * tick)) + uint32_t tick = results->rawbuf[offset++] * kRawTick / kRc6HdrMarkTicks; + if (!matchSpace(results->rawbuf[offset++], kRc6HdrSpaceTicks * tick)) return false; uint16_t used = 0; // Get the start bit. e.g. 1. - if (getRClevel(results, &offset, &used, tick) != kMARK) return false; - if (getRClevel(results, &offset, &used, tick) != kSPACE) return false; + if (getRClevel(results, &offset, &used, tick) != kMark) return false; + if (getRClevel(results, &offset, &used, tick) != kSpace) return false; uint16_t actual_bits; uint64_t data = 0; @@ -496,17 +495,15 @@ bool IRrecv::decodeRC6(decode_results *results, uint16_t nbits, bool strict) { int16_t levelA, levelB; // Next two levels levelA = getRClevel(results, &offset, &used, tick); // T bit is double wide; make sure second half matches - if (actual_bits == 3 && - levelA != getRClevel(results, &offset, &used, tick)) + if (actual_bits == 3 && levelA != getRClevel(results, &offset, &used, tick)) return false; levelB = getRClevel(results, &offset, &used, tick); // T bit is double wide; make sure second half matches - if (actual_bits == 3 && - levelB != getRClevel(results, &offset, &used, tick)) + if (actual_bits == 3 && levelB != getRClevel(results, &offset, &used, tick)) return false; - if (levelA == kMARK && levelB == kSPACE) // reversed compared to RC5 - data = (data << 1) | 1; // 1 - else if (levelA == kSPACE && levelB == kMARK) + if (levelA == kMark && levelB == kSpace) // reversed compared to RC5 + data = (data << 1) | 1; // 1 + else if (levelA == kSpace && levelB == kMark) data <<= 1; // 0 else break; diff --git a/lib/IRremoteESP8266/src/ir_RCMM.cpp b/lib/IRremoteESP8266/src/ir_RCMM.cpp index 3d8d244..1b03d2c 100644 --- a/lib/IRremoteESP8266/src/ir_RCMM.cpp +++ b/lib/IRremoteESP8266/src/ir_RCMM.cpp @@ -17,28 +17,28 @@ // Constants // Ref: // http://www.sbprojects.com/knowledge/ir/rcmm.php -#define RCMM_TICK 28U // Technically it would be 27.777* -#define RCMM_HDR_MARK_TICKS 15U -#define RCMM_HDR_MARK 416U -#define RCMM_HDR_SPACE_TICKS 10U -#define RCMM_HDR_SPACE 277U -#define RCMM_BIT_MARK_TICKS 6U -#define RCMM_BIT_MARK 166U -#define RCMM_BIT_SPACE_0_TICKS 10U -#define RCMM_BIT_SPACE_0 277U -#define RCMM_BIT_SPACE_1_TICKS 16U -#define RCMM_BIT_SPACE_1 444U -#define RCMM_BIT_SPACE_2_TICKS 22U -#define RCMM_BIT_SPACE_2 611U -#define RCMM_BIT_SPACE_3_TICKS 28U -#define RCMM_BIT_SPACE_3 777U -#define RCMM_RPT_LENGTH_TICKS 992U -#define RCMM_RPT_LENGTH 27778U -#define RCMM_MIN_GAP_TICKS 120U -#define RCMM_MIN_GAP 3360U +const uint16_t kRcmmTick = 28; // Technically it would be 27.777* +const uint16_t kRcmmHdrMarkTicks = 15; +const uint16_t kRcmmHdrMark = 416; +const uint16_t kRcmmHdrSpaceTicks = 10; +const uint16_t kRcmmHdrSpace = 277; +const uint16_t kRcmmBitMarkTicks = 6; +const uint16_t kRcmmBitMark = 166; +const uint16_t kRcmmBitSpace0Ticks = 10; +const uint16_t kRcmmBitSpace0 = 277; +const uint16_t kRcmmBitSpace1Ticks = 16; +const uint16_t kRcmmBitSpace1 = 444; +const uint16_t kRcmmBitSpace2Ticks = 22; +const uint16_t kRcmmBitSpace2 = 611; +const uint16_t kRcmmBitSpace3Ticks = 28; +const uint16_t kRcmmBitSpace3 = 777; +const uint16_t kRcmmRptLengthTicks = 992; +const uint32_t kRcmmRptLength = 27778; +const uint16_t kRcmmMinGapTicks = 120; +const uint32_t kRcmmMinGap = 3360; // Use a tolerance of +/-10% when matching some data spaces. -#define RCMM_TOLERANCE 10U -#define RCMM_EXCESS 50U +const uint8_t kRcmmTolerance = 10; +const uint16_t kRcmmExcess = 50; #if SEND_RCMM // Send a Philips RC-MM packet. @@ -60,27 +60,35 @@ void IRsend::sendRCMM(uint64_t data, uint16_t nbits, uint16_t repeat) { for (uint16_t r = 0; r <= repeat; r++) { usecs.reset(); // Header - mark(RCMM_HDR_MARK); - space(RCMM_HDR_SPACE); + mark(kRcmmHdrMark); + space(kRcmmHdrSpace); // Data uint64_t mask = 0b11ULL << (nbits - 2); // RC-MM sends data 2 bits at a time. for (int32_t i = nbits; i > 0; i -= 2) { - mark(RCMM_BIT_MARK); + mark(kRcmmBitMark); // Grab the next Most Significant Bits to send. switch ((data & mask) >> (i - 2)) { - case 0b00: space(RCMM_BIT_SPACE_0); break; - case 0b01: space(RCMM_BIT_SPACE_1); break; - case 0b10: space(RCMM_BIT_SPACE_2); break; - case 0b11: space(RCMM_BIT_SPACE_3); break; + case 0b00: + space(kRcmmBitSpace0); + break; + case 0b01: + space(kRcmmBitSpace1); + break; + case 0b10: + space(kRcmmBitSpace2); + break; + case 0b11: + space(kRcmmBitSpace3); + break; } mask >>= 2; } // Footer - mark(RCMM_BIT_MARK); - // Protocol requires us to wait at least RCMM_RPT_LENGTH usecs from the - // start or RCMM_MIN_GAP usecs. - space(std::max(RCMM_RPT_LENGTH - usecs.elapsed(), RCMM_MIN_GAP)); + mark(kRcmmBitMark); + // Protocol requires us to wait at least kRcmmRptLength usecs from the + // start or kRcmmMinGap usecs. + space(std::max(kRcmmRptLength - usecs.elapsed(), kRcmmMinGap)); } } #endif @@ -90,7 +98,7 @@ void IRsend::sendRCMM(uint64_t data, uint16_t nbits, uint16_t repeat) { // Places successful decode information in the results pointer. // Args: // results: Ptr to the data to decode and where to store the decode result. -// nbits: Nr. of bits to expect in the data portion. Typically RCMM_BITS. +// nbits: Nr. of bits to expect in the data portion. Typically kRCMMBits. // strict: Flag to indicate if we strictly adhere to the specification. // Returns: // boolean: True if it can decode it, false if it can't. @@ -101,67 +109,65 @@ void IRsend::sendRCMM(uint64_t data, uint16_t nbits, uint16_t repeat) { // http://www.sbprojects.com/knowledge/ir/rcmm.php bool IRrecv::decodeRCMM(decode_results *results, uint16_t nbits, bool strict) { uint64_t data = 0; - uint16_t offset = OFFSET_START; + uint16_t offset = kStartOffset; if (results->rawlen <= 4) return false; // Not enough entries to ever be RCMM. // Calc the maximum size in bits, the message can be, or that we can accept. - int16_t maxBitSize = std::min((uint16_t) results->rawlen - 5, - (uint16_t) sizeof(data) * 8); + int16_t maxBitSize = + std::min((uint16_t)results->rawlen - 5, (uint16_t)sizeof(data) * 8); // Compliance if (strict) { // Technically the spec says bit sizes should be 12 xor 24. however // 32 bits has been seen from a device. We are going to assume // 12 <= bits <= 32 is the 'required' bit length for the spec. - if (maxBitSize < 12 || maxBitSize > 32) - return false; + if (maxBitSize < 12 || maxBitSize > 32) return false; if (maxBitSize < nbits) return false; // Short cut, we can never reach the expected nr. of bits. } // Header decode - if (!matchMark(results->rawbuf[offset], RCMM_HDR_MARK)) return false; + if (!matchMark(results->rawbuf[offset], kRcmmHdrMark)) return false; // Calculate how long the common tick time is based on the header mark. - uint32_t m_tick = results->rawbuf[offset++] * RAWTICK / RCMM_HDR_MARK_TICKS; - if (!matchSpace(results->rawbuf[offset], RCMM_HDR_SPACE)) return false; + uint32_t m_tick = results->rawbuf[offset++] * kRawTick / kRcmmHdrMarkTicks; + if (!matchSpace(results->rawbuf[offset], kRcmmHdrSpace)) return false; // Calculate how long the common tick time is based on the header space. - uint32_t s_tick = results->rawbuf[offset++] * RAWTICK / RCMM_HDR_SPACE_TICKS; + uint32_t s_tick = results->rawbuf[offset++] * kRawTick / kRcmmHdrSpaceTicks; // Data decode // RC-MM has two bits of data per mark/space pair. uint16_t actualBits; for (actualBits = 0; actualBits < maxBitSize; actualBits += 2, offset++) { - if (!match(results->rawbuf[offset++], RCMM_BIT_MARK_TICKS * m_tick)) + if (!match(results->rawbuf[offset++], kRcmmBitMarkTicks * m_tick)) return false; data <<= 2; // Use non-default tolerance & excess for matching some of the spaces as the // defaults are too generous and causes mis-matches in some cases. - if (match(results->rawbuf[offset], RCMM_BIT_SPACE_0_TICKS * s_tick, - TOLERANCE)) + if (match(results->rawbuf[offset], kRcmmBitSpace0Ticks * s_tick, + kTolerance)) data += 0; - else if (match(results->rawbuf[offset], RCMM_BIT_SPACE_1_TICKS * s_tick, - TOLERANCE)) + else if (match(results->rawbuf[offset], kRcmmBitSpace1Ticks * s_tick, + kTolerance)) data += 1; - else if (match(results->rawbuf[offset], RCMM_BIT_SPACE_2_TICKS * s_tick, - RCMM_TOLERANCE)) + else if (match(results->rawbuf[offset], kRcmmBitSpace2Ticks * s_tick, + kRcmmTolerance)) data += 2; - else if (match(results->rawbuf[offset], RCMM_BIT_SPACE_3_TICKS * s_tick, - RCMM_TOLERANCE)) + else if (match(results->rawbuf[offset], kRcmmBitSpace3Ticks * s_tick, + kRcmmTolerance)) data += 3; else return false; } // Footer decode - if (!match(results->rawbuf[offset++], RCMM_BIT_MARK_TICKS * m_tick)) + if (!match(results->rawbuf[offset++], kRcmmBitMarkTicks * m_tick)) return false; if (offset < results->rawlen && - !matchAtLeast(results->rawbuf[offset], RCMM_MIN_GAP_TICKS * s_tick)) + !matchAtLeast(results->rawbuf[offset], kRcmmMinGapTicks * s_tick)) return false; // Compliance - if (strict && actualBits != nbits) - return false; + if (strict && actualBits != nbits) return false; // Success results->value = data; diff --git a/lib/IRremoteESP8266/src/ir_Samsung.cpp b/lib/IRremoteESP8266/src/ir_Samsung.cpp index a7acead..d70e571 100644 --- a/lib/IRremoteESP8266/src/ir_Samsung.cpp +++ b/lib/IRremoteESP8266/src/ir_Samsung.cpp @@ -1,7 +1,11 @@ // Copyright 2009 Ken Shirriff // Copyright 2017 David Conran +#include "ir_Samsung.h" #include +#ifndef ARDUINO +#include +#endif #include "IRrecv.h" #include "IRsend.h" #include "IRutils.h" @@ -17,29 +21,38 @@ // Constants // Ref: // http://elektrolab.wz.cz/katalog/samsung_protocol.pdf -#define SAMSUNG_TICK 560U -#define SAMSUNG_HDR_MARK_TICKS 8U -#define SAMSUNG_HDR_MARK (SAMSUNG_HDR_MARK_TICKS * SAMSUNG_TICK) -#define SAMSUNG_HDR_SPACE_TICKS 8U -#define SAMSUNG_HDR_SPACE (SAMSUNG_HDR_SPACE_TICKS * SAMSUNG_TICK) -#define SAMSUNG_BIT_MARK_TICKS 1U -#define SAMSUNG_BIT_MARK (SAMSUNG_BIT_MARK_TICKS * SAMSUNG_TICK) -#define SAMSUNG_ONE_SPACE_TICKS 3U -#define SAMSUNG_ONE_SPACE (SAMSUNG_ONE_SPACE_TICKS * SAMSUNG_TICK) -#define SAMSUNG_ZERO_SPACE_TICKS 1U -#define SAMSUNG_ZERO_SPACE (SAMSUNG_ZERO_SPACE_TICKS * SAMSUNG_TICK) -#define SAMSUNG_RPT_SPACE_TICKS 4U -#define SAMSUNG_RPT_SPACE (SAMSUNG_RPT_SPACE_TICKS * SAMSUNG_TICK) -#define SAMSUNG_MIN_MESSAGE_LENGTH_TICKS 193U -#define SAMSUNG_MIN_MESSAGE_LENGTH (SAMSUNG_MIN_MESSAGE_LENGTH_TICKS * \ - SAMSUNG_TICK) -#define SAMSUNG_MIN_GAP_TICKS (SAMSUNG_MIN_MESSAGE_LENGTH_TICKS - \ - (SAMSUNG_HDR_MARK_TICKS + SAMSUNG_HDR_SPACE_TICKS + \ - SAMSUNG_BITS * (SAMSUNG_BIT_MARK_TICKS + SAMSUNG_ONE_SPACE_TICKS) + \ - SAMSUNG_BIT_MARK_TICKS)) -#define SAMSUNG_MIN_GAP (SAMSUNG_MIN_GAP_TICKS * SAMSUNG_TICK) - +const uint16_t kSamsungTick = 560; +const uint16_t kSamsungHdrMarkTicks = 8; +const uint16_t kSamsungHdrMark = kSamsungHdrMarkTicks * kSamsungTick; +const uint16_t kSamsungHdrSpaceTicks = 8; +const uint16_t kSamsungHdrSpace = kSamsungHdrSpaceTicks * kSamsungTick; +const uint16_t kSamsungBitMarkTicks = 1; +const uint16_t kSamsungBitMark = kSamsungBitMarkTicks * kSamsungTick; +const uint16_t kSamsungOneSpaceTicks = 3; +const uint16_t kSamsungOneSpace = kSamsungOneSpaceTicks * kSamsungTick; +const uint16_t kSamsungZeroSpaceTicks = 1; +const uint16_t kSamsungZeroSpace = kSamsungZeroSpaceTicks * kSamsungTick; +const uint16_t kSamsungRptSpaceTicks = 4; +const uint16_t kSamsungRptSpace = kSamsungRptSpaceTicks * kSamsungTick; +const uint16_t kSamsungMinMessageLengthTicks = 193; +const uint32_t kSamsungMinMessageLength = + kSamsungMinMessageLengthTicks * kSamsungTick; +const uint16_t kSamsungMinGapTicks = + kSamsungMinMessageLengthTicks - + (kSamsungHdrMarkTicks + kSamsungHdrSpaceTicks + + kSamsungBits * (kSamsungBitMarkTicks + kSamsungOneSpaceTicks) + + kSamsungBitMarkTicks); +const uint32_t kSamsungMinGap = kSamsungMinGapTicks * kSamsungTick; +const uint16_t kSamsungAcHdrMark = 690; +const uint16_t kSamsungAcHdrSpace = 17844; +const uint8_t kSamsungAcSections = 2; +const uint16_t kSamsungAcSectionMark = 3086; +const uint16_t kSamsungAcSectionSpace = 8864; +const uint16_t kSamsungAcSectionGap = 2886; +const uint16_t kSamsungAcBitMark = 586; +const uint16_t kSamsungAcOneSpace = 1432; +const uint16_t kSamsungAcZeroSpace = 436; #if SEND_SAMSUNG // Send a Samsung formatted message. @@ -49,19 +62,17 @@ // // Args: // data: The message to be sent. -// nbits: The bit size of the message being sent. typically SAMSUNG_BITS. +// nbits: The bit size of the message being sent. typically kSamsungBits. // repeat: The number of times the message is to be repeated. // // Status: BETA / Should be working. // // Ref: http://elektrolab.wz.cz/katalog/samsung_protocol.pdf void IRsend::sendSAMSUNG(uint64_t data, uint16_t nbits, uint16_t repeat) { - sendGeneric(SAMSUNG_HDR_MARK, SAMSUNG_HDR_SPACE, - SAMSUNG_BIT_MARK, SAMSUNG_ONE_SPACE, - SAMSUNG_BIT_MARK, SAMSUNG_ZERO_SPACE, - SAMSUNG_BIT_MARK, - SAMSUNG_MIN_GAP, SAMSUNG_MIN_MESSAGE_LENGTH, - data, nbits, 38, true, repeat, 33); + sendGeneric(kSamsungHdrMark, kSamsungHdrSpace, kSamsungBitMark, + kSamsungOneSpace, kSamsungBitMark, kSamsungZeroSpace, + kSamsungBitMark, kSamsungMinGap, kSamsungMinMessageLength, data, + nbits, 38, true, repeat, 33); } // Construct a raw Samsung message from the supplied customer(address) & @@ -77,8 +88,8 @@ void IRsend::sendSAMSUNG(uint64_t data, uint16_t nbits, uint16_t repeat) { uint32_t IRsend::encodeSAMSUNG(uint8_t customer, uint8_t command) { customer = reverseBits(customer, sizeof(customer) * 8); command = reverseBits(command, sizeof(command) * 8); - return((command ^ 0xFF) | (command << 8) | - (customer << 16) | (customer << 24)); + return ((command ^ 0xFF) | (command << 8) | (customer << 16) | + (customer << 24)); } #endif @@ -90,7 +101,7 @@ uint32_t IRsend::encodeSAMSUNG(uint8_t customer, uint8_t command) { // // Args: // results: Ptr to the data to decode and where to store the decode result. -// nbits: Nr. of bits to expect in the data portion. Typically SAMSUNG_BITS. +// nbits: Nr. of bits to expect in the data portion. Typically kSamsungBits. // strict: Flag to indicate if we strictly adhere to the specification. // Returns: // boolean: True if it can decode it, false if it can't. @@ -104,37 +115,35 @@ uint32_t IRsend::encodeSAMSUNG(uint8_t customer, uint8_t command) { // http://elektrolab.wz.cz/katalog/samsung_protocol.pdf bool IRrecv::decodeSAMSUNG(decode_results *results, uint16_t nbits, bool strict) { - if (results->rawlen < 2 * nbits + HEADER + FOOTER - 1) + if (results->rawlen < 2 * nbits + kHeader + kFooter - 1) return false; // Can't possibly be a valid Samsung message. - if (strict && nbits != SAMSUNG_BITS) + if (strict && nbits != kSamsungBits) return false; // We expect Samsung to be 32 bits of message. uint64_t data = 0; - uint16_t offset = OFFSET_START; + uint16_t offset = kStartOffset; // Header - if (!matchMark(results->rawbuf[offset], SAMSUNG_HDR_MARK)) return false; + if (!matchMark(results->rawbuf[offset], kSamsungHdrMark)) return false; // Calculate how long the common tick time is based on the header mark. - uint32_t m_tick = results->rawbuf[offset++] * RAWTICK / - SAMSUNG_HDR_MARK_TICKS; - if (!matchSpace(results->rawbuf[offset], SAMSUNG_HDR_SPACE)) return false; + uint32_t m_tick = results->rawbuf[offset++] * kRawTick / kSamsungHdrMarkTicks; + if (!matchSpace(results->rawbuf[offset], kSamsungHdrSpace)) return false; // Calculate how long the common tick time is based on the header space. - uint32_t s_tick = results->rawbuf[offset++] * RAWTICK / - SAMSUNG_HDR_SPACE_TICKS; + uint32_t s_tick = + results->rawbuf[offset++] * kRawTick / kSamsungHdrSpaceTicks; // Data - match_result_t data_result = matchData(&(results->rawbuf[offset]), nbits, - SAMSUNG_BIT_MARK_TICKS * m_tick, - SAMSUNG_ONE_SPACE_TICKS * s_tick, - SAMSUNG_BIT_MARK_TICKS * m_tick, - SAMSUNG_ZERO_SPACE_TICKS * s_tick); + match_result_t data_result = + matchData(&(results->rawbuf[offset]), nbits, + kSamsungBitMarkTicks * m_tick, kSamsungOneSpaceTicks * s_tick, + kSamsungBitMarkTicks * m_tick, kSamsungZeroSpaceTicks * s_tick); if (data_result.success == false) return false; data = data_result.data; offset += data_result.used; // Footer - if (!matchMark(results->rawbuf[offset++], SAMSUNG_BIT_MARK_TICKS * m_tick)) + if (!matchMark(results->rawbuf[offset++], kSamsungBitMarkTicks * m_tick)) return false; if (offset < results->rawlen && - !matchAtLeast(results->rawbuf[offset], SAMSUNG_MIN_GAP_TICKS * s_tick)) + !matchAtLeast(results->rawbuf[offset], kSamsungMinGapTicks * s_tick)) return false; // Compliance @@ -142,13 +151,11 @@ bool IRrecv::decodeSAMSUNG(decode_results *results, uint16_t nbits, // According to the spec, the customer (address) code is the first 8 // transmitted bits. It's then repeated. Check for that. uint8_t address = data >> 24; - if (strict && address != ((data >> 16) & 0xFF)) - return false; + if (strict && address != ((data >> 16) & 0xFF)) return false; // Spec says the command code is the 3rd block of transmitted 8-bits, // followed by the inverted command code. uint8_t command = (data & 0xFF00) >> 8; - if (strict && command != ((data & 0xFF) ^ 0xFF)) - return false; + if (strict && command != ((data & 0xFF) ^ 0xFF)) return false; // Success results->bits = nbits; @@ -160,3 +167,435 @@ bool IRrecv::decodeSAMSUNG(decode_results *results, uint16_t nbits, return true; } #endif + +#if SEND_SAMSUNG_AC +// Send a Samsung A/C message. +// +// Args: +// data: An array of bytes containing the IR command. +// nbytes: Nr. of bytes of data in the array. (>=kSamsungAcStateLength) +// repeat: Nr. of times the message is to be repeated. (Default = 0). +// +// Status: ALPHA / Untested. +// +// Ref: +// https://github.com/markszabo/IRremoteESP8266/issues/505 +void IRsend::sendSamsungAC(uint8_t data[], uint16_t nbytes, uint16_t repeat) { + if (nbytes < kSamsungAcStateLength && nbytes % kSamsungACSectionLength) + return; // Not an appropriate number of bytes to send a proper message. + + enableIROut(38); + for (uint16_t r = 0; r <= repeat; r++) { + // Header + mark(kSamsungAcHdrMark); + space(kSamsungAcHdrSpace); + // Send in 7 byte sections. + for (uint16_t offset = 0; offset < nbytes; + offset += kSamsungACSectionLength) { + sendGeneric(kSamsungAcSectionMark, kSamsungAcSectionSpace, + kSamsungAcBitMark, kSamsungAcOneSpace, kSamsungAcBitMark, + kSamsungAcZeroSpace, kSamsungAcBitMark, kSamsungAcSectionGap, + data + offset, kSamsungACSectionLength, // 7 bytes == 56 bits + 38000, false, 0, 50); // Send in LSBF order + } + // Complete made up guess at inter-message gap. + space(100000 - kSamsungAcSectionGap); + } +} +#endif // SEND_SAMSUNG_AC + +IRSamsungAc::IRSamsungAc(uint16_t pin) : _irsend(pin) { stateReset(); } + +void IRSamsungAc::stateReset() { + for (uint8_t i = 0; i < kSamsungAcExtendedStateLength; i++) + remote_state[i] = 0x0; + remote_state[0] = 0x02; + remote_state[1] = 0x92; + remote_state[2] = 0x0F; + remote_state[6] = 0xF0; + remote_state[7] = 0x01; + remote_state[8] = 0x02; + remote_state[9] = 0xAE; + remote_state[10] = 0x71; + remote_state[12] = 0x15; + remote_state[13] = 0xF0; +} + +void IRSamsungAc::begin() { _irsend.begin(); } + +uint8_t IRSamsungAc::calcChecksum(const uint8_t state[], + const uint16_t length) { + uint8_t sum = 0; + // Safety check so we don't go outside the array. + if (length < 7) return 255; + // Shamelessly inspired by: + // https://github.com/adafruit/Raw-IR-decoder-for-Arduino/pull/3/files + // Count most of the '1' bits after the checksum location. + sum += countBits(state[length - 7], 8); + sum -= countBits(state[length - 6] & 0xF, 8); + sum += countBits(state[length - 5] & 0b11111110, 8); + sum += countBits(state + length - 4, 3); + return (28 - sum) & 0xF; +} + +bool IRSamsungAc::validChecksum(const uint8_t state[], const uint16_t length) { + if (length < kSamsungAcStateLength) + return true; // No checksum to compare with. Assume okay. + uint8_t offset = 0; + if (length >= kSamsungAcExtendedStateLength) offset = 7; + return ((state[length - 6] >> 4) == calcChecksum(state, length) && + (state[length - (13 + offset)] >> 4) == calcChecksum(state, length - + (7 + offset))); +} + +// Update the checksum for the internal state. +void IRSamsungAc::checksum(uint16_t length) { + if (length < 13) return; + remote_state[length - 6] &= 0x0F; + remote_state[length - 6] |= (calcChecksum(remote_state, length) << 4); + remote_state[length - 13] &= 0x0F; + remote_state[length - 13] |= (calcChecksum(remote_state, length - 7) << 4); +} + +#if SEND_SAMSUNG_AC +// Use for most function/mode/settings changes to the unit. +// i.e. When the device is already running. +void IRSamsungAc::send(const uint16_t repeat, const bool calcchecksum) { + if (calcchecksum) checksum(); + _irsend.sendSamsungAC(remote_state, kSamsungAcStateLength, repeat); +} +#endif // SEND_SAMSUNG_AC + +#if SEND_SAMSUNG_AC +// Use this for when you need to power on/off the device. +// Samsung A/C requires an extended length message when you want to +// change the power operating mode of the A/C unit. +void IRSamsungAc::sendExtended(const uint16_t repeat, const bool calcchecksum) { + if (calcchecksum) checksum(); + uint8_t extended_state[kSamsungAcExtendedStateLength] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0xD2, 0x0F, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + // Copy/convert the internal state to an extended state. + for (uint16_t i = 0; i < kSamsungACSectionLength; i++) + extended_state[i] = remote_state[i]; + for (uint16_t i = kSamsungACSectionLength; i < kSamsungAcStateLength; i++) + extended_state[i + kSamsungACSectionLength] = remote_state[i]; + // extended_state[8] seems special. This is a guess on how to calculate it. + extended_state[8] = (extended_state[1] & 0x9F) | 0x40; + // Send it. + _irsend.sendSamsungAC(extended_state, kSamsungAcExtendedStateLength, repeat); +} +#endif // SEND_SAMSUNG_AC + +uint8_t *IRSamsungAc::getRaw() { + checksum(); + return remote_state; +} + +void IRSamsungAc::setRaw(const uint8_t new_code[], const uint16_t length) { + for (uint8_t i = 0; i < length && i < kSamsungAcExtendedStateLength; i++) { + remote_state[i] = new_code[i]; + } + // Shrink the extended state into a normal state. + if (length > kSamsungAcStateLength) { + for (uint8_t i = kSamsungAcStateLength; i < length; i++) + remote_state[i - kSamsungACSectionLength] = remote_state[i]; + } +} + +void IRSamsungAc::on() { + remote_state[1] &= ~kSamsungAcPowerMask1; + remote_state[6] |= kSamsungAcPowerMask2; +} + +void IRSamsungAc::off() { + remote_state[1] |= kSamsungAcPowerMask1; + remote_state[6] &= ~kSamsungAcPowerMask2; +} + +void IRSamsungAc::setPower(const bool state) { + if (state) + on(); + else + off(); +} + +bool IRSamsungAc::getPower() { + return ((remote_state[6] & kSamsungAcPowerMask2) != 0) && + ((remote_state[1] & kSamsungAcPowerMask1) == 0); +} + +// Set the temp. in deg C +void IRSamsungAc::setTemp(const uint8_t temp) { + uint8_t newtemp = std::max(kSamsungAcMinTemp, temp); + newtemp = std::min(kSamsungAcMaxTemp, newtemp); + remote_state[11] = (remote_state[11] & ~kSamsungAcTempMask) | + ((newtemp - kSamsungAcMinTemp) << 4); +} + +// Return the set temp. in deg C +uint8_t IRSamsungAc::getTemp() { + return ((remote_state[11] & kSamsungAcTempMask) >> 4) + kSamsungAcMinTemp; +} + +void IRSamsungAc::setMode(const uint8_t mode) { + // If we get an unexpected mode, default to AUTO. + uint8_t newmode = mode; + if (newmode > kSamsungAcHeat) newmode = kSamsungAcAuto; + remote_state[12] = (remote_state[12] & ~kSamsungAcModeMask) | (newmode << 4); + + // Auto mode has a special fan setting valid only in auto mode. + if (newmode == kSamsungAcAuto) { + setFan(kSamsungAcFanAuto2); + } else { + if (getFan() == kSamsungAcFanAuto2) // Non-Auto can't have this fan setting + setFan(kSamsungAcFanAuto); // Default to something safe. + } +} + +uint8_t IRSamsungAc::getMode() { + return (remote_state[12] & kSamsungAcModeMask) >> 4; +} + +void IRSamsungAc::setFan(const uint8_t speed) { + switch (speed) { + case kSamsungAcFanAuto: + case kSamsungAcFanLow: + case kSamsungAcFanMed: + case kSamsungAcFanHigh: + case kSamsungAcFanTurbo: + if (getMode() == kSamsungAcAuto) return; // Not valid in Auto mode. + break; + case kSamsungAcFanAuto2: // Special fan setting for when in Auto mode. + if (getMode() != kSamsungAcAuto) return; + break; + default: + return; + } + remote_state[12] = (remote_state[12] & ~kSamsungAcFanMask) | (speed << 1); +} + +uint8_t IRSamsungAc::getFan() { + return ((remote_state[12] & kSamsungAcFanMask) >> 1); +} + +bool IRSamsungAc::getSwing() { + // TODO(Hollako): Explain why sometimes the LSB of remote_state[9] is a 1. + // e.g. 0xAE or 0XAF for swing move. + return ((remote_state[9] & kSamsungAcSwingMask) >> 4) == kSamsungAcSwingMove; +} + +void IRSamsungAc::setSwing(const bool state) { + // TODO(Hollako): Explain why sometimes the LSB of remote_state[9] is a 1. + // e.g. 0xAE or 0XAF for swing move. + remote_state[9] &= ~kSamsungAcSwingMask; // Clear the previous swing state. + if (state) + remote_state[9] |= (kSamsungAcSwingMove << 4); + else + remote_state[9] |= (kSamsungAcSwingStop << 4); +} + +bool IRSamsungAc::getBeep() { return remote_state[13] & kSamsungAcBeepMask; } + +void IRSamsungAc::setBeep(const bool state) { + if (state) + remote_state[13] |= kSamsungAcBeepMask; + else + remote_state[13] &= ~kSamsungAcBeepMask; +} + +bool IRSamsungAc::getClean() { + return (remote_state[10] & kSamsungAcCleanMask10) && + (remote_state[11] & kSamsungAcCleanMask11); +} + +void IRSamsungAc::setClean(const bool state) { + if (state) { + remote_state[10] |= kSamsungAcCleanMask10; + remote_state[11] |= kSamsungAcCleanMask11; + } else { + remote_state[10] &= ~kSamsungAcCleanMask10; + remote_state[11] &= ~kSamsungAcCleanMask11; + } +} + +// Very unsure this is correct. +bool IRSamsungAc::getQuiet() { + return remote_state[11] & kSamsungAcQuietMask11; +} + +// Very unsure this is correct. +void IRSamsungAc::setQuiet(const bool state) { + if (state) { + remote_state[11] |= kSamsungAcQuietMask11; + setFan(kSamsungAcFanAuto); // Quiet mode seems to set fan speed to auto. + } else { + remote_state[11] &= ~kSamsungAcQuietMask11; + } +} + +// Convert the internal state into a human readable string. +#ifdef ARDUINO +String IRSamsungAc::toString() { + String result = ""; +#else +std::string IRSamsungAc::toString() { + std::string result = ""; +#endif // ARDUINO + result += "Power: "; + if (getPower()) + result += "On"; + else + result += "Off"; + result += ", Mode: " + uint64ToString(getMode()); + switch (getMode()) { + case kSamsungAcAuto: + result += " (AUTO)"; + break; + case kSamsungAcCool: + result += " (COOL)"; + break; + case kSamsungAcHeat: + result += " (HEAT)"; + break; + case kSamsungAcDry: + result += " (DRY)"; + break; + case kSamsungAcFan: + result += " (FAN)"; + break; + default: + result += " (UNKNOWN)"; + } + result += ", Temp: " + uint64ToString(getTemp()) + "C"; + result += ", Fan: " + uint64ToString(getFan()); + switch (getFan()) { + case kSamsungAcFanAuto: + case kSamsungAcFanAuto2: + result += " (AUTO)"; + break; + case kSamsungAcFanLow: + result += " (LOW)"; + break; + case kSamsungAcFanMed: + result += " (MED)"; + break; + case kSamsungAcFanHigh: + result += " (HIGH)"; + break; + case kSamsungAcFanTurbo: + result += " (TURBO)"; + break; + default: + result += " (UNKNOWN)"; + break; + } + result += ", Swing: "; + if (getSwing()) + result += "On"; + else + result += "Off"; + result += ", Beep: "; + if (getBeep()) + result += "On"; + else + result += "Off"; + result += ", Clean: "; + if (getBeep()) + result += "On"; + else + result += "Off"; + result += ", Quiet: "; + if (getQuiet()) + result += "On"; + else + result += "Off"; + return result; +} + +#if DECODE_SAMSUNG_AC +// Decode the supplied Samsung A/C message. +// +// Args: +// results: Ptr to the data to decode and where to store the decode result. +// nbits: The number of data bits to expect. Typically kSamsungAcBits +// 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 mostly work. +// +// Ref: +// https://github.com/markszabo/IRremoteESP8266/issues/505 +bool IRrecv::decodeSamsungAC(decode_results *results, uint16_t nbits, + bool strict) { + if (results->rawlen < 2 * nbits + kHeader * 3 + kFooter * 2 - 1) + return false; // Can't possibly be a valid Samsung A/C message. + if (nbits != kSamsungAcBits && nbits != kSamsungAcExtendedBits) return false; + + uint16_t offset = kStartOffset; + uint16_t dataBitsSoFar = 0; + match_result_t data_result; + + // Message Header + if (!matchMark(results->rawbuf[offset++], kSamsungAcBitMark)) return false; + if (!matchSpace(results->rawbuf[offset++], kSamsungAcHdrSpace)) return false; + // Section(s) + for (uint16_t pos = kSamsungACSectionLength, i = 0; pos <= nbits / 8; + pos += kSamsungACSectionLength) { + uint64_t sectiondata = 0; + // Section Header + if (!matchMark(results->rawbuf[offset++], kSamsungAcSectionMark)) + return false; + if (!matchSpace(results->rawbuf[offset++], kSamsungAcSectionSpace)) + return false; + // Section Data + // Keep reading bytes until we either run out of section or state to fill. + for (; offset <= results->rawlen - 16 && i < pos; + i++, dataBitsSoFar += 8, offset += data_result.used) { + data_result = matchData(&(results->rawbuf[offset]), 8, kSamsungAcBitMark, + kSamsungAcOneSpace, kSamsungAcBitMark, + kSamsungAcZeroSpace, kTolerance, 0, false); + if (data_result.success == false) { + DPRINT("DEBUG: offset = "); + DPRINTLN(offset + data_result.used); + return false; // Fail + } + results->state[i] = data_result.data; + sectiondata = (sectiondata << 8) + data_result.data; + } + DPRINTLN("DEBUG: sectiondata = 0x" + uint64ToString(sectiondata, 16)); + // Section Footer + if (!matchMark(results->rawbuf[offset++], kSamsungAcBitMark)) return false; + if (pos < nbits / 8) { // Inter-section gap. + if (!matchSpace(results->rawbuf[offset++], kSamsungAcSectionGap)) + return false; + } else { // Last section / End of message gap. + if (offset <= results->rawlen && + !matchAtLeast(results->rawbuf[offset++], kSamsungAcSectionGap)) + return false; + } + } + // Compliance + // Re-check we got the correct size/length due to the way we read the data. + if (dataBitsSoFar != nbits) return false; + // Is the signature correct? + DPRINTLN("DEBUG: Checking signature."); + if (results->state[0] != 0x02 || results->state[2] != 0x0F) return false; + if (strict) { + // Is the checksum valid? + if (!IRSamsungAc::validChecksum(results->state, nbits / 8)) { + DPRINTLN("DEBUG: Checksum failed!"); + return false; + } + } + // Success + results->decode_type = SAMSUNG_AC; + results->bits = dataBitsSoFar; + // No need to record the state as we stored it as we decoded it. + // As we use result->state, we don't record value, address, or command as it + // is a union data type. + return true; +} +#endif // DECODE_SAMSUNG_AC diff --git a/lib/IRremoteESP8266/src/ir_Samsung.h b/lib/IRremoteESP8266/src/ir_Samsung.h new file mode 100644 index 0000000..e8bcc4c --- /dev/null +++ b/lib/IRremoteESP8266/src/ir_Samsung.h @@ -0,0 +1,109 @@ +// Samsung A/C +// +// Copyright 2018 David Conran + +#ifndef IR_SAMSUNG_H_ +#define IR_SAMSUNG_H_ + +#define __STDC_LIMIT_MACROS +#include +#ifndef UNIT_TEST +#include +#else +#include +#endif +#include "IRremoteESP8266.h" +#include "IRsend.h" + +// SSSS AAA MMM SSSS U U N N GGGG +// S A A M M M S U U NN N G +// SSS AAAAA M M M SSS U U N N N G GG +// S A A M M S U U N NN G G +// SSSS A A M M SSSS UUU N N GGG + +// Ref: +// https://github.com/markszabo/IRremoteESP8266/issues/505 + +// Constants +const uint8_t kSamsungAcAuto = 0; +const uint8_t kSamsungAcCool = 1; +const uint8_t kSamsungAcDry = 2; +const uint8_t kSamsungAcFan = 3; +const uint8_t kSamsungAcHeat = 4; +const uint8_t kSamsungAcModeMask = 0x70; +const uint8_t kSamsungAcFanAuto = 0; +const uint8_t kSamsungAcFanLow = 2; +const uint8_t kSamsungAcFanMed = 4; +const uint8_t kSamsungAcFanHigh = 5; +const uint8_t kSamsungAcFanAuto2 = 6; +const uint8_t kSamsungAcFanTurbo = 7; +const uint8_t kSamsungAcMinTemp = 16; // 16C +const uint8_t kSamsungAcMaxTemp = 30; // 30C +const uint8_t kSamsungAcAutoTemp = 25; // 25C +const uint8_t kSamsungAcTempMask = 0xF0; +const uint8_t kSamsungAcPowerMask1 = 0x20; +const uint8_t kSamsungAcPowerMask2 = 0x30; +const uint8_t kSamsungAcFanMask = 0x0E; +const uint8_t kSamsungAcSwingMask = 0x70; +const uint8_t kSamsungAcSwingMove = 0b010; +const uint8_t kSamsungAcSwingStop = 0b111; +const uint8_t kSamsungAcBeepMask = 0x02; +const uint8_t kSamsungAcCleanMask10 = 0x80; +const uint8_t kSamsungAcCleanMask11 = 0x02; +const uint8_t kSamsungAcQuietMask11 = 0x01; + +const uint16_t kSamsungACSectionLength = 7; +const uint64_t kSamsungAcPowerSection = 0x1D20F00000000; + +// Classes +class IRSamsungAc { + public: + explicit IRSamsungAc(uint16_t pin); + + void stateReset(); +#if SEND_SAMSUNG_AC + void send(const uint16_t repeat = kSamsungAcDefaultRepeat, + const bool calcchecksum = true); + void sendExtended(const uint16_t repeat = kSamsungAcDefaultRepeat, + const bool calcchecksum = true); +#endif // SEND_SAMSUNG_AC + void begin(); + void on(); + void off(); + void setPower(const bool state); + bool getPower(); + void setTemp(const uint8_t temp); + uint8_t getTemp(); + void setFan(const uint8_t speed); + uint8_t getFan(); + void setMode(const uint8_t mode); + uint8_t getMode(); + void setSwing(const bool state); + bool getSwing(); + void setBeep(const bool state); + bool getBeep(); + void setClean(const bool state); + bool getClean(); + void setQuiet(const bool state); + bool getQuiet(); + uint8_t* getRaw(); + void setRaw(const uint8_t new_code[], + const uint16_t length = kSamsungAcStateLength); + static bool validChecksum(const uint8_t state[], + const uint16_t length = kSamsungAcStateLength); + static uint8_t calcChecksum(const uint8_t state[], + const uint16_t length = kSamsungAcStateLength); +#ifdef ARDUINO + String toString(); +#else + std::string toString(); +#endif + + private: + // The state of the IR remote in IR code form. + uint8_t remote_state[kSamsungAcExtendedStateLength]; + void checksum(const uint16_t length = kSamsungAcStateLength); + IRsend _irsend; +}; + +#endif // IR_SAMSUNG_H_ diff --git a/lib/IRremoteESP8266/src/ir_Sanyo.cpp b/lib/IRremoteESP8266/src/ir_Sanyo.cpp index fc9d64f..b2b4d78 100644 --- a/lib/IRremoteESP8266/src/ir_Sanyo.cpp +++ b/lib/IRremoteESP8266/src/ir_Sanyo.cpp @@ -20,31 +20,35 @@ // Sanyo SA 8650B // Ref: // https://github.com/z3t0/Arduino-IRremote/blob/master/ir_Sanyo.cpp -#define SANYO_SA8650B_HDR_MARK 3500U // seen range 3500 -#define SANYO_SA8650B_HDR_SPACE 950U // seen 950 -#define SANYO_SA8650B_ONE_MARK 2400U // seen 2400 -#define SANYO_SA8650B_ZERO_MARK 700U // seen 700 + +const uint16_t kSanyoSa8650bHdrMark = 3500; // seen range 3500 +const uint16_t kSanyoSa8650bHdrSpace = 950; // seen 950 +const uint16_t kSanyoSa8650bOneMark = 2400; // seen 2400 +const uint16_t kSanyoSa8650bZeroMark = 700; // seen 700 // usually see 713 - not using ticks as get number wrapround -#define SANYO_SA8650B_DOUBLE_SPACE_USECS 800U -#define SANYO_SA8650B_RPT_LENGTH 45000U +const uint16_t kSanyoSa8650bDoubleSpaceUsecs = 800; +const uint16_t kSanyoSa8650bRptLength = 45000; // Sanyo LC7461 // Ref: // https://github.com/marcosamarinho/IRremoteESP8266/blob/master/ir_Sanyo.cpp // http://slydiman.narod.ru/scr/kb/sanyo.htm // http://pdf.datasheetcatalog.com/datasheet/sanyo/LC7461.pdf -#define SANYO_LC7461_ADDRESS_MASK ((1 << SANYO_LC7461_ADDRESS_BITS) - 1) -#define SANYO_LC7461_COMMAND_MASK ((1 << SANYO_LC7461_COMMAND_BITS) - 1) -#define SANYO_LC7461_HDR_MARK 9000U -#define SANYO_LC7461_HDR_SPACE 4500U -#define SANYO_LC7461_BIT_MARK 560U // 1T -#define SANYO_LC7461_ONE_SPACE 1690U // 3T -#define SANYO_LC7461_ZERO_SPACE 560U // 1T -#define SANYO_LC7461_MIN_COMMAND_LENGTH 108000UL -#define SANYO_LC7461_MIN_GAP SANYO_LC7461_MIN_COMMAND_LENGTH - \ - (SANYO_LC7461_HDR_MARK + SANYO_LC7461_HDR_SPACE + SANYO_LC7461_BITS * \ - (SANYO_LC7461_BIT_MARK + (SANYO_LC7461_ONE_SPACE + \ - SANYO_LC7461_ZERO_SPACE) / 2) \ - + SANYO_LC7461_BIT_MARK) + +const uint16_t kSanyoLc7461AddressMask = (1 << kSanyoLC7461AddressBits) - 1; +const uint16_t kSanyoLc7461CommandMask = (1 << kSanyoLC7461CommandBits) - 1; +const uint16_t kSanyoLc7461HdrMark = 9000; +const uint16_t kSanyoLc7461HdrSpace = 4500; +const uint16_t kSanyoLc7461BitMark = 560; // 1T +const uint16_t kSanyoLc7461OneSpace = 1690; // 3T +const uint16_t kSanyoLc7461ZeroSpace = 560; // 1T +const uint32_t kSanyoLc7461MinCommandLength = 108000; + +const uint16_t kSanyoLc7461MinGap = + kSanyoLc7461MinCommandLength - + (kSanyoLc7461HdrMark + kSanyoLc7461HdrSpace + + kSanyoLC7461Bits * (kSanyoLc7461BitMark + + (kSanyoLc7461OneSpace + kSanyoLc7461ZeroSpace) / 2) + + kSanyoLc7461BitMark); #if SEND_SANYO // Construct a Sanyo LC7461 message. @@ -61,18 +65,18 @@ // According with LIRC, this protocol is used on Sanyo, Aiwa and Chinon uint64_t IRsend::encodeSanyoLC7461(uint16_t address, uint8_t command) { // Mask our input values to ensure the correct bit sizes. - address &= SANYO_LC7461_ADDRESS_MASK; - command &= SANYO_LC7461_COMMAND_MASK; + address &= kSanyoLc7461AddressMask; + command &= kSanyoLc7461CommandMask; uint64_t data = address; - address ^= SANYO_LC7461_ADDRESS_MASK; // Invert the 13 LSBs. + address ^= kSanyoLc7461AddressMask; // Invert the 13 LSBs. // Append the now inverted address. - data = (data << SANYO_LC7461_ADDRESS_BITS) | address; + data = (data << kSanyoLC7461AddressBits) | address; // Append the command. - data = (data << SANYO_LC7461_COMMAND_BITS) | command; - command ^= SANYO_LC7461_COMMAND_MASK; // Invert the command. + data = (data << kSanyoLC7461CommandBits) | command; + command ^= kSanyoLc7461CommandMask; // Invert the command. // Append the now inverted command. - data = (data << SANYO_LC7461_COMMAND_BITS) | command; + data = (data << kSanyoLC7461CommandBits) | command; return data; } @@ -127,31 +131,30 @@ void IRsend::sendSanyoLC7461(uint64_t data, uint16_t nbits, uint16_t repeat) { // http://pdf.datasheetcatalog.com/datasheet/sanyo/LC7461.pdf bool IRrecv::decodeSanyoLC7461(decode_results *results, uint16_t nbits, bool strict) { - if (strict && nbits != SANYO_LC7461_BITS) + if (strict && nbits != kSanyoLC7461Bits) return false; // Not strictly in spec. // This protocol is basically a 42-bit variant of the NEC protocol. if (!decodeNEC(results, nbits, false)) return false; // Didn't match a NEC format (without strict) // Bits 30 to 42+. - uint16_t address = results->value >> (SANYO_LC7461_BITS - - SANYO_LC7461_ADDRESS_BITS); + uint16_t address = + results->value >> (kSanyoLC7461Bits - kSanyoLC7461AddressBits); // Bits 9 to 16. - uint8_t command = (results->value >> SANYO_LC7461_COMMAND_BITS) & - SANYO_LC7461_COMMAND_MASK; + uint8_t command = + (results->value >> kSanyoLC7461CommandBits) & kSanyoLc7461CommandMask; // Compliance if (strict) { - if (results->bits != nbits) - return false; + if (results->bits != nbits) return false; // Bits 17 to 29. uint16_t inverted_address = - (results->value >> (SANYO_LC7461_COMMAND_BITS * 2)) & - SANYO_LC7461_ADDRESS_MASK; + (results->value >> (kSanyoLC7461CommandBits * 2)) & + kSanyoLc7461AddressMask; // Bits 1-8. - uint8_t inverted_command = results->value & SANYO_LC7461_COMMAND_MASK; - if ((address ^ SANYO_LC7461_ADDRESS_MASK) != inverted_address) + uint8_t inverted_command = results->value & kSanyoLc7461CommandMask; + if ((address ^ kSanyoLc7461AddressMask) != inverted_address) return false; // Address integrity check failed. - if ((command ^ SANYO_LC7461_COMMAND_MASK) != inverted_command) + if ((command ^ kSanyoLc7461CommandMask) != inverted_command) return false; // Command integrity check failed. } @@ -182,9 +185,9 @@ bool IRrecv::decodeSanyoLC7461(decode_results *results, uint16_t nbits, // Ref: // https://github.com/z3t0/Arduino-IRremote/blob/master/ir_Sanyo.cpp bool IRrecv::decodeSanyo(decode_results *results, uint16_t nbits, bool strict) { - if (results->rawlen < 2 * nbits + HEADER - 1) + if (results->rawlen < 2 * nbits + kHeader - 1) return false; // Shorter than shortest possible. - if (strict && nbits != SANYO_SA8650B_BITS) + if (strict && nbits != kSanyoSA8650BBits) return false; // Doesn't match the spec. uint16_t offset = 0; @@ -192,9 +195,9 @@ bool IRrecv::decodeSanyo(decode_results *results, uint16_t nbits, bool strict) { // TODO(crankyoldgit): This repeat code looks like garbage, it should never // match or if it does, it won't be reliable. We should probably just // remove it. - if (results->rawbuf[offset++] < SANYO_SA8650B_DOUBLE_SPACE_USECS) { + if (results->rawbuf[offset++] < kSanyoSa8650bDoubleSpaceUsecs) { results->bits = 0; - results->value = REPEAT; + results->value = kRepeat; results->decode_type = SANYO; results->address = 0; results->command = 0; @@ -203,27 +206,27 @@ bool IRrecv::decodeSanyo(decode_results *results, uint16_t nbits, bool strict) { } // Header - if (!matchMark(results->rawbuf[offset++], SANYO_SA8650B_HDR_MARK)) + if (!matchMark(results->rawbuf[offset++], kSanyoSa8650bHdrMark)) return false; // NOTE: These next two lines look very wrong. Treat as suspect. - if (!matchMark(results->rawbuf[offset++], SANYO_SA8650B_HDR_MARK)) + if (!matchMark(results->rawbuf[offset++], kSanyoSa8650bHdrMark)) return false; // Data uint64_t data = 0; while (offset + 1 < results->rawlen) { - if (!matchSpace(results->rawbuf[offset], SANYO_SA8650B_HDR_SPACE)) + if (!matchSpace(results->rawbuf[offset], kSanyoSa8650bHdrSpace)) break; offset++; - if (matchMark(results->rawbuf[offset], SANYO_SA8650B_ONE_MARK)) + if (matchMark(results->rawbuf[offset], kSanyoSa8650bOneMark)) data = (data << 1) | 1; // 1 - else if (matchMark(results->rawbuf[offset], SANYO_SA8650B_ZERO_MARK)) + else if (matchMark(results->rawbuf[offset], kSanyoSa8650bZeroMark)) data <<= 1; // 0 else return false; offset++; } - if (strict && SANYO_SA8650B_BITS > (offset - 1U) / 2U) + if (strict && kSanyoSA8650BBits > (offset - 1U) / 2U) return false; // Success diff --git a/lib/IRremoteESP8266/src/ir_Sharp.cpp b/lib/IRremoteESP8266/src/ir_Sharp.cpp index 982838d..ae1b59c 100644 --- a/lib/IRremoteESP8266/src/ir_Sharp.cpp +++ b/lib/IRremoteESP8266/src/ir_Sharp.cpp @@ -22,27 +22,27 @@ // Ref: // GlobalCache's IR Control Tower data. // http://www.sbprojects.com/knowledge/ir/sharp.php -#define SHARP_TICK 26U -#define SHARP_BIT_MARK_TICKS 10U -#define SHARP_BIT_MARK (SHARP_BIT_MARK_TICKS * SHARP_TICK) -#define SHARP_ONE_SPACE_TICKS 70U -#define SHARP_ONE_SPACE (SHARP_ONE_SPACE_TICKS * SHARP_TICK) -#define SHARP_ZERO_SPACE_TICKS 30U -#define SHARP_ZERO_SPACE (SHARP_ZERO_SPACE_TICKS * SHARP_TICK) -#define SHARP_GAP_TICKS 1677U -#define SHARP_GAP (SHARP_GAP_TICKS * SHARP_TICK) - +const uint16_t kSharpTick = 26; +const uint16_t kSharpBitMarkTicks = 10; +const uint16_t kSharpBitMark = kSharpBitMarkTicks * kSharpTick; +const uint16_t kSharpOneSpaceTicks = 70; +const uint16_t kSharpOneSpace = kSharpOneSpaceTicks * kSharpTick; +const uint16_t kSharpZeroSpaceTicks = 30; +const uint16_t kSharpZeroSpace = kSharpZeroSpaceTicks * kSharpTick; +const uint16_t kSharpGapTicks = 1677; +const uint16_t kSharpGap = kSharpGapTicks * kSharpTick; // Address(5) + Command(8) + Expansion(1) + Check(1) -#define SHARP_TOGGLE_MASK ((1 << (SHARP_BITS - SHARP_ADDRESS_BITS)) - 1) -#define SHARP_ADDRESS_MASK ((1 << SHARP_ADDRESS_BITS) - 1) -#define SHARP_COMMAND_MASK ((1 << SHARP_COMMAND_BITS) - 1) +const uint64_t kSharpToggleMask = + ((uint64_t)1 << (kSharpBits - kSharpAddressBits)) - 1; +const uint64_t kSharpAddressMask = ((uint64_t)1 << kSharpAddressBits) - 1; +const uint64_t kSharpCommandMask = ((uint64_t)1 << kSharpCommandBits) - 1; #if (SEND_SHARP || SEND_DENON) // Send a (raw) Sharp message // // Args: // data: Contents of the message to be sent. -// nbits: Nr. of bits of data to be sent. Typically SHARP_BITS. +// nbits: Nr. of bits of data to be sent. Typically kSharpBits. // repeat: Nr. of additional times the message is to be sent. // // Status: BETA / Previously working fine. @@ -67,14 +67,13 @@ void IRsend::sendSharpRaw(uint64_t data, uint16_t nbits, uint16_t repeat) { // normal), however all data points to that being incorrect. for (uint8_t n = 0; n < 2; n++) { sendGeneric(0, 0, // No Header - SHARP_BIT_MARK, SHARP_ONE_SPACE, - SHARP_BIT_MARK, SHARP_ZERO_SPACE, - SHARP_BIT_MARK, SHARP_GAP, - data, nbits, 38, true, 0, // Repeats are handled already. + kSharpBitMark, kSharpOneSpace, kSharpBitMark, kSharpZeroSpace, + kSharpBitMark, kSharpGap, data, nbits, 38, true, + 0, // Repeats are handled already. 33); // Invert the data per protocol. This is always called twice, so it's // retured to original upon exiting the inner loop. - data ^= SHARP_TOGGLE_MASK; + data ^= kSharpToggleMask; } } } @@ -107,17 +106,17 @@ uint32_t IRsend::encodeSharp(uint16_t address, uint16_t command, uint16_t expansion, uint16_t check, bool MSBfirst) { // Mask any unexpected bits. - address &= ((1 << SHARP_ADDRESS_BITS) - 1); - command &= ((1 << SHARP_COMMAND_BITS) - 1); + address &= ((1 << kSharpAddressBits) - 1); + command &= ((1 << kSharpCommandBits) - 1); expansion &= 1; check &= 1; if (!MSBfirst) { // Correct bit order if needed. - address = reverseBits(address, SHARP_ADDRESS_BITS); - command = reverseBits(command, SHARP_COMMAND_BITS); + address = reverseBits(address, kSharpAddressBits); + command = reverseBits(command, kSharpCommandBits); } // Concatinate all the bits. - return (address << (SHARP_COMMAND_BITS + 2)) | (command << 2) | + return (address << (kSharpCommandBits + 2)) | (command << 2) | (expansion << 1) | check; } @@ -126,7 +125,7 @@ uint32_t IRsend::encodeSharp(uint16_t address, uint16_t command, // Args: // address: Address value to be sent. // command: Command value to be sent. -// nbits: Nr. of bits of data to be sent. Typically SHARP_BITS. +// nbits: Nr. of bits of data to be sent. Typically kSharpBits. // repeat: Nr. of additional times the message is to be sent. // // Status: DEPRICATED / Previously working fine. @@ -156,7 +155,7 @@ void IRsend::sendSharp(uint16_t address, uint16_t command, uint16_t nbits, // // Args: // results: Ptr to the data to decode and where to store the decode result. -// nbits: Nr. of data bits to expect. Typically SHARP_BITS. +// nbits: Nr. of data bits to expect. Typically kSharpBits. // strict: Flag indicating if we should perform strict matching. // expansion: Should we expect the expansion bit to be set. Default is true. // Returns: @@ -175,90 +174,83 @@ void IRsend::sendSharp(uint16_t address, uint16_t command, uint16_t nbits, // http://www.hifi-remote.com/johnsfine/DecodeIR.html#Sharp bool IRrecv::decodeSharp(decode_results *results, uint16_t nbits, bool strict, bool expansion) { - if (results->rawlen < 2 * nbits + FOOTER - 1) + if (results->rawlen < 2 * nbits + kFooter - 1) return false; // Not enough entries to be a Sharp message. // Compliance if (strict) { - if (nbits != SHARP_BITS) - return false; // Request is out of spec. + if (nbits != kSharpBits) return false; // Request is out of spec. // DISABLED - See TODO #ifdef UNIT_TEST // An in spec message has the data sent normally, then inverted. So we // expect twice as many entries than to just get the results. - if (results->rawlen < 2 * (2 * nbits + FOOTER)) - return false; + if (results->rawlen < 2 * (2 * nbits + kFooter)) return false; #endif } uint64_t data = 0; - uint16_t offset = OFFSET_START; + uint16_t offset = kStartOffset; // No header // But try to auto-calibrate off the initial mark signal. - if (!matchMark(results->rawbuf[offset], SHARP_BIT_MARK, 35)) return false; + if (!matchMark(results->rawbuf[offset], kSharpBitMark, 35)) return false; // Calculate how long the common tick time is based on the header mark. - uint32_t tick = results->rawbuf[offset] * RAWTICK / SHARP_BIT_MARK_TICKS; + uint32_t tick = results->rawbuf[offset] * kRawTick / kSharpBitMarkTicks; // Data for (uint16_t i = 0; i < nbits; i++, offset++) { - // Use a higher tolerance value for SHARP_BIT_MARK as it is quite small. - if (!matchMark(results->rawbuf[offset++], SHARP_BIT_MARK_TICKS * tick, 35)) + // Use a higher tolerance value for kSharpBitMark as it is quite small. + if (!matchMark(results->rawbuf[offset++], kSharpBitMarkTicks * tick, 35)) return false; - if (matchSpace(results->rawbuf[offset], SHARP_ONE_SPACE_TICKS * tick)) + if (matchSpace(results->rawbuf[offset], kSharpOneSpaceTicks * tick)) data = (data << 1) | 1; // 1 - else if (matchSpace(results->rawbuf[offset], SHARP_ZERO_SPACE_TICKS * tick)) + else if (matchSpace(results->rawbuf[offset], kSharpZeroSpaceTicks * tick)) data <<= 1; // 0 else return false; } // Footer - if (!match(results->rawbuf[offset++], SHARP_BIT_MARK_TICKS * tick)) + if (!match(results->rawbuf[offset++], kSharpBitMarkTicks * tick)) return false; if (offset < results->rawlen && - !matchAtLeast(results->rawbuf[offset], SHARP_GAP_TICKS * tick)) + !matchAtLeast(results->rawbuf[offset], kSharpGapTicks * tick)) return false; // Compliance if (strict) { // Check the state of the expansion bit is what we expect. - if ((data & 0b10) >> 1 != expansion) - return false; + if ((data & 0b10) >> 1 != expansion) return false; // The check bit should be cleared in a normal message. - if (data & 0b1) - return false; - // DISABLED - See TODO + if (data & 0b1) return false; + // DISABLED - See TODO #ifdef UNIT_TEST // Grab the second copy of the data (i.e. inverted) // Header // i.e. The inter-data/command repeat gap. - if (!matchSpace(results->rawbuf[offset++], SHARP_GAP_TICKS * tick)) + if (!matchSpace(results->rawbuf[offset++], kSharpGapTicks * tick)) return false; // Data uint64_t second_data = 0; for (uint16_t i = 0; i < nbits; i++, offset++) { - // Use a higher tolerance value for SHARP_BIT_MARK as it is quite small. - if (!matchMark(results->rawbuf[offset++], SHARP_BIT_MARK_TICKS * tick, - 35)) + // Use a higher tolerance value for kSharpBitMark as it is quite small. + if (!matchMark(results->rawbuf[offset++], kSharpBitMarkTicks * tick, 35)) return false; - if (matchSpace(results->rawbuf[offset], SHARP_ONE_SPACE_TICKS * tick)) + if (matchSpace(results->rawbuf[offset], kSharpOneSpaceTicks * tick)) second_data = (second_data << 1) | 1; // 1 - else if (matchSpace(results->rawbuf[offset], - SHARP_ZERO_SPACE_TICKS * tick)) + else if (matchSpace(results->rawbuf[offset], kSharpZeroSpaceTicks * tick)) second_data <<= 1; // 0 else return false; } // Footer - if (!match(results->rawbuf[offset++], SHARP_BIT_MARK_TICKS * tick)) + if (!match(results->rawbuf[offset++], kSharpBitMarkTicks * tick)) return false; if (offset < results->rawlen && - !matchAtLeast(results->rawbuf[offset], SHARP_GAP_TICKS * tick)) + !matchAtLeast(results->rawbuf[offset], kSharpGapTicks * tick)) return false; // Check that second_data has been inverted correctly. - if (data != (second_data ^ SHARP_TOGGLE_MASK)) - return false; + if (data != (second_data ^ kSharpToggleMask)) return false; #endif // UNIT_TEST } @@ -267,9 +259,9 @@ bool IRrecv::decodeSharp(decode_results *results, uint16_t nbits, bool strict, results->bits = nbits; results->value = data; // Address & command are actually transmitted in LSB first order. - results->address = reverseBits(data, nbits) & SHARP_ADDRESS_MASK; - results->command = reverseBits((data >> 2) & SHARP_COMMAND_MASK, - SHARP_COMMAND_BITS); + results->address = reverseBits(data, nbits) & kSharpAddressMask; + results->command = + reverseBits((data >> 2) & kSharpCommandMask, kSharpCommandBits); return true; } #endif // (DECODE_SHARP || DECODE_DENON) diff --git a/lib/IRremoteESP8266/src/ir_Sherwood.cpp b/lib/IRremoteESP8266/src/ir_Sherwood.cpp index 97e7506..8af7dfb 100644 --- a/lib/IRremoteESP8266/src/ir_Sherwood.cpp +++ b/lib/IRremoteESP8266/src/ir_Sherwood.cpp @@ -14,16 +14,15 @@ // // Args: // data: The contents of the command you want to send. -// nbits: The bit size of the command being sent. (SHERWOOD_BITS) +// nbits: The bit size of the command being sent. (kSherwoodBits) // repeat: The nr. of times you want the command to be repeated. (Default: 1) // // Status: STABLE / Known working. // // Note: // Sherwood remote codes appear to be NEC codes with a manditory repeat code. -// i.e. repeat should be >= SHERWOOD_MIN_REPEAT (1). -void IRsend::sendSherwood(uint64_t data, uint16_t nbits, - uint16_t repeat) { - sendNEC(data, nbits, std::max((uint16_t) SHERWOOD_MIN_REPEAT, repeat)); +// i.e. repeat should be >= kSherwoodMinRepeat (1). +void IRsend::sendSherwood(uint64_t data, uint16_t nbits, uint16_t repeat) { + sendNEC(data, nbits, std::max((uint16_t)kSherwoodMinRepeat, repeat)); } #endif diff --git a/lib/IRremoteESP8266/src/ir_Sony.cpp b/lib/IRremoteESP8266/src/ir_Sony.cpp index 132c18a..efa6e6a 100644 --- a/lib/IRremoteESP8266/src/ir_Sony.cpp +++ b/lib/IRremoteESP8266/src/ir_Sony.cpp @@ -19,19 +19,19 @@ // Constants // Ref: // http://www.sbprojects.com/knowledge/ir/sirc.php -#define SONY_TICK 200U -#define SONY_HDR_MARK_TICKS 12U -#define SONY_HDR_MARK (SONY_HDR_MARK_TICKS * SONY_TICK) -#define SONY_SPACE_TICKS 3U -#define SONY_SPACE (SONY_SPACE_TICKS * SONY_TICK) -#define SONY_ONE_MARK_TICKS 6U -#define SONY_ONE_MARK (SONY_ONE_MARK_TICKS * SONY_TICK) -#define SONY_ZERO_MARK_TICKS 3U -#define SONY_ZERO_MARK (SONY_ZERO_MARK_TICKS * SONY_TICK) -#define SONY_RPT_LENGTH_TICKS 225U -#define SONY_RPT_LENGTH (SONY_RPT_LENGTH_TICKS * SONY_TICK) -#define SONY_MIN_GAP_TICKS 50U -#define SONY_MIN_GAP (SONY_MIN_GAP_TICKS * SONY_TICK) +const uint16_t kSonyTick = 200; +const uint16_t kSonyHdrMarkTicks = 12; +const uint16_t kSonyHdrMark = kSonyHdrMarkTicks * kSonyTick; +const uint16_t kSonySpaceTicks = 3; +const uint16_t kSonySpace = kSonySpaceTicks * kSonyTick; +const uint16_t kSonyOneMarkTicks = 6; +const uint16_t kSonyOneMark = kSonyOneMarkTicks * kSonyTick; +const uint16_t kSonyZeroMarkTicks = 3; +const uint16_t kSonyZeroMark = kSonyZeroMarkTicks * kSonyTick; +const uint16_t kSonyRptLengthTicks = 225; +const uint16_t kSonyRptLength = kSonyRptLengthTicks * kSonyTick; +const uint16_t kSonyMinGapTicks = 50; +const uint16_t kSonyMinGap = kSonyMinGapTicks * kSonyTick; #if SEND_SONY // Send a Sony/SIRC(Serial Infra-Red Control) message. @@ -50,12 +50,10 @@ // Ref: // http://www.sbprojects.com/knowledge/ir/sirc.php void IRsend::sendSony(uint64_t data, uint16_t nbits, uint16_t repeat) { - sendGeneric(SONY_HDR_MARK, SONY_SPACE, - SONY_ONE_MARK, SONY_SPACE, - SONY_ZERO_MARK, SONY_SPACE, + sendGeneric(kSonyHdrMark, kSonySpace, kSonyOneMark, kSonySpace, kSonyZeroMark, + kSonySpace, 0, // No Footer mark. - SONY_MIN_GAP, SONY_RPT_LENGTH, - data, nbits, 40, true, repeat, 33); + kSonyMinGap, kSonyRptLength, data, nbits, 40, true, repeat, 33); } // Convert Sony/SIRC command, address, & extended bits into sendSony format. @@ -68,8 +66,8 @@ void IRsend::sendSony(uint64_t data, uint16_t nbits, uint16_t repeat) { // A sendSony compatible data message. // // Status: BETA / Should be working. -uint32_t IRsend::encodeSony(uint16_t nbits, uint16_t command, - uint16_t address, uint16_t extended) { +uint32_t IRsend::encodeSony(uint16_t nbits, uint16_t command, uint16_t address, + uint16_t extended) { uint32_t result = 0; switch (nbits) { case 12: // 5 address bits. @@ -107,7 +105,7 @@ uint32_t IRsend::encodeSony(uint16_t nbits, uint16_t command, // Ref: // http://www.sbprojects.com/knowledge/ir/sirc.php bool IRrecv::decodeSony(decode_results *results, uint16_t nbits, bool strict) { - if (results->rawlen < 2 * nbits + HEADER - 1) + if (results->rawlen < 2 * nbits + kHeader - 1) return false; // Message is smaller than we expected. // Compliance @@ -123,31 +121,30 @@ bool IRrecv::decodeSony(decode_results *results, uint16_t nbits, bool strict) { } uint64_t data = 0; - uint16_t offset = OFFSET_START; + uint16_t offset = kStartOffset; uint16_t actualBits; uint32_t timeSoFar = 0; // Time in uSecs of the message length. // Header - timeSoFar += results->rawbuf[offset] * RAWTICK; - if (!matchMark(results->rawbuf[offset], SONY_HDR_MARK)) - return false; + timeSoFar += results->rawbuf[offset] * kRawTick; + if (!matchMark(results->rawbuf[offset], kSonyHdrMark)) return false; // Calculate how long the common tick time is based on the header mark. - uint32_t tick = results->rawbuf[offset++] * RAWTICK / SONY_HDR_MARK_TICKS; + uint32_t tick = results->rawbuf[offset++] * kRawTick / kSonyHdrMarkTicks; // Data for (actualBits = 0; offset < results->rawlen - 1; actualBits++, offset++) { - // The gap after a Sony packet for a repeat should be SONY_MIN_GAP or - // (SONY_RPT_LENGTH - timeSoFar) according to the spec. - if (matchSpace(results->rawbuf[offset], SONY_MIN_GAP_TICKS * tick) || - matchAtLeast(results->rawbuf[offset], SONY_RPT_LENGTH - timeSoFar)) + // The gap after a Sony packet for a repeat should be kSonyMinGap or + // (kSonyRptLength - timeSoFar) according to the spec. + if (matchSpace(results->rawbuf[offset], kSonyMinGapTicks * tick) || + matchAtLeast(results->rawbuf[offset], kSonyRptLength - timeSoFar)) break; // Found a repeat space. - timeSoFar += results->rawbuf[offset] * RAWTICK; - if (!matchSpace(results->rawbuf[offset++], SONY_SPACE_TICKS * tick)) + timeSoFar += results->rawbuf[offset] * kRawTick; + if (!matchSpace(results->rawbuf[offset++], kSonySpaceTicks * tick)) return false; - timeSoFar += results->rawbuf[offset] * RAWTICK; - if (matchMark(results->rawbuf[offset], SONY_ONE_MARK_TICKS * tick)) + timeSoFar += results->rawbuf[offset] * kRawTick; + if (matchMark(results->rawbuf[offset], kSonyOneMarkTicks * tick)) data = (data << 1) | 1; - else if (matchMark(results->rawbuf[offset], SONY_ZERO_MARK_TICKS * tick)) + else if (matchMark(results->rawbuf[offset], kSonyZeroMarkTicks * tick)) data <<= 1; else return false; @@ -166,14 +163,14 @@ bool IRrecv::decodeSony(decode_results *results, uint16_t nbits, bool strict) { data = reverseBits(data, actualBits); // Decode the address & command from raw decode value. switch (actualBits) { - case 12: // 7 command bits, 5 address bits. - case 15: // 7 command bits, 8 address bits. + case 12: // 7 command bits, 5 address bits. + case 15: // 7 command bits, 8 address bits. results->command = data & 0x7F; // Bits 0-6 - results->address = data >> 7; // Bits 7-14 + results->address = data >> 7; // Bits 7-14 break; case 20: // 7 command bits, 5 address bits, 8 extended (command) bits. results->command = (data & 0x7F) + ((data >> 12) << 7); // Bits 0-6,12-19 - results->address = (data >> 7) & 0x1F; // Bits 7-11 + results->address = (data >> 7) & 0x1F; // Bits 7-11 break; default: // Shouldn't happen, but just in case. results->address = 0; diff --git a/lib/IRremoteESP8266/src/ir_Toshiba.cpp b/lib/IRremoteESP8266/src/ir_Toshiba.cpp index bea29ce..467745e 100644 --- a/lib/IRremoteESP8266/src/ir_Toshiba.cpp +++ b/lib/IRremoteESP8266/src/ir_Toshiba.cpp @@ -28,33 +28,32 @@ // Toshiba A/C // Ref: // https://github.com/r45635/HVAC-IR-Control/blob/master/HVAC_ESP8266/HVAC_ESP8266T.ino#L77 -#define TOSHIBA_AC_HDR_MARK 4400U -#define TOSHIBA_AC_HDR_SPACE 4300U -#define TOSHIBA_AC_BIT_MARK 543U -#define TOSHIBA_AC_ONE_SPACE 1623U -#define TOSHIBA_AC_ZERO_SPACE 472U -#define TOSHIBA_AC_MIN_GAP 7048U +const uint16_t kToshibaAcHdrMark = 4400; +const uint16_t kToshibaAcHdrSpace = 4300; +const uint16_t kToshibaAcBitMark = 543; +const uint16_t kToshibaAcOneSpace = 1623; +const uint16_t kToshibaAcZeroSpace = 472; +const uint16_t kToshibaAcMinGap = 7048; #if SEND_TOSHIBA_AC // Send a Toshiba A/C message. // // Args: // data: An array of bytes containing the IR command. -// nbytes: Nr. of bytes of data in the array. (>=TOSHIBA_AC_STATE_LENGTH) +// nbytes: Nr. of bytes of data in the array. (>=kToshibaACStateLength) // repeat: Nr. of times the message is to be repeated. -// (Default = TOSHIBA_AC_MIN_REPEAT). +// (Default = kToshibaACMinRepeat). // // Status: StABLE / Working. // void IRsend::sendToshibaAC(unsigned char data[], uint16_t nbytes, - uint16_t repeat) { - if (nbytes < TOSHIBA_AC_STATE_LENGTH) + uint16_t repeat) { + if (nbytes < kToshibaACStateLength) return; // Not enough bytes to send a proper message. - sendGeneric(TOSHIBA_AC_HDR_MARK, TOSHIBA_AC_HDR_SPACE, - TOSHIBA_AC_BIT_MARK, TOSHIBA_AC_ONE_SPACE, - TOSHIBA_AC_BIT_MARK, TOSHIBA_AC_ZERO_SPACE, - TOSHIBA_AC_BIT_MARK, TOSHIBA_AC_MIN_GAP, - data, nbytes, 38, true, repeat, 50); + sendGeneric(kToshibaAcHdrMark, kToshibaAcHdrSpace, kToshibaAcBitMark, + kToshibaAcOneSpace, kToshibaAcBitMark, kToshibaAcZeroSpace, + kToshibaAcBitMark, kToshibaAcMinGap, data, nbytes, 38, true, + repeat, 50); } #endif // SEND_TOSHIBA_AC @@ -65,9 +64,7 @@ void IRsend::sendToshibaAC(unsigned char data[], uint16_t nbytes, // Status: STABLE / Working. // // Initialise the object. -IRToshibaAC::IRToshibaAC(uint16_t pin) : _irsend(pin) { - stateReset(); -} +IRToshibaAC::IRToshibaAC(uint16_t pin) : _irsend(pin) { stateReset(); } // Reset the state of the remote to a known good state/sequence. void IRToshibaAC::stateReset() { @@ -75,29 +72,26 @@ void IRToshibaAC::stateReset() { // Known good state obtained from: // https://github.com/r45635/HVAC-IR-Control/blob/master/HVAC_ESP8266/HVAC_ESP8266T.ino#L103 // Note: Can't use the following because it requires -std=c++11 - // uint8_t remote_state[TOSHIBA_AC_STATE_LENGTH] = { + // uint8_t remote_state[kToshibaACStateLength] = { // 0xF2, 0x0D, 0x03, 0xFC, 0x01, 0x00, 0x00, 0x00, 0x00 }; remote_state[0] = 0xF2; remote_state[1] = 0x0D; remote_state[2] = 0x03; remote_state[3] = 0xFC; remote_state[4] = 0x01; - for (uint8_t i = 5; i < TOSHIBA_AC_STATE_LENGTH; i++) - remote_state[i] = 0; + for (uint8_t i = 5; i < kToshibaACStateLength; i++) remote_state[i] = 0; mode_state = remote_state[6] & 0b00000011; checksum(); // Calculate the checksum } // Configure the pin for output. -void IRToshibaAC::begin() { - _irsend.begin(); -} +void IRToshibaAC::begin() { _irsend.begin(); } #if SEND_TOSHIBA_AC // Send the current desired state to the IR LED. -void IRToshibaAC::send() { - checksum(); // Ensure correct checksum before sending. - _irsend.sendToshibaAC(remote_state); +void IRToshibaAC::send(const uint16_t repeat) { + checksum(); // Ensure correct checksum before sending. + _irsend.sendToshibaAC(remote_state, kToshibaACStateLength, repeat); } #endif // SEND_TOSHIBA_AC @@ -109,7 +103,7 @@ uint8_t* IRToshibaAC::getRaw() { // Override the internal state with the new state. void IRToshibaAC::setRaw(uint8_t newState[]) { - for (uint8_t i = 0; i < TOSHIBA_AC_STATE_LENGTH; i++) { + for (uint8_t i = 0; i < kToshibaACStateLength; i++) { remote_state[i] = newState[i]; } mode_state = getMode(true); @@ -127,8 +121,7 @@ uint8_t IRToshibaAC::calcChecksum(const uint8_t state[], // Only calculate it for valid lengths. if (length > 1) { // Checksum is simple XOR of all bytes except the last one. - for (uint8_t i = 0; i < length - 1; i++) - checksum ^= state[i]; + for (uint8_t i = 0; i < length - 1; i++) checksum ^= state[i]; } return checksum; } @@ -139,29 +132,27 @@ uint8_t IRToshibaAC::calcChecksum(const uint8_t state[], // length: The size of the state. // Returns: // A boolean. -bool IRToshibaAC::validChecksum(const uint8_t state[], - const uint16_t length) { +bool IRToshibaAC::validChecksum(const uint8_t state[], const uint16_t length) { return (length > 1 && state[length - 1] == calcChecksum(state, length)); } // Calculate & set the checksum for the current internal state of the remote. void IRToshibaAC::checksum(const uint16_t length) { // Stored the checksum value in the last byte. - if (length > 1) - remote_state[length - 1] = calcChecksum(remote_state, length); + if (length > 1) remote_state[length - 1] = calcChecksum(remote_state, length); } // Set the requested power state of the A/C to off. void IRToshibaAC::on() { // state = ON; - remote_state[6] &= ~TOSHIBA_AC_POWER; + remote_state[6] &= ~kToshibaAcPower; setMode(mode_state); } // Set the requested power state of the A/C to off. void IRToshibaAC::off() { // state = OFF; - remote_state[6] |= (TOSHIBA_AC_POWER | 0b00000011); + remote_state[6] |= (kToshibaAcPower | 0b00000011); } // Set the requested power state of the A/C. @@ -174,28 +165,28 @@ void IRToshibaAC::setPower(bool state) { // Return the requested power state of the A/C. bool IRToshibaAC::getPower() { - return((remote_state[6] & TOSHIBA_AC_POWER) == 0); + return ((remote_state[6] & kToshibaAcPower) == 0); } // Set the temp. in deg C void IRToshibaAC::setTemp(uint8_t temp) { - temp = std::max((uint8_t) TOSHIBA_AC_MIN_TEMP, temp); - temp = std::min((uint8_t) TOSHIBA_AC_MAX_TEMP, temp); - remote_state[5] = (temp - TOSHIBA_AC_MIN_TEMP) << 4; + temp = std::max((uint8_t)kToshibaAcMinTemp, temp); + temp = std::min((uint8_t)kToshibaAcMaxTemp, temp); + remote_state[5] = (temp - kToshibaAcMinTemp) << 4; } // Return the set temp. in deg C uint8_t IRToshibaAC::getTemp() { - return((remote_state[5] >> 4) + TOSHIBA_AC_MIN_TEMP); + return ((remote_state[5] >> 4) + kToshibaAcMinTemp); } // Set the speed of the fan, 0-5. // 0 is auto, 1-5 is the speed, 5 is Max. void IRToshibaAC::setFan(uint8_t fan) { // Bounds check - if (fan > TOSHIBA_AC_FAN_MAX) - fan = TOSHIBA_AC_FAN_MAX; // Set the fan to maximum if out of range. - if (fan > TOSHIBA_AC_FAN_AUTO) fan++; + if (fan > kToshibaAcFanMax) + fan = kToshibaAcFanMax; // Set the fan to maximum if out of range. + if (fan > kToshibaAcFanAuto) fan++; remote_state[6] &= 0b00011111; // Clear the previous fan state remote_state[6] |= (fan << 5); } @@ -203,7 +194,7 @@ void IRToshibaAC::setFan(uint8_t fan) { // Return the requested state of the unit's fan. uint8_t IRToshibaAC::getFan() { uint8_t fan = remote_state[6] >> 5; - if (fan == TOSHIBA_AC_FAN_AUTO) return TOSHIBA_AC_FAN_AUTO; + if (fan == kToshibaAcFanAuto) return kToshibaAcFanAuto; return --fan; } @@ -223,11 +214,16 @@ uint8_t IRToshibaAC::getMode(bool useRaw) { void IRToshibaAC::setMode(uint8_t mode) { // If we get an unexpected mode, default to AUTO. switch (mode) { - case TOSHIBA_AC_AUTO: break; - case TOSHIBA_AC_COOL: break; - case TOSHIBA_AC_DRY: break; - case TOSHIBA_AC_HEAT: break; - default: mode = TOSHIBA_AC_AUTO; + case kToshibaAcAuto: + break; + case kToshibaAcCool: + break; + case kToshibaAcDry: + break; + case kToshibaAcHeat: + break; + default: + mode = kToshibaAcAuto; } mode_state = mode; // Only adjust the remote_state if we have power set to on. @@ -252,16 +248,16 @@ std::string IRToshibaAC::toString() { result += "Off"; result += ", Mode: " + uint64ToString(getMode()); switch (getMode()) { - case TOSHIBA_AC_AUTO: + case kToshibaAcAuto: result += " (AUTO)"; break; - case TOSHIBA_AC_COOL: + case kToshibaAcCool: result += " (COOL)"; break; - case TOSHIBA_AC_HEAT: + case kToshibaAcHeat: result += " (HEAT)"; break; - case TOSHIBA_AC_DRY: + case kToshibaAcDry: result += " (DRY)"; break; default: @@ -270,10 +266,10 @@ std::string IRToshibaAC::toString() { result += ", Temp: " + uint64ToString(getTemp()) + "C"; result += ", Fan: " + uint64ToString(getFan()); switch (getFan()) { - case TOSHIBA_AC_FAN_AUTO: + case kToshibaAcFanAuto: result += " (AUTO)"; break; - case TOSHIBA_AC_FAN_MAX: + case kToshibaAcFanMax: result += " (MAX)"; break; } @@ -285,7 +281,7 @@ std::string IRToshibaAC::toString() { // Places successful decode information in the results pointer. // Args: // results: Ptr to the data to decode and where to store the decode result. -// nbits: The number of data bits to expect. Typically TOSHIBA_AC_BITS. +// nbits: The number of data bits to expect. Typically kToshibaACBits. // strict: Flag to indicate if we strictly adhere to the specification. // Returns: // boolean: True if it can decode it, false if it can't. @@ -294,43 +290,38 @@ std::string IRToshibaAC::toString() { // // Ref: // -bool IRrecv::decodeToshibaAC(decode_results *results, uint16_t nbits, +bool IRrecv::decodeToshibaAC(decode_results* results, uint16_t nbits, bool strict) { - uint16_t offset = OFFSET_START; + uint16_t offset = kStartOffset; uint16_t dataBitsSoFar = 0; // Have we got enough data to successfully decode? - if (results->rawlen < TOSHIBA_AC_BITS + HEADER + FOOTER - 1) + if (results->rawlen < kToshibaACBits + kHeader + kFooter - 1) return false; // Can't possibly be a valid message. - // Compliance - if (strict && nbits != TOSHIBA_AC_BITS) + if (strict && nbits != kToshibaACBits) return false; // Must be called with the correct nr. of bytes. // Header - if (!matchMark(results->rawbuf[offset++], TOSHIBA_AC_HDR_MARK)) - return false; - if (!matchSpace(results->rawbuf[offset++], TOSHIBA_AC_HDR_SPACE)) - return false; + if (!matchMark(results->rawbuf[offset++], kToshibaAcHdrMark)) return false; + if (!matchSpace(results->rawbuf[offset++], kToshibaAcHdrSpace)) return false; // Data - for (uint8_t i = 0; i < TOSHIBA_AC_STATE_LENGTH; i++) { + for (uint8_t i = 0; i < kToshibaACStateLength; i++) { // Read a byte's worth of data. - match_result_t data_result = matchData(&(results->rawbuf[offset]), 8, - TOSHIBA_AC_BIT_MARK, - TOSHIBA_AC_ONE_SPACE, - TOSHIBA_AC_BIT_MARK, - TOSHIBA_AC_ZERO_SPACE); + match_result_t data_result = + matchData(&(results->rawbuf[offset]), 8, kToshibaAcBitMark, + kToshibaAcOneSpace, kToshibaAcBitMark, kToshibaAcZeroSpace); if (data_result.success == false) return false; // Fail dataBitsSoFar += 8; - results->state[i] = (uint8_t) data_result.data; + results->state[i] = (uint8_t)data_result.data; offset += data_result.used; } // Footer - if (!matchMark(results->rawbuf[offset++], TOSHIBA_AC_BIT_MARK)) return false; - if (!matchSpace(results->rawbuf[offset++], TOSHIBA_AC_MIN_GAP)) return false; + if (!matchMark(results->rawbuf[offset++], kToshibaAcBitMark)) return false; + if (!matchSpace(results->rawbuf[offset++], kToshibaAcMinGap)) return false; // Compliance if (strict) { diff --git a/lib/IRremoteESP8266/src/ir_Toshiba.h b/lib/IRremoteESP8266/src/ir_Toshiba.h index a0c0df0..a6ea6c6 100644 --- a/lib/IRremoteESP8266/src/ir_Toshiba.h +++ b/lib/IRremoteESP8266/src/ir_Toshiba.h @@ -21,15 +21,26 @@ // Toshiba A/C support added by David Conran // Constants -#define TOSHIBA_AC_AUTO 0U -#define TOSHIBA_AC_COOL 1U -#define TOSHIBA_AC_DRY 2U -#define TOSHIBA_AC_HEAT 3U -#define TOSHIBA_AC_POWER 4U -#define TOSHIBA_AC_FAN_AUTO 0U -#define TOSHIBA_AC_FAN_MAX 5U -#define TOSHIBA_AC_MIN_TEMP 17U // 17C -#define TOSHIBA_AC_MAX_TEMP 30U // 30C +const uint8_t kToshibaAcAuto = 0; +const uint8_t kToshibaAcCool = 1; +const uint8_t kToshibaAcDry = 2; +const uint8_t kToshibaAcHeat = 3; +const uint8_t kToshibaAcPower = 4; +const uint8_t kToshibaAcFanAuto = 0; +const uint8_t kToshibaAcFanMax = 5; +const uint8_t kToshibaAcMinTemp = 17; // 17C +const uint8_t kToshibaAcMaxTemp = 30; // 30C + +// Legacy defines. (Deperecated) +#define TOSHIBA_AC_AUTO kToshibaAcAuto +#define TOSHIBA_AC_COOL kToshibaAcCool +#define TOSHIBA_AC_DRY kToshibaAcDry +#define TOSHIBA_AC_HEAT kToshibaAcHeat +#define TOSHIBA_AC_POWER kToshibaAcPower +#define TOSHIBA_AC_FAN_AUTO kToshibaAcFanAuto +#define TOSHIBA_AC_FAN_MAX kToshibaAcFanMax +#define TOSHIBA_AC_MIN_TEMP kToshibaAcMinTemp +#define TOSHIBA_AC_MAX_TEMP kToshibaAcMaxTemp class IRToshibaAC { public: @@ -37,7 +48,7 @@ class IRToshibaAC { void stateReset(); #if SEND_TOSHIBA_AC - void send(); + void send(const uint16_t repeat = kToshibaACMinRepeat); #endif // SEND_TOSHIBA_AC void begin(); void on(); @@ -53,7 +64,7 @@ class IRToshibaAC { void setRaw(uint8_t newState[]); uint8_t* getRaw(); static bool validChecksum(const uint8_t state[], - const uint16_t length = TOSHIBA_AC_STATE_LENGTH); + const uint16_t length = kToshibaACStateLength); #ifdef ARDUINO String toString(); #else @@ -63,10 +74,10 @@ class IRToshibaAC { private: #endif - uint8_t remote_state[TOSHIBA_AC_STATE_LENGTH]; - void checksum(const uint16_t length = TOSHIBA_AC_STATE_LENGTH); + uint8_t remote_state[kToshibaACStateLength]; + void checksum(const uint16_t length = kToshibaACStateLength); static uint8_t calcChecksum(const uint8_t state[], - const uint16_t length = TOSHIBA_AC_STATE_LENGTH); + const uint16_t length = kToshibaACStateLength); uint8_t mode_state; IRsend _irsend; }; diff --git a/lib/IRremoteESP8266/src/ir_Trotec.cpp b/lib/IRremoteESP8266/src/ir_Trotec.cpp index 6ecfcd8..77d84ee 100644 --- a/lib/IRremoteESP8266/src/ir_Trotec.cpp +++ b/lib/IRremoteESP8266/src/ir_Trotec.cpp @@ -5,49 +5,43 @@ #include "IRutils.h" // Constants -#define TROTEC_HDR_MARK 5952U -#define TROTEC_HDR_SPACE 7364U -#define TROTEC_ONE_MARK 592U -#define TROTEC_ONE_SPACE 1560U -#define TROTEC_ZERO_MARK 592U -#define TROTEC_ZERO_SPACE 592U -#define TROTEC_GAP 6184U -#define TROTEC_GAP_END 1500U // made up value +const uint16_t kTrotecHdrMark = 5952; +const uint16_t kTrotecHdrSpace = 7364; +const uint16_t kTrotecOneMark = 592; +const uint16_t kTrotecOneSpace = 1560; +const uint16_t kTrotecZeroMark = 592; +const uint16_t kTrotecZeroSpace = 592; +const uint16_t kTrotecGap = 6184; +const uint16_t kTrotecGapEnd = 1500; // made up value #if SEND_TROTEC void IRsend::sendTrotec(unsigned char data[], uint16_t nbytes, uint16_t repeat) { - if (nbytes < TROTEC_COMMAND_LENGTH) - return; + if (nbytes < kTrotecStateLength) return; for (uint16_t r = 0; r <= repeat; r++) { - sendGeneric(TROTEC_HDR_MARK, TROTEC_HDR_SPACE, - TROTEC_ONE_MARK, TROTEC_ONE_SPACE, - TROTEC_ZERO_MARK, TROTEC_ZERO_SPACE, - TROTEC_ONE_MARK, TROTEC_GAP, - data, nbytes, 36, false, 0, // Repeats handled elsewhere + sendGeneric(kTrotecHdrMark, kTrotecHdrSpace, kTrotecOneMark, + kTrotecOneSpace, kTrotecZeroMark, kTrotecZeroSpace, + kTrotecOneMark, kTrotecGap, data, nbytes, 36, false, + 0, // Repeats handled elsewhere 50); // More footer enableIROut(36); - mark(TROTEC_ONE_MARK); - space(TROTEC_GAP_END); + mark(kTrotecOneMark); + space(kTrotecGapEnd); } } #endif // SEND_TROTEC -IRTrotecESP::IRTrotecESP(uint16_t pin) : _irsend(pin) { - stateReset(); -} +IRTrotecESP::IRTrotecESP(uint16_t pin) : _irsend(pin) { stateReset(); } -void IRTrotecESP::begin() { - _irsend.begin(); -} +void IRTrotecESP::begin() { _irsend.begin(); } #if SEND_TROTEC -void IRTrotecESP::send() { +void IRTrotecESP::send(const uint16_t repeat) { checksum(); - _irsend.sendTrotec(trotec); + _irsend.sendTrotec(trotec, kTrotecStateLength, repeat); } #endif // SEND_TROTEC @@ -61,16 +55,15 @@ void IRTrotecESP::checksum() { } void IRTrotecESP::stateReset() { - for (uint8_t i = 2; i < TROTEC_COMMAND_LENGTH; i++) - trotec[i] = 0x0; + for (uint8_t i = 2; i < kTrotecStateLength; i++) trotec[i] = 0x0; - trotec[0] = TROTEC_INTRO1; - trotec[1] = TROTEC_INTRO2; + trotec[0] = kTrotecIntro1; + trotec[1] = kTrotecIntro2; setPower(false); - setTemp(TROTEC_DEF_TEMP); - setSpeed(TROTEC_FAN_MED); - setMode(TROTEC_AUTO); + setTemp(kTrotecDefTemp); + setSpeed(kTrotecFanMed); + setMode(kTrotecAuto); } uint8_t* IRTrotecESP::getRaw() { @@ -80,67 +73,55 @@ uint8_t* IRTrotecESP::getRaw() { void IRTrotecESP::setPower(bool state) { if (state) - trotec[2] |= (TROTEC_ON << 3); + trotec[2] |= (kTrotecOn << 3); else - trotec[2] &= ~(TROTEC_ON << 3); + trotec[2] &= ~(kTrotecOn << 3); } -uint8_t IRTrotecESP::getPower() { - return trotec[2] & (TROTEC_ON << 3); -} +uint8_t IRTrotecESP::getPower() { return trotec[2] & (kTrotecOn << 3); } void IRTrotecESP::setSpeed(uint8_t speed) { trotec[2] = (trotec[2] & 0xcf) | (speed << 4); } -uint8_t IRTrotecESP::getSpeed() { - return trotec[2] & 0x30; -} +uint8_t IRTrotecESP::getSpeed() { return trotec[2] & 0x30; } void IRTrotecESP::setMode(uint8_t mode) { trotec[2] = (trotec[2] & 0xfc) | mode; } -uint8_t IRTrotecESP::getMode() { - return trotec[2] & 0x03; -} +uint8_t IRTrotecESP::getMode() { return trotec[2] & 0x03; } void IRTrotecESP::setTemp(uint8_t temp) { - if (temp < TROTEC_MIN_TEMP) - temp = TROTEC_MIN_TEMP; - else if (temp > TROTEC_MAX_TEMP) - temp = TROTEC_MAX_TEMP; + if (temp < kTrotecMinTemp) + temp = kTrotecMinTemp; + else if (temp > kTrotecMaxTemp) + temp = kTrotecMaxTemp; - trotec[3] = (trotec[3] & 0x80) | (temp - TROTEC_MIN_TEMP); + trotec[3] = (trotec[3] & 0x80) | (temp - kTrotecMinTemp); } -uint8_t IRTrotecESP::getTemp() { - return trotec[3] & 0x7f; -} +uint8_t IRTrotecESP::getTemp() { return trotec[3] & 0x7f; } void IRTrotecESP::setSleep(bool sleep) { if (sleep) - trotec[3] |= (TROTEC_SLEEP_ON << 7); + trotec[3] |= (kTrotecSleepOn << 7); else - trotec[3] &= ~(TROTEC_SLEEP_ON << 7); + trotec[3] &= ~(kTrotecSleepOn << 7); } -bool IRTrotecESP::getSleep(void) { - return trotec[3] & (TROTEC_SLEEP_ON << 7); -} +bool IRTrotecESP::getSleep(void) { return trotec[3] & (kTrotecSleepOn << 7); } void IRTrotecESP::setTimer(uint8_t timer) { - if (timer > TROTEC_MAX_TIMER) timer = TROTEC_MAX_TIMER; + if (timer > kTrotecMaxTimer) timer = kTrotecMaxTimer; if (timer) { - trotec[5] |= (TROTEC_TIMER_ON << 6); + trotec[5] |= (kTrotecTimerOn << 6); trotec[6] = timer; } else { - trotec[5] &= ~(TROTEC_TIMER_ON << 6); + trotec[5] &= ~(kTrotecTimerOn << 6); trotec[6] = 0; } } -uint8_t IRTrotecESP::getTimer() { - return trotec[6]; -} +uint8_t IRTrotecESP::getTimer() { return trotec[6]; } diff --git a/lib/IRremoteESP8266/src/ir_Trotec.h b/lib/IRremoteESP8266/src/ir_Trotec.h index a02ab24..846381b 100644 --- a/lib/IRremoteESP8266/src/ir_Trotec.h +++ b/lib/IRremoteESP8266/src/ir_Trotec.h @@ -8,45 +8,57 @@ // Constants // Byte 0 -#define TROTEC_INTRO1 0x12 +const uint8_t kTrotecIntro1 = 0x12; // Byte 1 -#define TROTEC_INTRO2 0x34 +const uint8_t kTrotecIntro2 = 0x34; // Byte 2 -#define TROTEC_AUTO 0 -#define TROTEC_COOL 1 -#define TROTEC_DRY 2 -#define TROTEC_FAN 3 +const uint8_t kTrotecAuto = 0; +const uint8_t kTrotecCool = 1; +const uint8_t kTrotecDry = 2; +const uint8_t kTrotecFan = 3; -#define TROTEC_ON 1 -#define TROTEC_OFF 0 +const uint8_t kTrotecOn = 1; +const uint8_t kTrotecOff = 0; -#define TROTEC_FAN_LOW 1 -#define TROTEC_FAN_MED 2 -#define TROTEC_FAN_HIGH 3 +const uint8_t kTrotecFanLow = 1; +const uint8_t kTrotecFanMed = 2; +const uint8_t kTrotecFanHigh = 3; // Byte 3 -#define TROTEC_MIN_TEMP 18 -#define TROTEC_MAX_TEMP 32 -#define TROTEC_DEF_TEMP 25 +const uint8_t kTrotecMinTemp = 18; +const uint8_t kTrotecDefTemp = 25; +const uint8_t kTrotecMaxTemp = 32; -#define TROTEC_SLEEP_ON 1 +const uint8_t kTrotecSleepOn = 1; // Byte 5 -#define TROTEC_TIMER_ON 1 +const uint8_t kTrotecTimerOn = 1; // Byte 6 -#define TROTEC_MIN_TIMER 0 -#define TROTEC_MAX_TIMER 23 +const uint8_t kTrotecMinTimer = 0; +const uint8_t kTrotecMaxTimer = 23; +// Legacy defines. (Deperecated) +#define TROTEC_AUTO kTrotecAuto +#define TROTEC_COOL kTrotecCool +#define TROTEC_DRY kTrotecDry +#define TROTEC_FAN kTrotecFan +#define TROTEC_FAN_LOW kTrotecFanLow +#define TROTEC_FAN_MED kTrotecFanMed +#define TROTEC_FAN_HIGH kTrotecFanHigh +#define TROTEC_MIN_TEMP kTrotecMinTemp +#define TROTEC_MAX_TEMP kTrotecMaxTemp +#define TROTEC_MIN_TIMER kTrotecMinTimer +#define TROTEC_MAX_TIMER kTrotecMaxTimer class IRTrotecESP { public: explicit IRTrotecESP(uint16_t pin); #if SEND_TROTEC - void send(); + void send(const uint16_t repeat = kTrotecDefaultRepeat); #endif // SEND_TROTEC void begin(); @@ -71,7 +83,7 @@ class IRTrotecESP { uint8_t* getRaw(); private: - uint8_t trotec[TROTEC_COMMAND_LENGTH]; + uint8_t trotec[kTrotecStateLength]; void stateReset(); void checksum(); IRsend _irsend; diff --git a/lib/IRremoteESP8266/src/ir_Vestel.cpp b/lib/IRremoteESP8266/src/ir_Vestel.cpp new file mode 100644 index 0000000..3d3cee1 --- /dev/null +++ b/lib/IRremoteESP8266/src/ir_Vestel.cpp @@ -0,0 +1,481 @@ +// Copyright 2018 Erdem U. Altinyurt + +#include "ir_Vestel.h" +#include +#ifndef UNIT_TEST +#include +#else +#include +#endif +#include "IRrecv.h" +#include "IRremoteESP8266.h" +#include "IRsend.h" +#include "IRutils.h" +#include "ir_Haier.h" + +// VV VV EEEEEEE SSSSS TTTTTTTT EEEEEEE LL +// VV VV EE S TT EE LL +// VV VV EEEEE SSSS TT EEEEE LL +// VV VV EE S TT EE LL +// VVV EEEEEEE SSSSS TT EEEEEEE LLLLLLL + +// Vestel added by Erdem U. Altinyurt + +// Equipment it seems compatible with: +// * Vestel AC Model BIOX CXP-9 (9K BTU) +// * + +// Ref: +// None. Totally reverse engineered. + +#if SEND_VESTEL_AC +// Send a Vestel message +// +// Args: +// data: Contents of the message to be sent. +// nbits: Nr. of bits of data to be sent. Typically kVestelBits. +// +// Status: STABLE / Working. +// +void IRsend::sendVestelAC(const uint64_t data, const uint16_t nbits, + const uint16_t repeat) { + if (nbits % 8 != 0) return; // nbits is required to be a multiple of 8. + + sendGeneric(kVestelACHdrMark, kVestelACHdrSpace, // Header + kVestelACBitMark, kVestelACOneSpace, // Data + kVestelACBitMark, kVestelACZeroSpace, // Data + kVestelACBitMark, 100000, // Footer + repeat gap + data, nbits, 38, false, repeat, 50); +} +#endif + +// Code to emulate Vestel A/C IR remote control unit. + +// Initialise the object. +IRVestelAC::IRVestelAC(uint16_t pin) : _irsend(pin) { stateReset(); } + +// Reset the state of the remote to a known good state/sequence. +void IRVestelAC::stateReset() { + // Power On, Mode Auto, Fan Auto, Temp = 25C/77F + remote_state.rawCode = 0x0F00D9001FEF201LL; + remote_time_state.rawCode = 0x00; + use_time_state = false; +} + +// Configure the pin for output. +void IRVestelAC::begin() { + _irsend.begin(); + stateReset(); +} + +#if SEND_VESTEL_AC +// Send the current desired state to the IR LED. +void IRVestelAC::send() { + checksum(); // Ensure correct checksum before sending. + uint64_t code_to_send; + if (use_time_state) + code_to_send = remote_time_state.rawCode; + else + code_to_send = remote_state.rawCode; + _irsend.sendVestelAC(code_to_send); +} +#endif // SEND_VESTEL_AC + +// Return the internal state date of the remote. +uint64_t IRVestelAC::getRaw() { + checksum(); + if (use_time_state) return remote_time_state.rawCode; + return remote_state.rawCode; +} + +// Override the internal state with the new state. +void IRVestelAC::setRaw(uint8_t* newState) { + uint64_t upState = 0; + for (int i = 0; i < 7; i++) + upState |= static_cast(newState[i]) << (i * 8); + remote_state.rawCode = upState; + remote_time_state.rawCode = upState; +} + +void IRVestelAC::setRaw(const uint64_t newState) { + remote_state.rawCode = newState; + remote_time_state.rawCode = newState; +} + +// Set the requested power state of the A/C to on. +void IRVestelAC::on() { setPower(true); } + +// Set the requested power state of the A/C to off. +void IRVestelAC::off() { setPower(false); } + +// Set the requested power state of the A/C. +void IRVestelAC::setPower(const bool state) { + if (state) + remote_state.power = 0xF; + else + remote_state.power = 0xC; + use_time_state = false; +} + +// Return the requested power state of the A/C. +bool IRVestelAC::getPower() { return (remote_state.power == 0xF); } + +// Set the temperature in Celsius degrees. +void IRVestelAC::setTemp(const uint8_t temp) { + uint8_t new_temp = temp; + new_temp = std::max(kVestelACMinTempC, new_temp); + // new_temp = std::max(kVestelACMinTempH, new_temp); Check MODE + new_temp = std::min(kVestelACMaxTemp, new_temp); + remote_state.temp = new_temp - 16; + use_time_state = false; +} + +// Return the set temperature. +uint8_t IRVestelAC::getTemp(void) { return remote_state.temp + 16; } + +// Set the speed of the fan, +// 1-3 set the fan speed, 0 or anything else set it to auto. +void IRVestelAC::setFan(const uint8_t fan) { + switch (fan) { + case kVestelACFanLow: + case kVestelACFanMed: + case kVestelACFanHigh: + case kVestelACFanAutoCool: + case kVestelACFanAutoHot: + remote_state.fan = fan; + break; + default: + remote_state.fan = kVestelACFanAuto; + } + use_time_state = false; +} + +// Return the requested state of the unit's fan. +uint8_t IRVestelAC::getFan() { return remote_state.fan; } + +// Get the requested climate operation mode of the a/c unit. +// Returns: +// A uint8_t containing the A/C mode. +uint8_t IRVestelAC::getMode() { return remote_state.mode; } + +// Set the requested climate operation mode of the a/c unit. +void IRVestelAC::setMode(const uint8_t mode) { + // If we get an unexpected mode, default to AUTO. + switch (mode) { + case kVestelACAuto: + case kVestelACCool: + case kVestelACHeat: + case kVestelACDry: + case kVestelACFan: + remote_state.mode = mode; + break; + default: + remote_state.mode = kVestelACAuto; + } + use_time_state = false; +} +// Set Auto mode of AC. +void IRVestelAC::setAuto(const int8_t autoLevel) { + if (autoLevel < -2 || autoLevel > 2) return; + setMode(kVestelACAuto); + setFan((autoLevel < 0 ? kVestelACFanAutoCool : kVestelACFanAutoHot)); + if (autoLevel == 2) + setTemp(30); + else if (autoLevel == 1) + setTemp(31); + else if (autoLevel == 0) + setTemp(25); + else if (autoLevel == -1) + setTemp(16); + else if (autoLevel == -2) + setTemp(17); +} + +// Set Timer option of AC. +// Valid time arguments are 0, 0.5, 1, 2, 3 and 5 hours (in min). 0 disables the +// timer. +void IRVestelAC::setTimer(const uint16_t minutes) { + remote_time_state.t_turnOnMinute = 0; + remote_time_state.t_turnOnHour = 0; + remote_time_state.t_turnOffHour = minutes / 60; + remote_time_state.t_turnOffMinute = (minutes % 60) / 10; + remote_time_state.t_off_active = 0; + if (minutes) { + remote_time_state.t_timer_mode = 1; + // Yes. t_on_active instead of t_off_active. + remote_time_state.t_on_active = 1; + } else { // Turn off the timer. + remote_time_state.t_timer_mode = 0; + remote_time_state.t_on_active = 0; + } + use_time_state = true; +} + +uint16_t IRVestelAC::getTimer(void) { return getOffTimer(); } + +// Set the AC's internal clock +void IRVestelAC::setTime(const uint16_t minutes) { + remote_time_state.t_hour = minutes / 60; + remote_time_state.t_minute = minutes % 60; + use_time_state = true; +} + +uint16_t IRVestelAC::getTime(void) { + return remote_time_state.t_hour * 60 + remote_time_state.t_minute; +} + +// Set AC's wake up time. Takes time in minute. +void IRVestelAC::setOnTimer(const uint16_t minutes) { + remote_time_state.t_turnOnHour = minutes / 60; + // Register is 3 bit and can only hold minute/10 + remote_time_state.t_turnOnMinute = (minutes % 60) / 10; + if (minutes) + remote_time_state.t_on_active = 1; // activation + else + remote_time_state.t_on_active = 0; // deactivate + remote_time_state.t_timer_mode = 0; + use_time_state = true; +} + +uint16_t IRVestelAC::getOnTimer(void) { + return remote_time_state.t_turnOnHour * 60 + + remote_time_state.t_turnOnMinute * 10; +} + +// Set AC's turn off time. Takes time in minute. +void IRVestelAC::setOffTimer(const uint16_t minutes) { + remote_time_state.t_turnOffHour = minutes / 60; + // Register is 3 bit and can only hold minute/10 + remote_time_state.t_turnOffMinute = (minutes % 60) / 10; + if (minutes) + remote_time_state.t_off_active = 1; // activation + else + remote_time_state.t_off_active = 0; // deactivate + remote_time_state.t_timer_mode = 0; + use_time_state = true; +} + +uint16_t IRVestelAC::getOffTimer(void) { + return remote_time_state.t_turnOffHour * 60 + + remote_time_state.t_turnOffMinute * 10; +} + +// Set the Sleep state of the A/C. +void IRVestelAC::setSleep(const bool state) { + remote_state.turbo_sleep_normal = state ? kVestelACSleep : kVestelACNormal; + use_time_state = false; +} + +// Return the Sleep state of the A/C. +bool IRVestelAC::getSleep() { + return remote_state.turbo_sleep_normal == kVestelACSleep; +} + +// Set the Turbo state of the A/C. +void IRVestelAC::setTurbo(const bool state) { + remote_state.turbo_sleep_normal = state ? kVestelACTurbo : kVestelACNormal; + use_time_state = false; +} + +// Return the Turbo state of the A/C. +bool IRVestelAC::getTurbo() { + return remote_state.turbo_sleep_normal == kVestelACTurbo; +} + +// Set the Ion state of the A/C. +void IRVestelAC::setIon(const bool state) { + remote_state.ion = state ? kVestelACIon : 0; + use_time_state = false; +} + +// Return the Ion state of the A/C. +bool IRVestelAC::getIon() { return remote_state.ion == kVestelACIon; } + +// Set the Swing Roaming state of the A/C. +void IRVestelAC::setSwing(const bool state) { + remote_state.swing = state ? kVestelACSwing : 0xF; + use_time_state = false; +} + +// Return the Swing Roaming state of the A/C. +bool IRVestelAC::getSwing() { return remote_state.swing == kVestelACSwing; } + +// Calculate the checksum for a given array. +// Args: +// state: The state to calculate the checksum over. +// Returns: +// The 8 bit checksum value. +uint8_t IRVestelAC::calcChecksum(const uint64_t state) { + // Just counts the set bits +1 on stream and take inverse after mask + uint8_t sum = 0; + uint64_t temp_state = state & kVestelACCRCMask; + for (; temp_state; temp_state >>= 1) + if (temp_state & 1) sum++; + sum += 2; + sum = 0xff - sum; + return sum; +} + +// Verify the checksum is valid for a given state. +// Args: +// state: The state to verify the checksum of. +// Returns: +// A boolean. +bool IRVestelAC::validChecksum(const uint64_t state) { + return (((state >> 12) & 0xFF) == calcChecksum(state)); +} + +// Calculate & set the checksum for the current internal state of the remote. +void IRVestelAC::checksum() { + // Stored the checksum value in the last byte. + remote_state.CRC = calcChecksum(remote_state.rawCode); + remote_time_state.CRC = calcChecksum(remote_time_state.rawCode); +} + +bool IRVestelAC::isTimeCommand() { + return (remote_state.power == 0x00 || use_time_state); +} + +// Convert the internal state into a human readable string. +#ifdef ARDUINO +String IRVestelAC::toString() { + String result = ""; +#else +std::string IRVestelAC::toString() { + std::string result = ""; +#endif // ARDUINO + if (isTimeCommand()) { + result += "Time: " + IRHaierAC::timeToString(getTime()); + + result += ", Timer: "; + result += remote_time_state.t_timer_mode + ? IRHaierAC::timeToString(getTimer()) + : "Off"; + + result += ", On Timer: "; + result += (remote_time_state.t_on_active && !remote_time_state.t_timer_mode) + ? IRHaierAC::timeToString(getOnTimer()) + : "Off"; + + result += ", Off Timer: "; + result += remote_time_state.t_off_active + ? IRHaierAC::timeToString(getOffTimer()) + : "Off"; + return result; + } + // Not a time command, it's a normal command. + result += "Power: "; + result += (getPower() ? "On" : "Off"); + result += ", Mode: " + uint64ToString(getMode()); + switch (getMode()) { + case kVestelACAuto: + result += " (AUTO)"; + break; + case kVestelACCool: + result += " (COOL)"; + break; + case kVestelACHeat: + result += " (HEAT)"; + break; + case kVestelACDry: + result += " (DRY)"; + break; + case kVestelACFan: + result += " (FAN)"; + break; + default: + result += " (UNKNOWN)"; + } + result += ", Temp: " + uint64ToString(getTemp()) + "C"; + result += ", Fan: " + uint64ToString(getFan()); + switch (getFan()) { + case kVestelACFanAuto: + result += " (AUTO)"; + break; + case kVestelACFanLow: + result += " (LOW)"; + break; + case kVestelACFanMed: + result += " (MEDIUM)"; + break; + case kVestelACFanHigh: + result += " (HIGH)"; + break; + case kVestelACFanAutoCool: + result += " (AUTO COOL)"; + break; + case kVestelACFanAutoHot: + result += " (AUTO HOT)"; + break; + default: + result += " (UNKNOWN)"; + } + result += ", Sleep: "; + result += (getSleep() ? "On" : "Off"); + result += ", Turbo: "; + result += (getTurbo() ? "On" : "Off"); + result += ", Ion: "; + result += (getIon() ? "On" : "Off"); + result += ", Swing: "; + result += (getSwing() ? "On" : "Off"); + return result; +} + +#if DECODE_VESTEL_AC +// Decode the supplied Vestel message. +// +// Args: +// results: Ptr to the data to decode and where to store the decode result. +// nbits: The number of data bits to expect. Typically kVestelBits. +// strict: Flag indicating if we should perform strict matching. +// Returns: +// boolean: True if it can decode it, false if it can't. +// +// Status: Alpha / Needs testing against a real device. +// +bool IRrecv::decodeVestelAC(decode_results* results, uint16_t nbits, + bool strict) { + if (nbits % 8 != 0) // nbits has to be a multiple of nr. of bits in a byte. + return false; + + if (strict) + if (nbits != kVestelACBits) + return false; // Not strictly a Vestel AC message. + + uint64_t data = 0; + uint16_t offset = kStartOffset; + + if (nbits > sizeof(data) * 8) + return false; // We can't possibly capture a Vestel packet that big. + + // Header + if (!matchMark(results->rawbuf[offset++], kVestelACHdrMark)) return false; + if (!matchSpace(results->rawbuf[offset++], kVestelACHdrSpace)) return false; + + // Data (Normal) + match_result_t data_result = + matchData(&(results->rawbuf[offset]), nbits, kVestelACBitMark, + kVestelACOneSpace, kVestelACBitMark, kVestelACZeroSpace, + kVestelACTolerance, kMarkExcess, false); + + if (data_result.success == false) return false; + offset += data_result.used; + data = data_result.data; + + // Footer + if (!matchMark(results->rawbuf[offset++], kVestelACBitMark)) return false; + + // Compliance + if (strict) + if (!IRVestelAC::validChecksum(data_result.data)) return false; + + // Success + results->decode_type = VESTEL_AC; + results->bits = nbits; + results->value = data; + results->address = 0; + results->command = 0; + + return true; +} +#endif // DECODE_VESTEL_AC diff --git a/lib/IRremoteESP8266/src/ir_Vestel.h b/lib/IRremoteESP8266/src/ir_Vestel.h new file mode 100644 index 0000000..b8a8872 --- /dev/null +++ b/lib/IRremoteESP8266/src/ir_Vestel.h @@ -0,0 +1,160 @@ +// Copyright 2018 Erdem U. Altinyurt +// (Used Midea.h as template) +#ifndef IR_VESTEL_H_ +#define IR_VESTEL_H_ + +#define __STDC_LIMIT_MACROS +#include +#ifdef ARDUINO +#include +#else +#include +#endif +#include "IRremoteESP8266.h" +#include "IRsend.h" + +// VV VV EEEEEEE SSSSS TTTTTTTT EEEEEEE LL +// VV VV EE S TT EE LL +// VV VV EEEEE SSSS TT EEEEE LL +// VV VV EE S TT EE LL +// VVV EEEEEEE SSSSS TT EEEEEEE LLLLLLL + +// Vestel added by Erdem U. Altinyurt + +// Constants +const uint16_t kVestelACHdrMark = 3110; +const uint16_t kVestelACHdrSpace = 9066; +const uint16_t kVestelACBitMark = 520; +const uint16_t kVestelACOneSpace = 1535; +const uint16_t kVestelACZeroSpace = 480; +const uint16_t kVestelACTolerance = 30; + +const uint8_t kVestelACMinTempH = 16; +const uint8_t kVestelACMinTempC = 18; +const uint8_t kVestelACMaxTemp = 30; + +const uint64_t kVestelACCRCMask = 0xFFFFFFFFFFF00000; + +const uint8_t kVestelACAuto = 0; +const uint8_t kVestelACCool = 1; +const uint8_t kVestelACDry = 2; +const uint8_t kVestelACFan = 3; +const uint8_t kVestelACHeat = 4; + +const uint8_t kVestelACFanAuto = 1; +const uint8_t kVestelACFanLow = 5; +const uint8_t kVestelACFanMed = 9; +const uint8_t kVestelACFanHigh = 0xB; +const uint8_t kVestelACFanAutoCool = 0xC; +const uint8_t kVestelACFanAutoHot = 0xD; + +const uint8_t kVestelACNormal = 1; +const uint8_t kVestelACSleep = 3; +const uint8_t kVestelACTurbo = 7; +const uint8_t kVestelACIon = 4; +const uint8_t kVestelACSwing = 0xA; + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpacked-bitfield-compat" +union VestelACState { + // Remotes Command Stack + struct { + uint16_t footer : 12; // 0x201 footer + uint8_t CRC : 8; + uint8_t swing : 4; // auto 0xA, stop 0xF + uint8_t turbo_sleep_normal : 4; // normal 0x1, sleep 0x3, turbo 0x7 + uint8_t zero : 8; // 0x00 + uint8_t temp : 4; // temp-16 degree Celcius + uint8_t fan : 4; // auto 0x1, low 0x5, mid 0x9, high 0xB, 0xD auto hot, 0xC + // auto cool + uint8_t mode : 4; // auto 0x0, cold 0x1, dry 0x2, fan 0x3, hot 0x4 + uint8_t ion : 4; // on 0x4, off 0x0 + uint8_t power : 4; // on 0xF, off 0xC + uint8_t not_used : 8; + } __attribute__((packed)); // avoids padding. + + uint64_t rawCode; + + // Remotes Timer Stack for programming AC unit for turn of after some time or + // self wakeup - turn off at defined time. There are no timer functions + // implemented. + // Here is the stack only for decoding and reverse enginering purposes. + struct { + uint16_t t_footer : 12; // 0x201 footer + uint8_t t_CRC : 8; + // timer regs has 0x18 hour mask & 0x3=Minute mask minutes are divided to 10 + // format. Need to multiply with 10 Examples: 0x01= xx:10 and 0x08 = 01:00, + // 0x03= 00:30 0x08=01:00 0x10=02:00 0x44=08:40 + uint8_t t_turnOffMinute : 3; // off minute/10 + uint8_t t_turnOffHour : 5; + uint8_t t_turnOnMinute : 3; // on minute/10 + uint8_t t_turnOnHour : 5; + uint8_t t_hour : 5; // actual time hour + uint8_t t_on_active : 1; + uint8_t t_off_active : 1; + uint8_t t_timer_mode : 1; // For timer operation, also need t_on_active bit + uint8_t t_minute : 8; // actual time minute + uint16_t t_not_used : 16; // 00 + } __attribute__((packed)); // avoids padding. +}; +#pragma GCC diagnostic pop + +class IRVestelAC { + public: + explicit IRVestelAC(uint16_t pin); + + void stateReset(); +#if SEND_VESTEL_AC + void send(); +#endif // SEND_VESTEL_AC + void begin(void); + void on(void); + void off(void); + void setPower(const bool state); + bool getPower(); + void setAuto(const int8_t autoLevel); + void setTimer(const uint16_t minutes); + uint16_t getTimer(void); + void setTime(const uint16_t minutes); + uint16_t getTime(void); + void setOnTimer(const uint16_t minutes); + uint16_t getOnTimer(void); + void setOffTimer(const uint16_t minutes); + uint16_t getOffTimer(void); + void setTemp(const uint8_t temp); + uint8_t getTemp(void); + void setFan(const uint8_t fan); + uint8_t getFan(void); + void setMode(const uint8_t mode); + uint8_t getMode(void); + void setRaw(uint8_t* newState); + void setRaw(const uint64_t newState); + uint64_t getRaw(void); + static bool validChecksum(const uint64_t state); + void setSwing(const bool state); + bool getSwing(void); + void setSleep(const bool state); + bool getSleep(void); + void setTurbo(const bool state); + bool getTurbo(void); + void setIon(const bool state); + bool getIon(void); + bool isTimeCommand(void); +#ifdef ARDUINO + String toString(); +#else + std::string toString(); +#endif + +#ifndef UNIT_TEST +// private: +#endif + VestelACState remote_state; + VestelACState remote_time_state; + bool use_time_state = false; + void checksum(); + static uint8_t calcChecksum(const uint64_t state); + IRsend _irsend; +}; + +#endif // IR_VESTEL_H_ diff --git a/lib/IRremoteESP8266/src/ir_Whirlpool.cpp b/lib/IRremoteESP8266/src/ir_Whirlpool.cpp new file mode 100644 index 0000000..bc5c988 --- /dev/null +++ b/lib/IRremoteESP8266/src/ir_Whirlpool.cpp @@ -0,0 +1,634 @@ +// Copyright 2018 David Conran +// +// Code to emulate Whirlpool protocol compatible devices. +// Should be compatible with: +// * SPIS409L, SPIS412L, SPIW409L, SPIW412L, SPIW418L +// Remotes: +// * DG11J1-3A / DG11J1-04 +// * DG11J1-91 +// +// Note: Smart, iFeel, AroundU, PowerSave, & Silent modes are unsupported. +// Advanced 6thSense, Dehumidify, & Sleep modes are not supported. +// FYI: +// Dim == !Light +// Jet == Super == Turbo +// + +#include "ir_Whirlpool.h" +#include +#ifndef ARDUINO +#include +#endif +#include "IRrecv.h" +#include "IRremoteESP8266.h" +#include "IRsend.h" +#include "IRutils.h" + +// WW WW HH HH IIIII RRRRRR LL PPPPPP OOOOO OOOOO LL +// WW WW HH HH III RR RR LL PP PP OO OO OO OO LL +// WW W WW HHHHHHH III RRRRRR LL PPPPPP OO OO OO OO LL +// WW WWW WW HH HH III RR RR LL PP OO OO OO OO LL +// WW WW HH HH IIIII RR RR LLLLLLL PP OOOO0 OOOO0 LLLLLLL + +// Constants +// Ref: https://github.com/markszabo/IRremoteESP8266/issues/509 +const uint16_t kWhirlpoolAcHdrMark = 8950; +const uint16_t kWhirlpoolAcHdrSpace = 4484; +const uint16_t kWhirlpoolAcBitMark = 597; +const uint16_t kWhirlpoolAcOneSpace = 1649; +const uint16_t kWhirlpoolAcZeroSpace = 533; +const uint16_t kWhirlpoolAcGap = 7920; +const uint32_t kWhirlpoolAcMinGap = 100000; // Completely made up value. +const uint8_t kWhirlpoolAcSections = 3; + +#if SEND_WHIRLPOOL_AC +// Send a Whirlpool A/C message. +// +// Args: +// data: An array of bytes containing the IR command. +// nbytes: Nr. of bytes of data in the array. (>=kWhirlpoolAcStateLength) +// repeat: Nr. of times the message is to be repeated. (Default = 0). +// +// Status: ALPHA / Untested. +// +// Ref: +// https://github.com/markszabo/IRremoteESP8266/issues/509 +void IRsend::sendWhirlpoolAC(unsigned char data[], uint16_t nbytes, + uint16_t repeat) { + if (nbytes < kWhirlpoolAcStateLength) + return; // Not enough bytes to send a proper message. + for (uint16_t r = 0; r <= repeat; r++) { + // Section 1 + sendGeneric(kWhirlpoolAcHdrMark, kWhirlpoolAcHdrSpace, kWhirlpoolAcBitMark, + kWhirlpoolAcOneSpace, kWhirlpoolAcBitMark, + kWhirlpoolAcZeroSpace, kWhirlpoolAcBitMark, kWhirlpoolAcGap, + data, 6, // 6 bytes == 48 bits + 38000, // Complete guess of the modulation frequency. + false, 0, 50); + // Section 2 + sendGeneric(0, 0, kWhirlpoolAcBitMark, kWhirlpoolAcOneSpace, + kWhirlpoolAcBitMark, kWhirlpoolAcZeroSpace, kWhirlpoolAcBitMark, + kWhirlpoolAcGap, data + 6, 8, // 8 bytes == 64 bits + 38000, // Complete guess of the modulation frequency. + false, 0, 50); + // Section 3 + sendGeneric(0, 0, kWhirlpoolAcBitMark, kWhirlpoolAcOneSpace, + kWhirlpoolAcBitMark, kWhirlpoolAcZeroSpace, kWhirlpoolAcBitMark, + kWhirlpoolAcMinGap, data + 14, 7, // 7 bytes == 56 bits + 38000, // Complete guess of the modulation frequency. + false, 0, 50); + } +} +#endif // SEND_WHIRLPOOL_AC + +// Class for emulating a Whirlpool A/C remote. +// Decoding help from: +// @redmusicxd, @josh929800, @raducostea + +IRWhirlpoolAc::IRWhirlpoolAc(uint16_t pin) : _irsend(pin) { stateReset(); } + +void IRWhirlpoolAc::stateReset() { + for (uint8_t i = 2; i < kWhirlpoolAcStateLength; i++) remote_state[i] = 0x0; + remote_state[0] = 0x83; + remote_state[1] = 0x06; + remote_state[6] = 0x80; + _setTemp(kWhirlpoolAcAutoTemp); // Default to a sane value. +} + +void IRWhirlpoolAc::begin() { _irsend.begin(); } + +bool IRWhirlpoolAc::validChecksum(uint8_t state[], const uint16_t length) { + if (length > kWhirlpoolAcChecksumByte1 && + state[kWhirlpoolAcChecksumByte1] != + xorBytes(state + 2, kWhirlpoolAcChecksumByte1 - 1 - 2)) { + DPRINTLN("DEBUG: First Whirlpool AC checksum failed."); + return false; + } + if (length > kWhirlpoolAcChecksumByte2 && + state[kWhirlpoolAcChecksumByte2] != + xorBytes(state + kWhirlpoolAcChecksumByte1 + 1, + kWhirlpoolAcChecksumByte2 - kWhirlpoolAcChecksumByte1 - 1)) { + DPRINTLN("DEBUG: Second Whirlpool AC checksum failed."); + return false; + } + // State is too short to have a checksum or everything checked out. + return true; +} + +// Update the checksum for the internal state. +void IRWhirlpoolAc::checksum(uint16_t length) { + if (length >= kWhirlpoolAcChecksumByte1) + remote_state[kWhirlpoolAcChecksumByte1] = + xorBytes(remote_state + 2, kWhirlpoolAcChecksumByte1 - 1 - 2); + if (length >= kWhirlpoolAcChecksumByte2) + remote_state[kWhirlpoolAcChecksumByte2] = + xorBytes(remote_state + kWhirlpoolAcChecksumByte1 + 1, + kWhirlpoolAcChecksumByte2 - kWhirlpoolAcChecksumByte1 - 1); +} + +#if SEND_WHIRLPOOL_AC +void IRWhirlpoolAc::send(const uint16_t repeat, const bool calcchecksum) { + if (calcchecksum) checksum(); + _irsend.sendWhirlpoolAC(remote_state, kWhirlpoolAcStateLength, repeat); +} +#endif // SEND_WHIRLPOOL_AC + +uint8_t *IRWhirlpoolAc::getRaw(const bool calcchecksum) { + if (calcchecksum) checksum(); + return remote_state; +} + +void IRWhirlpoolAc::setRaw(const uint8_t new_code[], const uint16_t length) { + for (uint8_t i = 0; i < length && i < kWhirlpoolAcStateLength; i++) + remote_state[i] = new_code[i]; +} + +whirlpool_ac_remote_model_t IRWhirlpoolAc::getModel() { + if (remote_state[kWhirlpoolAcAltTempPos] & kWhirlpoolAcAltTempMask) + return DG11J191; + else + return DG11J13A; +} + +void IRWhirlpoolAc::setModel(const whirlpool_ac_remote_model_t model) { + switch (model) { + case DG11J191: + remote_state[kWhirlpoolAcAltTempPos] |= kWhirlpoolAcAltTempMask; + break; + case DG11J13A: + // FALL THRU + default: + remote_state[kWhirlpoolAcAltTempPos] &= ~kWhirlpoolAcAltTempMask; + } + _setTemp(_desiredtemp); // Different models have different temp values. +} + +// Return the temp. offset in deg C for the current model. +int8_t IRWhirlpoolAc::getTempOffset() { + switch (getModel()) { + case DG11J191: + return -2; + break; + default: + return 0; + } +} + +// Set the temp. in deg C +void IRWhirlpoolAc::_setTemp(const uint8_t temp, const bool remember) { + if (remember) _desiredtemp = temp; + int8_t offset = getTempOffset(); // Cache the min temp for the model. + uint8_t newtemp = std::max((uint8_t)(kWhirlpoolAcMinTemp + offset), temp); + newtemp = std::min((uint8_t)(kWhirlpoolAcMaxTemp + offset), newtemp); + remote_state[kWhirlpoolAcTempPos] = + (remote_state[kWhirlpoolAcTempPos] & ~kWhirlpoolAcTempMask) | + ((newtemp - (kWhirlpoolAcMinTemp + offset)) << 4); +} + +// Set the temp. in deg C +void IRWhirlpoolAc::setTemp(const uint8_t temp) { + _setTemp(temp); + setSuper(false); // Changing temp cancels Super/Jet mode. + setCommand(kWhirlpoolAcCommandTemp); +} + +// Return the set temp. in deg C +uint8_t IRWhirlpoolAc::getTemp() { + return ((remote_state[kWhirlpoolAcTempPos] & kWhirlpoolAcTempMask) >> 4) + + + kWhirlpoolAcMinTemp + getTempOffset(); +} + +void IRWhirlpoolAc::_setMode(const uint8_t mode) { + switch (mode) { + case kWhirlpoolAcAuto: + setFan(kWhirlpoolAcFanAuto); + _setTemp(kWhirlpoolAcAutoTemp, false); + setSleep(false); // Cancel sleep mode when in auto/6thsense mode. + // FALL THRU + case kWhirlpoolAcHeat: + case kWhirlpoolAcCool: + case kWhirlpoolAcDry: + case kWhirlpoolAcFan: + remote_state[kWhirlpoolAcModePos] &= ~kWhirlpoolAcModeMask; + remote_state[kWhirlpoolAcModePos] |= mode; + setCommand(kWhirlpoolAcCommandMode); + break; + default: + return; + } + if (mode == kWhirlpoolAcAuto) setCommand(kWhirlpoolAcCommand6thSense); +} + +void IRWhirlpoolAc::setMode(const uint8_t mode) { + setSuper(false); // Changing mode cancels Super/Jet mode. + _setMode(mode); +} + +uint8_t IRWhirlpoolAc::getMode() { + return remote_state[kWhirlpoolAcModePos] & kWhirlpoolAcModeMask; +} + +void IRWhirlpoolAc::setFan(const uint8_t speed) { + switch (speed) { + case kWhirlpoolAcFanAuto: + case kWhirlpoolAcFanLow: + case kWhirlpoolAcFanMedium: + case kWhirlpoolAcFanHigh: + remote_state[kWhirlpoolAcFanPos] = + (remote_state[kWhirlpoolAcFanPos] & ~kWhirlpoolAcFanMask) | speed; + setSuper(false); // Changing fan speed cancels Super/Jet mode. + setCommand(kWhirlpoolAcCommandFanSpeed); + break; + } +} + +uint8_t IRWhirlpoolAc::getFan() { + return remote_state[kWhirlpoolAcFanPos] & kWhirlpoolAcFanMask; +} + +void IRWhirlpoolAc::setSwing(const bool on) { + if (on) { + remote_state[kWhirlpoolAcFanPos] |= kWhirlpoolAcSwing1Mask; + remote_state[kWhirlpoolAcOffTimerPos] |= kWhirlpoolAcSwing2Mask; + } else { + remote_state[kWhirlpoolAcFanPos] &= ~kWhirlpoolAcSwing1Mask; + remote_state[kWhirlpoolAcOffTimerPos] &= ~kWhirlpoolAcSwing2Mask; + } + setCommand(kWhirlpoolAcCommandSwing); +} + +bool IRWhirlpoolAc::getSwing() { + return (remote_state[kWhirlpoolAcFanPos] & kWhirlpoolAcSwing1Mask) && + (remote_state[kWhirlpoolAcOffTimerPos] & kWhirlpoolAcSwing2Mask); +} + +void IRWhirlpoolAc::setLight(const bool on) { + if (on) + remote_state[kWhirlpoolAcClockPos] &= ~kWhirlpoolAcLightMask; + else + remote_state[kWhirlpoolAcClockPos] |= kWhirlpoolAcLightMask; +} + +bool IRWhirlpoolAc::getLight() { + return !(remote_state[kWhirlpoolAcClockPos] & kWhirlpoolAcLightMask); +} + +void IRWhirlpoolAc::setTime(const uint16_t pos, + const uint16_t minspastmidnight) { + // Hours + remote_state[pos] &= ~kWhirlpoolAcHourMask; + remote_state[pos] |= (minspastmidnight / 60) % 24; + // Minutes + remote_state[pos + 1] &= ~kWhirlpoolAcMinuteMask; + remote_state[pos + 1] |= minspastmidnight % 60; +} + +uint16_t IRWhirlpoolAc::getTime(const uint16_t pos) { + return (remote_state[pos] & kWhirlpoolAcHourMask) * 60 + + (remote_state[pos + 1] & kWhirlpoolAcMinuteMask); +} + +bool IRWhirlpoolAc::isTimerEnabled(const uint16_t pos) { + return remote_state[pos - 1] & kWhirlpoolAcTimerEnableMask; +} + +void IRWhirlpoolAc::enableTimer(const uint16_t pos, const bool state) { + if (state) + remote_state[pos - 1] |= kWhirlpoolAcTimerEnableMask; + else + remote_state[pos - 1] &= ~kWhirlpoolAcTimerEnableMask; +} + +void IRWhirlpoolAc::setClock(const uint16_t minspastmidnight) { + setTime(kWhirlpoolAcClockPos, minspastmidnight); +} + +uint16_t IRWhirlpoolAc::getClock() { return getTime(kWhirlpoolAcClockPos); } + +void IRWhirlpoolAc::setOffTimer(const uint16_t minspastmidnight) { + setTime(kWhirlpoolAcOffTimerPos, minspastmidnight); +} + +uint16_t IRWhirlpoolAc::getOffTimer() { + return getTime(kWhirlpoolAcOffTimerPos); +} + +bool IRWhirlpoolAc::isOffTimerEnabled() { + return isTimerEnabled(kWhirlpoolAcOffTimerPos); +} + +void IRWhirlpoolAc::enableOffTimer(const bool state) { + enableTimer(kWhirlpoolAcOffTimerPos, state); + setCommand(kWhirlpoolAcCommandOffTimer); +} + +void IRWhirlpoolAc::setOnTimer(const uint16_t minspastmidnight) { + setTime(kWhirlpoolAcOnTimerPos, minspastmidnight); +} + +uint16_t IRWhirlpoolAc::getOnTimer() { return getTime(kWhirlpoolAcOnTimerPos); } + +bool IRWhirlpoolAc::isOnTimerEnabled() { + return isTimerEnabled(kWhirlpoolAcOnTimerPos); +} + +void IRWhirlpoolAc::enableOnTimer(const bool state) { + enableTimer(kWhirlpoolAcOnTimerPos, state); + setCommand(kWhirlpoolAcCommandOnTimer); +} + +void IRWhirlpoolAc::setPowerToggle(const bool on) { + if (on) + remote_state[kWhirlpoolAcPowerTogglePos] |= kWhirlpoolAcPowerToggleMask; + else + remote_state[kWhirlpoolAcPowerTogglePos] &= ~kWhirlpoolAcPowerToggleMask; + setSuper(false); // Changing power cancels Super/Jet mode. + setCommand(kWhirlpoolAcCommandPower); +} + +bool IRWhirlpoolAc::getPowerToggle() { + return remote_state[kWhirlpoolAcPowerTogglePos] & kWhirlpoolAcPowerToggleMask; +} + +uint8_t IRWhirlpoolAc::getCommand() { + return remote_state[kWhirlpoolAcCommandPos]; +} + +void IRWhirlpoolAc::setSleep(const bool on) { + if (on) { + remote_state[kWhirlpoolAcSleepPos] |= kWhirlpoolAcSleepMask; + setFan(kWhirlpoolAcFanLow); + } else { + remote_state[kWhirlpoolAcSleepPos] &= ~kWhirlpoolAcSleepMask; + } + setCommand(kWhirlpoolAcCommandSleep); +} + +bool IRWhirlpoolAc::getSleep() { + return remote_state[kWhirlpoolAcSleepPos] & kWhirlpoolAcSleepMask; +} + +// AKA Jet/Turbo mode. +void IRWhirlpoolAc::setSuper(const bool on) { + if (on) { + setFan(kWhirlpoolAcFanHigh); + switch (getMode()) { + case kWhirlpoolAcHeat: + setTemp(kWhirlpoolAcMaxTemp + getTempOffset()); + break; + case kWhirlpoolAcCool: + default: + setTemp(kWhirlpoolAcMinTemp + getTempOffset()); + setMode(kWhirlpoolAcCool); + break; + } + remote_state[kWhirlpoolAcSuperPos] |= kWhirlpoolAcSuperMask; + } else { + remote_state[kWhirlpoolAcSuperPos] &= ~kWhirlpoolAcSuperMask; + } + setCommand(kWhirlpoolAcCommandSuper); +} + +bool IRWhirlpoolAc::getSuper() { + return remote_state[kWhirlpoolAcSuperPos] & kWhirlpoolAcSuperMask; +} + +void IRWhirlpoolAc::setCommand(const uint8_t code) { + remote_state[kWhirlpoolAcCommandPos] = code; +} + +#ifdef ARDUINO +String IRWhirlpoolAc::timeToString(const uint16_t minspastmidnight) { + String result = ""; +#else +std::string IRWhirlpoolAc::timeToString(const uint16_t minspastmidnight) { + std::string result = ""; +#endif // ARDUINO + uint8_t hours = minspastmidnight / 60; + if (hours < 10) result += "0"; + result += uint64ToString(hours); + result += ":"; + uint8_t mins = minspastmidnight % 60; + if (mins < 10) result += "0"; + result += uint64ToString(mins); + return result; +} + +// Convert the internal state into a human readable string. +#ifdef ARDUINO +String IRWhirlpoolAc::toString() { + String result = ""; +#else +std::string IRWhirlpoolAc::toString() { + std::string result = ""; +#endif // ARDUINO + result += "Model: " + uint64ToString(getModel()); + switch (getModel()) { + case DG11J191: + result += " (DG11J191)"; + break; + case DG11J13A: + result += " (DG11J13A)"; + break; + default: + result += " (UNKNOWN)"; + } + result += ", Power toggle: "; + if (getPowerToggle()) + result += "On"; + else + result += "Off"; + result += ", Mode: " + uint64ToString(getMode()); + switch (getMode()) { + case kWhirlpoolAcHeat: + result += " (HEAT)"; + break; + case kWhirlpoolAcAuto: + result += " (AUTO)"; + break; + case kWhirlpoolAcCool: + result += " (COOL)"; + break; + case kWhirlpoolAcDry: + result += " (DRY)"; + break; + case kWhirlpoolAcFan: + result += " (FAN)"; + break; + default: + result += " (UNKNOWN)"; + } + result += ", Temp: " + uint64ToString(getTemp()) + "C"; + result += ", Fan: " + uint64ToString(getFan()); + switch (getFan()) { + case kWhirlpoolAcFanAuto: + result += " (AUTO)"; + break; + case kWhirlpoolAcFanHigh: + result += " (HIGH)"; + break; + case kWhirlpoolAcFanMedium: + result += " (MEDIUM)"; + break; + case kWhirlpoolAcFanLow: + result += " (LOW)"; + break; + default: + result += " (UNKNOWN)"; + break; + } + result += ", Swing: "; + if (getSwing()) + result += "On"; + else + result += "Off"; + result += ", Light: "; + if (getLight()) + result += "On"; + else + result += "Off"; + result += ", Clock: "; + result += timeToString(getClock()); + result += ", On Timer: "; + if (isOnTimerEnabled()) + result += timeToString(getOnTimer()); + else + result += "Off"; + result += ", Off Timer: "; + if (isOffTimerEnabled()) + result += timeToString(getOffTimer()); + else + result += "Off"; + result += ", Sleep: "; + if (getSleep()) + result += "On"; + else + result += "Off"; + result += ", Super: "; + if (getSuper()) + result += "On"; + else + result += "Off"; + result += ", Command: " + uint64ToString(getCommand()); + switch (getCommand()) { + case kWhirlpoolAcCommandLight: + result += " (LIGHT)"; + break; + case kWhirlpoolAcCommandPower: + result += " (POWER)"; + break; + case kWhirlpoolAcCommandTemp: + result += " (TEMP)"; + break; + case kWhirlpoolAcCommandSleep: + result += " (SLEEP)"; + break; + case kWhirlpoolAcCommandSuper: + result += " (SUPER)"; + break; + case kWhirlpoolAcCommandOnTimer: + result += " (ONTIMER)"; + break; + case kWhirlpoolAcCommandMode: + result += " (MODE)"; + break; + case kWhirlpoolAcCommandSwing: + result += " (SWING)"; + break; + case kWhirlpoolAcCommandIFeel: + result += " (IFEEL)"; + break; + case kWhirlpoolAcCommandFanSpeed: + result += " (FANSPEED)"; + break; + case kWhirlpoolAcCommand6thSense: + result += " (6THSENSE)"; + break; + case kWhirlpoolAcCommandOffTimer: + result += " (OFFTIMER)"; + break; + default: + result += " (UNKNOWN)"; + break; + } + return result; +} + +#if DECODE_WHIRLPOOL_AC +// Decode the supplied Whirlpool A/C message. +// +// Args: +// results: Ptr to the data to decode and where to store the decode result. +// nbits: The number of data bits to expect. Typically kWhirlpoolAcBits +// strict: Flag indicating if we should perform strict matching. +// Returns: +// boolean: True if it can decode it, false if it can't. +// +// Status: STABLE / Working as intended. +// +// +// Ref: +// https://github.com/markszabo/IRremoteESP8266/issues/509 +bool IRrecv::decodeWhirlpoolAC(decode_results *results, uint16_t nbits, + bool strict) { + if (results->rawlen < 2 * nbits + 4 + kHeader + kFooter - 1) + return false; // Can't possibly be a valid Whirlpool A/C message. + if (strict) { + if (nbits != kWhirlpoolAcBits) return false; + } + + uint16_t offset = kStartOffset; + uint16_t dataBitsSoFar = 0; + uint16_t i = 0; + match_result_t data_result; + uint8_t sectionSize[kWhirlpoolAcSections] = {6, 8, 7}; + + // Header + if (!matchMark(results->rawbuf[offset++], kWhirlpoolAcHdrMark)) return false; + if (!matchSpace(results->rawbuf[offset++], kWhirlpoolAcHdrSpace)) + return false; + + // Data Section + // Keep reading bytes until we either run out of section or state to fill. + for (uint8_t section = 0, pos = 0; section < kWhirlpoolAcSections; + section++) { + pos += sectionSize[section]; + for (; offset <= results->rawlen - 16 && i < pos; + i++, dataBitsSoFar += 8, offset += data_result.used) { + data_result = + matchData(&(results->rawbuf[offset]), 8, kWhirlpoolAcBitMark, + kWhirlpoolAcOneSpace, kWhirlpoolAcBitMark, + kWhirlpoolAcZeroSpace, kTolerance, kMarkExcess, false); + if (data_result.success == false) break; // Fail + // Data is in LSB order. We need to reverse it. + results->state[i] = (uint8_t)data_result.data; + } + // Section Footer + if (!matchMark(results->rawbuf[offset++], kWhirlpoolAcBitMark)) + return false; + if (section < kWhirlpoolAcSections - 1) { // Inter-section gaps. + if (!matchSpace(results->rawbuf[offset++], kWhirlpoolAcGap)) return false; + } else { // Last section / End of message gap. + if (offset <= results->rawlen && + !matchAtLeast(results->rawbuf[offset++], kWhirlpoolAcGap)) + return false; + } + } + + // Compliance + if (strict) { + // Re-check we got the correct size/length due to the way we read the data. + if (dataBitsSoFar != kWhirlpoolAcBits) return false; + if (!IRWhirlpoolAc::validChecksum(results->state, dataBitsSoFar / 8)) + return false; + } + + // Success + results->decode_type = WHIRLPOOL_AC; + results->bits = dataBitsSoFar; + // No need to record the state as we stored it as we decoded it. + // As we use result->state, we don't record value, address, or command as it + // is a union data type. + return true; +} +#endif // WHIRLPOOL_AC diff --git a/lib/IRremoteESP8266/src/ir_Whirlpool.h b/lib/IRremoteESP8266/src/ir_Whirlpool.h new file mode 100644 index 0000000..211e30f --- /dev/null +++ b/lib/IRremoteESP8266/src/ir_Whirlpool.h @@ -0,0 +1,161 @@ +// Whirlpool A/C +// +// Copyright 2018 David Conran + +#ifndef IR_WHIRLPOOL_H_ +#define IR_WHIRLPOOL_H_ + +#define __STDC_LIMIT_MACROS +#include +#ifndef UNIT_TEST +#include +#else +#include +#endif +#include "IRremoteESP8266.h" +#include "IRsend.h" + +// WW WW HH HH IIIII RRRRRR LL PPPPPP OOOOO OOOOO LL +// WW WW HH HH III RR RR LL PP PP OO OO OO OO LL +// WW W WW HHHHHHH III RRRRRR LL PPPPPP OO OO OO OO LL +// WW WWW WW HH HH III RR RR LL PP OO OO OO OO LL +// WW WW HH HH IIIII RR RR LLLLLLL PP OOOO0 OOOO0 LLLLLLL + +// Ref: +// https://github.com/markszabo/IRremoteESP8266/issues/509 + +// Constants +const uint8_t kWhirlpoolAcChecksumByte1 = 13; +const uint8_t kWhirlpoolAcChecksumByte2 = kWhirlpoolAcStateLength - 1; +const uint8_t kWhirlpoolAcHeat = 0; +const uint8_t kWhirlpoolAcAuto = 1; +const uint8_t kWhirlpoolAcCool = 2; +const uint8_t kWhirlpoolAcDry = 3; +const uint8_t kWhirlpoolAcFan = 4; +const uint8_t kWhirlpoolAcModeMask = 0b00000111; +const uint8_t kWhirlpoolAcModePos = 3; +const uint8_t kWhirlpoolAcFanAuto = 0; +const uint8_t kWhirlpoolAcFanHigh = 1; +const uint8_t kWhirlpoolAcFanMedium = 2; +const uint8_t kWhirlpoolAcFanLow = 3; +const uint8_t kWhirlpoolAcFanMask = 0b00000011; +const uint8_t kWhirlpoolAcFanPos = 2; +const uint8_t kWhirlpoolAcMinTemp = 18; // 18C (DG11J1-3A), 16C (DG11J1-91) +const uint8_t kWhirlpoolAcMaxTemp = 32; // 32C (DG11J1-3A), 30C (DG11J1-91) +const uint8_t kWhirlpoolAcAutoTemp = 23; // 23C +const uint8_t kWhirlpoolAcTempMask = 0b11110000; +const uint8_t kWhirlpoolAcTempPos = 3; +const uint8_t kWhirlpoolAcSwing1Mask = 0b10000000; +const uint8_t kWhirlpoolAcSwing2Mask = 0b01000000; +const uint8_t kWhirlpoolAcLightMask = 0b00100000; +const uint8_t kWhirlpoolAcPowerToggleMask = 0b00000100; +const uint8_t kWhirlpoolAcPowerTogglePos = 2; +const uint8_t kWhirlpoolAcSleepMask = 0b00001000; +const uint8_t kWhirlpoolAcSleepPos = 2; +const uint8_t kWhirlpoolAcSuperMask = 0b10010000; +const uint8_t kWhirlpoolAcSuperPos = 5; +const uint8_t kWhirlpoolAcHourMask = 0b00011111; +const uint8_t kWhirlpoolAcMinuteMask = 0b00111111; +const uint8_t kWhirlpoolAcTimerEnableMask = 0b10000000; +const uint8_t kWhirlpoolAcClockPos = 6; +const uint8_t kWhirlpoolAcOffTimerPos = 8; +const uint8_t kWhirlpoolAcOnTimerPos = 10; +const uint8_t kWhirlpoolAcCommandPos = 15; +const uint8_t kWhirlpoolAcCommandLight = 0x00; +const uint8_t kWhirlpoolAcCommandPower = 0x01; +const uint8_t kWhirlpoolAcCommandTemp = 0x02; +const uint8_t kWhirlpoolAcCommandSleep = 0x03; +const uint8_t kWhirlpoolAcCommandSuper = 0x04; +const uint8_t kWhirlpoolAcCommandOnTimer = 0x05; +const uint8_t kWhirlpoolAcCommandMode = 0x06; +const uint8_t kWhirlpoolAcCommandSwing = 0x07; +const uint8_t kWhirlpoolAcCommandIFeel = 0x0D; +const uint8_t kWhirlpoolAcCommandFanSpeed = 0x11; +const uint8_t kWhirlpoolAcCommand6thSense = 0x17; +const uint8_t kWhirlpoolAcCommandOffTimer = 0x1D; +const uint8_t kWhirlpoolAcAltTempMask = 0b00001000; +const uint8_t kWhirlpoolAcAltTempPos = 18; + +enum whirlpool_ac_remote_model_t { + DG11J13A = 1, // DG11J1-04 too + DG11J191, +}; + +// Classes +class IRWhirlpoolAc { + public: + explicit IRWhirlpoolAc(uint16_t pin); + + void stateReset(); +#if SEND_WHIRLPOOL_AC + void send(const uint16_t repeat = kWhirlpoolAcDefaultRepeat, + const bool calcchecksum = true); +#endif // SEND_WHIRLPOOL_AC + void begin(); + void on(); + void off(); + void setPowerToggle(const bool on); + bool getPowerToggle(); + void setSleep(const bool on); + bool getSleep(); + void setSuper(const bool on); + bool getSuper(); + void setTemp(const uint8_t temp); + uint8_t getTemp(); + void setFan(const uint8_t speed); + uint8_t getFan(); + void setMode(const uint8_t mode); + uint8_t getMode(); + void setSwing(const bool on); + bool getSwing(); + void setLight(const bool on); + bool getLight(); + uint16_t getClock(); + void setClock(const uint16_t minspastmidnight); + uint16_t getOnTimer(); + void setOnTimer(const uint16_t minspastmidnight); + void enableOnTimer(const bool state); + bool isOnTimerEnabled(); + uint16_t getOffTimer(); + void setOffTimer(const uint16_t minspastmidnight); + void enableOffTimer(const bool state); + bool isOffTimerEnabled(); + void setCommand(const uint8_t code); + uint8_t getCommand(); + whirlpool_ac_remote_model_t getModel(); + void setModel(const whirlpool_ac_remote_model_t model); + uint8_t* getRaw(const bool calcchecksum = true); + void setRaw(const uint8_t new_code[], + const uint16_t length = kWhirlpoolAcStateLength); + static bool validChecksum(uint8_t state[], + const uint16_t length = kWhirlpoolAcStateLength); +#ifdef ARDUINO + String toString(); +#else + std::string toString(); +#endif + +#ifndef UNIT_TEST + + private: +#endif + // The state of the IR remote in IR code form. + uint8_t remote_state[kWhirlpoolAcStateLength]; + IRsend _irsend; + uint8_t _desiredtemp; + void checksum(const uint16_t length = kWhirlpoolAcStateLength); + uint16_t getTime(const uint16_t pos); + void setTime(const uint16_t pos, const uint16_t minspastmidnight); + bool isTimerEnabled(const uint16_t pos); + void enableTimer(const uint16_t pos, const bool state); + void _setTemp(const uint8_t temp, const bool remember = true); + void _setMode(const uint8_t mode); + int8_t getTempOffset(); +#ifdef ARDUINO + String timeToString(uint16_t minspastmidnight); +#else + std::string timeToString(uint16_t minspastmidnight); +#endif +}; + +#endif // IR_WHIRLPOOL_H_ diff --git a/lib/IRremoteESP8266/src/ir_Whynter.cpp b/lib/IRremoteESP8266/src/ir_Whynter.cpp index 2306343..555c507 100644 --- a/lib/IRremoteESP8266/src/ir_Whynter.cpp +++ b/lib/IRremoteESP8266/src/ir_Whynter.cpp @@ -16,27 +16,26 @@ // Whynter originally added from https://github.com/shirriff/Arduino-IRremote/ // Constants -#define WHYNTER_TICK 50U -#define WHYNTER_HDR_MARK_TICKS 57U -#define WHYNTER_HDR_MARK (WHYNTER_HDR_MARK_TICKS * WHYNTER_TICK) -#define WHYNTER_HDR_SPACE_TICKS 57U -#define WHYNTER_HDR_SPACE (WHYNTER_HDR_SPACE_TICKS * \ - WHYNTER_TICK) -#define WHYNTER_BIT_MARK_TICKS 15U -#define WHYNTER_BIT_MARK (WHYNTER_BIT_MARK_TICKS * WHYNTER_TICK) -#define WHYNTER_ONE_SPACE_TICKS 43U -#define WHYNTER_ONE_SPACE (WHYNTER_ONE_SPACE_TICKS * \ - WHYNTER_TICK) -#define WHYNTER_ZERO_SPACE_TICKS 15U -#define WHYNTER_ZERO_SPACE (WHYNTER_ZERO_SPACE_TICKS * \ - WHYNTER_TICK) -#define WHYNTER_MIN_COMMAND_LENGTH_TICKS 2160U // Completely made up value. -#define WHYNTER_MIN_COMMAND_LENGTH (WHYNTER_MIN_COMMAND_LENGTH_TICKS * \ - WHYNTER_TICK) -#define WHYNTER_MIN_GAP_TICKS (WHYNTER_MIN_COMMAND_LENGTH_TICKS - \ - (2 * (WHYNTER_BIT_MARK_TICKS + WHYNTER_ZERO_SPACE_TICKS) + \ - WHYNTER_BITS * (WHYNTER_BIT_MARK_TICKS + WHYNTER_ONE_SPACE_TICKS))) -#define WHYNTER_MIN_GAP (WHYNTER_MIN_GAP_TICKS * WHYNTER_TICK) + +const uint16_t kWhynterTick = 50; +const uint16_t kWhynterHdrMarkTicks = 57; +const uint16_t kWhynterHdrMark = kWhynterHdrMarkTicks * kWhynterTick; +const uint16_t kWhynterHdrSpaceTicks = 57; +const uint16_t kWhynterHdrSpace = kWhynterHdrSpaceTicks * kWhynterTick; +const uint16_t kWhynterBitMarkTicks = 15; +const uint16_t kWhynterBitMark = kWhynterBitMarkTicks * kWhynterTick; +const uint16_t kWhynterOneSpaceTicks = 43; +const uint16_t kWhynterOneSpace = kWhynterOneSpaceTicks * kWhynterTick; +const uint16_t kWhynterZeroSpaceTicks = 15; +const uint16_t kWhynterZeroSpace = kWhynterZeroSpaceTicks * kWhynterTick; +const uint16_t kWhynterMinCommandLengthTicks = 2160; // Totally made up value. +const uint32_t kWhynterMinCommandLength = + kWhynterMinCommandLengthTicks * kWhynterTick; +const uint16_t kWhynterMinGapTicks = + kWhynterMinCommandLengthTicks - + (2 * (kWhynterBitMarkTicks + kWhynterZeroSpaceTicks) + + kWhynterBits * (kWhynterBitMarkTicks + kWhynterOneSpaceTicks)); +const uint16_t kWhynterMinGap = kWhynterMinGapTicks * kWhynterTick; #if SEND_WHYNTER // Send a Whynter message. @@ -56,16 +55,14 @@ void IRsend::sendWhynter(uint64_t data, uint16_t nbits, uint16_t repeat) { for (uint16_t i = 0; i <= repeat; i++) { // (Pre-)Header - mark(WHYNTER_BIT_MARK); - space(WHYNTER_ZERO_SPACE); - sendGeneric(WHYNTER_HDR_MARK, WHYNTER_HDR_SPACE, - WHYNTER_BIT_MARK, WHYNTER_ONE_SPACE, - WHYNTER_BIT_MARK, WHYNTER_ZERO_SPACE, - WHYNTER_BIT_MARK, WHYNTER_MIN_GAP, - WHYNTER_MIN_COMMAND_LENGTH - (WHYNTER_BIT_MARK + - WHYNTER_ZERO_SPACE), - data, nbits, 38, true, 0, // Repeats are already handled. - 50); + mark(kWhynterBitMark); + space(kWhynterZeroSpace); + sendGeneric( + kWhynterHdrMark, kWhynterHdrSpace, kWhynterBitMark, kWhynterOneSpace, + kWhynterBitMark, kWhynterZeroSpace, kWhynterBitMark, kWhynterMinGap, + kWhynterMinCommandLength - (kWhynterBitMark + kWhynterZeroSpace), data, + nbits, 38, true, 0, // Repeats are already handled. + 50); } } #endif @@ -86,47 +83,45 @@ void IRsend::sendWhynter(uint64_t data, uint16_t nbits, uint16_t repeat) { // https://github.com/z3t0/Arduino-IRremote/blob/master/ir_Whynter.cpp bool IRrecv::decodeWhynter(decode_results *results, uint16_t nbits, bool strict) { - if (results->rawlen < 2 * nbits + 2 * HEADER + FOOTER - 1) - return false; // We don't have enough entries to possibly match. + if (results->rawlen < 2 * nbits + 2 * kHeader + kFooter - 1) + return false; // We don't have enough entries to possibly match. // Compliance - if (strict && nbits != WHYNTER_BITS) + if (strict && nbits != kWhynterBits) return false; // Incorrect nr. of bits per spec. - uint16_t offset = OFFSET_START; + uint16_t offset = kStartOffset; // Header // Sequence begins with a bit mark and a zero space. // These are typically small, so we'll prefer to do the calibration // on the much larger header mark & space that are next. - if (!matchMark(results->rawbuf[offset++], WHYNTER_BIT_MARK)) return false; - if (!matchSpace(results->rawbuf[offset++], WHYNTER_ZERO_SPACE)) return false; + if (!matchMark(results->rawbuf[offset++], kWhynterBitMark)) return false; + if (!matchSpace(results->rawbuf[offset++], kWhynterZeroSpace)) return false; // Main header mark and space - if (!matchMark(results->rawbuf[offset], WHYNTER_HDR_MARK)) return false; + if (!matchMark(results->rawbuf[offset], kWhynterHdrMark)) return false; // Calculate how long the common tick time is based on the header mark. - uint32_t m_tick = results->rawbuf[offset++] * RAWTICK / - WHYNTER_HDR_MARK_TICKS; - if (!matchSpace(results->rawbuf[offset], WHYNTER_HDR_SPACE)) return false; + uint32_t m_tick = results->rawbuf[offset++] * kRawTick / kWhynterHdrMarkTicks; + if (!matchSpace(results->rawbuf[offset], kWhynterHdrSpace)) return false; // Calculate how long the common tick time is based on the header space. - uint32_t s_tick = results->rawbuf[offset++] * RAWTICK / - WHYNTER_HDR_SPACE_TICKS; + uint32_t s_tick = + results->rawbuf[offset++] * kRawTick / kWhynterHdrSpaceTicks; // Data uint64_t data = 0; - match_result_t data_result = matchData(&(results->rawbuf[offset]), nbits, - WHYNTER_BIT_MARK_TICKS * m_tick, - WHYNTER_ONE_SPACE_TICKS * s_tick, - WHYNTER_BIT_MARK_TICKS * m_tick, - WHYNTER_ZERO_SPACE_TICKS * s_tick); + match_result_t data_result = + matchData(&(results->rawbuf[offset]), nbits, + kWhynterBitMarkTicks * m_tick, kWhynterOneSpaceTicks * s_tick, + kWhynterBitMarkTicks * m_tick, kWhynterZeroSpaceTicks * s_tick); if (data_result.success == false) return false; data = data_result.data; offset += data_result.used; // Footer - if (!matchMark(results->rawbuf[offset++], WHYNTER_BIT_MARK_TICKS * m_tick)) + if (!matchMark(results->rawbuf[offset++], kWhynterBitMarkTicks * m_tick)) return false; if (offset < results->rawlen && - !matchAtLeast(results->rawbuf[offset], WHYNTER_MIN_GAP_TICKS * s_tick)) + !matchAtLeast(results->rawbuf[offset], kWhynterMinGapTicks * s_tick)) return false; // Success diff --git a/lib/IRremoteESP8266/test/IRrecv_test.cpp b/lib/IRremoteESP8266/test/IRrecv_test.cpp index b682508..85b6685 100644 --- a/lib/IRremoteESP8266/test/IRrecv_test.cpp +++ b/lib/IRremoteESP8266/test/IRrecv_test.cpp @@ -1,8 +1,8 @@ // Copyright 2017 David Conran #include "IRrecv_test.h" -#include "IRremoteESP8266.h" #include "IRrecv.h" +#include "IRremoteESP8266.h" #include "IRsend.h" #include "IRsend_test.h" #include "gtest/gtest.h" @@ -10,7 +10,7 @@ // Tests for the IRrecv object. TEST(TestIRrecv, DefaultBufferSize) { IRrecv irrecv_default(1); - EXPECT_EQ(RAWBUF, irrecv_default.getBufSize()); + EXPECT_EQ(kRawBuf, irrecv_default.getBufSize()); } TEST(TestIRrecv, LargeBufferSize) { @@ -30,7 +30,7 @@ TEST(TestIRrecv, MediumBufferSize) { TEST(TestIRrecv, IRrecvDestructor) { IRrecv *irrecv_ptr = new IRrecv(1); - EXPECT_EQ(RAWBUF, irrecv_ptr->getBufSize()); + EXPECT_EQ(kRawBuf, irrecv_ptr->getBufSize()); delete irrecv_ptr; irrecv_ptr = new IRrecv(1, 1234); @@ -120,7 +120,7 @@ TEST(TestDecode, DecodeNEC) { irsend.makeDecodeResult(); ASSERT_TRUE(irrecv.decode(&irsend.capture)); EXPECT_EQ(NEC, irsend.capture.decode_type); - EXPECT_EQ(NEC_BITS, irsend.capture.bits); + EXPECT_EQ(kNECBits, irsend.capture.bits); EXPECT_EQ(0x807F40BF, irsend.capture.value); } @@ -134,7 +134,7 @@ TEST(TestDecode, DecodeJVC) { irsend.makeDecodeResult(); ASSERT_TRUE(irrecv.decode(&irsend.capture)); EXPECT_EQ(JVC, irsend.capture.decode_type); - EXPECT_EQ(JVC_BITS, irsend.capture.bits); + EXPECT_EQ(kJvcBits, irsend.capture.bits); EXPECT_EQ(0xC2B8, irsend.capture.value); } @@ -148,15 +148,15 @@ TEST(TestDecode, DecodeLG) { irsend.makeDecodeResult(); ASSERT_TRUE(irrecv.decode(&irsend.capture)); EXPECT_EQ(LG, irsend.capture.decode_type); - EXPECT_EQ(LG_BITS, irsend.capture.bits); + EXPECT_EQ(kLgBits, irsend.capture.bits); EXPECT_EQ(0x4B4AE51, irsend.capture.value); irsend.reset(); - irsend.sendLG(0xB4B4AE51, LG32_BITS); + irsend.sendLG(0xB4B4AE51, kLg32Bits); irsend.makeDecodeResult(); ASSERT_TRUE(irrecv.decode(&irsend.capture)); EXPECT_EQ(LG, irsend.capture.decode_type); - EXPECT_EQ(LG32_BITS, irsend.capture.bits); + EXPECT_EQ(kLg32Bits, irsend.capture.bits); EXPECT_EQ(0xB4B4AE51, irsend.capture.value); } @@ -168,9 +168,9 @@ TEST(TestDecode, DecodePanasonic) { irsend.reset(); irsend.sendPanasonic64(0x40040190ED7C); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodePanasonic(&irsend.capture, PANASONIC_BITS, true)); + ASSERT_TRUE(irrecv.decodePanasonic(&irsend.capture, kPanasonicBits, true)); EXPECT_EQ(PANASONIC, irsend.capture.decode_type); - EXPECT_EQ(PANASONIC_BITS, irsend.capture.bits); + EXPECT_EQ(kPanasonicBits, irsend.capture.bits); EXPECT_EQ(0x40040190ED7C, irsend.capture.value); } @@ -184,7 +184,7 @@ TEST(TestDecode, DecodeSamsung) { irsend.makeDecodeResult(); ASSERT_TRUE(irrecv.decode(&irsend.capture)); EXPECT_EQ(SAMSUNG, irsend.capture.decode_type); - EXPECT_EQ(SAMSUNG_BITS, irsend.capture.bits); + EXPECT_EQ(kSamsungBits, irsend.capture.bits); EXPECT_EQ(0xE0E09966, irsend.capture.value); } @@ -199,7 +199,7 @@ TEST(TestDecode, DecodeSherwood) { ASSERT_TRUE(irrecv.decode(&irsend.capture)); // Sherwood codes are really NEC codes. EXPECT_EQ(NEC, irsend.capture.decode_type); - EXPECT_EQ(NEC_BITS, irsend.capture.bits); + EXPECT_EQ(kNECBits, irsend.capture.bits); EXPECT_EQ(0x807F40BF, irsend.capture.value); } @@ -213,7 +213,7 @@ TEST(TestDecode, DecodeWhynter) { irsend.makeDecodeResult(); ASSERT_TRUE(irrecv.decode(&irsend.capture)); EXPECT_EQ(WHYNTER, irsend.capture.decode_type); - EXPECT_EQ(WHYNTER_BITS, irsend.capture.bits); + EXPECT_EQ(kWhynterBits, irsend.capture.bits); EXPECT_EQ(0x87654321, irsend.capture.value); } @@ -225,30 +225,29 @@ TEST(TestDecode, DecodeSony) { // Synthesised Normal Sony 20-bit message. irsend.reset(); - irsend.sendSony(irsend.encodeSony(SONY_20_BITS, 0x1, 0x1, 0x1)); + irsend.sendSony(irsend.encodeSony(kSony20Bits, 0x1, 0x1, 0x1)); irsend.makeDecodeResult(); ASSERT_TRUE(irrecv.decode(&irsend.capture)); EXPECT_EQ(SONY, irsend.capture.decode_type); - EXPECT_EQ(SONY_20_BITS, irsend.capture.bits); + EXPECT_EQ(kSony20Bits, irsend.capture.bits); EXPECT_EQ(0x81080, irsend.capture.value); // Synthesised Normal Sony 15-bit message. irsend.reset(); - irsend.sendSony(irsend.encodeSony(SONY_15_BITS, 21, 1), SONY_15_BITS); + irsend.sendSony(irsend.encodeSony(kSony15Bits, 21, 1), kSony15Bits); irsend.makeDecodeResult(); ASSERT_TRUE(irrecv.decode(&irsend.capture)); EXPECT_EQ(SONY, irsend.capture.decode_type); - EXPECT_EQ(SONY_15_BITS, irsend.capture.bits); + EXPECT_EQ(kSony15Bits, irsend.capture.bits); EXPECT_EQ(0x5480, irsend.capture.value); - // Synthesised Normal Sony 12-bit message. irsend.reset(); - irsend.sendSony(irsend.encodeSony(SONY_12_BITS, 21, 1), SONY_12_BITS); + irsend.sendSony(irsend.encodeSony(kSony12Bits, 21, 1), kSony12Bits); irsend.makeDecodeResult(); ASSERT_TRUE(irrecv.decode(&irsend.capture)); EXPECT_EQ(SONY, irsend.capture.decode_type); - EXPECT_EQ(SONY_12_BITS, irsend.capture.bits); + EXPECT_EQ(kSony12Bits, irsend.capture.bits); EXPECT_EQ(0xA90, irsend.capture.value); } @@ -262,7 +261,7 @@ TEST(TestDecode, DecodeSharp) { irsend.makeDecodeResult(); ASSERT_TRUE(irrecv.decode(&irsend.capture)); EXPECT_EQ(SHARP, irsend.capture.decode_type); - EXPECT_EQ(SHARP_BITS, irsend.capture.bits); + EXPECT_EQ(kSharpBits, irsend.capture.bits); EXPECT_EQ(0x454A, irsend.capture.value); } @@ -276,7 +275,7 @@ TEST(TestDecode, DecodeSanyo) { irsend.makeDecodeResult(); ASSERT_TRUE(irrecv.decode(&irsend.capture)); EXPECT_EQ(SANYO_LC7461, irsend.capture.decode_type); - EXPECT_EQ(SANYO_LC7461_BITS, irsend.capture.bits); + EXPECT_EQ(kSanyoLC7461Bits, irsend.capture.bits); EXPECT_EQ(0x2468DCB56A9, irsend.capture.value); } @@ -292,7 +291,7 @@ TEST(TestDecode, DecodeRCMM) { irsend.makeDecodeResult(); ASSERT_TRUE(irrecv.decode(&irsend.capture)); EXPECT_EQ(RCMM, irsend.capture.decode_type); - EXPECT_EQ(RCMM_BITS, irsend.capture.bits); + EXPECT_EQ(kRCMMBits, irsend.capture.bits); EXPECT_EQ(0xe0a600, irsend.capture.value); // Normal RCMM 12-bit message. @@ -324,7 +323,7 @@ TEST(TestDecode, DecodeMitsubishi) { irsend.makeDecodeResult(); ASSERT_TRUE(irrecv.decode(&irsend.capture)); EXPECT_EQ(MITSUBISHI, irsend.capture.decode_type); - EXPECT_EQ(MITSUBISHI_BITS, irsend.capture.bits); + EXPECT_EQ(kMitsubishiBits, irsend.capture.bits); EXPECT_EQ(0xC2B8, irsend.capture.value); } @@ -339,15 +338,15 @@ TEST(TestDecode, DecodeRC5) { irsend.makeDecodeResult(); ASSERT_TRUE(irrecv.decode(&irsend.capture)); EXPECT_EQ(RC5, irsend.capture.decode_type); - EXPECT_EQ(RC5_BITS, irsend.capture.bits); + EXPECT_EQ(kRC5Bits, irsend.capture.bits); EXPECT_EQ(0x175, irsend.capture.value); // Synthesised Normal RC-5X 13-bit message. irsend.reset(); - irsend.sendRC5(irsend.encodeRC5X(0x02, 0x41, true), RC5X_BITS); + irsend.sendRC5(irsend.encodeRC5X(0x02, 0x41, true), kRC5XBits); irsend.makeDecodeResult(); ASSERT_TRUE(irrecv.decode(&irsend.capture)); EXPECT_EQ(RC5X, irsend.capture.decode_type); - EXPECT_EQ(RC5X_BITS, irsend.capture.bits); + EXPECT_EQ(kRC5XBits, irsend.capture.bits); EXPECT_EQ(0x1881, irsend.capture.value); } @@ -362,16 +361,16 @@ TEST(TestDecode, DecodeRC6) { irsend.makeDecodeResult(); ASSERT_TRUE(irrecv.decode(&irsend.capture)); EXPECT_EQ(RC6, irsend.capture.decode_type); - EXPECT_EQ(RC6_MODE0_BITS, irsend.capture.bits); + EXPECT_EQ(kRC6Mode0Bits, irsend.capture.bits); EXPECT_EQ(0x175, irsend.capture.value); // Normal RC-6 36-bit message. irsend.reset(); - irsend.sendRC6(0xC800F742A, RC6_36_BITS); + irsend.sendRC6(0xC800F742A, kRC6_36Bits); irsend.makeDecodeResult(); ASSERT_TRUE(irrecv.decode(&irsend.capture)); EXPECT_EQ(RC6, irsend.capture.decode_type); - EXPECT_EQ(RC6_36_BITS, irsend.capture.bits); + EXPECT_EQ(kRC6_36Bits, irsend.capture.bits); EXPECT_EQ(0xC800F742A, irsend.capture.value); } @@ -385,7 +384,7 @@ TEST(TestDecode, DecodeDish) { irsend.makeDecodeResult(); ASSERT_TRUE(irrecv.decode(&irsend.capture)); EXPECT_EQ(DISH, irsend.capture.decode_type); - EXPECT_EQ(DISH_BITS, irsend.capture.bits); + EXPECT_EQ(kDishBits, irsend.capture.bits); EXPECT_EQ(0x9C00, irsend.capture.value); } @@ -404,7 +403,7 @@ TEST(TestDecode, DecodeDenon) { EXPECT_EQ(0x2278, irsend.capture.value); // Legacy Denon 14-bit message. irsend.reset(); - irsend.sendDenon(0x1278, DENON_LEGACY_BITS); + irsend.sendDenon(0x1278, kDenonLegacyBits); irsend.makeDecodeResult(); ASSERT_TRUE(irrecv.decode(&irsend.capture)); EXPECT_EQ(DENON, irsend.capture.decode_type); @@ -430,7 +429,7 @@ TEST(TestDecode, DecodeCoolix) { irsend.makeDecodeResult(); ASSERT_TRUE(irrecv.decode(&irsend.capture)); EXPECT_EQ(COOLIX, irsend.capture.decode_type); - EXPECT_EQ(COOLIX_BITS, irsend.capture.bits); + EXPECT_EQ(kCoolixBits, irsend.capture.bits); EXPECT_EQ(0x123456, irsend.capture.value); } @@ -444,7 +443,7 @@ TEST(TestDecode, DecodeAiwa) { irsend.makeDecodeResult(); ASSERT_TRUE(irrecv.decode(&irsend.capture)); EXPECT_EQ(AIWA_RC_T501, irsend.capture.decode_type); - EXPECT_EQ(AIWA_RC_T501_BITS, irsend.capture.bits); + EXPECT_EQ(kAiwaRcT501Bits, irsend.capture.bits); EXPECT_EQ(0x7F, irsend.capture.value); } @@ -454,14 +453,8 @@ TEST(TestMatchData, SpaceEncoded) { IRrecv irrecv(1); irsend.begin(); - uint16_t space_encoded_raw[11] = { - 500, 500, - 500, 1500, - 499, 499, - 501, 1501, - 499, 1490, - 500 - }; + uint16_t space_encoded_raw[11] = {500, 500, 500, 1500, 499, 499, + 501, 1501, 499, 1490, 500}; match_result_t result; irsend.reset(); @@ -485,29 +478,35 @@ TEST(TestMatchData, MarkEncoded) { IRrecv irrecv(1); irsend.begin(); - uint16_t mark_encoded_raw[11] = { - 500, 500, - 1500, 500, - 499, 499, - 1501, 501, - 1499, 490, - 500 - }; + uint16_t mark_encoded_raw[11] = {500, 500, 1500, 500, 499, 499, + 1501, 501, 1499, 490, 500}; match_result_t result; irsend.reset(); irsend.sendRaw(mark_encoded_raw, 11, 38000); irsend.makeDecodeResult(); + // MSBF order. result = irrecv.matchData(irsend.capture.rawbuf + 1, 5, 1500, 500, 500, 500); ASSERT_TRUE(result.success); EXPECT_EQ(0b01011, result.data); EXPECT_EQ(10, result.used); + // LSBF order. + result = irrecv.matchData(irsend.capture.rawbuf + 1, 5, 1500, 500, 500, 500, + kTolerance, kMarkExcess, false); + ASSERT_TRUE(result.success); + EXPECT_EQ(0b11010, result.data); // Bits reversed of the previous test. + EXPECT_EQ(10, result.used); irsend.reset(); irsend.sendRaw(mark_encoded_raw, 11, 38000); irsend.makeDecodeResult(); + // MSBF order. result = irrecv.matchData(irsend.capture.rawbuf + 1, 5, 1000, 500, 500, 500); ASSERT_FALSE(result.success); + // LSBF order. + result = irrecv.matchData(irsend.capture.rawbuf + 1, 5, 1000, 500, 500, 500, + kTolerance, kMarkExcess, false); + ASSERT_FALSE(result.success); } // Test matchData() on "equal total bit time" encoded data. @@ -516,14 +515,8 @@ TEST(TestMatchData, EqualTotalBitTimeEncoded) { IRrecv irrecv(1); irsend.begin(); - uint16_t equal_encoded_raw[11] = { - 500, 1500, - 1500, 500, - 499, 1499, - 1501, 501, - 1499, 490, - 500 - }; + uint16_t equal_encoded_raw[11] = {500, 1500, 1500, 500, 499, 1499, + 1501, 501, 1499, 490, 500}; match_result_t result; irsend.reset(); @@ -547,21 +540,15 @@ TEST(TestMatchData, ArbitraryEncoded) { IRrecv irrecv(1); irsend.begin(); - uint16_t arbitrary_encoded_raw[11] = { - 500, 1500, - 3000, 1000, - 499, 1499, - 3001, 1001, - 2999, 990, - 500 - }; + uint16_t arbitrary_encoded_raw[11] = {500, 1500, 3000, 1000, 499, 1499, + 3001, 1001, 2999, 990, 500}; match_result_t result; irsend.reset(); irsend.sendRaw(arbitrary_encoded_raw, 11, 38000); irsend.makeDecodeResult(); - result = irrecv.matchData(irsend.capture.rawbuf + 1, 5, - 3000, 1000, 500, 1500); + result = + irrecv.matchData(irsend.capture.rawbuf + 1, 5, 3000, 1000, 500, 1500); ASSERT_TRUE(result.success); EXPECT_EQ(0b01011, result.data); EXPECT_EQ(10, result.used); diff --git a/lib/IRremoteESP8266/test/IRrecv_test.h b/lib/IRremoteESP8266/test/IRrecv_test.h index 0ef2bab..bb366c1 100644 --- a/lib/IRremoteESP8266/test/IRrecv_test.h +++ b/lib/IRremoteESP8266/test/IRrecv_test.h @@ -8,7 +8,10 @@ #include #include "IRutils.h" -#define EXPECT_STATE_EQ(a, b, c) for (uint8_t i = 0; i < c / 8; ++i) {\ - EXPECT_EQ(a[i], b[i]) << "Expected state "\ - "differs at i = " << uint64ToString(i); } +#define EXPECT_STATE_EQ(a, b, c) \ + for (uint8_t i = 0; i < c / 8; ++i) { \ + EXPECT_EQ(a[i], b[i]) << "Expected state " \ + "differs at i = " \ + << uint64ToString(i); \ + } #endif // TEST_IRRECV_TEST_H_ diff --git a/lib/IRremoteESP8266/test/IRsend_test.cpp b/lib/IRremoteESP8266/test/IRsend_test.cpp index ecd785a..3536399 100644 --- a/lib/IRremoteESP8266/test/IRsend_test.cpp +++ b/lib/IRremoteESP8266/test/IRsend_test.cpp @@ -44,11 +44,12 @@ TEST(TestSendData, SendTypicalData) { EXPECT_EQ("m1s2m3s4m1s2m3s4m1s2m1s2m3s4m3s4m1s2m1s2m1s2m1s2m3s4m3s4m3s4m3s4", irsend.outputStr()); irsend.sendData(1, 2, 3, 4, 0x1234567890ABCDEF, 64, true); - EXPECT_EQ("m3s4m3s4m3s4m1s2m3s4m3s4m1s2m3s4m3s4m3s4m1s2m1s2m3s4m1s2m3s4m3s4" - "m3s4m1s2m3s4m1s2m3s4m1s2m1s2m3s4m3s4m1s2m1s2m1s2m1s2m3s4m3s4m3s4" - "m1s2m3s4m3s4m1s2m3s4m3s4m3s4m3s4m1s2m3s4m1s2m3s4m1s2m3s4m1s2m1s2" - "m1s2m1s2m3s4m3s4m1s2m1s2m3s4m1s2m1s2m1s2m1s2m3s4m1s2m1s2m1s2m1s2", - irsend.outputStr()); + EXPECT_EQ( + "m3s4m3s4m3s4m1s2m3s4m3s4m1s2m3s4m3s4m3s4m1s2m1s2m3s4m1s2m3s4m3s4" + "m3s4m1s2m3s4m1s2m3s4m1s2m1s2m3s4m3s4m1s2m1s2m1s2m1s2m3s4m3s4m3s4" + "m1s2m3s4m3s4m1s2m3s4m3s4m3s4m3s4m1s2m3s4m1s2m3s4m1s2m3s4m1s2m1s2" + "m1s2m1s2m3s4m3s4m1s2m1s2m3s4m1s2m1s2m1s2m1s2m3s4m1s2m1s2m1s2m1s2", + irsend.outputStr()); } // Test sending more than expected bits. @@ -56,12 +57,13 @@ TEST(TestSendData, SendOverLargeData) { IRsendTest irsend(4); irsend.begin(); irsend.sendData(1, 2, 3, 4, 0xFFFFFFFFFFFFFFFF, 70, true); - EXPECT_EQ("m3s4m3s4m3s4m3s4m3s4m3s4" - "m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2" - "m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2" - "m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2" - "m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2", - irsend.outputStr()); + EXPECT_EQ( + "m3s4m3s4m3s4m3s4m3s4m3s4" + "m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2" + "m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2" + "m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2" + "m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2", + irsend.outputStr()); } // Test inverting the output. @@ -81,13 +83,13 @@ TEST(TestSendRaw, GeneralUse) { irsend.begin(); // NEC C3E0E0E8 as measured in #204 - uint16_t rawData[67] = {8950, 4500, 550, 1650, 600, 1650, 550, 550, 600, 500, - 600, 550, 550, 550, 600, 1650, 550, 1650, 600, 1650, - 600, 1650, 550, 1700, 550, 550, 600, 550, 550, 550, - 600, 500, 600, 550, 550, 1650, 600, 1650, 600, 1650, - 550, 550, 600, 500, 600, 500, 600, 550, 550, 550, - 600, 1650, 550, 1650, 600, 1650, 600, 500, 650, 1600, - 600, 500, 600, 550, 550, 550, 600}; + uint16_t rawData[67] = { + 8950, 4500, 550, 1650, 600, 1650, 550, 550, 600, 500, 600, 550, + 550, 550, 600, 1650, 550, 1650, 600, 1650, 600, 1650, 550, 1700, + 550, 550, 600, 550, 550, 550, 600, 500, 600, 550, 550, 1650, + 600, 1650, 600, 1650, 550, 550, 600, 500, 600, 500, 600, 550, + 550, 550, 600, 1650, 550, 1650, 600, 1650, 600, 500, 650, 1600, + 600, 500, 600, 550, 550, 550, 600}; irsend.sendRaw(rawData, 67, 38); EXPECT_EQ( @@ -96,12 +98,13 @@ TEST(TestSendRaw, GeneralUse) { "m600s1650m600s1650m550s1700m550s550m600s550m550s550m600s500m600s550" "m550s1650m600s1650m600s1650m550s550m600s500m600s500m600s550m550s550" "m600s1650m550s1650m600s1650m600s500m650s1600m600s500m600s550m550s550" - "m600", irsend.outputStr()); + "m600", + irsend.outputStr()); irsend.reset(); irsend.sendRaw(rawData, 67, 38); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodeNEC(&irsend.capture, NEC_BITS, false)); + ASSERT_TRUE(irrecv.decodeNEC(&irsend.capture, kNECBits, false)); EXPECT_EQ(NEC, irsend.capture.decode_type); EXPECT_EQ(32, irsend.capture.bits); EXPECT_EQ(0xC3E0E0E8, irsend.capture.value); @@ -111,7 +114,8 @@ TEST(TestSendRaw, GeneralUse) { "m600s1650m600s1650m550s1700m550s550m600s550m550s550m600s500m600s550" "m550s1650m600s1650m600s1650m550s550m600s500m600s500m600s550m550s550" "m600s1650m550s1650m600s1650m600s500m650s1600m600s500m600s550m550s550" - "m600", irsend.outputStr()); + "m600", + irsend.outputStr()); } // Incorrect handling of decodes from Raw. i.e. There is no gap recorded at @@ -124,18 +128,18 @@ TEST(TestSendRaw, NoTrailingGap) { irsend.begin(); irsend.reset(); - uint16_t rawData[67] = {9000, 4500, 650, 550, 650, 1650, 600, 550, 650, 550, - 600, 1650, 650, 550, 600, 1650, 650, 1650, 650, 1650, - 600, 550, 650, 1650, 650, 1650, 650, 550, 600, 1650, - 650, 1650, 650, 550, 650, 550, 650, 1650, 650, 550, - 650, 550, 650, 550, 600, 550, 650, 550, 650, 550, - 650, 1650, 600, 550, 650, 1650, 650, 1650, 650, 1650, - 650, 1650, 650, 1650, 650, 1650, 600}; + uint16_t rawData[67] = { + 9000, 4500, 650, 550, 650, 1650, 600, 550, 650, 550, 600, 1650, + 650, 550, 600, 1650, 650, 1650, 650, 1650, 600, 550, 650, 1650, + 650, 1650, 650, 550, 600, 1650, 650, 1650, 650, 550, 650, 550, + 650, 1650, 650, 550, 650, 550, 650, 550, 600, 550, 650, 550, + 650, 550, 650, 1650, 600, 550, 650, 1650, 650, 1650, 650, 1650, + 650, 1650, 650, 1650, 650, 1650, 600}; irsend.sendRaw(rawData, 67, 38); irsend.makeDecodeResult(); EXPECT_TRUE(irrecv.decodeNEC(&irsend.capture)); EXPECT_EQ(NEC, irsend.capture.decode_type); - EXPECT_EQ(NEC_BITS, irsend.capture.bits); + EXPECT_EQ(kNECBits, irsend.capture.bits); } TEST(TestLowLevelSend, MarkFrequencyModulationAt38kHz) { diff --git a/lib/IRremoteESP8266/test/IRsend_test.h b/lib/IRremoteESP8266/test/IRsend_test.h index 2f7660e..6d9fe51 100644 --- a/lib/IRremoteESP8266/test/IRsend_test.h +++ b/lib/IRremoteESP8266/test/IRsend_test.h @@ -20,32 +20,29 @@ uint32_t _IRtimer_unittest_now = 0; #endif // UNIT_TEST -class IRsendTest: public IRsend { +class IRsendTest : public IRsend { public: uint32_t output[OUTPUT_BUF]; uint16_t last; uint16_t rawbuf[RAW_BUF]; decode_results capture; - explicit IRsendTest(uint16_t x, bool i = false, bool j = true) : - IRsend(x, i, j) { + explicit IRsendTest(uint16_t x, bool i = false, bool j = true) + : IRsend(x, i, j) { reset(); } void reset() { last = 0; - for (uint16_t i = 0; i < OUTPUT_BUF; i++) - output[i] = 0; - for (uint16_t i = 0; i < RAW_BUF; i++) - rawbuf[i] = 0; + for (uint16_t i = 0; i < OUTPUT_BUF; i++) output[i] = 0; + for (uint16_t i = 0; i < RAW_BUF; i++) rawbuf[i] = 0; } std::string outputStr() { std::stringstream result; - if (last == 0 && output[0] == 0) - return ""; + if (last == 0 && output[0] == 0) return ""; for (uint16_t i = 0; i <= last; i++) { - if ((i & 1) != outputOff ) // Odd XOR outputOff + if ((i & 1) != outputOff) // Odd XOR outputOff result << "s"; else result << "m"; @@ -59,45 +56,38 @@ class IRsendTest: public IRsend { capture.decode_type = UNKNOWN; capture.bits = 0; capture.rawlen = last + 2 - offset; - capture.overflow = (last - offset >= (int16_t) RAW_BUF); + capture.overflow = (last - offset >= (int16_t)RAW_BUF); capture.repeat = false; capture.address = 0; capture.command = 0; capture.value = 0; capture.rawbuf = rawbuf; - for (uint16_t i = 0; - (i < RAW_BUF - 1) && (offset < OUTPUT_BUF); + for (uint16_t i = 0; (i < RAW_BUF - 1) && (offset < OUTPUT_BUF); i++, offset++) - if (output[offset] / RAWTICK > UINT16_MAX) + if (output[offset] / kRawTick > UINT16_MAX) rawbuf[i + 1] = UINT16_MAX; else - rawbuf[i + 1] = output[offset] / RAWTICK; + rawbuf[i + 1] = output[offset] / kRawTick; } void dumpRawResult() { std::cout << std::dec; if (capture.rawlen == 0) return; - std::cout << "uint16_t rawbuf["<< capture.rawlen - 1 << "] = {"; + std::cout << "uint16_t rawbuf[" << capture.rawlen - 1 << "] = {"; for (uint16_t i = 1; i < capture.rawlen; i++) { - if (i % 8 == 1) - std::cout << std::endl << " "; - std::cout << (capture.rawbuf[i] * RAWTICK); + if (i % 8 == 1) std::cout << std::endl << " "; + std::cout << (capture.rawbuf[i] * kRawTick); // std::cout << "(" << capture.rawbuf[i] << ")"; - if (i < capture.rawlen - 1) - std::cout << ", "; + if (i < capture.rawlen - 1) std::cout << ", "; } std::cout << "};" << std::endl; } - void addGap(uint32_t usecs) { - space(usecs); - } + void addGap(uint32_t usecs) { space(usecs); } - protected: uint16_t mark(uint16_t usec) { IRtimer::add(usec); - if (last >= OUTPUT_BUF) - return 0; + if (last >= OUTPUT_BUF) return 0; if (last & 1) // Is odd? (i.e. last call was a space()) output[++last] = usec; else @@ -107,8 +97,7 @@ class IRsendTest: public IRsend { void space(uint32_t time) { IRtimer::add(time); - if (last >= OUTPUT_BUF) - return; + if (last >= OUTPUT_BUF) return; if (last & 1) { // Is odd? (i.e. last call was a space()) output[last] += time; } else { @@ -118,18 +107,16 @@ class IRsendTest: public IRsend { }; #ifdef UNIT_TEST -class IRsendLowLevelTest: public IRsend { +class IRsendLowLevelTest : public IRsend { public: std::string low_level_sequence; - explicit IRsendLowLevelTest(uint16_t x, bool i = false, bool j = true) : - IRsend(x, i, j) { + explicit IRsendLowLevelTest(uint16_t x, bool i = false, bool j = true) + : IRsend(x, i, j) { reset(); } - void reset() { - low_level_sequence = ""; - } + void reset() { low_level_sequence = ""; } protected: void _delayMicroseconds(uint32_t usec) { @@ -139,13 +126,9 @@ class IRsendLowLevelTest: public IRsend { low_level_sequence += Convert.str() + "usecs"; } - void ledOff() { - low_level_sequence += "[Off]"; - } + void ledOff() { low_level_sequence += "[Off]"; } - void ledOn() { - low_level_sequence += "[On]"; - } + void ledOn() { low_level_sequence += "[On]"; } }; #endif // UNIT_TEST diff --git a/lib/IRremoteESP8266/test/IRutils_test.cpp b/lib/IRremoteESP8266/test/IRutils_test.cpp index edec177..57eceed 100644 --- a/lib/IRremoteESP8266/test/IRutils_test.cpp +++ b/lib/IRremoteESP8266/test/IRutils_test.cpp @@ -41,14 +41,14 @@ TEST(ReverseBitsTest, LessBitsReversedThanInputHasSet) { // Tests for uint64ToString() TEST(TestUint64ToString, TrivialCases) { - EXPECT_EQ("0", uint64ToString(0)); // Default base (10) - EXPECT_EQ("0", uint64ToString(0, 2)); // Base-2 - EXPECT_EQ("0", uint64ToString(0, 8)); // Base-8 + EXPECT_EQ("0", uint64ToString(0)); // Default base (10) + EXPECT_EQ("0", uint64ToString(0, 2)); // Base-2 + EXPECT_EQ("0", uint64ToString(0, 8)); // Base-8 EXPECT_EQ("0", uint64ToString(0, 10)); // Base-10 EXPECT_EQ("0", uint64ToString(0, 16)); // Base-16 - EXPECT_EQ("1", uint64ToString(1, 2)); // Base-2 - EXPECT_EQ("2", uint64ToString(2, 8)); // Base-8 + EXPECT_EQ("1", uint64ToString(1, 2)); // Base-2 + EXPECT_EQ("2", uint64ToString(2, 8)); // Base-8 EXPECT_EQ("3", uint64ToString(3, 10)); // Base-10 EXPECT_EQ("4", uint64ToString(4, 16)); // Base-16 } @@ -65,17 +65,17 @@ TEST(TestUint64ToString, NormalUse) { TEST(TestUint64ToString, Max64Bit) { EXPECT_EQ("18446744073709551615", uint64ToString(UINT64_MAX)); // Default EXPECT_EQ("1111111111111111111111111111111111111111111111111111111111111111", - uint64ToString(UINT64_MAX, 2)); // Base-2 + uint64ToString(UINT64_MAX, 2)); // Base-2 EXPECT_EQ("1777777777777777777777", uint64ToString(UINT64_MAX, 8)); // Base-8 EXPECT_EQ("18446744073709551615", uint64ToString(UINT64_MAX, 10)); // Base-10 - EXPECT_EQ("FFFFFFFFFFFFFFFF", uint64ToString(UINT64_MAX, 16)); // Base-16 + EXPECT_EQ("FFFFFFFFFFFFFFFF", uint64ToString(UINT64_MAX, 16)); // Base-16 } TEST(TestUint64ToString, Max32Bit) { - EXPECT_EQ("4294967295", uint64ToString(UINT32_MAX)); // Default + EXPECT_EQ("4294967295", uint64ToString(UINT32_MAX)); // Default EXPECT_EQ("37777777777", uint64ToString(UINT32_MAX, 8)); // Base-8 EXPECT_EQ("4294967295", uint64ToString(UINT32_MAX, 10)); // Base-10 - EXPECT_EQ("FFFFFFFF", uint64ToString(UINT32_MAX, 16)); // Base-16 + EXPECT_EQ("FFFFFFFF", uint64ToString(UINT32_MAX, 16)); // Base-16 } TEST(TestUint64ToString, InterestingCases) { @@ -89,8 +89,8 @@ TEST(TestUint64ToString, SillyBases) { EXPECT_EQ("12345", uint64ToString(12345, 0)); // Super silly, makes no sense. EXPECT_EQ("12345", uint64ToString(12345, 1)); // We don't do unary. EXPECT_EQ("12345", uint64ToString(12345, 100)); // We can't print base-100. - EXPECT_EQ("12345", uint64ToString(12345, 37)); // Base-37 is one to far. - EXPECT_EQ("9IX", uint64ToString(12345, 36)); // But we *can* do base-36. + EXPECT_EQ("12345", uint64ToString(12345, 37)); // Base-37 is one to far. + EXPECT_EQ("9IX", uint64ToString(12345, 36)); // But we *can* do base-36. } TEST(TestGetCorrectedRawLength, NoLargeValues) { @@ -115,7 +115,7 @@ TEST(TestGetCorrectedRawLength, WithLargeValues) { irsend.makeDecodeResult(); irrecv.decode(&irsend.capture); irsend.capture.rawbuf[3] = 60000; - ASSERT_EQ(2, RAWTICK); // The following values rely on RAWTICK being 2. + ASSERT_EQ(2, kRawTick); // The following values rely on kRawTick being 2. EXPECT_EQ(7 + 2, getCorrectedRawLength(&irsend.capture)); irsend.capture.rawbuf[4] = UINT16_MAX - 1; EXPECT_EQ(7 + 2 * 2, getCorrectedRawLength(&irsend.capture)); @@ -132,18 +132,22 @@ TEST(TestResultToSourceCode, SimpleTests) { irsend.sendRaw(test_data, 7, 38000); irsend.makeDecodeResult(); irrecv.decode(&irsend.capture); - EXPECT_EQ("uint16_t rawData[7] = {10, 20, 30, 40, 50, 60, 70};" - " // UNKNOWN A5E5F35D\n", resultToSourceCode(&irsend.capture)); + EXPECT_EQ( + "uint16_t rawData[7] = {10, 20, 30, 40, 50, 60, 70};" + " // UNKNOWN A5E5F35D\n", + resultToSourceCode(&irsend.capture)); // Stick in some large values. irsend.capture.rawbuf[3] = 60000; - EXPECT_EQ("uint16_t rawData[9] = {10, 20, 65535, 0, 54465, 40," - " 50, 60, 70}; // UNKNOWN A5E5F35D\n", - resultToSourceCode(&irsend.capture)); + EXPECT_EQ( + "uint16_t rawData[9] = {10, 20, 65535, 0, 54465, 40," + " 50, 60, 70}; // UNKNOWN A5E5F35D\n", + resultToSourceCode(&irsend.capture)); irsend.capture.rawbuf[5] = UINT16_MAX; - EXPECT_EQ("uint16_t rawData[11] = {10, 20, 65535, 0, 54465, 40," - " 65535, 0, 65535, 60, 70}; // UNKNOWN A5E5F35D\n", - resultToSourceCode(&irsend.capture)); + EXPECT_EQ( + "uint16_t rawData[11] = {10, 20, 65535, 0, 54465, 40," + " 65535, 0, 65535, 60, 70}; // UNKNOWN A5E5F35D\n", + resultToSourceCode(&irsend.capture)); // Reset and put the large value in a space location. irsend.reset(); @@ -151,9 +155,10 @@ TEST(TestResultToSourceCode, SimpleTests) { irsend.makeDecodeResult(); irrecv.decode(&irsend.capture); irsend.capture.rawbuf[4] = UINT16_MAX - 1; - EXPECT_EQ("uint16_t rawData[9] = {10, 20, 30, 65535, 0, 65533," - " 50, 60, 70}; // UNKNOWN A5E5F35D\n", - resultToSourceCode(&irsend.capture)); + EXPECT_EQ( + "uint16_t rawData[9] = {10, 20, 30, 65535, 0, 65533," + " 50, 60, 70}; // UNKNOWN A5E5F35D\n", + resultToSourceCode(&irsend.capture)); } TEST(TestResultToSourceCode, SimpleProtocols) { @@ -167,7 +172,7 @@ TEST(TestResultToSourceCode, SimpleProtocols) { irsend.makeDecodeResult(); ASSERT_TRUE(irrecv.decode(&irsend.capture)); ASSERT_EQ(NEC, irsend.capture.decode_type); - ASSERT_EQ(NEC_BITS, irsend.capture.bits); + ASSERT_EQ(kNECBits, irsend.capture.bits); EXPECT_EQ( "uint16_t rawData[68] = {8960, 4480, 560, 560, 560, 560, 560, 560, " "560, 560, 560, 1680, 560, 560, 560, 560, 560, 560, 560, 1680, " @@ -178,7 +183,8 @@ TEST(TestResultToSourceCode, SimpleProtocols) { "}; // NEC 8F704FB\n" "uint32_t address = 0x10;\n" "uint32_t command = 0x20;\n" - "uint64_t data = 0x8F704FB;\n", resultToSourceCode(&irsend.capture)); + "uint64_t data = 0x8F704FB;\n", + resultToSourceCode(&irsend.capture)); // Generate a code which DOESN'T have address & command values. irsend.reset(); @@ -186,7 +192,7 @@ TEST(TestResultToSourceCode, SimpleProtocols) { irsend.makeDecodeResult(); ASSERT_TRUE(irrecv.decode(&irsend.capture)); ASSERT_EQ(NIKAI, irsend.capture.decode_type); - ASSERT_EQ(NIKAI_BITS, irsend.capture.bits); + ASSERT_EQ(kNikaiBits, irsend.capture.bits); EXPECT_EQ( "uint16_t rawData[52] = {4000, 4000, 500, 2000, 500, 2000, " "500, 2000, 500, 2000, 500, 1000, 500, 1000, 500, 2000, 500, 1000, " @@ -194,7 +200,8 @@ TEST(TestResultToSourceCode, SimpleProtocols) { "500, 1000, 500, 1000, 500, 2000, 500, 2000, 500, 1000, 500, 2000, " "500, 1000, 500, 1000, 500, 1000, 500, 1000, 500, 8500 };" " // NIKAI D0F2F\n" - "uint64_t data = 0xD0F2F;\n", resultToSourceCode(&irsend.capture)); + "uint64_t data = 0xD0F2F;\n", + resultToSourceCode(&irsend.capture)); } TEST(TestResultToSourceCode, ComplexProtocols) { @@ -202,15 +209,15 @@ TEST(TestResultToSourceCode, ComplexProtocols) { IRrecv irrecv(1); irsend.begin(); - uint8_t state[TOSHIBA_AC_STATE_LENGTH] = { - 0xF2, 0x0D, 0x03, 0xFC, 0x01, 0x00, 0x00, 0x00, 0x01}; + uint8_t state[kToshibaACStateLength] = {0xF2, 0x0D, 0x03, 0xFC, 0x01, + 0x00, 0x00, 0x00, 0x01}; irsend.reset(); irsend.sendToshibaAC(state); irsend.makeDecodeResult(); ASSERT_TRUE(irrecv.decode(&irsend.capture)); ASSERT_EQ(TOSHIBA_AC, irsend.capture.decode_type); - ASSERT_EQ(TOSHIBA_AC_BITS, irsend.capture.bits); + ASSERT_EQ(kToshibaACBits, irsend.capture.bits); EXPECT_EQ( "uint16_t rawData[296] = {4400, 4300, 542, 1622, 542, 1622, " "542, 1622, 542, 1622, 542, 472, 542, 472, 542, 1622, 542, 472, " @@ -239,7 +246,8 @@ TEST(TestResultToSourceCode, ComplexProtocols) { "542, 472, 542, 472, 542, 472, 542, 472, 542, 472, 542, 1622, " "542, 7048 }; // TOSHIBA_AC\n" "uint8_t state[9] = {0xF2, 0x0D, 0x03, 0xFC, 0x01, 0x00, 0x00, 0x00, " - "0x01};\n", resultToSourceCode(&irsend.capture)); + "0x01};\n", + resultToSourceCode(&irsend.capture)); } TEST(TestResultToTimingInfo, General) { @@ -252,7 +260,7 @@ TEST(TestResultToTimingInfo, General) { irsend.makeDecodeResult(); ASSERT_TRUE(irrecv.decode(&irsend.capture)); ASSERT_EQ(NEC, irsend.capture.decode_type); - ASSERT_EQ(NEC_BITS, irsend.capture.bits); + ASSERT_EQ(kNECBits, irsend.capture.bits); EXPECT_EQ( "Raw Timing[68]:\n" " + 8960, - 4480, + 560, - 560, + 560, - 560," @@ -297,7 +305,7 @@ TEST(TestResultToHumanReadableBasic, SimpleCodes) { irsend.makeDecodeResult(); ASSERT_TRUE(irrecv.decode(&irsend.capture)); ASSERT_EQ(NEC, irsend.capture.decode_type); - ASSERT_EQ(NEC_BITS, irsend.capture.bits); + ASSERT_EQ(kNECBits, irsend.capture.bits); EXPECT_EQ( "Encoding : NEC\n" "Code : 8F704FB (32 bits)\n", @@ -309,16 +317,15 @@ TEST(TestResultToHumanReadableBasic, ComplexCodes) { IRrecv irrecv(1); irsend.begin(); - - uint8_t state[TOSHIBA_AC_STATE_LENGTH] = { - 0xF2, 0x0D, 0x03, 0xFC, 0x01, 0x00, 0x00, 0x00, 0x01}; + uint8_t state[kToshibaACStateLength] = {0xF2, 0x0D, 0x03, 0xFC, 0x01, + 0x00, 0x00, 0x00, 0x01}; irsend.reset(); irsend.sendToshibaAC(state); irsend.makeDecodeResult(); ASSERT_TRUE(irrecv.decode(&irsend.capture)); ASSERT_EQ(TOSHIBA_AC, irsend.capture.decode_type); - ASSERT_EQ(TOSHIBA_AC_BITS, irsend.capture.bits); + ASSERT_EQ(kToshibaACBits, irsend.capture.bits); EXPECT_EQ( "Encoding : TOSHIBA_AC\n" "Code : F20D03FC0100000001 (72 bits)\n", @@ -343,3 +350,48 @@ TEST(TestInvertBits, MoreThan64Bits) { ASSERT_EQ(0xAAAA5555AAAA5555, invertBits(0x5555AAAA5555AAAA, 70)); ASSERT_EQ(0xFFFFFFFFFFFFFFFF, invertBits(0x0, 128)); } + +TEST(TestCountBits, Pointer) { + uint8_t data[14] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}; + + ASSERT_EQ(0, countBits(data, 0)); + ASSERT_EQ(0, countBits(data, 1)); + ASSERT_EQ(0, countBits(data, 1, true)); + ASSERT_EQ(8, countBits(data, 1, false)); + ASSERT_EQ(1, countBits(data, 2)); + ASSERT_EQ(15, countBits(data, 2, false)); + ASSERT_EQ(1, countBits(data + 1, 1)); + ASSERT_EQ(2, countBits(data, 3)); + ASSERT_EQ(4, countBits(data, 4)); + ASSERT_EQ(25, countBits(data, 14)); + ASSERT_EQ(25, countBits(data, 14)); + ASSERT_EQ(14 * 8, countBits(data, 14, true) + countBits(data, 14, false)); + ASSERT_EQ(125, countBits(data, 14, true, 100)); +} + +TEST(TestCountBits, Integer) { + uint64_t data = 0xAAAAAAAAAAAAAAAA; + + ASSERT_EQ(0, countBits(data, 0)); + ASSERT_EQ(0, countBits(data, 1)); + ASSERT_EQ(0, countBits(data, 1, true)); + ASSERT_EQ(1, countBits(data, 1, false)); + ASSERT_EQ(1, countBits(data, 3)); + ASSERT_EQ(2, countBits(data, 3, false)); + ASSERT_EQ(4, countBits(data, 8)); + ASSERT_EQ(4, countBits(data, 8, false)); + ASSERT_EQ(32, countBits(data, 64)); + ASSERT_EQ(32, countBits(data, 64, false)); + + data = 0; + ASSERT_EQ(0, countBits(data, 1, true)); + ASSERT_EQ(1, countBits(data, 1, false)); + ASSERT_EQ(0, countBits(data, 64)); + ASSERT_EQ(64, countBits(data, 64, false)); + + data = 0xFFFFFFFFFFFFFFFF; + ASSERT_EQ(1, countBits(data, 1, true)); + ASSERT_EQ(0, countBits(data, 1, false)); + ASSERT_EQ(64, countBits(data, 64)); + ASSERT_EQ(0, countBits(data, 64, false)); +} diff --git a/lib/IRremoteESP8266/test/Makefile b/lib/IRremoteESP8266/test/Makefile index 17b8611..c684b5e 100644 --- a/lib/IRremoteESP8266/test/Makefile +++ b/lib/IRremoteESP8266/test/Makefile @@ -34,7 +34,9 @@ TESTS = IRutils_test IRsend_test ir_NEC_test ir_GlobalCache_test \ ir_Aiwa_test ir_Denon_test ir_Sanyo_test ir_Daikin_test ir_Coolix_test \ ir_Gree_test IRrecv_test ir_Pronto_test ir_Fujitsu_test ir_Nikai_test \ ir_Toshiba_test ir_Midea_test ir_Magiquest_test ir_Lasertag_test \ - ir_Carrier_test ir_Haier_test ir_Hitachi_test ir_GICable_test + ir_Carrier_test ir_Haier_test ir_Hitachi_test ir_GICable_test \ + ir_Whirlpool_test ir_Lutron_test ir_Electra_test ir_Pioneer_test \ + ir_MWM_test ir_Vestel_test # All Google Test headers. Usually you shouldn't change this # definition. @@ -63,7 +65,7 @@ run : all run_tests : run install-googletest : - git clone https://github.com/google/googletest.git ../lib/googletest + git clone -b v1.8.x https://github.com/google/googletest.git ../lib/googletest # Builds gtest.a and gtest_main.a. @@ -73,18 +75,40 @@ GTEST_SRCS_ = $(GTEST_DIR)/src/*.cc $(GTEST_DIR)/src/*.h $(GTEST_HEADERS) # All the IR protocol object files. PROTOCOLS = ir_NEC.o ir_Sony.o ir_Samsung.o ir_JVC.o ir_RCMM.o ir_RC5_RC6.o \ - ir_LG.o ir_Mitsubishi.o ir_Fujitsu.o ir_Sharp.o ir_Sanyo.o ir_Denon.o ir_Dish.o \ - ir_Panasonic.o ir_Whynter.o ir_Coolix.o ir_Aiwa.o ir_Sherwood.o \ - ir_Kelvinator.o ir_Daikin.o ir_Gree.o ir_Pronto.o ir_Nikai.o ir_Toshiba.o \ - ir_Midea.o ir_Magiquest.o ir_Lasertag.o ir_Carrier.o ir_Haier.o \ - ir_Hitachi.o ir_GICable.o + ir_LG.o ir_Mitsubishi.o ir_Fujitsu.o ir_Sharp.o ir_Sanyo.o ir_Denon.o ir_Dish.o \ + ir_Panasonic.o ir_Whynter.o ir_Coolix.o ir_Aiwa.o ir_Sherwood.o \ + ir_Kelvinator.o ir_Daikin.o ir_Gree.o ir_Pronto.o ir_Nikai.o ir_Toshiba.o \ + ir_Midea.o ir_Magiquest.o ir_Lasertag.o ir_Carrier.o ir_Haier.o \ + ir_Hitachi.o ir_GICable.o ir_Whirlpool.o ir_Lutron.o ir_Electra.o \ + ir_Pioneer.o ir_MWM.o ir_Vestel.o +# All the IR Protocol header files. +PROTOCOLS_H = $(USER_DIR)/ir_Argo.h \ + $(USER_DIR)/ir_Gree.h \ + $(USER_DIR)/ir_Magiquest.h \ + $(USER_DIR)/ir_Coolix.h \ + $(USER_DIR)/ir_Haier.h \ + $(USER_DIR)/ir_Midea.h \ + $(USER_DIR)/ir_Toshiba.h \ + $(USER_DIR)/ir_Daikin.h \ + $(USER_DIR)/ir_Kelvinator.h \ + $(USER_DIR)/ir_Mitsubishi.h \ + $(USER_DIR)/ir_NEC.h \ + $(USER_DIR)/ir_Samsung.h \ + $(USER_DIR)/ir_Trotec.h \ + $(USER_DIR)/ir_Fujitsu.h \ + $(USER_DIR)/ir_LG.h \ + $(USER_DIR)/ir_Panasonic.h \ + $(USER_DIR)/ir_Whirlpool.h \ + $(USER_DIR)/ir_Vestel.h # Common object files COMMON_OBJ = IRutils.o IRtimer.o IRsend.o IRrecv.o ir_GlobalCache.o \ $(PROTOCOLS) gtest_main.a # Common dependencies COMMON_DEPS = $(USER_DIR)/IRrecv.h $(USER_DIR)/IRsend.h $(USER_DIR)/IRtimer.h \ - $(USER_DIR)/IRutils.h $(USER_DIR)/IRremoteESP8266.h + $(USER_DIR)/IRutils.h $(USER_DIR)/IRremoteESP8266.h \ + $(PROTOCOLS_H) + # Common test dependencies COMMON_TEST_DEPS = $(COMMON_DEPS) IRrecv_test.h IRsend_test.h @@ -140,7 +164,7 @@ IRrecv_test.o : IRrecv_test.cpp $(USER_DIR)/IRsend.h $(USER_DIR)/IRrecv.h IRsend IRrecv_test : IRrecv_test.o $(COMMON_OBJ) $(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@ -ir_NEC.o : $(USER_DIR)/ir_NEC.cpp $(COMMON_DEPS) +ir_NEC.o : $(USER_DIR)/ir_NEC.cpp $(USER_DIR)/ir_NEC.h $(COMMON_DEPS) $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_NEC.cpp ir_NEC_test.o : ir_NEC_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS) @@ -176,10 +200,10 @@ ir_Sony_test.o : ir_Sony_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS) ir_Sony_test : $(COMMON_OBJ) ir_Sony_test.o $(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@ -ir_Samsung.o : $(USER_DIR)/ir_Samsung.cpp $(COMMON_DEPS) +ir_Samsung.o : $(USER_DIR)/ir_Samsung.cpp $(USER_DIR)/ir_Samsung.h $(COMMON_DEPS) $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Samsung.cpp -ir_Samsung_test.o : ir_Samsung_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS) +ir_Samsung_test.o : ir_Samsung_test.cpp $(USER_DIR)/ir_Samsung.h $(COMMON_TEST_DEPS) $(GTEST_HEADERS) $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_Samsung_test.cpp ir_Samsung_test : $(COMMON_OBJ) ir_Samsung_test.o @@ -287,7 +311,7 @@ ir_Whynter_test : $(COMMON_OBJ) ir_Whynter_test.o ir_Coolix.o : $(USER_DIR)/ir_Coolix.cpp $(COMMON_DEPS) $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Coolix.cpp -ir_Coolix_test.o : ir_Coolix_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS) +ir_Coolix_test.o : ir_Coolix_test.cpp $(USER_DIR)/ir_Coolix.h $(COMMON_TEST_DEPS) $(GTEST_HEADERS) $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_Coolix_test.cpp ir_Coolix_test : $(COMMON_OBJ) ir_Coolix_test.o @@ -427,3 +451,57 @@ ir_GICable_test.o : ir_GICable_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS) ir_GICable_test : $(COMMON_OBJ) ir_GICable_test.o $(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@ + +ir_Whirlpool.o : $(USER_DIR)/ir_Whirlpool.cpp $(COMMON_DEPS) $(GTEST_HEADERS) + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Whirlpool.cpp + +ir_Whirlpool_test.o : ir_Whirlpool_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS) + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_Whirlpool_test.cpp + +ir_Whirlpool_test : $(COMMON_OBJ) ir_Whirlpool_test.o + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@ + +ir_Lutron.o : $(USER_DIR)/ir_Lutron.cpp $(COMMON_DEPS) $(GTEST_HEADERS) + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Lutron.cpp + +ir_Lutron_test.o : ir_Lutron_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS) + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_Lutron_test.cpp + +ir_Lutron_test : $(COMMON_OBJ) ir_Lutron_test.o + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@ + +ir_Electra.o : $(USER_DIR)/ir_Electra.cpp $(COMMON_DEPS) $(GTEST_HEADERS) + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Electra.cpp + +ir_Electra_test.o : ir_Electra_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS) + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_Electra_test.cpp + +ir_Electra_test : $(COMMON_OBJ) ir_Electra_test.o + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@ + +ir_Pioneer.o : $(USER_DIR)/ir_Pioneer.cpp $(COMMON_DEPS) $(GTEST_HEADERS) + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Pioneer.cpp + +ir_Pioneer_test.o : ir_Pioneer_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS) + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_Pioneer_test.cpp + +ir_Pioneer_test : $(COMMON_OBJ) ir_Pioneer_test.o + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@ + +ir_MWM.o : $(USER_DIR)/ir_MWM.cpp $(COMMON_DEPS) + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_MWM.cpp + +ir_MWM_test.o : ir_MWM_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS) + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_MWM_test.cpp + +ir_MWM_test : $(COMMON_OBJ) ir_MWM_test.o + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@ + +ir_Vestel.o : $(USER_DIR)/ir_Vestel.cpp $(COMMON_DEPS) + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Vestel.cpp + +ir_Vestel_test.o : ir_Vestel_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS) + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_Vestel_test.cpp + +ir_Vestel_test : $(COMMON_OBJ) ir_Vestel_test.o + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@ diff --git a/lib/IRremoteESP8266/test/ir_Aiwa_test.cpp b/lib/IRremoteESP8266/test/ir_Aiwa_test.cpp index 2c533e8..c5469d4 100644 --- a/lib/IRremoteESP8266/test/ir_Aiwa_test.cpp +++ b/lib/IRremoteESP8266/test/ir_Aiwa_test.cpp @@ -21,7 +21,8 @@ TEST(TestSendAiwa, SendDataOnly) { "m560s1680m560s1680m560s560m560s560m560s560m560s560m560s560m560s560" "m560s560m560s560m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680" "m560s1680m560s1680m560s23520" - "m8960s2240m560s96320", irsend.outputStr()); + "m8960s2240m560s96320", + irsend.outputStr()); } // Test sending oversized data. @@ -40,7 +41,7 @@ TEST(TestSendAiwa, SendWithRepeats) { irsend.begin(); irsend.reset(); - irsend.sendAiwaRCT501(0x7F, AIWA_RC_T501_BITS, 0); // No repeats. + irsend.sendAiwaRCT501(0x7F, kAiwaRcT501Bits, 0); // No repeats. EXPECT_EQ( "m8960s4480" "m560s560m560s1680m560s1680m560s1680m560s560m560s1680m560s1680m560s560" @@ -48,9 +49,10 @@ TEST(TestSendAiwa, SendWithRepeats) { "m560s560m560s1680m560s560m560s560m560s1680m560s1680m560s1680m560s1680" "m560s1680m560s1680m560s560m560s560m560s560m560s560m560s560m560s560" "m560s560m560s560m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680" - "m560s1680m560s1680m560s23520", irsend.outputStr()); + "m560s1680m560s1680m560s23520", + irsend.outputStr()); irsend.reset(); - irsend.sendAiwaRCT501(0x7F, AIWA_RC_T501_BITS, 1); // 1 repeat. + irsend.sendAiwaRCT501(0x7F, kAiwaRcT501Bits, 1); // 1 repeat. EXPECT_EQ( "m8960s4480" "m560s560m560s1680m560s1680m560s1680m560s560m560s1680m560s1680m560s560" @@ -59,9 +61,10 @@ TEST(TestSendAiwa, SendWithRepeats) { "m560s1680m560s1680m560s560m560s560m560s560m560s560m560s560m560s560" "m560s560m560s560m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680" "m560s1680m560s1680m560s23520" - "m8960s2240m560s96320", irsend.outputStr()); + "m8960s2240m560s96320", + irsend.outputStr()); irsend.reset(); - irsend.sendAiwaRCT501(0x7F, AIWA_RC_T501_BITS, 2); // 2 repeats. + irsend.sendAiwaRCT501(0x7F, kAiwaRcT501Bits, 2); // 2 repeats. EXPECT_EQ( "m8960s4480" "m560s560m560s1680m560s1680m560s1680m560s560m560s1680m560s1680m560s560" @@ -71,7 +74,8 @@ TEST(TestSendAiwa, SendWithRepeats) { "m560s560m560s560m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680" "m560s1680m560s1680m560s23520" "m8960s2240m560s96320" - "m8960s2240m560s96320", irsend.outputStr()); + "m8960s2240m560s96320", + irsend.outputStr()); } // Test sending an atypical data size. @@ -88,7 +92,8 @@ TEST(TestSendAiwa, SendUnusualSize) { "m560s560m560s1680m560s560m560s560m560s1680m560s1680m560s1680m560s1680" "m560s1680m560s1680m560s560m560s560m560s560m560s1680m560s560m560s560" "m560s1680m560s560m560s1680m560s36960" - "m8960s2240m560s96320", irsend.outputStr()); + "m8960s2240m560s96320", + irsend.outputStr()); irsend.reset(); irsend.sendAiwaRCT501(0x1234567890, 37); @@ -103,7 +108,8 @@ TEST(TestSendAiwa, SendUnusualSize) { "m560s1680m560s1680m560s1680m560s1680m560s560m560s560m560s560m560s1680" "m560s560m560s560m560s1680m560s560m560s560m560s560m560s560m560s1680" "m560s22400" - "m8960s2240m560s96320", irsend.outputStr()); + "m8960s2240m560s96320", + irsend.outputStr()); } // Tests for decodeAiwaRCT501(). @@ -118,10 +124,9 @@ TEST(TestDecodeAiwa, NormalDecodeWithStrict) { irsend.reset(); irsend.sendAiwaRCT501(0x7F); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodeAiwaRCT501(&irsend.capture, AIWA_RC_T501_BITS, - true)); + ASSERT_TRUE(irrecv.decodeAiwaRCT501(&irsend.capture, kAiwaRcT501Bits, true)); EXPECT_EQ(AIWA_RC_T501, irsend.capture.decode_type); - EXPECT_EQ(AIWA_RC_T501_BITS, irsend.capture.bits); + EXPECT_EQ(kAiwaRcT501Bits, irsend.capture.bits); EXPECT_EQ(0x7F, irsend.capture.value); EXPECT_EQ(0x0, irsend.capture.address); EXPECT_EQ(0x0, irsend.capture.command); @@ -131,10 +136,9 @@ TEST(TestDecodeAiwa, NormalDecodeWithStrict) { irsend.reset(); irsend.sendAiwaRCT501(0x0); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodeAiwaRCT501(&irsend.capture, AIWA_RC_T501_BITS, - true)); + ASSERT_TRUE(irrecv.decodeAiwaRCT501(&irsend.capture, kAiwaRcT501Bits, true)); EXPECT_EQ(AIWA_RC_T501, irsend.capture.decode_type); - EXPECT_EQ(AIWA_RC_T501_BITS, irsend.capture.bits); + EXPECT_EQ(kAiwaRcT501Bits, irsend.capture.bits); EXPECT_EQ(0x0, irsend.capture.value); EXPECT_EQ(0x0, irsend.capture.address); EXPECT_EQ(0x0, irsend.capture.command); @@ -144,10 +148,9 @@ TEST(TestDecodeAiwa, NormalDecodeWithStrict) { irsend.reset(); irsend.sendAiwaRCT501(0x7FFF); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodeAiwaRCT501(&irsend.capture, AIWA_RC_T501_BITS, - true)); + ASSERT_TRUE(irrecv.decodeAiwaRCT501(&irsend.capture, kAiwaRcT501Bits, true)); EXPECT_EQ(AIWA_RC_T501, irsend.capture.decode_type); - EXPECT_EQ(AIWA_RC_T501_BITS, irsend.capture.bits); + EXPECT_EQ(kAiwaRcT501Bits, irsend.capture.bits); EXPECT_EQ(0x7FFF, irsend.capture.value); EXPECT_EQ(0x0, irsend.capture.address); EXPECT_EQ(0x0, irsend.capture.command); @@ -162,12 +165,11 @@ TEST(TestDecodeAiwa, NormalDecodeWithRepeatAndStrict) { // Normal Aiwa 15-bit(42bit) message with 2 repeats. irsend.reset(); - irsend.sendAiwaRCT501(0x7F, AIWA_RC_T501_BITS, 2); + irsend.sendAiwaRCT501(0x7F, kAiwaRcT501Bits, 2); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodeAiwaRCT501(&irsend.capture, AIWA_RC_T501_BITS, - true)); + ASSERT_TRUE(irrecv.decodeAiwaRCT501(&irsend.capture, kAiwaRcT501Bits, true)); EXPECT_EQ(AIWA_RC_T501, irsend.capture.decode_type); - EXPECT_EQ(AIWA_RC_T501_BITS, irsend.capture.bits); + EXPECT_EQ(kAiwaRcT501Bits, irsend.capture.bits); EXPECT_EQ(0x7F, irsend.capture.value); EXPECT_EQ(0x0, irsend.capture.address); EXPECT_EQ(0x0, irsend.capture.command); @@ -182,48 +184,44 @@ TEST(TestDecodeAiwa, DecodeWithNonStrictValues) { irsend.reset(); // Confirm using sendNEC(data, 42, 1) can make a legal Aiwa message. - irsend.sendNEC(0x1D8113F00FF, 42, AIWA_RC_T501_MIN_REPEAT); + irsend.sendNEC(0x1D8113F00FF, 42, kAiwaRcT501MinRepeats); irsend.makeDecodeResult(); // MUST pass with strict on. - ASSERT_TRUE(irrecv.decodeAiwaRCT501(&irsend.capture, AIWA_RC_T501_BITS, - true)); + ASSERT_TRUE(irrecv.decodeAiwaRCT501(&irsend.capture, kAiwaRcT501Bits, true)); ASSERT_EQ(0x7F, irsend.capture.value); irsend.reset(); // Use sendNEC(data, 42) to make/send an illegal value Aiwa message. // Value is illegal due to bad pre & post data. - irsend.sendNEC(0x1234567890A, 42, AIWA_RC_T501_MIN_REPEAT); + irsend.sendNEC(0x1234567890A, 42, kAiwaRcT501MinRepeats); irsend.makeDecodeResult(); // Should fail with strict on. - ASSERT_FALSE(irrecv.decodeAiwaRCT501(&irsend.capture, AIWA_RC_T501_BITS, - true)); + ASSERT_FALSE(irrecv.decodeAiwaRCT501(&irsend.capture, kAiwaRcT501Bits, true)); // Should fail if strict off too. - ASSERT_FALSE(irrecv.decodeAiwaRCT501(&irsend.capture, AIWA_RC_T501_BITS, - false)); + ASSERT_FALSE( + irrecv.decodeAiwaRCT501(&irsend.capture, kAiwaRcT501Bits, false)); irsend.reset(); // Use sendNEC(data, 42) to make/send an illegal value Aiwa message. // Value is illegal due to bad post data only. - irsend.sendNEC(0x1D8113F00FE, 42, AIWA_RC_T501_MIN_REPEAT); + irsend.sendNEC(0x1D8113F00FE, 42, kAiwaRcT501MinRepeats); irsend.makeDecodeResult(); // Should fail with strict on. - ASSERT_FALSE(irrecv.decodeAiwaRCT501(&irsend.capture, AIWA_RC_T501_BITS, - true)); + ASSERT_FALSE(irrecv.decodeAiwaRCT501(&irsend.capture, kAiwaRcT501Bits, true)); // Should fail if strict off too. - ASSERT_FALSE(irrecv.decodeAiwaRCT501(&irsend.capture, AIWA_RC_T501_BITS, - false)); + ASSERT_FALSE( + irrecv.decodeAiwaRCT501(&irsend.capture, kAiwaRcT501Bits, false)); irsend.reset(); // Use sendNEC(data, 42) to make/send an illegal value Aiwa message. // Value is illegal due to bad pre data only. - irsend.sendNEC(0x0D8113F00FF, 42, AIWA_RC_T501_MIN_REPEAT); + irsend.sendNEC(0x0D8113F00FF, 42, kAiwaRcT501MinRepeats); irsend.makeDecodeResult(); // Should fail with strict on. - ASSERT_FALSE(irrecv.decodeAiwaRCT501(&irsend.capture, AIWA_RC_T501_BITS, - true)); + ASSERT_FALSE(irrecv.decodeAiwaRCT501(&irsend.capture, kAiwaRcT501Bits, true)); // Should fail if strict off too. - ASSERT_FALSE(irrecv.decodeAiwaRCT501(&irsend.capture, AIWA_RC_T501_BITS, - false)); + ASSERT_FALSE( + irrecv.decodeAiwaRCT501(&irsend.capture, kAiwaRcT501Bits, false)); } // Decode unsupported Aiwa messages. @@ -236,8 +234,7 @@ TEST(TestDecodeAiwa, DecodeWithNonStrictSizes) { irsend.sendAiwaRCT501(0x0, 8); // Illegal size Aiwa 8-bit message. irsend.makeDecodeResult(); // Should fail with strict on. - ASSERT_FALSE(irrecv.decodeAiwaRCT501(&irsend.capture, AIWA_RC_T501_BITS, - true)); + ASSERT_FALSE(irrecv.decodeAiwaRCT501(&irsend.capture, kAiwaRcT501Bits, true)); // Should pass if strict off. ASSERT_TRUE(irrecv.decodeAiwaRCT501(&irsend.capture, 8, false)); EXPECT_EQ(AIWA_RC_T501, irsend.capture.decode_type); @@ -248,8 +245,7 @@ TEST(TestDecodeAiwa, DecodeWithNonStrictSizes) { irsend.sendAiwaRCT501(0x12345678, 32); // Illegal size Aiwa 32-bit message. irsend.makeDecodeResult(); // Should fail with strict on. - ASSERT_FALSE(irrecv.decodeAiwaRCT501(&irsend.capture, AIWA_RC_T501_BITS, - true)); + ASSERT_FALSE(irrecv.decodeAiwaRCT501(&irsend.capture, kAiwaRcT501Bits, true)); // Should fail with strict when we ask for the wrong bit size. ASSERT_FALSE(irrecv.decodeAiwaRCT501(&irsend.capture, 32, true)); @@ -278,7 +274,7 @@ TEST(TestDecodeAiwa, Decode64BitMessages) { // Reconfirm it by sending a true 64bit NEC message with the Aiwa prefix. irsend.reset(); - irsend.sendNEC(0x76044FFFFFFFFFFF, 64, AIWA_RC_T501_MIN_REPEAT); + irsend.sendNEC(0x76044FFFFFFFFFFF, 64, kAiwaRcT501MinRepeats); irsend.makeDecodeResult(); // Should work with a 'normal' match (not strict) ASSERT_TRUE(irrecv.decodeAiwaRCT501(&irsend.capture, 37, false)); @@ -295,20 +291,19 @@ TEST(TestDecodeAiwa, DecodeGlobalCacheExample) { irsend.reset(); // Aiwa Power Toggle from Global Cache. - uint16_t gc_test[95] = {38000, 1, 89, 342, 171, 21, 21, 21, 64, 21, 64, - 21, 64, 21, 21, 21, 64, 21, 64, 21, 21, 21, 21, - 21, 21, 21, 21, 21, 21, 21, 21, 21, 64, 21, 21, - 21, 21, 21, 21, 21, 64, 21, 21, 21, 21, 21, 64, - 21, 64, 21, 64, 21, 64, 21, 64, 21, 64, 21, 21, - 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, - 21, 21, 21, 64, 21, 64, 21, 64, 21, 64, 21, 64, - 21, 64, 21, 64, 21, 64, 21, 875, 342, 171, 21, 3565}; + uint16_t gc_test[95] = { + 38000, 1, 89, 342, 171, 21, 21, 21, 64, 21, 64, 21, 64, 21, 21, 21, + 64, 21, 64, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 64, 21, 21, 21, 21, 21, 21, 21, 64, 21, 21, 21, 21, 21, 64, 21, + 64, 21, 64, 21, 64, 21, 64, 21, 64, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 64, 21, 64, 21, 64, 21, + 64, 21, 64, 21, 64, 21, 64, 21, 64, 21, 875, 342, 171, 21, 3565}; irsend.sendGC(gc_test, 95); irsend.makeDecodeResult(); ASSERT_TRUE(irrecv.decodeAiwaRCT501(&irsend.capture)); EXPECT_EQ(AIWA_RC_T501, irsend.capture.decode_type); - EXPECT_EQ(AIWA_RC_T501_BITS, irsend.capture.bits); + EXPECT_EQ(kAiwaRcT501Bits, irsend.capture.bits); EXPECT_EQ(0x7F, irsend.capture.value); EXPECT_EQ(0x0, irsend.capture.address); EXPECT_EQ(0x0, irsend.capture.command); @@ -326,13 +321,14 @@ TEST(TestDecodeAiwa, FailToDecodeNonAiwaExample) { irsend.begin(); irsend.reset(); - uint16_t gc_test[39] = {38000, 1, 1, 322, 162, 20, 61, 20, 61, 20, 20, 20, 20, - 20, 20, 20, 127, 20, 61, 9, 20, 20, 61, 20, 20, 20, - 61, 20, 61, 20, 61, 20, 20, 20, 20, 20, 20, 20, 884}; + uint16_t gc_test[39] = {38000, 1, 1, 322, 162, 20, 61, 20, 61, 20, + 20, 20, 20, 20, 20, 20, 127, 20, 61, 9, + 20, 20, 61, 20, 20, 20, 61, 20, 61, 20, + 61, 20, 20, 20, 20, 20, 20, 20, 884}; irsend.sendGC(gc_test, 39); irsend.makeDecodeResult(); ASSERT_FALSE(irrecv.decodeAiwaRCT501(&irsend.capture)); - ASSERT_FALSE(irrecv.decodeAiwaRCT501(&irsend.capture, AIWA_RC_T501_BITS, - false)); + ASSERT_FALSE( + irrecv.decodeAiwaRCT501(&irsend.capture, kAiwaRcT501Bits, false)); } diff --git a/lib/IRremoteESP8266/test/ir_Carrier_test.cpp b/lib/IRremoteESP8266/test/ir_Carrier_test.cpp index 3fe5ce1..24bdc23 100644 --- a/lib/IRremoteESP8266/test/ir_Carrier_test.cpp +++ b/lib/IRremoteESP8266/test/ir_Carrier_test.cpp @@ -32,7 +32,8 @@ TEST(TestSendCarrierAC, SendDataOnly) { "m628s532m628s532m628s532m628s532m628s532m628s532m628s532m628s532" "m628s532m628s532m628s532m628s532m628s532m628s532m628s532m628s532" "m628s532m628s532m628s532m628s532m628s532m628s532m628s532m628s532" - "m628s20000", irsend.outputStr()); + "m628s20000", + irsend.outputStr()); irsend.reset(); irsend.sendCarrierAC(0x12345678); EXPECT_EQ( @@ -53,7 +54,8 @@ TEST(TestSendCarrierAC, SendDataOnly) { "m628s532m628s532m628s1320m628s1320m628s532m628s1320m628s532m628s532" "m628s532m628s1320m628s532m628s1320m628s532m628s1320m628s1320m628s532" "m628s532m628s1320m628s1320m628s1320m628s1320m628s532m628s532m628s532" - "m628s20000", irsend.outputStr()); + "m628s20000", + irsend.outputStr()); irsend.reset(); irsend.sendCarrierAC(0x4CCA541D); @@ -75,7 +77,8 @@ TEST(TestSendCarrierAC, SendDataOnly) { "m628s1320m628s1320m628s532m628s532m628s1320m628s532m628s1320m628s532" "m628s532m628s1320m628s532m628s1320m628s532m628s1320m628s532m628s532" "m628s532m628s532m628s532m628s1320m628s1320m628s1320m628s532m628s1320" - "m628s20000", irsend.outputStr()); + "m628s20000", + irsend.outputStr()); } // Test sending typical data only. @@ -84,62 +87,63 @@ TEST(TestSendCarrierAC, SendWithRepeats) { irsend.begin(); irsend.reset(); - irsend.sendCarrierAC(0x12345678, CARRIER_AC_BITS, 2); // two repeats. + irsend.sendCarrierAC(0x12345678, kCarrierAcBits, 2); // two repeats. EXPECT_EQ( - "m8532s4228" - "m628s532m628s532m628s532m628s1320m628s532m628s532m628s1320m628s532" - "m628s532m628s532m628s1320m628s1320m628s532m628s1320m628s532m628s532" - "m628s532m628s1320m628s532m628s1320m628s532m628s1320m628s1320m628s532" - "m628s532m628s1320m628s1320m628s1320m628s1320m628s532m628s532m628s532" - "m628s20000" - "m8532s4228" - "m628s1320m628s1320m628s1320m628s532m628s1320m628s1320m628s532m628s1320" - "m628s1320m628s1320m628s532m628s532m628s1320m628s532m628s1320m628s1320" - "m628s1320m628s532m628s1320m628s532m628s1320m628s532m628s532m628s1320" - "m628s1320m628s532m628s532m628s532m628s532m628s1320m628s1320m628s1320" - "m628s20000" - "m8532s4228" - "m628s532m628s532m628s532m628s1320m628s532m628s532m628s1320m628s532" - "m628s532m628s532m628s1320m628s1320m628s532m628s1320m628s532m628s532" - "m628s532m628s1320m628s532m628s1320m628s532m628s1320m628s1320m628s532" - "m628s532m628s1320m628s1320m628s1320m628s1320m628s532m628s532m628s532" - "m628s20000" - "m8532s4228" - "m628s532m628s532m628s532m628s1320m628s532m628s532m628s1320m628s532" - "m628s532m628s532m628s1320m628s1320m628s532m628s1320m628s532m628s532" - "m628s532m628s1320m628s532m628s1320m628s532m628s1320m628s1320m628s532" - "m628s532m628s1320m628s1320m628s1320m628s1320m628s532m628s532m628s532" - "m628s20000" - "m8532s4228" - "m628s1320m628s1320m628s1320m628s532m628s1320m628s1320m628s532m628s1320" - "m628s1320m628s1320m628s532m628s532m628s1320m628s532m628s1320m628s1320" - "m628s1320m628s532m628s1320m628s532m628s1320m628s532m628s532m628s1320" - "m628s1320m628s532m628s532m628s532m628s532m628s1320m628s1320m628s1320" - "m628s20000" - "m8532s4228" - "m628s532m628s532m628s532m628s1320m628s532m628s532m628s1320m628s532" - "m628s532m628s532m628s1320m628s1320m628s532m628s1320m628s532m628s532" - "m628s532m628s1320m628s532m628s1320m628s532m628s1320m628s1320m628s532" - "m628s532m628s1320m628s1320m628s1320m628s1320m628s532m628s532m628s532" - "m628s20000" - "m8532s4228" - "m628s532m628s532m628s532m628s1320m628s532m628s532m628s1320m628s532" - "m628s532m628s532m628s1320m628s1320m628s532m628s1320m628s532m628s532" - "m628s532m628s1320m628s532m628s1320m628s532m628s1320m628s1320m628s532" - "m628s532m628s1320m628s1320m628s1320m628s1320m628s532m628s532m628s532" - "m628s20000" - "m8532s4228" - "m628s1320m628s1320m628s1320m628s532m628s1320m628s1320m628s532m628s1320" - "m628s1320m628s1320m628s532m628s532m628s1320m628s532m628s1320m628s1320" - "m628s1320m628s532m628s1320m628s532m628s1320m628s532m628s532m628s1320" - "m628s1320m628s532m628s532m628s532m628s532m628s1320m628s1320m628s1320" - "m628s20000" - "m8532s4228" - "m628s532m628s532m628s532m628s1320m628s532m628s532m628s1320m628s532" - "m628s532m628s532m628s1320m628s1320m628s532m628s1320m628s532m628s532" - "m628s532m628s1320m628s532m628s1320m628s532m628s1320m628s1320m628s532" - "m628s532m628s1320m628s1320m628s1320m628s1320m628s532m628s532m628s532" - "m628s20000", irsend.outputStr()); + "m8532s4228" + "m628s532m628s532m628s532m628s1320m628s532m628s532m628s1320m628s532" + "m628s532m628s532m628s1320m628s1320m628s532m628s1320m628s532m628s532" + "m628s532m628s1320m628s532m628s1320m628s532m628s1320m628s1320m628s532" + "m628s532m628s1320m628s1320m628s1320m628s1320m628s532m628s532m628s532" + "m628s20000" + "m8532s4228" + "m628s1320m628s1320m628s1320m628s532m628s1320m628s1320m628s532m628s1320" + "m628s1320m628s1320m628s532m628s532m628s1320m628s532m628s1320m628s1320" + "m628s1320m628s532m628s1320m628s532m628s1320m628s532m628s532m628s1320" + "m628s1320m628s532m628s532m628s532m628s532m628s1320m628s1320m628s1320" + "m628s20000" + "m8532s4228" + "m628s532m628s532m628s532m628s1320m628s532m628s532m628s1320m628s532" + "m628s532m628s532m628s1320m628s1320m628s532m628s1320m628s532m628s532" + "m628s532m628s1320m628s532m628s1320m628s532m628s1320m628s1320m628s532" + "m628s532m628s1320m628s1320m628s1320m628s1320m628s532m628s532m628s532" + "m628s20000" + "m8532s4228" + "m628s532m628s532m628s532m628s1320m628s532m628s532m628s1320m628s532" + "m628s532m628s532m628s1320m628s1320m628s532m628s1320m628s532m628s532" + "m628s532m628s1320m628s532m628s1320m628s532m628s1320m628s1320m628s532" + "m628s532m628s1320m628s1320m628s1320m628s1320m628s532m628s532m628s532" + "m628s20000" + "m8532s4228" + "m628s1320m628s1320m628s1320m628s532m628s1320m628s1320m628s532m628s1320" + "m628s1320m628s1320m628s532m628s532m628s1320m628s532m628s1320m628s1320" + "m628s1320m628s532m628s1320m628s532m628s1320m628s532m628s532m628s1320" + "m628s1320m628s532m628s532m628s532m628s532m628s1320m628s1320m628s1320" + "m628s20000" + "m8532s4228" + "m628s532m628s532m628s532m628s1320m628s532m628s532m628s1320m628s532" + "m628s532m628s532m628s1320m628s1320m628s532m628s1320m628s532m628s532" + "m628s532m628s1320m628s532m628s1320m628s532m628s1320m628s1320m628s532" + "m628s532m628s1320m628s1320m628s1320m628s1320m628s532m628s532m628s532" + "m628s20000" + "m8532s4228" + "m628s532m628s532m628s532m628s1320m628s532m628s532m628s1320m628s532" + "m628s532m628s532m628s1320m628s1320m628s532m628s1320m628s532m628s532" + "m628s532m628s1320m628s532m628s1320m628s532m628s1320m628s1320m628s532" + "m628s532m628s1320m628s1320m628s1320m628s1320m628s532m628s532m628s532" + "m628s20000" + "m8532s4228" + "m628s1320m628s1320m628s1320m628s532m628s1320m628s1320m628s532m628s1320" + "m628s1320m628s1320m628s532m628s532m628s1320m628s532m628s1320m628s1320" + "m628s1320m628s532m628s1320m628s532m628s1320m628s532m628s532m628s1320" + "m628s1320m628s532m628s532m628s532m628s532m628s1320m628s1320m628s1320" + "m628s20000" + "m8532s4228" + "m628s532m628s532m628s532m628s1320m628s532m628s532m628s1320m628s532" + "m628s532m628s532m628s1320m628s1320m628s532m628s1320m628s532m628s532" + "m628s532m628s1320m628s532m628s1320m628s532m628s1320m628s1320m628s532" + "m628s532m628s1320m628s1320m628s1320m628s1320m628s532m628s532m628s532" + "m628s20000", + irsend.outputStr()); } // Tests for decodeCarrierAC(). @@ -153,9 +157,9 @@ TEST(TestDecodeCarrierAC, NormalDecodeWithStrict) { irsend.reset(); irsend.sendCarrierAC(0x0); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodeCarrierAC(&irsend.capture, CARRIER_AC_BITS, true)); + ASSERT_TRUE(irrecv.decodeCarrierAC(&irsend.capture, kCarrierAcBits, true)); EXPECT_EQ(CARRIER_AC, irsend.capture.decode_type); - EXPECT_EQ(CARRIER_AC_BITS, irsend.capture.bits); + EXPECT_EQ(kCarrierAcBits, irsend.capture.bits); EXPECT_EQ(0x0, irsend.capture.value); EXPECT_EQ(0x0, irsend.capture.address); EXPECT_EQ(0x0, irsend.capture.command); @@ -164,9 +168,9 @@ TEST(TestDecodeCarrierAC, NormalDecodeWithStrict) { irsend.reset(); irsend.sendCarrierAC(0xB335ABE2); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodeCarrierAC(&irsend.capture, CARRIER_AC_BITS, true)); + ASSERT_TRUE(irrecv.decodeCarrierAC(&irsend.capture, kCarrierAcBits, true)); EXPECT_EQ(CARRIER_AC, irsend.capture.decode_type); - EXPECT_EQ(CARRIER_AC_BITS, irsend.capture.bits); + EXPECT_EQ(kCarrierAcBits, irsend.capture.bits); EXPECT_EQ(0xB335ABE2, irsend.capture.value); EXPECT_EQ(0xB335, irsend.capture.address); EXPECT_EQ(0xABE2, irsend.capture.command); @@ -178,7 +182,7 @@ TEST(TestDecodeCarrierAC, NormalDecodeWithStrict) { irsend.makeDecodeResult(); ASSERT_TRUE(irrecv.decode(&irsend.capture)); EXPECT_EQ(CARRIER_AC, irsend.capture.decode_type); - EXPECT_EQ(CARRIER_AC_BITS, irsend.capture.bits); + EXPECT_EQ(kCarrierAcBits, irsend.capture.bits); EXPECT_EQ(0xB335ABE2, irsend.capture.value); } @@ -191,27 +195,29 @@ TEST(TestDecodeCarrierAC, RealExamples) { irsend.reset(); // Data from Issue #385 captured by gnkarn uint16_t rawData[203] = { - 8532, 4216, 628, 1312, 628, 528, 628, 1312, 628, 1312, 628, 528, 628, 524, - 628, 1316, 624, 1316, 628, 524, 628, 528, 628, 1312, 628, 1316, 624, 528, - 628, 1312, 628, 528, 628, 1312, 628, 1312, 628, 528, 628, 1316, 624, 528, - 628, 1312, 628, 528, 628, 1312, 628, 1316, 624, 1316, 628, 1312, 628, - 1316, 628, 524, 628, 528, 628, 528, 624, 1316, 628, 528, 628, 20064, 8504, - 4228, 628, 528, 628, 1312, 628, 528, 628, 528, 628, 1312, 628, 1316, 624, - 532, 624, 528, 628, 1316, 628, 1312, 628, 528, 628, 528, 628, 1312, 628, - 528, 628, 1316, 628, 528, 624, 528, 628, 1316, 628, 528, 628, 1316, 624, - 528, 628, 1316, 628, 528, 624, 532, 624, 528, 628, 528, 628, 528, 628, - 1316, 624, 1316, 628, 1316, 628, 528, 624, 1316, 628, 20076, 8528, 4212, - 624, 1316, 628, 528, 628, 1316, 628, 1316, 624, 528, 628, 528, 628, 1316, - 628, 1316, 628, 528, 624, 532, 624, 1316, 628, 1316, 628, 528, 628, 1316, - 624, 528, 628, 1316, 628, 1316, 628, 528, 628, 1316, 624, 532, 624, 1316, - 628, 532, 624, 1316, 628, 1316, 624, 1320, 624, 1316, 628, 1316, 628, 528, - 628, 528, 628, 528, 628, 1316, 624, 532, 624}; + 8532, 4216, 628, 1312, 628, 528, 628, 1312, 628, 1312, 628, 528, + 628, 524, 628, 1316, 624, 1316, 628, 524, 628, 528, 628, 1312, + 628, 1316, 624, 528, 628, 1312, 628, 528, 628, 1312, 628, 1312, + 628, 528, 628, 1316, 624, 528, 628, 1312, 628, 528, 628, 1312, + 628, 1316, 624, 1316, 628, 1312, 628, 1316, 628, 524, 628, 528, + 628, 528, 624, 1316, 628, 528, 628, 20064, 8504, 4228, 628, 528, + 628, 1312, 628, 528, 628, 528, 628, 1312, 628, 1316, 624, 532, + 624, 528, 628, 1316, 628, 1312, 628, 528, 628, 528, 628, 1312, + 628, 528, 628, 1316, 628, 528, 624, 528, 628, 1316, 628, 528, + 628, 1316, 624, 528, 628, 1316, 628, 528, 624, 532, 624, 528, + 628, 528, 628, 528, 628, 1316, 624, 1316, 628, 1316, 628, 528, + 624, 1316, 628, 20076, 8528, 4212, 624, 1316, 628, 528, 628, 1316, + 628, 1316, 624, 528, 628, 528, 628, 1316, 628, 1316, 628, 528, + 624, 532, 624, 1316, 628, 1316, 628, 528, 628, 1316, 624, 528, + 628, 1316, 628, 1316, 628, 528, 628, 1316, 624, 532, 624, 1316, + 628, 532, 624, 1316, 628, 1316, 624, 1320, 624, 1316, 628, 1316, + 628, 528, 628, 528, 628, 528, 628, 1316, 624, 532, 624}; irsend.sendRaw(rawData, 203, 38000); irsend.makeDecodeResult(); ASSERT_TRUE(irrecv.decode(&irsend.capture)); EXPECT_EQ(CARRIER_AC, irsend.capture.decode_type); - EXPECT_EQ(CARRIER_AC_BITS, irsend.capture.bits); + EXPECT_EQ(kCarrierAcBits, irsend.capture.bits); EXPECT_EQ(0xB335ABE2, irsend.capture.value); EXPECT_EQ(0xB335, irsend.capture.address); EXPECT_EQ(0xABE2, irsend.capture.command); diff --git a/lib/IRremoteESP8266/test/ir_Coolix_test.cpp b/lib/IRremoteESP8266/test/ir_Coolix_test.cpp index ada05fe..86cbba5 100644 --- a/lib/IRremoteESP8266/test/ir_Coolix_test.cpp +++ b/lib/IRremoteESP8266/test/ir_Coolix_test.cpp @@ -1,5 +1,6 @@ -// Copyright 2017 David Conran +// Copyright 2017-2018 David Conran +#include "ir_Coolix.h" #include "IRsend.h" #include "IRsend_test.h" #include "gtest/gtest.h" @@ -21,7 +22,8 @@ TEST(TestSendCoolix, SendDataOnly) { "m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680" "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560" "m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680" - "m560s5040", irsend.outputStr()); + "m560s5040", + irsend.outputStr()); irsend.reset(); irsend.sendCOOLIX(0xAA55AA); @@ -33,7 +35,8 @@ TEST(TestSendCoolix, SendDataOnly) { "m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560" "m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560" "m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680" - "m560s5040", irsend.outputStr()); + "m560s5040", + irsend.outputStr()); irsend.reset(); irsend.sendCOOLIX(0xFFFFFF); @@ -45,7 +48,8 @@ TEST(TestSendCoolix, SendDataOnly) { "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560" "m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680" "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560" - "m560s5040", irsend.outputStr()); + "m560s5040", + irsend.outputStr()); } // Test sending with different repeats. @@ -54,7 +58,7 @@ TEST(TestSendCoolix, SendWithRepeats) { irsend.begin(); irsend.reset(); - irsend.sendCOOLIX(0xAA55AA, COOLIX_BITS, 1); // 1 repeat. + irsend.sendCOOLIX(0xAA55AA, kCoolixBits, 1); // 1 repeat. EXPECT_EQ( "m4480s4480" "m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560" @@ -71,8 +75,9 @@ TEST(TestSendCoolix, SendWithRepeats) { "m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560" "m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560" "m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680" - "m560s5040", irsend.outputStr()); - irsend.sendCOOLIX(0xAA55AA, COOLIX_BITS, 2); // 2 repeats. + "m560s5040", + irsend.outputStr()); + irsend.sendCOOLIX(0xAA55AA, kCoolixBits, 2); // 2 repeats. EXPECT_EQ( "m4480s4480" "m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560" @@ -97,7 +102,8 @@ TEST(TestSendCoolix, SendWithRepeats) { "m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560" "m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560" "m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680" - "m560s5040", irsend.outputStr()); + "m560s5040", + irsend.outputStr()); } // Test sending an atypical data size. @@ -111,7 +117,8 @@ TEST(TestSendCoolix, SendUnusualSize) { "m4480s4480" "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560" "m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680" - "m560s5040", irsend.outputStr()); + "m560s5040", + irsend.outputStr()); irsend.reset(); irsend.sendCOOLIX(0x1234567890ABCDEF, 64); @@ -133,12 +140,13 @@ TEST(TestSendCoolix, SendUnusualSize) { "m560s560m560s560m560s1680m560s1680m560s560m560s560m560s1680m560s560" "m560s1680m560s1680m560s1680m560s560m560s1680m560s1680m560s1680m560s1680" "m560s560m560s560m560s560m560s1680m560s560m560s560m560s560m560s560" - "m560s5040", irsend.outputStr()); + "m560s5040", + irsend.outputStr()); // Bit sizes must be a multiple of 8. irsend.reset(); irsend.sendCOOLIX(0x0, 17); - EXPECT_EQ("" , irsend.outputStr()); + EXPECT_EQ("", irsend.outputStr()); } // Tests for decodeCOOLIX(). @@ -153,9 +161,9 @@ TEST(TestDecodeCoolix, NormalDecodeWithStrict) { irsend.reset(); irsend.sendCOOLIX(0x123456); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodeCOOLIX(&irsend.capture, COOLIX_BITS, true)); + ASSERT_TRUE(irrecv.decodeCOOLIX(&irsend.capture, kCoolixBits, true)); EXPECT_EQ(COOLIX, irsend.capture.decode_type); - EXPECT_EQ(COOLIX_BITS, irsend.capture.bits); + EXPECT_EQ(kCoolixBits, irsend.capture.bits); EXPECT_EQ(0x123456, irsend.capture.value); EXPECT_EQ(0x0, irsend.capture.address); EXPECT_EQ(0x0, irsend.capture.command); @@ -165,9 +173,9 @@ TEST(TestDecodeCoolix, NormalDecodeWithStrict) { irsend.reset(); irsend.sendCOOLIX(0x0); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodeCOOLIX(&irsend.capture, COOLIX_BITS, true)); + ASSERT_TRUE(irrecv.decodeCOOLIX(&irsend.capture, kCoolixBits, true)); EXPECT_EQ(COOLIX, irsend.capture.decode_type); - EXPECT_EQ(COOLIX_BITS, irsend.capture.bits); + EXPECT_EQ(kCoolixBits, irsend.capture.bits); EXPECT_EQ(0x0, irsend.capture.value); EXPECT_EQ(0x0, irsend.capture.address); EXPECT_EQ(0x0, irsend.capture.command); @@ -177,9 +185,9 @@ TEST(TestDecodeCoolix, NormalDecodeWithStrict) { irsend.reset(); irsend.sendCOOLIX(0xFFFFFF); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodeCOOLIX(&irsend.capture, COOLIX_BITS, true)); + ASSERT_TRUE(irrecv.decodeCOOLIX(&irsend.capture, kCoolixBits, true)); EXPECT_EQ(COOLIX, irsend.capture.decode_type); - EXPECT_EQ(COOLIX_BITS, irsend.capture.bits); + EXPECT_EQ(kCoolixBits, irsend.capture.bits); EXPECT_EQ(0xFFFFFF, irsend.capture.value); EXPECT_EQ(0x0, irsend.capture.address); EXPECT_EQ(0x0, irsend.capture.command); @@ -194,24 +202,24 @@ TEST(TestDecodeCoolix, NormalDecodeWithRepeatAndStrict) { // Normal Coolix 16-bit message with 2 repeats. irsend.reset(); - irsend.sendCOOLIX(0x123456, COOLIX_BITS, 2); + irsend.sendCOOLIX(0x123456, kCoolixBits, 2); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodeCOOLIX(&irsend.capture, COOLIX_BITS, true)); + ASSERT_TRUE(irrecv.decodeCOOLIX(&irsend.capture, kCoolixBits, true)); EXPECT_EQ(COOLIX, irsend.capture.decode_type); - EXPECT_EQ(COOLIX_BITS, irsend.capture.bits); + EXPECT_EQ(kCoolixBits, irsend.capture.bits); EXPECT_EQ(0x123456, irsend.capture.value); EXPECT_FALSE(irsend.capture.repeat); - irsend.makeDecodeResult(4 * COOLIX_BITS + 4); - ASSERT_TRUE(irrecv.decodeCOOLIX(&irsend.capture, COOLIX_BITS, true)); + irsend.makeDecodeResult(4 * kCoolixBits + 4); + ASSERT_TRUE(irrecv.decodeCOOLIX(&irsend.capture, kCoolixBits, true)); EXPECT_EQ(COOLIX, irsend.capture.decode_type); - EXPECT_EQ(COOLIX_BITS, irsend.capture.bits); + EXPECT_EQ(kCoolixBits, irsend.capture.bits); EXPECT_EQ(0x123456, irsend.capture.value); - irsend.makeDecodeResult(2 * (4 * COOLIX_BITS + 4)); - ASSERT_TRUE(irrecv.decodeCOOLIX(&irsend.capture, COOLIX_BITS, true)); + irsend.makeDecodeResult(2 * (4 * kCoolixBits + 4)); + ASSERT_TRUE(irrecv.decodeCOOLIX(&irsend.capture, kCoolixBits, true)); EXPECT_EQ(COOLIX, irsend.capture.decode_type); - EXPECT_EQ(COOLIX_BITS, irsend.capture.bits); + EXPECT_EQ(kCoolixBits, irsend.capture.bits); EXPECT_EQ(0x123456, irsend.capture.value); } @@ -225,7 +233,7 @@ TEST(TestDecodeCoolix, DecodeWithNonStrictSizes) { irsend.sendCOOLIX(0x12, 8); // Illegal value Coolix 8-bit message. irsend.makeDecodeResult(); // Should fail with strict on. - ASSERT_FALSE(irrecv.decodeCOOLIX(&irsend.capture, COOLIX_BITS, true)); + ASSERT_FALSE(irrecv.decodeCOOLIX(&irsend.capture, kCoolixBits, true)); // Should pass if strict off. ASSERT_TRUE(irrecv.decodeCOOLIX(&irsend.capture, 8, false)); EXPECT_EQ(COOLIX, irsend.capture.decode_type); @@ -236,7 +244,7 @@ TEST(TestDecodeCoolix, DecodeWithNonStrictSizes) { irsend.sendCOOLIX(0x12345678, 32); // Illegal value Coolix 32-bit message. irsend.makeDecodeResult(); // Shouldn't pass with strict when we ask for less bits than we got. - ASSERT_FALSE(irrecv.decodeCOOLIX(&irsend.capture, COOLIX_BITS, true)); + ASSERT_FALSE(irrecv.decodeCOOLIX(&irsend.capture, kCoolixBits, true)); irsend.makeDecodeResult(); // Should fail with strict when we ask for the wrong bit size. @@ -249,7 +257,7 @@ TEST(TestDecodeCoolix, DecodeWithNonStrictSizes) { // Decode should fail if asked to decode non-multiples of 8 bits. irsend.reset(); - irsend.sendCOOLIX(0x123456, COOLIX_BITS, 2); + irsend.sendCOOLIX(0x123456, kCoolixBits, 2); irsend.makeDecodeResult(); ASSERT_FALSE(irrecv.decodeCOOLIX(&irsend.capture, 9, false)); } @@ -279,12 +287,207 @@ TEST(TestDecodeCoolix, FailToDecodeNonCoolixExample) { irsend.reset(); // Modified a few entries to unexpected values, based on previous test case. - uint16_t gc_test[39] = {38000, 1, 1, 322, 162, 20, 61, 20, 61, 20, 20, 20, 20, - 20, 20, 20, 127, 20, 61, 9, 20, 20, 61, 20, 20, 20, - 61, 20, 61, 20, 61, 20, 20, 20, 20, 20, 20, 20, 884}; + uint16_t gc_test[39] = {38000, 1, 1, 322, 162, 20, 61, 20, 61, 20, + 20, 20, 20, 20, 20, 20, 127, 20, 61, 9, + 20, 20, 61, 20, 20, 20, 61, 20, 61, 20, + 61, 20, 20, 20, 20, 20, 20, 20, 884}; irsend.sendGC(gc_test, 39); irsend.makeDecodeResult(); ASSERT_FALSE(irrecv.decodeCOOLIX(&irsend.capture)); - ASSERT_FALSE(irrecv.decodeCOOLIX(&irsend.capture, COOLIX_BITS, false)); + ASSERT_FALSE(irrecv.decodeCOOLIX(&irsend.capture, kCoolixBits, false)); +} + +// Tests for the IRCoolixAC class. + +TEST(TestCoolixACClass, SetAndGetRaw) { + IRCoolixAC ircoolix(0); + + ircoolix.setRaw(kCoolixOff); + EXPECT_EQ(kCoolixOff, ircoolix.getRaw()); + ircoolix.setRaw(kCoolixDefaultState); + EXPECT_EQ(kCoolixDefaultState, ircoolix.getRaw()); +} + +TEST(TestCoolixACClass, SetAndGetTemp) { + IRCoolixAC ircoolix(0); + + ircoolix.setTemp(25); + EXPECT_EQ(25, ircoolix.getTemp()); + ircoolix.setTemp(kCoolixTempMin); + EXPECT_EQ(kCoolixTempMin, ircoolix.getTemp()); + ircoolix.setTemp(kCoolixTempMax); + EXPECT_EQ(kCoolixTempMax, ircoolix.getTemp()); + ircoolix.setTemp(kCoolixTempMin - 1); + EXPECT_EQ(kCoolixTempMin, ircoolix.getTemp()); + ircoolix.setTemp(kCoolixTempMax + 1); + EXPECT_EQ(kCoolixTempMax, ircoolix.getTemp()); +} + +TEST(TestCoolixACClass, SetAndGetMode) { + IRCoolixAC ircoolix(0); + + ircoolix.setMode(kCoolixHeat); + EXPECT_EQ(kCoolixHeat, ircoolix.getMode()); + ircoolix.setMode(kCoolixCool); + EXPECT_EQ(kCoolixCool, ircoolix.getMode()); + ircoolix.setMode(kCoolixDry); + EXPECT_EQ(kCoolixDry, ircoolix.getMode()); + ircoolix.setMode(kCoolixAuto); + EXPECT_EQ(kCoolixAuto, ircoolix.getMode()); + ircoolix.setMode(kCoolixFan); + EXPECT_EQ(kCoolixFan, ircoolix.getMode()); +} + +TEST(TestCoolixACClass, SetAndGetFan) { + IRCoolixAC ircoolix(0); + + ircoolix.setFan(kCoolixFanMax); + EXPECT_EQ(kCoolixFanMax, ircoolix.getFan()); + ircoolix.setFan(kCoolixFanMin); + EXPECT_EQ(kCoolixFanMin, ircoolix.getFan()); + ircoolix.setFan(kCoolixFanZoneFollow); + EXPECT_EQ(kCoolixFanZoneFollow, ircoolix.getFan()); + ircoolix.setFan(kCoolixFanAuto); + EXPECT_EQ(kCoolixFanAuto, ircoolix.getFan()); + ircoolix.setFan(kCoolixFanMax); + EXPECT_EQ(kCoolixFanMax, ircoolix.getFan()); + ASSERT_NE(3, kCoolixFanAuto); + // Now try some unexpected value. + ircoolix.setFan(3); + EXPECT_EQ(kCoolixFanAuto, ircoolix.getFan()); +} + +TEST(TestCoolixACClass, SetGetClearSensorTempAndZoneFollow) { + IRCoolixAC ircoolix(0); + + ircoolix.setRaw(kCoolixDefaultState); + EXPECT_FALSE(ircoolix.getZoneFollow()); + EXPECT_LT(kCoolixSensorTempMax, ircoolix.getSensorTemp()); + + ircoolix.setSensorTemp(25); + EXPECT_TRUE(ircoolix.getZoneFollow()); + EXPECT_EQ(25, ircoolix.getSensorTemp()); + + // Lower bounds + ircoolix.setSensorTemp(kCoolixSensorTempMin); + EXPECT_TRUE(ircoolix.getZoneFollow()); + EXPECT_EQ(kCoolixSensorTempMin, ircoolix.getSensorTemp()); + ircoolix.setSensorTemp(kCoolixSensorTempMin - 1); + EXPECT_TRUE(ircoolix.getZoneFollow()); + EXPECT_EQ(kCoolixSensorTempMin, ircoolix.getSensorTemp()); + // Upper bounds + ircoolix.setSensorTemp(kCoolixSensorTempMax); + EXPECT_TRUE(ircoolix.getZoneFollow()); + EXPECT_EQ(kCoolixSensorTempMax, ircoolix.getSensorTemp()); + ircoolix.setSensorTemp(kCoolixSensorTempMax + 1); + EXPECT_TRUE(ircoolix.getZoneFollow()); + EXPECT_EQ(kCoolixSensorTempMax, ircoolix.getSensorTemp()); + // Clearing + ircoolix.clearSensorTemp(); + EXPECT_FALSE(ircoolix.getZoneFollow()); + EXPECT_LT(kCoolixSensorTempMax, ircoolix.getSensorTemp()); +} + +TEST(TestCoolixACClass, SpecialModesAndReset) { + IRCoolixAC ircoolix(0); + ASSERT_NE(kCoolixSwing, ircoolix.getRaw()); + ircoolix.setSwing(); + ASSERT_EQ(kCoolixSwing, ircoolix.getRaw()); + ircoolix.setTurbo(); + ASSERT_EQ(kCoolixTurbo, ircoolix.getRaw()); + ircoolix.setSleep(); + ASSERT_EQ(kCoolixSleep, ircoolix.getRaw()); + ircoolix.setLed(); + ASSERT_EQ(kCoolixLed, ircoolix.getRaw()); + ircoolix.setClean(); + ASSERT_EQ(kCoolixClean, ircoolix.getRaw()); + ircoolix.stateReset(); + ASSERT_NE(kCoolixClean, ircoolix.getRaw()); +} + +TEST(TestCoolixACClass, HumanReadable) { + IRCoolixAC ircoolix(0); + + // Initial starting point. + EXPECT_EQ( + "Power: On, Fan: 5 (AUTO), Mode: 2 (AUTO), Temp: 25C, " + "Zone Follow: Off, Sensor Temp: Ignored", + ircoolix.toString()); + + ircoolix.setSensorTemp(24); + ircoolix.setTemp(22); + ircoolix.setMode(kCoolixCool); + ircoolix.setFan(kCoolixFanMin); + EXPECT_EQ( + "Power: On, Fan: 4 (MIN), Mode: 0 (COOL), Temp: 22C, " + "Zone Follow: On, Sensor Temp: 24C", + ircoolix.toString()); + ircoolix.setSwing(); + EXPECT_EQ("Power: On, Fan: 3 (UNKNOWN), Swing: Toggle", ircoolix.toString()); + ircoolix.setPower(false); + EXPECT_EQ("Power: Off", ircoolix.toString()); +} + +TEST(TestCoolixACClass, KnownExamples) { + IRCoolixAC ircoolix(0); + + ircoolix.setRaw(0b101100101011111111100100); + EXPECT_EQ( + "Power: On, Fan: 5 (AUTO), Mode: 4 (FAN), Zone Follow: Off, " + "Sensor Temp: Ignored", + ircoolix.toString()); + ircoolix.setRaw(0b101100101001111100000000); + EXPECT_EQ( + "Power: On, Fan: 4 (MIN), Mode: 0 (COOL), Temp: 17C, " + "Zone Follow: Off, Sensor Temp: Ignored", + ircoolix.toString()); +} + +TEST(TestCoolixACClass, Issue579FanAuto0) { + IRCoolixAC ircoolix(0); + + ircoolix.setRaw(0xB21F28); + EXPECT_EQ( + "Power: On, Fan: 0 (AUTO0), Mode: 2 (AUTO), Temp: 20C, " + "Zone Follow: Off, Sensor Temp: Ignored", + ircoolix.toString()); +} + +TEST(TestCoolixACClass, RealCaptureExample) { + IRsendTest irsend(0); + IRrecv irrecv(0); + + // From Issue #579 + uint16_t powerOffRawData[199] = { + 4444, 4434, 590, 1578, 698, 446, 590, 1578, 622, 1596, 622, 500, + 644, 476, 644, 1548, 588, 532, 594, 530, 612, 1578, 590, 532, + 588, 534, 672, 1518, 594, 1598, 590, 510, 612, 1580, 644, 480, + 612, 1578, 644, 1548, 644, 1548, 594, 1598, 642, 506, 644, 1550, + 644, 1548, 594, 1600, 644, 478, 644, 478, 642, 480, 644, 478, + 642, 1548, 594, 530, 590, 532, 614, 1578, 644, 1548, 594, 1600, + 588, 534, 566, 556, 588, 530, 590, 532, 586, 514, 612, 532, + 588, 532, 590, 534, 588, 1578, 642, 1576, 642, 1550, 588, 1602, + 588, 1580, 642, 4712, 4546, 4406, 588, 1606, 642, 478, 644, 1550, + 590, 1604, 588, 534, 586, 532, 586, 1582, 642, 480, 642, 480, + 668, 1550, 642, 480, 642, 478, 642, 1552, 612, 1578, 586, 538, + 588, 1580, 674, 472, 590, 1602, 586, 1580, 618, 1576, 642, 1548, + 594, 530, 590, 1584, 608, 1578, 644, 1550, 642, 480, 642, 478, + 642, 480, 642, 480, 642, 1550, 590, 530, 592, 528, 592, 1602, + 642, 1548, 592, 1604, 586, 584, 642, 480, 640, 480, 640, 480, + 642, 480, 642, 480, 642, 480, 642, 480, 642, 1552, 590, 1604, + 588, 1578, 642, 1552, 640, 1550, 592}; // COOLIX B27BE0 + + irsend.begin(); + + irsend.reset(); + + irsend.sendRaw(powerOffRawData, 199, 38000); + irsend.makeDecodeResult(); + ASSERT_TRUE(irrecv.decode(&irsend.capture)); + EXPECT_EQ(COOLIX, irsend.capture.decode_type); + EXPECT_EQ(kCoolixBits, irsend.capture.bits); + EXPECT_EQ(kCoolixOff, irsend.capture.value); + EXPECT_EQ(0x0, irsend.capture.address); + EXPECT_EQ(0x0, irsend.capture.command); } diff --git a/lib/IRremoteESP8266/test/ir_Daikin_test.cpp b/lib/IRremoteESP8266/test/ir_Daikin_test.cpp index 041c666..e258993 100644 --- a/lib/IRremoteESP8266/test/ir_Daikin_test.cpp +++ b/lib/IRremoteESP8266/test/ir_Daikin_test.cpp @@ -1,9 +1,9 @@ // Copyright 2017 David Conran +#include "ir_Daikin.h" #include "IRrecv.h" #include "IRrecv_test.h" #include "IRsend.h" #include "IRsend_test.h" -#include "ir_Daikin.h" #include "gtest/gtest.h" // Tests for sendDaikin(). @@ -13,10 +13,10 @@ TEST(TestSendDaikin, SendDataOnly) { IRsendTest irsend(4); irsend.begin(); - uint8_t daikin_code[DAIKIN_COMMAND_LENGTH] = { - 0x11, 0xDA, 0x27, 0xF0, 0x00, 0x00, 0x00, 0x20, - 0x11, 0xDA, 0x27, 0x00, 0x00, 0x41, 0x1E, 0x00, - 0xB0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0xE3}; + uint8_t daikin_code[kDaikinStateLength] = { + 0x11, 0xDA, 0x27, 0xF0, 0x00, 0x00, 0x00, 0x20, 0x11, + 0xDA, 0x27, 0x00, 0x00, 0x41, 0x1E, 0x00, 0xB0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0xE3}; irsend.reset(); irsend.sendDaikin(daikin_code); @@ -60,7 +60,8 @@ TEST(TestSendDaikin, SendDataOnly) { "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428" "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428" "m428s1280m428s1280m428s428m428s428m428s428m428s1280m428s1280m428s1280" - "m428s29428", irsend.outputStr()); + "m428s29428", + irsend.outputStr()); } // Test sending with repeats. @@ -69,13 +70,13 @@ TEST(TestSendDaikin, SendWithRepeats) { irsend.begin(); irsend.reset(); - uint8_t daikin_code[DAIKIN_COMMAND_LENGTH] = { - 0x11, 0xDA, 0x27, 0xF0, 0x00, 0x00, 0x00, 0x20, - 0x11, 0xDA, 0x27, 0x00, 0x00, 0x41, 0x1E, 0x00, - 0xB0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0xE3}; + uint8_t daikin_code[kDaikinStateLength] = { + 0x11, 0xDA, 0x27, 0xF0, 0x00, 0x00, 0x00, 0x20, 0x11, + 0xDA, 0x27, 0x00, 0x00, 0x41, 0x1E, 0x00, 0xB0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0xE3}; irsend.reset(); - irsend.sendDaikin(daikin_code, DAIKIN_COMMAND_LENGTH, 1); + irsend.sendDaikin(daikin_code, kDaikinStateLength, 1); EXPECT_EQ( "m428s428m428s428m428s428m428s428m428s428" "m428s29428m3650s1623" @@ -156,7 +157,8 @@ TEST(TestSendDaikin, SendWithRepeats) { "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428" "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428" "m428s1280m428s1280m428s428m428s428m428s428m428s1280m428s1280m428s1280" - "m428s29428", irsend.outputStr()); + "m428s29428", + irsend.outputStr()); } // Test sending atypical sizes. @@ -164,21 +166,21 @@ TEST(TestSendDaikin, SendUnexpectedSizes) { IRsendTest irsend(4); irsend.begin(); - uint8_t daikin_short_code[DAIKIN_COMMAND_LENGTH - 1] = { - 0x11, 0xDA, 0x27, 0xF0, 0x00, 0x00, 0x00, 0x20, - 0x11, 0xDA, 0x27, 0x00, 0x00, 0x41, 0x1E, 0x00, - 0xB0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00}; + uint8_t daikin_short_code[kDaikinStateLength - 1] = { + 0x11, 0xDA, 0x27, 0xF0, 0x00, 0x00, 0x00, 0x20, 0x11, + 0xDA, 0x27, 0x00, 0x00, 0x41, 0x1E, 0x00, 0xB0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00}; irsend.reset(); - irsend.sendDaikin(daikin_short_code, DAIKIN_COMMAND_LENGTH - 1); + irsend.sendDaikin(daikin_short_code, kDaikinStateLength - 1); ASSERT_EQ("", irsend.outputStr()); - uint8_t daikin_long_code[DAIKIN_COMMAND_LENGTH + 1] = { - 0x11, 0xDA, 0x27, 0xF0, 0x00, 0x00, 0x00, 0x20, - 0x11, 0xDA, 0x27, 0x00, 0x00, 0x41, 0x1E, 0x00, - 0xB0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0xE3, 0x11}; + uint8_t daikin_long_code[kDaikinStateLength + 1] = { + 0x11, 0xDA, 0x27, 0xF0, 0x00, 0x00, 0x00, 0x20, 0x11, 0xDA, + 0x27, 0x00, 0x00, 0x41, 0x1E, 0x00, 0xB0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0xE3, 0x11}; irsend.reset(); - irsend.sendDaikin(daikin_long_code, DAIKIN_COMMAND_LENGTH + 1); + irsend.sendDaikin(daikin_long_code, kDaikinStateLength + 1); ASSERT_EQ( "m428s428m428s428m428s428m428s428m428s428" "m428s29428m3650s1623" @@ -220,7 +222,8 @@ TEST(TestSendDaikin, SendUnexpectedSizes) { "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428" "m428s1280m428s1280m428s428m428s428m428s428m428s1280m428s1280m428s1280" "m428s1280m428s428m428s428m428s428m428s1280m428s428m428s428m428s428" - "m428s29428", irsend.outputStr()); + "m428s29428", + irsend.outputStr()); } // Tests for IRDaikinESP class. @@ -247,25 +250,25 @@ TEST(TestDaikinClass, Temperature) { irdaikin.begin(); irdaikin.setTemp(0); - EXPECT_EQ(DAIKIN_MIN_TEMP, irdaikin.getTemp()); + EXPECT_EQ(kDaikinMinTemp, irdaikin.getTemp()); irdaikin.setTemp(255); - EXPECT_EQ(DAIKIN_MAX_TEMP, irdaikin.getTemp()); + EXPECT_EQ(kDaikinMaxTemp, irdaikin.getTemp()); - irdaikin.setTemp(DAIKIN_MIN_TEMP); - EXPECT_EQ(DAIKIN_MIN_TEMP, irdaikin.getTemp()); + irdaikin.setTemp(kDaikinMinTemp); + EXPECT_EQ(kDaikinMinTemp, irdaikin.getTemp()); - irdaikin.setTemp(DAIKIN_MAX_TEMP); - EXPECT_EQ(DAIKIN_MAX_TEMP, irdaikin.getTemp()); + irdaikin.setTemp(kDaikinMaxTemp); + EXPECT_EQ(kDaikinMaxTemp, irdaikin.getTemp()); - irdaikin.setTemp(DAIKIN_MIN_TEMP - 1); - EXPECT_EQ(DAIKIN_MIN_TEMP, irdaikin.getTemp()); + irdaikin.setTemp(kDaikinMinTemp - 1); + EXPECT_EQ(kDaikinMinTemp, irdaikin.getTemp()); - irdaikin.setTemp(DAIKIN_MAX_TEMP + 1); - EXPECT_EQ(DAIKIN_MAX_TEMP, irdaikin.getTemp()); + irdaikin.setTemp(kDaikinMaxTemp + 1); + EXPECT_EQ(kDaikinMaxTemp, irdaikin.getTemp()); - irdaikin.setTemp(DAIKIN_MIN_TEMP + 1); - EXPECT_EQ(DAIKIN_MIN_TEMP + 1, irdaikin.getTemp()); + irdaikin.setTemp(kDaikinMinTemp + 1); + EXPECT_EQ(kDaikinMinTemp + 1, irdaikin.getTemp()); irdaikin.setTemp(21); EXPECT_EQ(21, irdaikin.getTemp()); @@ -281,29 +284,29 @@ TEST(TestDaikinClass, OperatingMode) { IRDaikinESP irdaikin(0); irdaikin.begin(); - irdaikin.setMode(DAIKIN_AUTO); - EXPECT_EQ(DAIKIN_AUTO, irdaikin.getMode()); + irdaikin.setMode(kDaikinAuto); + EXPECT_EQ(kDaikinAuto, irdaikin.getMode()); - irdaikin.setMode(DAIKIN_COOL); - EXPECT_EQ(DAIKIN_COOL, irdaikin.getMode()); + irdaikin.setMode(kDaikinCool); + EXPECT_EQ(kDaikinCool, irdaikin.getMode()); - irdaikin.setMode(DAIKIN_HEAT); - EXPECT_EQ(DAIKIN_HEAT, irdaikin.getMode()); + irdaikin.setMode(kDaikinHeat); + EXPECT_EQ(kDaikinHeat, irdaikin.getMode()); - irdaikin.setMode(DAIKIN_DRY); - EXPECT_EQ(DAIKIN_DRY, irdaikin.getMode()); + irdaikin.setMode(kDaikinDry); + EXPECT_EQ(kDaikinDry, irdaikin.getMode()); - irdaikin.setMode(DAIKIN_FAN); - EXPECT_EQ(DAIKIN_FAN, irdaikin.getMode()); + irdaikin.setMode(kDaikinFan); + EXPECT_EQ(kDaikinFan, irdaikin.getMode()); - irdaikin.setMode(DAIKIN_FAN + 1); - EXPECT_EQ(DAIKIN_AUTO, irdaikin.getMode()); + irdaikin.setMode(kDaikinFan + 1); + EXPECT_EQ(kDaikinAuto, irdaikin.getMode()); - irdaikin.setMode(DAIKIN_AUTO + 1); - EXPECT_EQ(DAIKIN_AUTO, irdaikin.getMode()); + irdaikin.setMode(kDaikinAuto + 1); + EXPECT_EQ(kDaikinAuto, irdaikin.getMode()); irdaikin.setMode(255); - EXPECT_EQ(DAIKIN_AUTO, irdaikin.getMode()); + EXPECT_EQ(kDaikinAuto, irdaikin.getMode()); } TEST(TestDaikinClass, VaneSwing) { @@ -405,40 +408,40 @@ TEST(TestDaikinClass, FanSpeed) { // Unexpected value should default to Auto. irdaikin.setFan(0); - EXPECT_EQ(DAIKIN_FAN_AUTO, irdaikin.getFan()); + EXPECT_EQ(kDaikinFanAuto, irdaikin.getFan()); // Unexpected value should default to Auto. irdaikin.setFan(255); - EXPECT_EQ(DAIKIN_FAN_AUTO, irdaikin.getFan()); + EXPECT_EQ(kDaikinFanAuto, irdaikin.getFan()); - irdaikin.setFan(DAIKIN_FAN_MAX); - EXPECT_EQ(DAIKIN_FAN_MAX, irdaikin.getFan()); + irdaikin.setFan(kDaikinFanMax); + EXPECT_EQ(kDaikinFanMax, irdaikin.getFan()); // Beyond Max should default to Auto. - irdaikin.setFan(DAIKIN_FAN_MAX + 1); - EXPECT_EQ(DAIKIN_FAN_AUTO, irdaikin.getFan()); + irdaikin.setFan(kDaikinFanMax + 1); + EXPECT_EQ(kDaikinFanAuto, irdaikin.getFan()); - irdaikin.setFan(DAIKIN_FAN_MAX - 1); - EXPECT_EQ(DAIKIN_FAN_MAX - 1, irdaikin.getFan()); + irdaikin.setFan(kDaikinFanMax - 1); + EXPECT_EQ(kDaikinFanMax - 1, irdaikin.getFan()); - irdaikin.setFan(DAIKIN_FAN_MIN); - EXPECT_EQ(DAIKIN_FAN_MIN, irdaikin.getFan()); + irdaikin.setFan(kDaikinFanMin); + EXPECT_EQ(kDaikinFanMin, irdaikin.getFan()); - irdaikin.setFan(DAIKIN_FAN_MIN + 1); - EXPECT_EQ(DAIKIN_FAN_MIN + 1, irdaikin.getFan()); + irdaikin.setFan(kDaikinFanMin + 1); + EXPECT_EQ(kDaikinFanMin + 1, irdaikin.getFan()); // Beyond Min should default to Auto. - irdaikin.setFan(DAIKIN_FAN_MIN - 1); - EXPECT_EQ(DAIKIN_FAN_AUTO, irdaikin.getFan()); + irdaikin.setFan(kDaikinFanMin - 1); + EXPECT_EQ(kDaikinFanAuto, irdaikin.getFan()); irdaikin.setFan(3); EXPECT_EQ(3, irdaikin.getFan()); - irdaikin.setFan(DAIKIN_FAN_AUTO); - EXPECT_EQ(DAIKIN_FAN_AUTO, irdaikin.getFan()); + irdaikin.setFan(kDaikinFanAuto); + EXPECT_EQ(kDaikinFanAuto, irdaikin.getFan()); - irdaikin.setFan(DAIKIN_FAN_QUIET); - EXPECT_EQ(DAIKIN_FAN_QUIET, irdaikin.getFan()); + irdaikin.setFan(kDaikinFanQuiet); + EXPECT_EQ(kDaikinFanQuiet, irdaikin.getFan()); } TEST(TestDaikinClass, CurrentTime) { @@ -463,16 +466,16 @@ TEST(TestDaikinClass, OnOffTimers) { irdaikin.disableOnTimer(); irdaikin.disableOffTimer(); EXPECT_FALSE(irdaikin.getOnTimerEnabled()); - EXPECT_EQ(0x600, irdaikin.getOnTime()); + EXPECT_EQ(kDaikinUnusedTime, irdaikin.getOnTime()); EXPECT_FALSE(irdaikin.getOffTimerEnabled()); - EXPECT_EQ(0x600, irdaikin.getOffTime()); + EXPECT_EQ(kDaikinUnusedTime, irdaikin.getOffTime()); // Turn on just the On Timer. irdaikin.enableOnTimer(123); EXPECT_TRUE(irdaikin.getOnTimerEnabled()); EXPECT_EQ(123, irdaikin.getOnTime()); EXPECT_FALSE(irdaikin.getOffTimerEnabled()); - EXPECT_EQ(0x600, irdaikin.getOffTime()); + EXPECT_EQ(kDaikinUnusedTime, irdaikin.getOffTime()); // Now turn on the Off Timer. irdaikin.enableOffTimer(754); @@ -484,16 +487,16 @@ TEST(TestDaikinClass, OnOffTimers) { // Turn off the just the On Timer. irdaikin.disableOnTimer(); EXPECT_FALSE(irdaikin.getOnTimerEnabled()); - EXPECT_EQ(0x600, irdaikin.getOnTime()); + EXPECT_EQ(kDaikinUnusedTime, irdaikin.getOnTime()); EXPECT_TRUE(irdaikin.getOffTimerEnabled()); EXPECT_EQ(754, irdaikin.getOffTime()); // Now turn off the Off Timer. irdaikin.disableOffTimer(); EXPECT_FALSE(irdaikin.getOffTimerEnabled()); - EXPECT_EQ(0x600, irdaikin.getOffTime()); + EXPECT_EQ(kDaikinUnusedTime, irdaikin.getOffTime()); EXPECT_FALSE(irdaikin.getOnTimerEnabled()); - EXPECT_EQ(0x600, irdaikin.getOnTime()); + EXPECT_EQ(kDaikinUnusedTime, irdaikin.getOnTime()); // Use some canary values around the timers to ensure no accidental // bit flips happen. i.e. Neighbouring bytes in the state. @@ -598,30 +601,30 @@ TEST(TestDaikinClass, RenderTime) { TEST(TestDaikinClass, SetAndGetRaw) { IRDaikinESP irdaikin(0); - uint8_t initialState[DAIKIN_COMMAND_LENGTH] = { - 0x11, 0xDA, 0x27, 0x00, 0x42, 0x00, 0x00, 0x54, - 0x11, 0xDA, 0x27, 0x00, 0x00, 0x49, 0x1E, 0x00, - 0xB0, 0x00, 0x00, 0x06, 0x60, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x4F}; - uint8_t expectedState[DAIKIN_COMMAND_LENGTH] = { - 0x11, 0xDA, 0x27, 0x00, 0x42, 0x00, 0x00, 0x54, - 0x11, 0xDA, 0x27, 0x00, 0x00, 0x48, 0x2A, 0x00, - 0xB0, 0x00, 0x00, 0x06, 0x60, 0x00, 0x00, 0xC0, 0x00, 0x02, 0x5A}; + uint8_t initialState[kDaikinStateLength] = { + 0x11, 0xDA, 0x27, 0x00, 0x42, 0x00, 0x00, 0x54, 0x11, + 0xDA, 0x27, 0x00, 0x00, 0x49, 0x1E, 0x00, 0xB0, 0x00, + 0x00, 0x06, 0x60, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x4F}; + uint8_t expectedState[kDaikinStateLength] = { + 0x11, 0xDA, 0x27, 0x00, 0x42, 0x00, 0x00, 0x54, 0x11, + 0xDA, 0x27, 0x00, 0x00, 0x48, 0x2A, 0x00, 0xB0, 0x00, + 0x00, 0x06, 0x60, 0x00, 0x00, 0xC0, 0x00, 0x02, 0x5A}; - EXPECT_STATE_EQ(initialState, irdaikin.getRaw(), DAIKIN_BITS); + EXPECT_STATE_EQ(initialState, irdaikin.getRaw(), kDaikinBits); // toggle the power state. irdaikin.setPower(!irdaikin.getPower()); irdaikin.setTemp(21); irdaikin.setMold(true); - EXPECT_STATE_EQ(expectedState, irdaikin.getRaw(), DAIKIN_BITS); + EXPECT_STATE_EQ(expectedState, irdaikin.getRaw(), kDaikinBits); irdaikin.setRaw(initialState); - EXPECT_STATE_EQ(initialState, irdaikin.getRaw(), DAIKIN_BITS); + EXPECT_STATE_EQ(initialState, irdaikin.getRaw(), kDaikinBits); } TEST(TestDaikinClass, ChecksumValidation) { - uint8_t daikin_code[DAIKIN_COMMAND_LENGTH] = { - 0x11, 0xDA, 0x27, 0xF0, 0x00, 0x00, 0x00, 0x02, - 0x11, 0xDA, 0x27, 0x00, 0x00, 0x41, 0x1E, 0x00, - 0xB0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0xE1}; + uint8_t daikin_code[kDaikinStateLength] = { + 0x11, 0xDA, 0x27, 0xF0, 0x00, 0x00, 0x00, 0x02, 0x11, + 0xDA, 0x27, 0x00, 0x00, 0x41, 0x1E, 0x00, 0xB0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0xE1}; EXPECT_TRUE(IRDaikinESP::validChecksum(daikin_code)); // Change the array so the checksum is invalid. @@ -643,14 +646,15 @@ TEST(TestDaikinClass, ChecksumValidation) { TEST(TestDaikinClass, HumanReadable) { IRDaikinESP irdaikin(0); - EXPECT_EQ("Power: On, Mode: 4 (HEAT), Temp: 15C, Fan: 11 (QUIET), " - "Powerful: Off, Quiet: Off, Sensor: Off, Eye: Off, Mold: Off, " - "Swing (Horizontal): Off, Swing (Vertical): Off, " - "Current Time: 0:00, On Time: Off, Off Time: Off", - irdaikin.toString()); - irdaikin.setMode(DAIKIN_AUTO); + EXPECT_EQ( + "Power: On, Mode: 4 (HEAT), Temp: 15C, Fan: 11 (QUIET), " + "Powerful: Off, Quiet: Off, Sensor: Off, Eye: Off, Mold: Off, " + "Swing (Horizontal): Off, Swing (Vertical): Off, " + "Current Time: 0:00, On Time: Off, Off Time: Off", + irdaikin.toString()); + irdaikin.setMode(kDaikinAuto); irdaikin.setTemp(25); - irdaikin.setFan(DAIKIN_FAN_AUTO); + irdaikin.setFan(kDaikinFanAuto); irdaikin.setQuiet(true); irdaikin.setSensor(true); irdaikin.setEye(true); @@ -661,11 +665,12 @@ TEST(TestDaikinClass, HumanReadable) { irdaikin.enableOnTimer(8 * 60 + 0); irdaikin.enableOffTimer(17 * 60 + 30); irdaikin.off(); - EXPECT_EQ("Power: Off, Mode: 0 (AUTO), Temp: 25C, Fan: 10 (AUTO), " - "Powerful: Off, Quiet: On, Sensor: On, Eye: On, Mold: On, " - "Swing (Horizontal): On, Swing (Vertical): On, " - "Current Time: 9:15, On Time: 8:00, Off Time: 17:30", - irdaikin.toString()); + EXPECT_EQ( + "Power: Off, Mode: 0 (AUTO), Temp: 25C, Fan: 10 (AUTO), " + "Powerful: Off, Quiet: On, Sensor: On, Eye: On, Mold: On, " + "Swing (Horizontal): On, Swing (Vertical): On, " + "Current Time: 9:15, On Time: 8:00, Off Time: 17:30", + irdaikin.toString()); } // Test general message construction after tweaking some settings. @@ -675,8 +680,8 @@ TEST(TestDaikinClass, MessageConstuction) { irdaikin.begin(); irsend.begin(); - irdaikin.setFan(DAIKIN_FAN_MIN); - irdaikin.setMode(DAIKIN_COOL); + irdaikin.setFan(kDaikinFanMin); + irdaikin.setMode(kDaikinCool); irdaikin.setTemp(27); irdaikin.setSwingVertical(false); irdaikin.setSwingHorizontal(true); @@ -684,8 +689,8 @@ TEST(TestDaikinClass, MessageConstuction) { irdaikin.setPower(true); // Check everything for kicks. - EXPECT_EQ(DAIKIN_FAN_MIN, irdaikin.getFan()); - EXPECT_EQ(DAIKIN_COOL, irdaikin.getMode()); + EXPECT_EQ(kDaikinFanMin, irdaikin.getFan()); + EXPECT_EQ(kDaikinCool, irdaikin.getMode()); EXPECT_EQ(27, irdaikin.getTemp()); EXPECT_FALSE(irdaikin.getSwingVertical()); EXPECT_TRUE(irdaikin.getSwingHorizontal()); @@ -734,7 +739,8 @@ TEST(TestDaikinClass, MessageConstuction) { "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428" "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428" "m428s428m428s1280m428s1280m428s428m428s428m428s1280m428s1280m428s1280" - "m428s29428", irsend.outputStr()); + "m428s29428", + irsend.outputStr()); } // Tests for decodeDaikin(). @@ -746,67 +752,67 @@ TEST(TestDecodeDaikin, RealExample) { IRrecv irrecv(4); irsend.begin(); - uint8_t expectedState[DAIKIN_COMMAND_LENGTH] = { - 0x11, 0xDA, 0x27, 0x00, 0x42, 0x3A, 0x05, 0x93, 0x11, 0xDA, 0x27, 0x00, - 0x00, 0x3F, 0x3A, 0x00, 0xA0, 0x00, 0x0A, 0x25, 0x17, 0x01, 0x00, 0xC0, - 0x00, 0x00, 0x32}; - uint16_t rawData[DAIKIN_RAW_BITS] = { - 416, 446, 416, 446, 416, 446, 418, 446, 416, 446, 416, 25434, - 3436, 1768, 390, 1336, 390, 446, 416, 446, 416, 446, 416, 1336, - 390, 446, 416, 446, 416, 446, 416, 446, 416, 1336, 390, 448, - 416, 1336, 390, 1336, 390, 448, 416, 1336, 390, 1336, 390, 1338, - 388, 1338, 390, 1336, 390, 446, 416, 446, 416, 1336, 390, 446, - 416, 446, 416, 446, 416, 446, 416, 446, 416, 446, 416, 448, - 416, 446, 416, 446, 416, 446, 416, 1336, 390, 446, 416, 1336, - 390, 448, 416, 446, 416, 446, 416, 1336, 390, 1336, 390, 446, - 416, 446, 416, 446, 416, 446, 416, 446, 416, 446, 416, 446, - 416, 446, 416, 446, 416, 448, 416, 446, 416, 446, 416, 446, - 416, 448, 414, 448, 416, 448, 416, 1336, 390, 1336, 390, 1336, - 390, 446, 414, 1336, 390, 448, 414, 1336, 390, 1336, 390, 34878, - 3436, 1768, 390, 1336, 390, 446, 416, 448, 416, 446, 416, 1336, - 390, 446, 416, 448, 416, 446, 416, 446, 416, 1336, 390, 446, - 416, 1336, 390, 1336, 390, 446, 416, 1336, 390, 1336, 390, 1336, - 390, 1336, 390, 1336, 392, 446, 414, 448, 416, 1336, 390, 446, - 416, 446, 416, 446, 416, 446, 414, 448, 416, 446, 416, 448, - 414, 448, 416, 446, 416, 446, 416, 446, 414, 1336, 390, 448, - 416, 446, 416, 446, 416, 448, 416, 1336, 390, 446, 416, 446, - 416, 1336, 390, 446, 416, 1336, 390, 1336, 390, 1336, 390, 446, - 416, 446, 414, 1338, 390, 446, 416, 1336, 390, 446, 416, 446, - 416, 446, 416, 446, 416, 446, 416, 1336, 390, 1336, 390, 446, - 416, 446, 416, 1336, 390, 446, 416, 446, 416, 1336, 390, 34876, - 3436, 1768, 388, 1336, 390, 446, 416, 446, 416, 448, 416, 1336, - 390, 446, 416, 446, 416, 446, 416, 448, 416, 1336, 390, 448, - 414, 1336, 390, 1336, 390, 446, 416, 1336, 388, 1338, 388, 1336, - 390, 1336, 390, 1336, 390, 446, 416, 446, 416, 1336, 390, 446, - 420, 442, 416, 446, 416, 446, 416, 446, 416, 446, 416, 446, - 416, 446, 416, 446, 416, 446, 416, 446, 416, 446, 416, 448, - 416, 446, 416, 448, 416, 446, 416, 448, 416, 446, 416, 1336, - 390, 1336, 390, 1336, 388, 1338, 390, 1336, 390, 1336, 392, 446, - 416, 446, 416, 448, 416, 1334, 390, 446, 416, 1338, 388, 1336, - 390, 1336, 390, 446, 416, 446, 416, 448, 414, 446, 416, 446, - 416, 446, 416, 448, 416, 446, 416, 446, 416, 446, 416, 446, - 416, 446, 416, 446, 416, 446, 416, 446, 416, 1336, 390, 446, - 416, 1336, 390, 446, 414, 448, 416, 446, 416, 446, 416, 446, - 416, 448, 416, 446, 416, 446, 416, 446, 416, 1336, 390, 446, - 416, 1336, 390, 446, 416, 446, 416, 446, 416, 448, 416, 1338, - 390, 444, 418, 1336, 390, 448, 416, 446, 416, 1336, 390, 446, - 416, 446, 416, 1336, 390, 1336, 388, 1336, 390, 446, 416, 1336, - 390, 448, 414, 448, 414, 448, 416, 1334, 390, 446, 416, 446, - 416, 446, 416, 448, 416, 446, 416, 446, 416, 448, 416, 446, - 416, 446, 416, 446, 416, 446, 416, 446, 416, 446, 416, 446, - 416, 446, 416, 446, 416, 446, 416, 446, 416, 446, 416, 446, - 416, 448, 416, 1336, 390, 1336, 390, 446, 416, 446, 416, 446, - 416, 446, 414, 446, 416, 448, 416, 446, 416, 448, 414, 446, - 418, 446, 416, 446, 416, 448, 416, 446, 416, 448, 416, 446, - 416, 448, 416, 446, 416, 1336, 390, 446, 416, 446, 416, 1338, - 390, 1336, 390, 446, 416, 446, 416}; // Captured by @sillyfrog + uint8_t expectedState[kDaikinStateLength] = { + 0x11, 0xDA, 0x27, 0x00, 0x42, 0x3A, 0x05, 0x93, 0x11, + 0xDA, 0x27, 0x00, 0x00, 0x3F, 0x3A, 0x00, 0xA0, 0x00, + 0x0A, 0x25, 0x17, 0x01, 0x00, 0xC0, 0x00, 0x00, 0x32}; + uint16_t rawData[kDaikinRawBits] = { + 416, 446, 416, 446, 416, 446, 418, 446, 416, 446, 416, 25434, + 3436, 1768, 390, 1336, 390, 446, 416, 446, 416, 446, 416, 1336, + 390, 446, 416, 446, 416, 446, 416, 446, 416, 1336, 390, 448, + 416, 1336, 390, 1336, 390, 448, 416, 1336, 390, 1336, 390, 1338, + 388, 1338, 390, 1336, 390, 446, 416, 446, 416, 1336, 390, 446, + 416, 446, 416, 446, 416, 446, 416, 446, 416, 446, 416, 448, + 416, 446, 416, 446, 416, 446, 416, 1336, 390, 446, 416, 1336, + 390, 448, 416, 446, 416, 446, 416, 1336, 390, 1336, 390, 446, + 416, 446, 416, 446, 416, 446, 416, 446, 416, 446, 416, 446, + 416, 446, 416, 446, 416, 448, 416, 446, 416, 446, 416, 446, + 416, 448, 414, 448, 416, 448, 416, 1336, 390, 1336, 390, 1336, + 390, 446, 414, 1336, 390, 448, 414, 1336, 390, 1336, 390, 34878, + 3436, 1768, 390, 1336, 390, 446, 416, 448, 416, 446, 416, 1336, + 390, 446, 416, 448, 416, 446, 416, 446, 416, 1336, 390, 446, + 416, 1336, 390, 1336, 390, 446, 416, 1336, 390, 1336, 390, 1336, + 390, 1336, 390, 1336, 392, 446, 414, 448, 416, 1336, 390, 446, + 416, 446, 416, 446, 416, 446, 414, 448, 416, 446, 416, 448, + 414, 448, 416, 446, 416, 446, 416, 446, 414, 1336, 390, 448, + 416, 446, 416, 446, 416, 448, 416, 1336, 390, 446, 416, 446, + 416, 1336, 390, 446, 416, 1336, 390, 1336, 390, 1336, 390, 446, + 416, 446, 414, 1338, 390, 446, 416, 1336, 390, 446, 416, 446, + 416, 446, 416, 446, 416, 446, 416, 1336, 390, 1336, 390, 446, + 416, 446, 416, 1336, 390, 446, 416, 446, 416, 1336, 390, 34876, + 3436, 1768, 388, 1336, 390, 446, 416, 446, 416, 448, 416, 1336, + 390, 446, 416, 446, 416, 446, 416, 448, 416, 1336, 390, 448, + 414, 1336, 390, 1336, 390, 446, 416, 1336, 388, 1338, 388, 1336, + 390, 1336, 390, 1336, 390, 446, 416, 446, 416, 1336, 390, 446, + 420, 442, 416, 446, 416, 446, 416, 446, 416, 446, 416, 446, + 416, 446, 416, 446, 416, 446, 416, 446, 416, 446, 416, 448, + 416, 446, 416, 448, 416, 446, 416, 448, 416, 446, 416, 1336, + 390, 1336, 390, 1336, 388, 1338, 390, 1336, 390, 1336, 392, 446, + 416, 446, 416, 448, 416, 1334, 390, 446, 416, 1338, 388, 1336, + 390, 1336, 390, 446, 416, 446, 416, 448, 414, 446, 416, 446, + 416, 446, 416, 448, 416, 446, 416, 446, 416, 446, 416, 446, + 416, 446, 416, 446, 416, 446, 416, 446, 416, 1336, 390, 446, + 416, 1336, 390, 446, 414, 448, 416, 446, 416, 446, 416, 446, + 416, 448, 416, 446, 416, 446, 416, 446, 416, 1336, 390, 446, + 416, 1336, 390, 446, 416, 446, 416, 446, 416, 448, 416, 1338, + 390, 444, 418, 1336, 390, 448, 416, 446, 416, 1336, 390, 446, + 416, 446, 416, 1336, 390, 1336, 388, 1336, 390, 446, 416, 1336, + 390, 448, 414, 448, 414, 448, 416, 1334, 390, 446, 416, 446, + 416, 446, 416, 448, 416, 446, 416, 446, 416, 448, 416, 446, + 416, 446, 416, 446, 416, 446, 416, 446, 416, 446, 416, 446, + 416, 446, 416, 446, 416, 446, 416, 446, 416, 446, 416, 446, + 416, 448, 416, 1336, 390, 1336, 390, 446, 416, 446, 416, 446, + 416, 446, 414, 446, 416, 448, 416, 446, 416, 448, 414, 446, + 418, 446, 416, 446, 416, 448, 416, 446, 416, 448, 416, 446, + 416, 448, 416, 446, 416, 1336, 390, 446, 416, 446, 416, 1338, + 390, 1336, 390, 446, 416, 446, 416}; // Captured by @sillyfrog irsend.reset(); - irsend.sendRaw(rawData, DAIKIN_RAW_BITS, 38000); + irsend.sendRaw(rawData, kDaikinRawBits, 38000); irsend.makeDecodeResult(); EXPECT_TRUE(irrecv.decode(&irsend.capture)); ASSERT_EQ(DAIKIN, irsend.capture.decode_type); - ASSERT_EQ(DAIKIN_BITS, irsend.capture.bits); + ASSERT_EQ(kDaikinBits, irsend.capture.bits); EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); } @@ -817,16 +823,631 @@ TEST(TestDecodeDaikin, SyntheticExample) { IRrecv irrecv(4); irsend.begin(); - uint8_t expectedState[DAIKIN_COMMAND_LENGTH] = { - 0x11, 0xDA, 0x27, 0x00, 0x42, 0x3A, 0x05, 0x93, 0x11, 0xDA, 0x27, 0x00, - 0x00, 0x3F, 0x3A, 0x00, 0xA0, 0x00, 0x0A, 0x25, 0x17, 0x01, 0x00, 0xC0, - 0x00, 0x00, 0x32}; + uint8_t expectedState[kDaikinStateLength] = { + 0x11, 0xDA, 0x27, 0x00, 0x42, 0x3A, 0x05, 0x93, 0x11, + 0xDA, 0x27, 0x00, 0x00, 0x3F, 0x3A, 0x00, 0xA0, 0x00, + 0x0A, 0x25, 0x17, 0x01, 0x00, 0xC0, 0x00, 0x00, 0x32}; irsend.reset(); irsend.sendDaikin(expectedState); irsend.makeDecodeResult(); EXPECT_TRUE(irrecv.decode(&irsend.capture)); ASSERT_EQ(DAIKIN, irsend.capture.decode_type); - ASSERT_EQ(DAIKIN_BITS, irsend.capture.bits); + ASSERT_EQ(kDaikinBits, irsend.capture.bits); EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); } + +// Test decoding a message captured from a real IR remote. +TEST(TestDecodeDaikin2, RealExample) { + IRsendTest irsend(0); + IRrecv irrecv(0); + irsend.begin(); + + uint8_t expectedState[kDaikin2StateLength] = { + 0x11, 0xDA, 0x27, 0x00, 0x01, 0x7A, 0xC3, 0x70, 0x28, 0x0C, + 0x80, 0x04, 0xB0, 0x16, 0x24, 0x00, 0x00, 0xBE, 0xD5, 0xF5, + 0x11, 0xDA, 0x27, 0x00, 0x00, 0x08, 0x26, 0x00, 0xA0, 0x00, + 0x00, 0x06, 0x60, 0x00, 0x00, 0xC1, 0x80, 0x60, 0xE7}; + // "Off" Data from https://github.com/markszabo/IRremoteESP8266/issues/582 + uint16_t rawData[633] = { // Data supplied by @sheppy99 + 10024, 25180, 3494, 1732, 436, 1300, 436, 436, 432, 438, 430, 438, + 426, 1306, 430, 442, 430, 438, 428, 440, 430, 440, 430, 1304, + 432, 442, 428, 1308, 424, 1312, 428, 442, 428, 1306, 424, 1314, + 426, 1308, 434, 1306, 426, 1308, 428, 444, 426, 442, 428, 1310, + 428, 442, 424, 444, 426, 442, 426, 444, 424, 444, 426, 444, + 424, 446, 422, 446, 422, 446, 422, 446, 418, 1318, 418, 450, + 420, 448, 420, 448, 422, 448, 420, 450, 420, 448, 420, 450, + 420, 452, 418, 1318, 420, 450, 420, 1318, 420, 1314, 418, 1318, + 424, 1314, 424, 448, 422, 1316, 424, 1312, 426, 446, 422, 448, + 420, 448, 422, 448, 422, 1314, 418, 1320, 416, 452, 420, 448, + 420, 448, 422, 448, 422, 1314, 416, 1320, 422, 1316, 422, 450, + 418, 450, 420, 448, 420, 448, 416, 1320, 418, 452, 418, 1316, + 422, 448, 420, 450, 420, 450, 420, 448, 422, 1314, 418, 1320, + 418, 450, 420, 448, 420, 448, 420, 450, 420, 450, 418, 450, + 418, 450, 420, 450, 418, 452, 416, 452, 420, 450, 418, 1318, + 420, 452, 418, 452, 418, 1322, 416, 452, 416, 452, 418, 452, + 418, 452, 416, 454, 418, 452, 416, 456, 414, 452, 418, 454, + 416, 1320, 410, 1324, 418, 452, 418, 1320, 416, 452, 418, 1320, + 418, 1318, 420, 448, 420, 1316, 420, 450, 420, 450, 418, 450, + 420, 450, 418, 452, 418, 1320, 418, 450, 418, 450, 416, 1322, + 412, 458, 420, 450, 416, 452, 418, 452, 416, 452, 418, 452, + 416, 454, 416, 452, 418, 452, 416, 454, 414, 454, 416, 454, + 416, 454, 414, 456, 414, 454, 414, 456, 412, 454, 416, 456, + 414, 456, 412, 1326, 412, 1320, 412, 1322, 414, 1322, 418, 1320, + 420, 452, 418, 1318, 420, 1316, 422, 450, 420, 1314, 424, 448, + 422, 1314, 422, 448, 422, 1314, 418, 1318, 424, 1316, 422, 448, + 422, 1312, 424, 446, 422, 1314, 420, 1318, 422, 1316, 426, 1310, + 426, 35166, 3500, 1724, 446, 1296, 444, 432, 436, 432, 438, 432, + 436, 1296, 440, 434, 434, 436, 432, 436, 434, 436, 434, 1298, + 438, 438, 432, 1304, 428, 1304, 432, 442, 430, 1302, 430, 1308, + 430, 1306, 434, 1302, 432, 1306, 430, 440, 430, 438, 430, 1308, + 434, 438, 430, 440, 428, 440, 430, 440, 428, 442, 426, 444, + 428, 442, 426, 444, 426, 442, 426, 444, 424, 446, 422, 446, + 424, 446, 424, 446, 422, 446, 424, 448, 420, 448, 422, 446, + 422, 448, 422, 450, 420, 450, 414, 1320, 420, 450, 418, 450, + 418, 448, 420, 450, 418, 452, 418, 1320, 418, 1316, 422, 450, + 418, 452, 418, 1320, 420, 448, 418, 450, 420, 450, 418, 452, + 416, 452, 418, 450, 418, 452, 416, 452, 418, 452, 416, 454, + 416, 452, 416, 454, 416, 454, 414, 456, 416, 454, 414, 1322, + 416, 454, 416, 1320, 418, 452, 416, 454, 414, 454, 416, 454, + 414, 454, 414, 454, 414, 456, 414, 456, 412, 456, 414, 456, + 414, 456, 412, 456, 414, 458, 406, 464, 410, 458, 412, 458, + 410, 460, 410, 1326, 412, 1324, 414, 456, 412, 458, 412, 456, + 414, 456, 412, 458, 410, 458, 414, 458, 410, 458, 408, 460, + 410, 470, 400, 1324, 408, 1328, 410, 458, 410, 460, 414, 456, + 410, 456, 414, 458, 412, 460, 410, 458, 412, 458, 412, 460, + 408, 460, 410, 460, 408, 472, 396, 462, 408, 470, 402, 470, + 396, 472, 400, 470, 398, 1326, 412, 460, 408, 472, 396, 472, + 400, 470, 400, 472, 396, 1328, 410, 1324, 414, 458, 410, 458, + 410, 458, 412, 458, 412, 460, 408, 460, 410, 460, 410, 1324, + 414, 458, 410, 460, 408, 460, 410, 458, 410, 460, 410, 1326, + 412, 1322, 416, 456, 412, 1322, 412, 1326, 416, 1322, 418, 452, + 416, 454, 412, 1324, 418, 1320, 420, 1316, 420}; + irsend.reset(); + irsend.sendRaw(rawData, 633, 38000); + irsend.makeDecodeResult(); + ASSERT_TRUE(irrecv.decode(&irsend.capture)); + ASSERT_EQ(DAIKIN2, irsend.capture.decode_type); + ASSERT_EQ(kDaikin2Bits, irsend.capture.bits); + EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); +} + +// Decoding a message we entirely constructed based solely on a given state. +TEST(TestDecodeDaikin2, SyntheticExample) { + IRDaikin2 ac(0); + IRsendTest irsend(0); + IRrecv irrecv(0); + irsend.begin(); + + uint8_t expectedState[kDaikin2StateLength] = { + 0x11, 0xDA, 0x27, 0x00, 0x01, 0x7A, 0xC3, 0x70, 0x28, 0x0C, + 0x80, 0x04, 0xB0, 0x16, 0x24, 0x00, 0x00, 0xBE, 0xD5, 0xF5, + 0x11, 0xDA, 0x27, 0x00, 0x00, 0x08, 0x26, 0x00, 0xA0, 0x00, + 0x00, 0x06, 0x60, 0x00, 0x00, 0xC1, 0x80, 0x60, 0xE7}; + + irsend.reset(); + irsend.sendDaikin2(expectedState); + irsend.makeDecodeResult(); + ASSERT_TRUE(irrecv.decode(&irsend.capture)); + ASSERT_EQ(DAIKIN2, irsend.capture.decode_type); + ASSERT_EQ(kDaikin2Bits, irsend.capture.bits); + EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); + ac.setRaw(irsend.capture.state); + EXPECT_EQ( + "Power: Off, Mode: 0 (AUTO), Temp: 19C, Fan: 10 (Auto), " + "Swing (V): 5, Swing (H): 190 (Auto), " + "Clock: 14:50, On Time: Off, Off Time: Off, Sleep Time: Off, " + "Beep: 1 (Quiet), Light: 3 (Off), Mold: On, Clean: On, Fresh Air: Off, " + "Eye: Off, Eye Auto: Off, Quiet: Off, Powerful: Off, Purify: Off, " + "Econo: Off", + ac.toString()); +} + +TEST(TestDaikin2Class, CurrentTime) { + IRDaikin2 ac(0); + ac.begin(); + + ac.setCurrentTime(0); // 00:00 + EXPECT_EQ(0, ac.getCurrentTime()); + + ac.setCurrentTime(754); // 12:34 + EXPECT_EQ(754, ac.getCurrentTime()); + + ac.setCurrentTime(1439); // 23:59 + EXPECT_EQ(1439, ac.getCurrentTime()); +} + +TEST(TestDaikin2Class, OnOffTimers) { + IRDaikin2 ac(0); + ac.begin(); + + // Both timers turned off. + ac.disableOnTimer(); + ac.disableOffTimer(); + EXPECT_FALSE(ac.getOnTimerEnabled()); + EXPECT_EQ(kDaikinUnusedTime, ac.getOnTime()); + EXPECT_FALSE(ac.getOffTimerEnabled()); + EXPECT_EQ(kDaikinUnusedTime, ac.getOffTime()); + + // Turn on just the On Timer. + ac.enableOnTimer(123); + EXPECT_TRUE(ac.getOnTimerEnabled()); + EXPECT_EQ(123, ac.getOnTime()); + EXPECT_FALSE(ac.getOffTimerEnabled()); + EXPECT_EQ(kDaikinUnusedTime, ac.getOffTime()); + + // Now turn on the Off Timer. + ac.enableOffTimer(754); + EXPECT_TRUE(ac.getOffTimerEnabled()); + EXPECT_EQ(754, ac.getOffTime()); + EXPECT_TRUE(ac.getOnTimerEnabled()); + EXPECT_EQ(123, ac.getOnTime()); + + // Turn off the just the On Timer. + ac.disableOnTimer(); + EXPECT_FALSE(ac.getOnTimerEnabled()); + EXPECT_EQ(kDaikinUnusedTime, ac.getOnTime()); + EXPECT_TRUE(ac.getOffTimerEnabled()); + EXPECT_EQ(754, ac.getOffTime()); + + // Now turn off the Off Timer. + ac.disableOffTimer(); + EXPECT_FALSE(ac.getOffTimerEnabled()); + EXPECT_EQ(kDaikinUnusedTime, ac.getOffTime()); + EXPECT_FALSE(ac.getOnTimerEnabled()); + EXPECT_EQ(kDaikinUnusedTime, ac.getOnTime()); +} + +TEST(TestDaikin2Class, LightAndBeep) { + IRDaikin2 ac(0); + ac.begin(); + + ac.setLight(kDaikinLightOff); + EXPECT_EQ(kDaikinLightOff, ac.getLight()); + ac.setBeep(kDaikinBeepOff); + EXPECT_EQ(kDaikinBeepOff, ac.getBeep()); + ac.setLight(kDaikinLightBright); + EXPECT_EQ(kDaikinLightBright, ac.getLight()); + EXPECT_EQ(kDaikinBeepOff, ac.getBeep()); + ac.setBeep(kDaikinBeepLoud); + EXPECT_EQ(kDaikinBeepLoud, ac.getBeep()); + EXPECT_EQ(kDaikinLightBright, ac.getLight()); +} + +TEST(TestDaikin2Class, FanSpeed) { + IRDaikin2 ac(0); + ac.begin(); + + // Unexpected value should default to Auto. + ac.setFan(0); + EXPECT_EQ(kDaikinFanAuto, ac.getFan()); + + // Unexpected value should default to Auto. + ac.setFan(255); + EXPECT_EQ(kDaikinFanAuto, ac.getFan()); + + ac.setFan(kDaikinFanMax); + EXPECT_EQ(kDaikinFanMax, ac.getFan()); + + // Beyond Max should default to Auto. + ac.setFan(kDaikinFanMax + 1); + EXPECT_EQ(kDaikinFanAuto, ac.getFan()); + + ac.setFan(kDaikinFanMax - 1); + EXPECT_EQ(kDaikinFanMax - 1, ac.getFan()); + + ac.setFan(kDaikinFanMin); + EXPECT_EQ(kDaikinFanMin, ac.getFan()); + + ac.setFan(kDaikinFanMin + 1); + EXPECT_EQ(kDaikinFanMin + 1, ac.getFan()); + + // Beyond Min should default to Auto. + ac.setFan(kDaikinFanMin - 1); + EXPECT_EQ(kDaikinFanAuto, ac.getFan()); + + ac.setFan(3); + EXPECT_EQ(3, ac.getFan()); + + ac.setFan(kDaikinFanAuto); + EXPECT_EQ(kDaikinFanAuto, ac.getFan()); + + ac.setFan(kDaikinFanQuiet); + EXPECT_EQ(kDaikinFanQuiet, ac.getFan()); +} + +// Test Mold mode. +TEST(TestDaikin2Class, MoldSetting) { + IRDaikin2 ac(0); + ac.begin(); + + ac.setMold(false); + ASSERT_FALSE(ac.getMold()); + + ac.setMold(true); + ASSERT_TRUE(ac.getMold()); + + ac.setMold(false); + ASSERT_FALSE(ac.getMold()); +} + +// Test Auto Clean setting. +TEST(TestDaikin2Class, CleanSetting) { + IRDaikin2 ac(0); + ac.begin(); + + ac.setClean(false); + ASSERT_FALSE(ac.getClean()); + + ac.setClean(true); + ASSERT_TRUE(ac.getClean()); + + ac.setClean(false); + ASSERT_FALSE(ac.getClean()); +} +// Test Fresh Air settings. +TEST(TestDaikin2Class, FreshAirSettings) { + IRDaikin2 ac(0); + ac.begin(); + + ac.setFreshAir(false); + ac.setFreshAirHigh(false); + ASSERT_FALSE(ac.getFreshAir()); + ASSERT_FALSE(ac.getFreshAirHigh()); + + ac.setFreshAir(true); + ASSERT_TRUE(ac.getFreshAir()); + ASSERT_FALSE(ac.getFreshAirHigh()); + + ac.setFreshAirHigh(true); + ASSERT_TRUE(ac.getFreshAir()); + ASSERT_TRUE(ac.getFreshAirHigh()); + + ac.setFreshAir(false); + ASSERT_FALSE(ac.getFreshAir()); + ASSERT_TRUE(ac.getFreshAirHigh()); + + ac.setFreshAirHigh(false); + ASSERT_FALSE(ac.getFreshAir()); + ASSERT_FALSE(ac.getFreshAirHigh()); +} + +// Test Eye mode. +TEST(TestDaikin2Class, EyeSetting) { + IRDaikin2 ac(0); + ac.begin(); + + ac.setEye(false); + ASSERT_FALSE(ac.getEye()); + ac.setEye(true); + ASSERT_TRUE(ac.getEye()); + ac.setEye(false); + ASSERT_FALSE(ac.getEye()); +} + +// Test Econo setting. +TEST(TestDaikin2Class, EconoSetting) { + IRDaikin2 ac(0); + ac.begin(); + + ac.setEcono(false); + ASSERT_FALSE(ac.getEcono()); + ac.setEcono(true); + ASSERT_TRUE(ac.getEcono()); + ac.setEcono(false); + ASSERT_FALSE(ac.getEcono()); +} + +TEST(TestDaikin2Class, SleepTimer) { + IRDaikin2 ac(0); + ac.begin(); + + // NOTE: On & Sleep timer share the same time location. + + // Both timers turned off. + ac.disableOnTimer(); + ac.disableSleepTimer(); + EXPECT_FALSE(ac.getOnTimerEnabled()); + EXPECT_EQ(kDaikinUnusedTime, ac.getOnTime()); + EXPECT_FALSE(ac.getSleepTimerEnabled()); + EXPECT_EQ(kDaikinUnusedTime, ac.getSleepTime()); + + // Turn on just the On Timer. + ac.enableOnTimer(123); + EXPECT_TRUE(ac.getOnTimerEnabled()); + EXPECT_EQ(123, ac.getOnTime()); + EXPECT_FALSE(ac.getSleepTimerEnabled()); + EXPECT_EQ(123, ac.getSleepTime()); + + // Now turn on the Sleep Timer. This shoud disable the On Timer. + ac.enableSleepTimer(754); + EXPECT_TRUE(ac.getSleepTimerEnabled()); + EXPECT_EQ(754, ac.getSleepTime()); + EXPECT_FALSE(ac.getOnTimerEnabled()); + EXPECT_EQ(754, ac.getOnTime()); + + // Turn off the just the On Timer. + ac.disableOnTimer(); + EXPECT_FALSE(ac.getOnTimerEnabled()); + EXPECT_EQ(kDaikinUnusedTime, ac.getOnTime()); + EXPECT_FALSE(ac.getSleepTimerEnabled()); + EXPECT_EQ(kDaikinUnusedTime, ac.getSleepTime()); + + // Now turn on the On Timer and turn off the Sleep Timer. + // Both should be off afterwards. + ac.enableOnTimer(123); + ac.disableSleepTimer(); + EXPECT_FALSE(ac.getSleepTimerEnabled()); + EXPECT_EQ(kDaikinUnusedTime, ac.getSleepTime()); + EXPECT_FALSE(ac.getOnTimerEnabled()); + EXPECT_EQ(kDaikinUnusedTime, ac.getOnTime()); +} + +// Test Vertical Swing. +TEST(TestDaikin2Class, Swing) { + IRDaikin2 ac(0); + ac.begin(); + + // Vertical + ac.setSwingVertical(1); + ASSERT_EQ(1, ac.getSwingVertical()); + ac.setSwingVertical(3); + ASSERT_EQ(3, ac.getSwingVertical()); + ac.setSwingVertical(6); + ASSERT_EQ(6, ac.getSwingVertical()); + ac.setSwingVertical(kDaikin2SwingVBreeze); + ASSERT_EQ(kDaikin2SwingVBreeze, ac.getSwingVertical()); + ac.setSwingVertical(kDaikin2SwingVCirculate); + ASSERT_EQ(kDaikin2SwingVCirculate, ac.getSwingVertical()); + ac.setSwingVertical(kDaikin2SwingVAuto); + ASSERT_EQ(kDaikin2SwingVAuto, ac.getSwingVertical()); + ac.setSwingVertical(0); + ASSERT_EQ(kDaikin2SwingVAuto, ac.getSwingVertical()); + ac.setSwingVertical(7); + ASSERT_EQ(kDaikin2SwingVAuto, ac.getSwingVertical()); + ac.setSwingVertical(255); + ASSERT_EQ(kDaikin2SwingVAuto, ac.getSwingVertical()); + + // Horizontal + ac.setSwingHorizontal(kDaikin2SwingHAuto); + ASSERT_EQ(kDaikin2SwingHAuto, ac.getSwingHorizontal()); + ac.setSwingHorizontal(kDaikin2SwingHSwing); + ASSERT_EQ(kDaikin2SwingHSwing, ac.getSwingHorizontal()); + + ac.setSwingHorizontal(0); + ASSERT_EQ(0, ac.getSwingHorizontal()); + ac.setSwingHorizontal(255); + ASSERT_EQ(255, ac.getSwingHorizontal()); +} + +TEST(TestDaikin2Class, QuietMode) { + IRDaikin2 ac(0); + ac.begin(); + + ac.setQuiet(true); + EXPECT_TRUE(ac.getQuiet()); + + ac.setQuiet(false); + EXPECT_FALSE(ac.getQuiet()); + + ac.setQuiet(true); + EXPECT_TRUE(ac.getQuiet()); + + // But setting Powerful mode should exit out of quiet mode. + ac.setPowerful(true); + EXPECT_FALSE(ac.getQuiet()); +} + +TEST(TestDaikin2Class, PowerfulMode) { + IRDaikin2 ac(0); + ac.begin(); + + ac.setPowerful(true); + EXPECT_TRUE(ac.getPowerful()); + + ac.setPowerful(false); + EXPECT_FALSE(ac.getPowerful()); + + ac.setPowerful(true); + EXPECT_TRUE(ac.getPowerful()); + + ac.setQuiet(true); + EXPECT_FALSE(ac.getPowerful()); +} + +// Test Purify mode. +TEST(TestDaikin2Class, PurifySetting) { + IRDaikin2 ac(0); + ac.begin(); + + ac.setPurify(false); + ASSERT_FALSE(ac.getPurify()); + ac.setPurify(true); + ASSERT_TRUE(ac.getPurify()); + ac.setPurify(false); + ASSERT_FALSE(ac.getPurify()); +} + +TEST(TestDaikin2Class, HumanReadable) { + IRDaikin2 ac(0); + ac.begin(); + ac.setPower(true); + ac.setMode(kDaikinCool); + ac.setTemp(21); + ac.setFan(kDaikinFanMax); + ac.setSwingVertical(kDaikin2SwingVAuto); + ac.setSwingHorizontal(kDaikin2SwingHSwing); + ac.setCurrentTime(12 * 60 + 34); // 12:34 + ac.disableOnTimer(); + ac.enableOffTimer(20 * 60); // 20:00 + ac.enableSleepTimer(4 * 60); // 4:00 + ac.setBeep(kDaikinBeepLoud); + ac.setLight(kDaikinLightDim); + ac.setMold(true); + ac.setClean(false); + ac.setFreshAir(true); + ac.setEye(true); + ac.setEyeAuto(true); + ac.setQuiet(false); + ac.setPowerful(true); + ac.setPurify(true); + ac.setEcono(false); + EXPECT_EQ( + "Power: On, Mode: 3 (COOL), Temp: 21C, Fan: 5 (Max), " + "Swing (V): 14 (Auto), Swing (H): 191 (Swing), Clock: 12:34, " + "On Time: Off, Off Time: 20:00, Sleep Time: 4:00, Beep: 2 (Loud), " + "Light: 2 (Dim), Mold: On, Clean: Off, Fresh Air: On, Eye: On, " + "Eye Auto: On, Quiet: Off, Powerful: On, Purify: On, Econo: Off", + ac.toString()); + ac.setQuiet(true); + ac.setMode(kDaikinHeat); + ac.setBeep(kDaikinBeepQuiet); + ac.setLight(kDaikinLightBright); + ac.setTemp(32); + ac.setFan(kDaikinFanMin); + ac.setCurrentTime(23 * 60 + 45); // 23:45 + ac.enableOnTimer(9 * 60 + 11); // 9:11 + EXPECT_EQ( + "Power: On, Mode: 4 (HEAT), Temp: 32C, Fan: 1 (Min), " + "Swing (V): 14 (Auto), Swing (H): 191 (Swing), Clock: 23:45, " + "On Time: 9:11, Off Time: 20:00, Sleep Time: Off, Beep: 1 (Quiet), " + "Light: 1 (Bright), Mold: On, Clean: Off, Fresh Air: On, Eye: On, " + "Eye Auto: On, Quiet: On, Powerful: Off, Purify: On, Econo: Off", + ac.toString()); +} + +// See if we can construct a known state. +TEST(TestDaikin2Class, KnownConstruction) { + IRDaikin2 ac(0); + + uint8_t expectedState[kDaikin2StateLength] = { + 0x11, 0xDA, 0x27, 0x00, 0x01, 0x7A, 0xC3, 0x70, 0x28, 0x0C, + 0x80, 0x04, 0xB0, 0x16, 0x24, 0x00, 0x00, 0xBE, 0xD5, 0xF5, + 0x11, 0xDA, 0x27, 0x00, 0x00, 0x08, 0x26, 0x00, 0xA0, 0x00, + 0x00, 0x06, 0x60, 0x00, 0x00, 0xC1, 0x80, 0x60, 0xE7}; + + ac.begin(); + ac.setPower(false); + ac.setMode(kDaikinAuto); + ac.setTemp(19); + ac.setFan(kDaikinFanAuto); + ac.setSwingVertical(5); + ac.setSwingHorizontal(kDaikin2SwingHAuto); + ac.setCurrentTime(14 * 60 + 50); // 14:50 + ac.disableOnTimer(); + ac.disableOffTimer(); + ac.disableSleepTimer(); + ac.setBeep(kDaikinBeepQuiet); + ac.setLight(kDaikinLightOff); + ac.setMold(true); + ac.setClean(true); + ac.setFreshAir(false); + ac.setEye(false); + ac.setEyeAuto(false); + ac.setQuiet(false); + ac.setPowerful(false); + ac.setPurify(false); + ac.setEcono(false); + EXPECT_EQ( + "Power: Off, Mode: 0 (AUTO), Temp: 19C, Fan: 10 (Auto), " + "Swing (V): 5, Swing (H): 190 (Auto), " + "Clock: 14:50, On Time: Off, Off Time: Off, Sleep Time: Off, " + "Beep: 1 (Quiet), Light: 3 (Off), Mold: On, Clean: On, Fresh Air: Off, " + "Eye: Off, Eye Auto: Off, Quiet: Off, Powerful: Off, Purify: Off, " + "Econo: Off", + ac.toString()); + EXPECT_STATE_EQ(expectedState, ac.getRaw(), kDaikin2Bits); +} + +TEST(TestUtils, Misc) { + ASSERT_EQ("DAIKIN", typeToString(DAIKIN)); + ASSERT_TRUE(hasACState(DAIKIN)); + ASSERT_EQ("DAIKIN2", typeToString(DAIKIN2)); + ASSERT_TRUE(hasACState(DAIKIN2)); +} + +// https://github.com/markszabo/IRremoteESP8266/issues/582#issuecomment-453863879 +TEST(TestDecodeDaikin2, Issue582DeepDecodeExample) { + IRDaikin2 ac(0); + + const uint8_t state[kDaikin2StateLength] = { + 0x11, 0xDA, 0x27, 0x00, 0x01, 0x30, 0x42, 0xF0, 0x28, 0x0C, + 0x80, 0x04, 0xB0, 0x16, 0x24, 0x00, 0x00, 0xBE, 0xCE, 0xA3, + 0x11, 0xDA, 0x27, 0x00, 0x00, 0x09, 0x26, 0x00, 0xA0, 0x00, + 0x00, 0x06, 0x60, 0x00, 0x00, 0xC1, 0x92, 0x60, 0xFA}; + + ac.setRaw(state); + ASSERT_TRUE(ac.getMold()); + ASSERT_TRUE(ac.getEye()); + ASSERT_TRUE(ac.getPurify()); + EXPECT_EQ( + "Power: On, Mode: 0 (AUTO), Temp: 19C, Fan: 10 (Auto), " + "Swing (V): 14 (Auto), Swing (H): 190 (Auto), Clock: 9:20, On Time: Off, " + "Off Time: Off, Sleep Time: Off, Beep: 3 (Off), Light: 3 (Off), " + "Mold: On, Clean: On, Fresh Air: Off, Eye: On, Eye Auto: Off, " + "Quiet: Off, Powerful: Off, Purify: On, Econo: Off", + ac.toString()); +} + +// https://docs.google.com/spreadsheets/d/1f8EGfIbBUo2B-CzUFdrgKQprWakoYNKM80IKZN4KXQE/edit?ts=5c317775#gid=1023395743 +TEST(TestDecodeDaikin2, Issue582PowerfulEconoFix) { + IRDaikin2 ac(0); + + const uint8_t PowerfulOn[39] = { + 0x11, 0xDA, 0x27, 0x00, 0x01, 0x3A, 0x43, 0xF0, 0x28, 0x0C, + 0x80, 0x04, 0xB0, 0x16, 0x24, 0x00, 0x00, 0xBE, 0xCE, 0xAE, + 0x11, 0xDA, 0x27, 0x00, 0x00, 0x39, 0x28, 0x00, 0xA0, 0x00, + 0x00, 0x06, 0x60, 0x01, 0x00, 0xC1, 0x90, 0x60, 0x2B}; + const uint8_t PowerfulOff[39] = { + 0x11, 0xDA, 0x27, 0x00, 0x01, 0x3A, 0x43, 0xF0, 0x28, 0x0C, + 0x80, 0x04, 0xB0, 0x16, 0x24, 0x00, 0x00, 0xBE, 0xCE, 0xAE, + 0x11, 0xDA, 0x27, 0x00, 0x00, 0x39, 0x28, 0x00, 0xA0, 0x00, + 0x00, 0x06, 0x60, 0x00, 0x00, 0xC1, 0x90, 0x60, 0x2A}; + ac.setRaw(PowerfulOn); + ASSERT_TRUE(ac.getPowerful()); + EXPECT_EQ( + "Power: On, Mode: 3 (COOL), Temp: 20C, Fan: 10 (Auto), " + "Swing (V): 14 (Auto), Swing (H): 190 (Auto), Clock: 13:46, " + "On Time: Off, Off Time: Off, Sleep Time: Off, Beep: 3 (Off), " + "Light: 3 (Off), Mold: On, Clean: On, Fresh Air: Off, Eye: Off, " + "Eye Auto: Off, Quiet: Off, Powerful: On, Purify: On, Econo: Off", + ac.toString()); + ac.setRaw(PowerfulOff); + ASSERT_FALSE(ac.getPowerful()); + EXPECT_EQ( + "Power: On, Mode: 3 (COOL), Temp: 20C, Fan: 10 (Auto), " + "Swing (V): 14 (Auto), Swing (H): 190 (Auto), Clock: 13:46, " + "On Time: Off, Off Time: Off, Sleep Time: Off, Beep: 3 (Off), " + "Light: 3 (Off), Mold: On, Clean: On, Fresh Air: Off, Eye: Off, " + "Eye Auto: Off, Quiet: Off, Powerful: Off, Purify: On, Econo: Off", + ac.toString()); + + const uint8_t EconoOn[39] = { + 0x11, 0xDA, 0x27, 0x00, 0x01, 0x3B, 0x43, 0xF0, 0x28, 0x0C, + 0x80, 0x04, 0xB0, 0x16, 0x24, 0x00, 0x00, 0xBE, 0xCE, 0xAF, + 0x11, 0xDA, 0x27, 0x00, 0x00, 0x39, 0x28, 0x00, 0xA0, 0x00, + 0x00, 0x06, 0x60, 0x00, 0x00, 0xC1, 0x94, 0x60, 0x2E}; + const uint8_t EconoOff[39] = { + 0x11, 0xDA, 0x27, 0x00, 0x01, 0x3B, 0x43, 0xF0, 0x28, 0x0C, + 0x80, 0x04, 0xB0, 0x16, 0x24, 0x00, 0x00, 0xBE, 0xCE, 0xAF, + 0x11, 0xDA, 0x27, 0x00, 0x00, 0x39, 0x28, 0x00, 0xA0, 0x00, + 0x00, 0x06, 0x60, 0x00, 0x00, 0xC1, 0x90, 0x60, 0x2A}; + ac.setRaw(EconoOn); + ASSERT_TRUE(ac.getEcono()); + EXPECT_EQ( + "Power: On, Mode: 3 (COOL), Temp: 20C, Fan: 10 (Auto), " + "Swing (V): 14 (Auto), Swing (H): 190 (Auto), Clock: 13:47, " + "On Time: Off, Off Time: Off, Sleep Time: Off, Beep: 3 (Off), " + "Light: 3 (Off), Mold: On, Clean: On, Fresh Air: Off, Eye: Off, " + "Eye Auto: Off, Quiet: Off, Powerful: Off, Purify: On, Econo: On", + ac.toString()); + ac.setRaw(EconoOff); + ASSERT_FALSE(ac.getEcono()); + EXPECT_EQ( + "Power: On, Mode: 3 (COOL), Temp: 20C, Fan: 10 (Auto), " + "Swing (V): 14 (Auto), Swing (H): 190 (Auto), Clock: 13:47, " + "On Time: Off, Off Time: Off, Sleep Time: Off, Beep: 3 (Off), " + "Light: 3 (Off), Mold: On, Clean: On, Fresh Air: Off, Eye: Off, " + "Eye Auto: Off, Quiet: Off, Powerful: Off, Purify: On, Econo: Off", + ac.toString()); +} diff --git a/lib/IRremoteESP8266/test/ir_Denon_test.cpp b/lib/IRremoteESP8266/test/ir_Denon_test.cpp index 321d91a..911fd75 100644 --- a/lib/IRremoteESP8266/test/ir_Denon_test.cpp +++ b/lib/IRremoteESP8266/test/ir_Denon_test.cpp @@ -19,7 +19,8 @@ TEST(TestSendDenon, SendDataOnly) { "m260s43602" "m260s780m260s1820m260s780m260s780m260s780m260s780m260s1820m260s1820" "m260s780m260s780m260s780m260s780m260s1820m260s1820m260s1820" - "m260s43602", irsend.outputStr()); + "m260s43602", + irsend.outputStr()); irsend.reset(); // Denon Eco Mode On. (Panasonic/Kaseikyo) @@ -32,7 +33,8 @@ TEST(TestSendDenon, SendDataOnly) { "m432s1296m432s432m432s432m432s432m432s1296m432s1296m432s432m432s1296" "m432s432m432s1296m432s1296m432s432m432s1296m432s1296m432s432m432s432" "m432s1296m432s1296m432s1296m432s432m432s432m432s432m432s1296m432s1296" - "m432s98928", irsend.outputStr()); + "m432s98928", + irsend.outputStr()); } // Test sending with different repeats. @@ -54,7 +56,8 @@ TEST(TestSendDenon, SendNormalWithRepeats) { "m260s43602" "m260s780m260s1820m260s780m260s780m260s780m260s780m260s1820m260s1820" "m260s780m260s780m260s780m260s780m260s1820m260s1820m260s1820" - "m260s43602", irsend.outputStr()); + "m260s43602", + irsend.outputStr()); irsend.sendDenon(0x2278, DENON_BITS, 2); // 2 repeats. EXPECT_EQ( "m260s780m260s1820m260s780m260s780m260s780m260s1820m260s780m260s780" @@ -74,7 +77,8 @@ TEST(TestSendDenon, SendNormalWithRepeats) { "m260s43602" "m260s780m260s1820m260s780m260s780m260s780m260s780m260s1820m260s1820" "m260s780m260s780m260s780m260s780m260s1820m260s1820m260s1820" - "m260s43602", irsend.outputStr()); + "m260s43602", + irsend.outputStr()); } TEST(TestSendDenon, Send48BitWithRepeats) { @@ -99,7 +103,8 @@ TEST(TestSendDenon, Send48BitWithRepeats) { "m432s1296m432s432m432s432m432s432m432s1296m432s1296m432s432m432s1296" "m432s432m432s1296m432s1296m432s432m432s1296m432s1296m432s432m432s432" "m432s1296m432s1296m432s1296m432s432m432s432m432s432m432s1296m432s1296" - "m432s98928", irsend.outputStr()); + "m432s98928", + irsend.outputStr()); irsend.sendDenon(0x2A4C028D6CE3, DENON_48_BITS, 2); // 2 repeats. EXPECT_EQ( "m3456s1728" @@ -125,7 +130,8 @@ TEST(TestSendDenon, Send48BitWithRepeats) { "m432s1296m432s432m432s432m432s432m432s1296m432s1296m432s432m432s1296" "m432s432m432s1296m432s1296m432s432m432s1296m432s1296m432s432m432s432" "m432s1296m432s1296m432s1296m432s432m432s432m432s432m432s1296m432s1296" - "m432s98928", irsend.outputStr()); + "m432s98928", + irsend.outputStr()); } // Test sending an atypical data size. @@ -139,7 +145,8 @@ TEST(TestSendDenon, SendUnusualSize) { "m260s780m260s780m260s780m260s1820m260s780m260s780m260s1820m260s780" "m260s43602" "m260s1820m260s1820m260s1820m260s780m260s1820m260s1820m260s780m260s1820" - "m260s43602", irsend.outputStr()); + "m260s43602", + irsend.outputStr()); irsend.reset(); irsend.sendDenon(0x1234567890ABCDEF, 64); @@ -153,7 +160,8 @@ TEST(TestSendDenon, SendUnusualSize) { "m432s1296m432s432m432s1296m432s432m432s1296m432s432m432s1296m432s1296" "m432s1296m432s1296m432s432m432s432m432s1296m432s1296m432s432m432s1296" "m432s1296m432s1296m432s1296m432s432m432s1296m432s1296m432s1296m432s1296" - "m432s74736", irsend.outputStr()); + "m432s74736", + irsend.outputStr()); } // Tests for decodeDenon(). @@ -179,12 +187,12 @@ TEST(TestDecodeDenon, NormalDecodeWithStrict) { // Legacy Denon 14-bit message. irsend.reset(); - irsend.sendDenon(0x1278, DENON_LEGACY_BITS); + irsend.sendDenon(0x1278, kDenonLegacyBits); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodeDenon(&irsend.capture, DENON_LEGACY_BITS, true)); + ASSERT_TRUE(irrecv.decodeDenon(&irsend.capture, kDenonLegacyBits, true)); EXPECT_EQ(DENON, irsend.capture.decode_type); - EXPECT_EQ(DENON_LEGACY_BITS, irsend.capture.bits); + EXPECT_EQ(kDenonLegacyBits, irsend.capture.bits); EXPECT_EQ(0x1278, irsend.capture.value); EXPECT_EQ(0x0, irsend.capture.address); EXPECT_EQ(0x0, irsend.capture.command); @@ -211,13 +219,11 @@ TEST(TestDecodeDenon, DecodeGlobalCacheExample) { irsend.reset(); // Denon AVR series Power On code from Global Cache. (Sharp style) - uint16_t gc_test_power[67] = {38000, 1, 1, - 10, 30, 10, 70, 10, 30, 10, 30, 10, 30, 10, 70, - 10, 30, 10, 30, 10, 70, 10, 70, 10, 70, 10, 70, - 10, 30, 10, 30, 10, 30, 10, 1657, - 10, 30, 10, 70, 10, 30, 10, 30, 10, 30, 10, 30, - 10, 70, 10, 70, 10, 30, 10, 30, 10, 30, 10, 30, - 10, 70, 10, 70, 10, 70, 10, 1657}; + uint16_t gc_test_power[67] = { + 38000, 1, 1, 10, 30, 10, 70, 10, 30, 10, 30, 10, 30, 10, 70, 10, 30, + 10, 30, 10, 70, 10, 70, 10, 70, 10, 70, 10, 30, 10, 30, 10, 30, 10, + 1657, 10, 30, 10, 70, 10, 30, 10, 30, 10, 30, 10, 30, 10, 70, 10, 70, + 10, 30, 10, 30, 10, 30, 10, 30, 10, 70, 10, 70, 10, 70, 10, 1657}; irsend.sendGC(gc_test_power, 67); irsend.makeDecodeResult(); @@ -230,15 +236,14 @@ TEST(TestDecodeDenon, DecodeGlobalCacheExample) { EXPECT_FALSE(irsend.capture.repeat); // Denon "Eco Mode Auto" code from Global Cache. (Panasonic style) - uint16_t gc_test_eco[103] = {37000, 1, 1, 128, 64, 16, 16, 16, 16, 16, 48, - 16, 16, 16, 48, 16, 16, 16, 48, 16, 16, 16, 16, - 16, 48, 16, 16, 16, 16, 16, 48, 16, 48, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 48, 16, 16, 16, 48, 16, 16, 16, 16, - 16, 16, 16, 48, 16, 48, 16, 16, 16, 48, 16, 16, - 16, 48, 16, 48, 16, 16, 16, 48, 16, 48, 16, 16, - 16, 16, 16, 48, 16, 48, 16, 48, 16, 16, 16, 16, - 16, 16, 16, 48, 16, 48, 16, 2766}; + uint16_t gc_test_eco[103] = { + 37000, 1, 1, 128, 64, 16, 16, 16, 16, 16, 48, 16, 16, 16, 48, + 16, 16, 16, 48, 16, 16, 16, 16, 16, 48, 16, 16, 16, 16, 16, + 48, 16, 48, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 48, 16, 16, 16, 48, 16, 16, 16, 16, 16, + 16, 16, 48, 16, 48, 16, 16, 16, 48, 16, 16, 16, 48, 16, 48, + 16, 16, 16, 48, 16, 48, 16, 16, 16, 16, 16, 48, 16, 48, 16, + 48, 16, 16, 16, 16, 16, 16, 16, 48, 16, 48, 16, 2766}; irsend.reset(); irsend.sendGC(gc_test_eco, 103); irsend.makeDecodeResult(); @@ -259,14 +264,15 @@ TEST(TestDecodeDenon, FailToDecodeNonDenonExample) { irsend.begin(); irsend.reset(); - uint16_t gc_test[39] = {38000, 1, 1, 322, 162, 20, 61, 20, 61, 20, 20, 20, 20, - 20, 20, 20, 127, 20, 61, 9, 20, 20, 61, 20, 20, 20, - 61, 20, 61, 20, 61, 20, 20, 20, 20, 20, 20, 20, 884}; + uint16_t gc_test[39] = {38000, 1, 1, 322, 162, 20, 61, 20, 61, 20, + 20, 20, 20, 20, 20, 20, 127, 20, 61, 9, + 20, 20, 61, 20, 20, 20, 61, 20, 61, 20, + 61, 20, 20, 20, 20, 20, 20, 20, 884}; irsend.sendGC(gc_test, 39); irsend.makeDecodeResult(); ASSERT_FALSE(irrecv.decodeDenon(&irsend.capture)); - ASSERT_FALSE(irrecv.decodeDenon(&irsend.capture, DENON_LEGACY_BITS, false)); + ASSERT_FALSE(irrecv.decodeDenon(&irsend.capture, kDenonLegacyBits, false)); ASSERT_FALSE(irrecv.decodeDenon(&irsend.capture, DENON_BITS, false)); ASSERT_FALSE(irrecv.decodeDenon(&irsend.capture, DENON_48_BITS, false)); } diff --git a/lib/IRremoteESP8266/test/ir_Dish_test.cpp b/lib/IRremoteESP8266/test/ir_Dish_test.cpp index afd76e8..0c58496 100644 --- a/lib/IRremoteESP8266/test/ir_Dish_test.cpp +++ b/lib/IRremoteESP8266/test/ir_Dish_test.cpp @@ -26,7 +26,8 @@ TEST(TestSendDish, SendDataOnly) { "m400s6100" "m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800" "m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800" - "m400s6100", irsend.outputStr()); + "m400s6100", + irsend.outputStr()); irsend.reset(); irsend.sendDISH(0x9C00); // Power on. @@ -43,7 +44,8 @@ TEST(TestSendDish, SendDataOnly) { "m400s6100" "m400s1700m400s2800m400s2800m400s1700m400s1700m400s1700m400s2800m400s2800" "m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800" - "m400s6100", irsend.outputStr()); + "m400s6100", + irsend.outputStr()); irsend.reset(); irsend.sendDISH(0xFFFF); @@ -60,7 +62,8 @@ TEST(TestSendDish, SendDataOnly) { "m400s6100" "m400s1700m400s1700m400s1700m400s1700m400s1700m400s1700m400s1700m400s1700" "m400s1700m400s1700m400s1700m400s1700m400s1700m400s1700m400s1700m400s1700" - "m400s6100", irsend.outputStr()); + "m400s6100", + irsend.outputStr()); } // Test sending with different repeats. @@ -69,15 +72,16 @@ TEST(TestSendDish, SendWithRepeats) { irsend.begin(); irsend.reset(); - irsend.sendDISH(0x9C00, DISH_BITS, 0); // 0 repeats. + irsend.sendDISH(0x9C00, kDishBits, 0); // 0 repeats. EXPECT_EQ( "m400s6100" "m400s1700m400s2800m400s2800m400s1700m400s1700m400s1700m400s2800m400s2800" "m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800" - "m400s6100", irsend.outputStr()); + "m400s6100", + irsend.outputStr()); irsend.reset(); - irsend.sendDISH(0x9C00, DISH_BITS, 1); // 1 repeat. + irsend.sendDISH(0x9C00, kDishBits, 1); // 1 repeat. EXPECT_EQ( "m400s6100" "m400s1700m400s2800m400s2800m400s1700m400s1700m400s1700m400s2800m400s2800" @@ -85,9 +89,10 @@ TEST(TestSendDish, SendWithRepeats) { "m400s6100" "m400s1700m400s2800m400s2800m400s1700m400s1700m400s1700m400s2800m400s2800" "m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800" - "m400s6100", irsend.outputStr()); + "m400s6100", + irsend.outputStr()); - irsend.sendDISH(0x9C00, DISH_BITS, 2); // 2 repeats. + irsend.sendDISH(0x9C00, kDishBits, 2); // 2 repeats. EXPECT_EQ( "m400s6100" "m400s1700m400s2800m400s2800m400s1700m400s1700m400s1700m400s2800m400s2800" @@ -98,7 +103,8 @@ TEST(TestSendDish, SendWithRepeats) { "m400s6100" "m400s1700m400s2800m400s2800m400s1700m400s1700m400s1700m400s2800m400s2800" "m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800" - "m400s6100", irsend.outputStr()); + "m400s6100", + irsend.outputStr()); } // Test sending an atypical data size. @@ -109,15 +115,16 @@ TEST(TestSendDish, SendUnusualSize) { irsend.reset(); irsend.sendDISH(0x0, 8); EXPECT_EQ( - "m400s6100" - "m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800" - "m400s6100" - "m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800" - "m400s6100" - "m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800" - "m400s6100" - "m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800" - "m400s6100", irsend.outputStr()); + "m400s6100" + "m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800" + "m400s6100" + "m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800" + "m400s6100" + "m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800" + "m400s6100" + "m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800" + "m400s6100", + irsend.outputStr()); irsend.reset(); irsend.sendDISH(0x1234567890ABCDEF, 64); @@ -158,7 +165,8 @@ TEST(TestSendDish, SendUnusualSize) { "m400s1700m400s2800m400s1700m400s2800m400s1700m400s2800m400s1700m400s1700" "m400s1700m400s1700m400s2800m400s2800m400s1700m400s1700m400s2800m400s1700" "m400s1700m400s1700m400s1700m400s2800m400s1700m400s1700m400s1700m400s1700" - "m400s6100", irsend.outputStr()); + "m400s6100", + irsend.outputStr()); } // Tests for decodeDISH(). @@ -173,9 +181,9 @@ TEST(TestDecodeDish, NormalDecodeWithStrict) { irsend.reset(); irsend.sendDISH(0x9C00); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodeDISH(&irsend.capture, DISH_BITS, true)); + ASSERT_TRUE(irrecv.decodeDISH(&irsend.capture, kDishBits, true)); EXPECT_EQ(DISH, irsend.capture.decode_type); - EXPECT_EQ(DISH_BITS, irsend.capture.bits); + EXPECT_EQ(kDishBits, irsend.capture.bits); EXPECT_EQ(0x9C00, irsend.capture.value); EXPECT_EQ(0x0, irsend.capture.address); EXPECT_EQ(0x0, irsend.capture.command); @@ -192,7 +200,7 @@ TEST(TestDecodeDish, DecodeWithNonStrictSize) { irsend.sendDISH(0x12, 8); // Illegal size Dish message. (smaller) irsend.makeDecodeResult(); - ASSERT_FALSE(irrecv.decodeDISH(&irsend.capture, DISH_BITS, true)); + ASSERT_FALSE(irrecv.decodeDISH(&irsend.capture, kDishBits, true)); irsend.makeDecodeResult(); // Should fail with strict when we ask for the wrong bit size. @@ -209,7 +217,7 @@ TEST(TestDecodeDish, DecodeWithNonStrictSize) { irsend.sendDISH(0x12345678, 32); // Illegal size Dish message. (larger) irsend.makeDecodeResult(); - ASSERT_FALSE(irrecv.decodeDISH(&irsend.capture, DISH_BITS, true)); + ASSERT_FALSE(irrecv.decodeDISH(&irsend.capture, kDishBits, true)); irsend.makeDecodeResult(); // Should fail with strict when we ask for the wrong bit size. @@ -247,47 +255,45 @@ TEST(TestDecodeDish, DecodeGlobalCacheExample) { IRrecv irrecv(4); irsend.begin(); -/* - irsend.reset(); - // Dish DTV Pal code from Global Cache. - uint16_t gc_test_dtv[27] = {58000, 1, 3, 22, 538, 22, 252, 22, 156, 22, 156, - 22, 156, 22, 156, 22, 252, 22, 252, 22, 252, 22, - 252, 22, 252, 22, 538}; - irsend.sendGC(gc_test_dtv, 27); - irsend.makeDecodeResult(); + /* + irsend.reset(); + // Dish DTV Pal code from Global Cache. + uint16_t gc_test_dtv[27] = {58000, 1, 3, 22, 538, 22, 252, 22, 156, 22, 156, + 22, 156, 22, 156, 22, 252, 22, 252, 22, 252, 22, + 252, 22, 252, 22, 538}; + irsend.sendGC(gc_test_dtv, 27); + irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodeDISH(&irsend.capture, DISH_BITS, true)); - EXPECT_EQ(DISH, irsend.capture.decode_type); - EXPECT_EQ(DISH_BITS, irsend.capture.bits); - EXPECT_EQ(0x0, irsend.capture.value); - EXPECT_EQ(0x0, irsend.capture.address); - EXPECT_EQ(0x0, irsend.capture.command); - EXPECT_FALSE(irsend.capture.repeat); + ASSERT_TRUE(irrecv.decodeDISH(&irsend.capture, kDishBits, true)); + EXPECT_EQ(DISH, irsend.capture.decode_type); + EXPECT_EQ(kDishBits, irsend.capture.bits); + EXPECT_EQ(0x0, irsend.capture.value); + EXPECT_EQ(0x0, irsend.capture.address); + EXPECT_EQ(0x0, irsend.capture.command); + EXPECT_FALSE(irsend.capture.repeat); - ASSERT_TRUE(irrecv.decodeDISH(&irsend.capture)); - EXPECT_EQ(DISH, irsend.capture.decode_type); - EXPECT_EQ(DISH_BITS, irsend.capture.bits); - EXPECT_EQ(0x0, irsend.capture.value); - EXPECT_EQ(0x0, irsend.capture.address); - EXPECT_EQ(0x0, irsend.capture.command); - EXPECT_FALSE(irsend.capture.repeat); -*/ + ASSERT_TRUE(irrecv.decodeDISH(&irsend.capture)); + EXPECT_EQ(DISH, irsend.capture.decode_type); + EXPECT_EQ(kDishBits, irsend.capture.bits); + EXPECT_EQ(0x0, irsend.capture.value); + EXPECT_EQ(0x0, irsend.capture.address); + EXPECT_EQ(0x0, irsend.capture.command); + EXPECT_FALSE(irsend.capture.repeat); + */ // Dish Hopper 3 code from Global Cache. - uint16_t gc_test_hopper[73] = {58000, 1, 37, 23, 351, 23, 94, 23, 164, - 23, 164, 23, 94, 23, 94, 23, 94, 23, 164, - 23, 164, 23, 164, 23, 164, 23, 164, 23, 164, - 23, 164, 23, 164, 23, 164, 23, 164, 23, 351, - 23, 94, 23, 164, 23, 164, 23, 94, 23, 94, - 23, 94, 23, 164, 23, 164, 23, 164, 23, 164, - 23, 164, 23, 164, 23, 164, 23, 164, 23, 164, - 23, 164, 23, 351}; + uint16_t gc_test_hopper[73] = { + 58000, 1, 37, 23, 351, 23, 94, 23, 164, 23, 164, 23, 94, 23, 94, 23, + 94, 23, 164, 23, 164, 23, 164, 23, 164, 23, 164, 23, 164, 23, 164, 23, + 164, 23, 164, 23, 164, 23, 351, 23, 94, 23, 164, 23, 164, 23, 94, 23, + 94, 23, 94, 23, 164, 23, 164, 23, 164, 23, 164, 23, 164, 23, 164, 23, + 164, 23, 164, 23, 164, 23, 164, 23, 351}; irsend.reset(); irsend.sendGC(gc_test_hopper, 73); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodeDISH(&irsend.capture, DISH_BITS, true)); + ASSERT_TRUE(irrecv.decodeDISH(&irsend.capture, kDishBits, true)); EXPECT_EQ(DISH, irsend.capture.decode_type); - EXPECT_EQ(DISH_BITS, irsend.capture.bits); + EXPECT_EQ(kDishBits, irsend.capture.bits); EXPECT_EQ(0x9C00, irsend.capture.value); EXPECT_EQ(0x0, irsend.capture.address); EXPECT_EQ(0x0, irsend.capture.command); @@ -295,7 +301,7 @@ TEST(TestDecodeDish, DecodeGlobalCacheExample) { ASSERT_TRUE(irrecv.decodeDISH(&irsend.capture)); EXPECT_EQ(DISH, irsend.capture.decode_type); - EXPECT_EQ(DISH_BITS, irsend.capture.bits); + EXPECT_EQ(kDishBits, irsend.capture.bits); EXPECT_EQ(0x9C00, irsend.capture.value); EXPECT_EQ(0x0, irsend.capture.address); EXPECT_EQ(0x0, irsend.capture.command); @@ -310,12 +316,13 @@ TEST(TestDecodeDish, FailToDecodeNonDishExample) { irsend.reset(); // Modified a few entries to unexpected values, based on previous test case. - uint16_t gc_test[39] = {38000, 1, 1, 322, 162, 20, 61, 20, 61, 20, 20, 20, 20, - 20, 20, 20, 127, 20, 61, 9, 20, 20, 61, 20, 20, 20, - 61, 20, 61, 20, 61, 20, 20, 20, 20, 20, 20, 20, 884}; + uint16_t gc_test[39] = {38000, 1, 1, 322, 162, 20, 61, 20, 61, 20, + 20, 20, 20, 20, 20, 20, 127, 20, 61, 9, + 20, 20, 61, 20, 20, 20, 61, 20, 61, 20, + 61, 20, 20, 20, 20, 20, 20, 20, 884}; irsend.sendGC(gc_test, 39); irsend.makeDecodeResult(); ASSERT_FALSE(irrecv.decodeDISH(&irsend.capture)); - ASSERT_FALSE(irrecv.decodeDISH(&irsend.capture, DISH_BITS, false)); + ASSERT_FALSE(irrecv.decodeDISH(&irsend.capture, kDishBits, false)); } diff --git a/lib/IRremoteESP8266/test/ir_Electra_test.cpp b/lib/IRremoteESP8266/test/ir_Electra_test.cpp new file mode 100644 index 0000000..df5dd7a --- /dev/null +++ b/lib/IRremoteESP8266/test/ir_Electra_test.cpp @@ -0,0 +1,98 @@ +// Copyright 2018 David Conran + +#include "IRrecv.h" +#include "IRrecv_test.h" +#include "IRsend.h" +#include "IRsend_test.h" +#include "gtest/gtest.h" + +// Tests for sendElectraAC(). + +// Test sending typical data only. +TEST(TestSendElectraAC, SendDataOnly) { + IRsendTest irsend(0); + irsend.begin(); + uint8_t data[kElectraAcStateLength] = {0xC3, 0xE1, 0x6F, 0x14, 0x06, + 0x00, 0x04, 0x00, 0x00, 0x04, + 0x00, 0xA0, 0xB0}; + + irsend.sendElectraAC(data); + EXPECT_EQ( + "m9166s4470" + "m646s1647m646s1647m646s547m646s547m646s547m646s547m646s1647m646s1647" + "m646s1647m646s1647m646s1647m646s547m646s547m646s547m646s547m646s1647" + "m646s547m646s1647m646s1647m646s547m646s1647m646s1647m646s1647m646s1647" + "m646s547m646s547m646s547m646s1647m646s547m646s1647m646s547m646s547" + "m646s547m646s547m646s547m646s547m646s547m646s1647m646s1647m646s547" + "m646s547m646s547m646s547m646s547m646s547m646s547m646s547m646s547" + "m646s547m646s547m646s547m646s547m646s547m646s1647m646s547m646s547" + "m646s547m646s547m646s547m646s547m646s547m646s547m646s547m646s547" + "m646s547m646s547m646s547m646s547m646s547m646s547m646s547m646s547" + "m646s547m646s547m646s547m646s547m646s547m646s1647m646s547m646s547" + "m646s547m646s547m646s547m646s547m646s547m646s547m646s547m646s547" + "m646s1647m646s547m646s1647m646s547m646s547m646s547m646s547m646s547" + "m646s1647m646s547m646s1647m646s1647m646s547m646s547m646s547m646s547" + "m646s100000", + irsend.outputStr()); +} + +// Tests for decodeElectraAC(). +// Decode normal ElectraAC messages. + +TEST(TestDecodeElectraAC, SyntheticDecode) { + IRsendTest irsend(0); + IRrecv irrecv(0); + irsend.begin(); + + // Synthesised Normal ElectraAC message. + irsend.reset(); + uint8_t expectedState[kElectraAcStateLength] = {0xC3, 0xE1, 0x6F, 0x14, 0x06, + 0x00, 0x04, 0x00, 0x00, 0x04, + 0x00, 0xA0, 0xB0}; + irsend.sendElectraAC(expectedState); + irsend.makeDecodeResult(); + EXPECT_TRUE(irrecv.decode(&irsend.capture)); + EXPECT_EQ(ELECTRA_AC, irsend.capture.decode_type); + EXPECT_EQ(kElectraAcBits, irsend.capture.bits); + EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); +} + +// Decode a recorded example +TEST(TestDecodeElectraAC, RealExampleDecode) { + IRsendTest irsend(0); + IRrecv irrecv(0); + irsend.begin(); + + // Real ElectraAC message. + // Ref: https://github.com/markszabo/IRremoteESP8266/issues/527 + uint16_t rawData[211] = { + 9166, 4470, 642, 1632, 642, 1632, 668, 534, 666, 534, 668, 534, + 614, 536, 640, 1636, 640, 1646, 694, 1662, 612, 1628, 642, 1666, + 664, 532, 668, 534, 666, 534, 666, 532, 666, 1644, 642, 532, + 640, 1634, 668, 1632, 642, 538, 666, 1660, 610, 1666, 664, 1632, + 642, 1672, 610, 536, 666, 534, 694, 532, 666, 1636, 614, 538, + 666, 1632, 642, 536, 666, 544, 692, 534, 640, 558, 640, 534, + 640, 540, 666, 534, 638, 1666, 638, 1636, 640, 550, 666, 534, + 640, 540, 666, 534, 640, 540, 666, 536, 638, 540, 666, 536, + 638, 550, 664, 536, 638, 540, 664, 536, 638, 540, 666, 534, + 638, 1640, 664, 536, 692, 546, 664, 536, 664, 536, 664, 536, + 664, 546, 612, 532, 636, 538, 664, 536, 664, 546, 612, 538, + 638, 538, 638, 538, 664, 536, 690, 538, 662, 538, 664, 538, + 662, 548, 664, 536, 662, 538, 662, 562, 638, 564, 636, 564, + 636, 1668, 582, 556, 652, 572, 612, 568, 636, 564, 610, 570, + 636, 556, 616, 550, 656, 566, 610, 570, 632, 578, 608, 1640, + 662, 562, 642, 1686, 582, 570, 634, 566, 604, 576, 636, 566, + 610, 578, 634, 1664, 584, 590, 660, 1636, 610, 1642, 664, 590, + 610, 590, 636, 566, 634, 568, 686}; // UNKNOWN 9AD8CDB5 + uint8_t expectedState[kElectraAcStateLength] = {0xC3, 0xE1, 0x6F, 0x14, 0x06, + 0x00, 0x04, 0x00, 0x00, 0x04, + 0x00, 0xA0, 0xB0}; + + irsend.reset(); + irsend.sendRaw(rawData, 211, 38000); + irsend.makeDecodeResult(); + ASSERT_TRUE(irrecv.decode(&irsend.capture)); + ASSERT_EQ(ELECTRA_AC, irsend.capture.decode_type); + EXPECT_EQ(kElectraAcBits, irsend.capture.bits); + EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); +} diff --git a/lib/IRremoteESP8266/test/ir_Fujitsu_test.cpp b/lib/IRremoteESP8266/test/ir_Fujitsu_test.cpp index 49279a5..23fa3e7 100644 --- a/lib/IRremoteESP8266/test/ir_Fujitsu_test.cpp +++ b/lib/IRremoteESP8266/test/ir_Fujitsu_test.cpp @@ -25,16 +25,16 @@ template // Test sending typical data only. TEST(TestIRFujitsuACClass, GetRawDefault) { IRFujitsuAC fujitsu = IRFujitsuAC(4); // AR-RAH2E - fujitsu.setCmd(FUJITSU_AC_CMD_TURN_ON); - fujitsu.setSwing(FUJITSU_AC_SWING_BOTH); - fujitsu.setMode(FUJITSU_AC_MODE_COOL); - fujitsu.setFanSpeed(FUJITSU_AC_FAN_HIGH); + fujitsu.setCmd(kFujitsuAcCmdTurnOn); + fujitsu.setSwing(kFujitsuAcSwingBoth); + fujitsu.setMode(kFujitsuAcModeCool); + fujitsu.setFanSpeed(kFujitsuAcFanHigh); fujitsu.setTemp(24); uint8_t expected_arrah2e[16] = { 0x14, 0x63, 0x00, 0x10, 0x10, 0xFE, 0x09, 0x30, 0x81, 0x01, 0x31, 0x00, 0x00, 0x00, 0x20, 0xFD}; EXPECT_TRUE(ArraysMatch(expected_arrah2e, fujitsu.getRaw())); - EXPECT_EQ(FUJITSU_AC_STATE_LENGTH, fujitsu.getStateLength()); + EXPECT_EQ(kFujitsuAcStateLength, fujitsu.getStateLength()); EXPECT_EQ("Power: On, Mode: 1 (COOL), Temp: 24C, Fan: 1 (HIGH), " "Swing: Vert + Horiz, Command: N/A", fujitsu.toString()); @@ -43,7 +43,7 @@ TEST(TestIRFujitsuACClass, GetRawDefault) { 0x81, 0x01, 0x31, 0x00, 0x00, 0x00, 0x1D}; fujitsu.setModel(ARDB1); EXPECT_TRUE(ArraysMatch(expected_ardb1, fujitsu.getRaw())); - EXPECT_EQ(FUJITSU_AC_STATE_LENGTH - 1, fujitsu.getStateLength()); + EXPECT_EQ(kFujitsuAcStateLength - 1, fujitsu.getStateLength()); EXPECT_EQ("Power: On, Mode: 1 (COOL), Temp: 24C, Fan: 1 (HIGH), " "Swing: Vert + Horiz, Command: N/A", fujitsu.toString()); } @@ -54,14 +54,14 @@ TEST(TestIRFujitsuACClass, GetRawTurnOff) { fujitsu.off(); uint8_t expected_arrah2e[7] = {0x14, 0x63, 0x0, 0x10, 0x10, 0x02, 0xFD}; EXPECT_TRUE(ArraysMatch(expected_arrah2e, fujitsu.getRaw())); - EXPECT_EQ(FUJITSU_AC_STATE_LENGTH_SHORT, fujitsu.getStateLength()); + EXPECT_EQ(kFujitsuAcStateLengthShort, fujitsu.getStateLength()); EXPECT_EQ("Power: Off, Mode: 1 (COOL), Temp: 24C, Fan: 1 (HIGH), " "Swing: Vert + Horiz, Command: N/A", fujitsu.toString()); fujitsu.setModel(ARDB1); uint8_t expected_ardb1[6] = {0x14, 0x63, 0x0, 0x10, 0x10, 0x02}; EXPECT_TRUE(ArraysMatch(expected_ardb1, fujitsu.getRaw())); - EXPECT_EQ(FUJITSU_AC_STATE_LENGTH_SHORT - 1, fujitsu.getStateLength()); + EXPECT_EQ(kFujitsuAcStateLengthShort - 1, fujitsu.getStateLength()); EXPECT_EQ("Power: Off, Mode: 1 (COOL), Temp: 24C, Fan: 1 (HIGH), " "Swing: Vert + Horiz, Command: N/A", fujitsu.toString()); } @@ -71,7 +71,7 @@ TEST(TestIRFujitsuACClass, GetRawStepHoriz) { fujitsu.stepHoriz(); uint8_t expected[7] = {0x14, 0x63, 0x0, 0x10, 0x10, 0x79, 0x86}; EXPECT_TRUE(ArraysMatch(expected, fujitsu.getRaw())); - EXPECT_EQ(FUJITSU_AC_STATE_LENGTH_SHORT, fujitsu.getStateLength()); + EXPECT_EQ(kFujitsuAcStateLengthShort, fujitsu.getStateLength()); EXPECT_EQ("Power: On, Mode: 1 (COOL), Temp: 24C, Fan: 1 (HIGH), " "Swing: Vert + Horiz, Command: Step vane horizontally", fujitsu.toString()); @@ -83,7 +83,7 @@ TEST(TestIRFujitsuACClass, GetRawStepVert) { fujitsu.stepVert(); uint8_t expected_arrah2e[7] = {0x14, 0x63, 0x0, 0x10, 0x10, 0x6C, 0x93}; EXPECT_TRUE(ArraysMatch(expected_arrah2e, fujitsu.getRaw())); - EXPECT_EQ(FUJITSU_AC_STATE_LENGTH_SHORT, fujitsu.getStateLength()); + EXPECT_EQ(kFujitsuAcStateLengthShort, fujitsu.getStateLength()); EXPECT_EQ("Power: On, Mode: 1 (COOL), Temp: 24C, Fan: 1 (HIGH), " "Swing: Vert + Horiz, Command: Step vane vertically", fujitsu.toString()); @@ -92,7 +92,7 @@ TEST(TestIRFujitsuACClass, GetRawStepVert) { fujitsu.stepVert(); uint8_t expected_ardb1[6] = {0x14, 0x63, 0x0, 0x10, 0x10, 0x6C}; EXPECT_TRUE(ArraysMatch(expected_ardb1, fujitsu.getRaw())); - EXPECT_EQ(FUJITSU_AC_STATE_LENGTH_SHORT - 1, + EXPECT_EQ(kFujitsuAcStateLengthShort - 1, fujitsu.getStateLength()); EXPECT_EQ("Power: On, Mode: 1 (COOL), Temp: 24C, Fan: 1 (HIGH), " "Swing: Vert + Horiz, Command: Step vane vertically", @@ -101,10 +101,10 @@ TEST(TestIRFujitsuACClass, GetRawStepVert) { TEST(TestIRFujitsuACClass, GetRawWithSwingHoriz) { IRFujitsuAC fujitsu = IRFujitsuAC(4); - fujitsu.setCmd(FUJITSU_AC_CMD_STAY_ON); - fujitsu.setSwing(FUJITSU_AC_SWING_HORIZ); - fujitsu.setMode(FUJITSU_AC_MODE_COOL); - fujitsu.setFanSpeed(FUJITSU_AC_FAN_QUIET); + fujitsu.setCmd(kFujitsuAcCmdStayOn); + fujitsu.setSwing(kFujitsuAcSwingHoriz); + fujitsu.setMode(kFujitsuAcModeCool); + fujitsu.setFanSpeed(kFujitsuAcFanQuiet); fujitsu.setTemp(25); uint8_t expected[16] = {0x14, 0x63, 0x0, 0x10, 0x10, 0xFE, 0x9, 0x30, 0x90, 0x1, 0x24, 0x0, 0x0, 0x0, 0x20, 0xFB}; @@ -116,10 +116,10 @@ TEST(TestIRFujitsuACClass, GetRawWithSwingHoriz) { TEST(TestIRFujitsuACClass, GetRawWithFan) { IRFujitsuAC fujitsu = IRFujitsuAC(4); - fujitsu.setCmd(FUJITSU_AC_CMD_STAY_ON); - fujitsu.setSwing(FUJITSU_AC_SWING_HORIZ); - fujitsu.setMode(FUJITSU_AC_MODE_FAN); - fujitsu.setFanSpeed(FUJITSU_AC_FAN_MED); + fujitsu.setCmd(kFujitsuAcCmdStayOn); + fujitsu.setSwing(kFujitsuAcSwingHoriz); + fujitsu.setMode(kFujitsuAcModeFan); + fujitsu.setFanSpeed(kFujitsuAcFanMed); fujitsu.setTemp(20); // temp doesn't matter for fan // but it is sent by the RC anyway fujitsu.setModel(ARRAH2E); @@ -127,7 +127,7 @@ TEST(TestIRFujitsuACClass, GetRawWithFan) { 0x14, 0x63, 0x0, 0x10, 0x10, 0xFE, 0x9, 0x30, 0x40, 0x3, 0x22, 0x0, 0x0, 0x0, 0x20, 0x4B}; EXPECT_TRUE(ArraysMatch(expected_arrah2e, fujitsu.getRaw())); - EXPECT_EQ(FUJITSU_AC_STATE_LENGTH, fujitsu.getStateLength()); + EXPECT_EQ(kFujitsuAcStateLength, fujitsu.getStateLength()); EXPECT_EQ("Power: On, Mode: 3 (FAN), Temp: 20C, Fan: 2 (MED), Swing: Horiz, " "Command: N/A", fujitsu.toString()); @@ -136,15 +136,15 @@ TEST(TestIRFujitsuACClass, GetRawWithFan) { 0x14, 0x63, 0x0, 0x10, 0x10, 0xFC, 0x8, 0x30, 0x40, 0x3, 0x22, 0x0, 0x0, 0x0, 0x6B}; EXPECT_TRUE(ArraysMatch(expected_ardb1, fujitsu.getRaw())); - EXPECT_EQ(FUJITSU_AC_STATE_LENGTH - 1, fujitsu.getStateLength()); + EXPECT_EQ(kFujitsuAcStateLength - 1, fujitsu.getStateLength()); EXPECT_EQ("Power: On, Mode: 3 (FAN), Temp: 20C, Fan: 2 (MED), Swing: Horiz, " "Command: N/A", fujitsu.toString()); } TEST(TestIRFujitsuACClass, SetRaw) { IRFujitsuAC fujitsu = IRFujitsuAC(0); - EXPECT_EQ(FUJITSU_AC_STATE_LENGTH, fujitsu.getStateLength()); - uint8_t expected_default_arrah2e[FUJITSU_AC_STATE_LENGTH] = { + EXPECT_EQ(kFujitsuAcStateLength, fujitsu.getStateLength()); + uint8_t expected_default_arrah2e[kFujitsuAcStateLength] = { 0x14, 0x63, 0x00, 0x10, 0x10, 0xFE, 0x09, 0x30, 0x81, 0x01, 0x31, 0x00, 0x00, 0x00, 0x20, 0xFD}; EXPECT_TRUE(ArraysMatch(expected_default_arrah2e, fujitsu.getRaw())); @@ -152,11 +152,11 @@ TEST(TestIRFujitsuACClass, SetRaw) { "Swing: Vert + Horiz, Command: N/A", fujitsu.toString()); // Now set a new state via setRaw(); // This state is a real state from an AR-DB1 remote. - uint8_t new_state1[FUJITSU_AC_STATE_LENGTH - 1] = { + uint8_t new_state1[kFujitsuAcStateLength - 1] = { 0x14, 0x63, 0x00, 0x10, 0x10, 0xFC, 0x08, 0x30, 0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x9F}; - fujitsu.setRaw(new_state1, FUJITSU_AC_STATE_LENGTH - 1); - EXPECT_EQ(FUJITSU_AC_STATE_LENGTH - 1, fujitsu.getStateLength()); + fujitsu.setRaw(new_state1, kFujitsuAcStateLength - 1); + EXPECT_EQ(kFujitsuAcStateLength - 1, fujitsu.getStateLength()); EXPECT_TRUE(ArraysMatch(new_state1, fujitsu.getRaw())); EXPECT_EQ("Power: On, Mode: 1 (COOL), Temp: 19C, Fan: 0 (AUTO), " "Swing: Off, Command: N/A", fujitsu.toString()); @@ -168,36 +168,39 @@ TEST(TestSendFujitsuAC, GenerateMessage) { fujitsu.begin(); irsend.begin(); - fujitsu.setCmd(FUJITSU_AC_CMD_STAY_ON); - fujitsu.setSwing(FUJITSU_AC_SWING_BOTH); - fujitsu.setMode(FUJITSU_AC_MODE_COOL); - fujitsu.setFanSpeed(FUJITSU_AC_FAN_HIGH); + fujitsu.setCmd(kFujitsuAcCmdStayOn); + fujitsu.setSwing(kFujitsuAcSwingBoth); + fujitsu.setMode(kFujitsuAcModeCool); + fujitsu.setFanSpeed(kFujitsuAcFanHigh); fujitsu.setTemp(24); - EXPECT_EQ(FUJITSU_AC_FAN_HIGH, fujitsu.getFanSpeed()); - EXPECT_EQ(FUJITSU_AC_MODE_COOL, fujitsu.getMode()); + EXPECT_EQ(kFujitsuAcFanHigh, fujitsu.getFanSpeed()); + EXPECT_EQ(kFujitsuAcModeCool, fujitsu.getMode()); EXPECT_EQ(24, fujitsu.getTemp()); - EXPECT_EQ(FUJITSU_AC_SWING_BOTH, fujitsu.getSwing()); - EXPECT_EQ(FUJITSU_AC_CMD_STAY_ON, fujitsu.getCmd()); + EXPECT_EQ(kFujitsuAcSwingBoth, fujitsu.getSwing()); + EXPECT_EQ(kFujitsuAcCmdStayOn, fujitsu.getCmd()); irsend.reset(); - irsend.sendFujitsuAC(fujitsu.getRaw(), FUJITSU_AC_STATE_LENGTH); + irsend.sendFujitsuAC(fujitsu.getRaw(), kFujitsuAcStateLength); EXPECT_EQ( - "m3324s1574m448s390m448s390m448s1182m448s390m448s1182m448s390m448s390m448" - "s390m448s1182m448s1182m448s390m448s390m448s390m448s1182m448s1182m448s390" - "m448s390m448s390m448s390m448s390m448s390m448s390m448s390m448s390m448" - "s390m448s390m448s390m448s390m448s1182m448s390m448s390m448s390m448s390m448" - "s390m448s390m448s390m448s1182m448s390m448s390m448s390m448s390m448s1182" - "m448s1182m448s1182m448s1182m448s1182m448s1182m448s1182m448s1182m448s390" - "m448s390m448s1182m448s390m448s390m448s390m448s390m448s390m448s390m448s390" - "m448s390m448s1182m448s1182m448s390m448s390m448s390m448s390m448s390m448s390" - "m448s390m448s390m448s390m448s1182m448s1182m448s390m448s390m448s390m448" - "s390m448s390m448s390m448s390m448s1182m448s390m448s390m448s390m448s1182m448" - "s1182m448s390m448s390m448s390m448s390m448s390m448s390m448s390m448s390m448" - "s390m448s390m448s390m448s390m448s390m448s390m448s390m448s390m448s390m448" - "s390m448s390m448s390m448s390m448s390m448s390m448s390m448s390m448s390m448" - "s390m448s390m448s390m448s390m448s390m448s1182m448s390m448s390m448s390m448" - "s1182m448s1182m448s1182m448s1182m448s1182m448s1182m448s1182m448s8100", + "m3324s1574" + "m448s390m448s390m448s1182m448s390m448s1182m448s390m448s390m448s390" + "m448s1182m448s1182m448s390m448s390m448s390m448s1182m448s1182m448s390" + "m448s390m448s390m448s390m448s390m448s390m448s390m448s390m448s390" + "m448s390m448s390m448s390m448s390m448s1182m448s390m448s390m448s390" + "m448s390m448s390m448s390m448s390m448s1182m448s390m448s390m448s390" + "m448s390m448s1182m448s1182m448s1182m448s1182m448s1182m448s1182m448s1182" + "m448s1182m448s390m448s390m448s1182m448s390m448s390m448s390m448s390" + "m448s390m448s390m448s390m448s390m448s1182m448s1182m448s390m448s390" + "m448s390m448s390m448s390m448s390m448s390m448s390m448s390m448s1182" + "m448s1182m448s390m448s390m448s390m448s390m448s390m448s390m448s390" + "m448s1182m448s390m448s390m448s390m448s1182m448s1182m448s390m448s390" + "m448s390m448s390m448s390m448s390m448s390m448s390m448s390m448s390" + "m448s390m448s390m448s390m448s390m448s390m448s390m448s390m448s390" + "m448s390m448s390m448s390m448s390m448s390m448s390m448s390m448s390" + "m448s390m448s390m448s390m448s390m448s390m448s1182m448s390m448s390" + "m448s390m448s1182m448s1182m448s1182m448s1182m448s1182m448s1182m448s1182" + "m448s8100", irsend.outputStr()); } @@ -209,10 +212,10 @@ TEST(TestSendFujitsuAC, GenerateShortMessage) { fujitsu.off(); - EXPECT_EQ(FUJITSU_AC_CMD_TURN_OFF, fujitsu.getCmd()); + EXPECT_EQ(kFujitsuAcCmdTurnOff, fujitsu.getCmd()); irsend.reset(); - irsend.sendFujitsuAC(fujitsu.getRaw(), FUJITSU_AC_STATE_LENGTH_SHORT); + irsend.sendFujitsuAC(fujitsu.getRaw(), kFujitsuAcStateLengthShort); EXPECT_EQ( "m3324s1574m448s390m448s390m448s1182m448s390m448s1182m448s390m448s390m448" "s390m448s1182m448s1182m448s390m448s390m448s390m448s1182m448s1182m448s390" @@ -232,8 +235,8 @@ TEST(TestSendFujitsuAC, Issue275) { irsend.begin(); irsend.reset(); - fujitsu.setCmd(FUJITSU_AC_CMD_TURN_OFF); - irsend.sendFujitsuAC(fujitsu.getRaw(), FUJITSU_AC_STATE_LENGTH_SHORT); + fujitsu.setCmd(kFujitsuAcCmdTurnOff); + irsend.sendFujitsuAC(fujitsu.getRaw(), kFujitsuAcStateLengthShort); EXPECT_EQ( // Header "m3324s1574" @@ -299,24 +302,24 @@ TEST(TestDecodeFujitsuAC, SyntheticShortMessages) { irsend.reset(); fujitsu.setModel(ARRAH2E); - fujitsu.setCmd(FUJITSU_AC_CMD_TURN_OFF); + fujitsu.setCmd(kFujitsuAcCmdTurnOff); irsend.sendFujitsuAC(fujitsu.getRaw(), fujitsu.getStateLength()); irsend.makeDecodeResult(); EXPECT_TRUE(irrecv.decode(&irsend.capture)); ASSERT_EQ(FUJITSU_AC, irsend.capture.decode_type); - ASSERT_EQ(FUJITSU_AC_MIN_BITS + 8, irsend.capture.bits); + ASSERT_EQ(kFujitsuAcMinBits + 8, irsend.capture.bits); uint8_t expected_arrah2e[7] = {0x14, 0x63, 0x0, 0x10, 0x10, 0x02, 0xFD}; EXPECT_TRUE(ArraysMatch(expected_arrah2e, irsend.capture.state)); irsend.reset(); fujitsu.setModel(ARDB1); - fujitsu.setCmd(FUJITSU_AC_CMD_TURN_OFF); + fujitsu.setCmd(kFujitsuAcCmdTurnOff); irsend.sendFujitsuAC(fujitsu.getRaw(), fujitsu.getStateLength()); irsend.makeDecodeResult(); EXPECT_TRUE(irrecv.decode(&irsend.capture)); ASSERT_EQ(FUJITSU_AC, irsend.capture.decode_type); - ASSERT_EQ(FUJITSU_AC_MIN_BITS, irsend.capture.bits); + ASSERT_EQ(kFujitsuAcMinBits, irsend.capture.bits); uint8_t expected_ardb1[6] = {0x14, 0x63, 0x0, 0x10, 0x10, 0x02}; EXPECT_TRUE(ArraysMatch(expected_ardb1, irsend.capture.state)); } @@ -330,23 +333,23 @@ TEST(TestDecodeFujitsuAC, SyntheticLongMessages) { irsend.reset(); fujitsu.setModel(ARRAH2E); - fujitsu.setCmd(FUJITSU_AC_CMD_STAY_ON); - fujitsu.setSwing(FUJITSU_AC_SWING_VERT); - fujitsu.setMode(FUJITSU_AC_MODE_COOL); - fujitsu.setFanSpeed(FUJITSU_AC_FAN_QUIET); + fujitsu.setCmd(kFujitsuAcCmdStayOn); + fujitsu.setSwing(kFujitsuAcSwingVert); + fujitsu.setMode(kFujitsuAcModeCool); + fujitsu.setFanSpeed(kFujitsuAcFanQuiet); fujitsu.setTemp(18); irsend.sendFujitsuAC(fujitsu.getRaw(), fujitsu.getStateLength()); - ASSERT_EQ(FUJITSU_AC_STATE_LENGTH, fujitsu.getStateLength()); + ASSERT_EQ(kFujitsuAcStateLength, fujitsu.getStateLength()); irsend.makeDecodeResult(); EXPECT_TRUE(irrecv.decodeFujitsuAC(&irsend.capture)); ASSERT_EQ(FUJITSU_AC, irsend.capture.decode_type); - ASSERT_EQ(FUJITSU_AC_BITS, irsend.capture.bits); - uint8_t expected_arrah2e[FUJITSU_AC_STATE_LENGTH] = { + ASSERT_EQ(kFujitsuAcBits, irsend.capture.bits); + uint8_t expected_arrah2e[kFujitsuAcStateLength] = { 0x14, 0x63, 0x00, 0x10, 0x10, 0xFE, 0x09, 0x30, 0x20, 0x01, 0x14, 0x00, 0x00, 0x00, 0x20, 0x7B}; EXPECT_TRUE(ArraysMatch(expected_arrah2e, irsend.capture.state)); fujitsu.setRaw(irsend.capture.state, irsend.capture.bits / 8); - EXPECT_EQ(FUJITSU_AC_STATE_LENGTH, fujitsu.getStateLength()); + EXPECT_EQ(kFujitsuAcStateLength, fujitsu.getStateLength()); EXPECT_EQ("Power: On, Mode: 1 (COOL), Temp: 18C, Fan: 4 (QUIET), " "Swing: Vert, Command: N/A", fujitsu.toString()); @@ -357,13 +360,13 @@ TEST(TestDecodeFujitsuAC, SyntheticLongMessages) { irsend.makeDecodeResult(); EXPECT_TRUE(irrecv.decode(&irsend.capture)); ASSERT_EQ(FUJITSU_AC, irsend.capture.decode_type); - ASSERT_EQ(FUJITSU_AC_BITS - 8, irsend.capture.bits); - uint8_t expected_ardb1[FUJITSU_AC_STATE_LENGTH - 1] = { + ASSERT_EQ(kFujitsuAcBits - 8, irsend.capture.bits); + uint8_t expected_ardb1[kFujitsuAcStateLength - 1] = { 0x14, 0x63, 0x00, 0x10, 0x10, 0xFC, 0x08, 0x30, 0x20, 0x01, 0x14, 0x00, 0x00, 0x00, 0x9B}; EXPECT_TRUE(ArraysMatch(expected_ardb1, irsend.capture.state)); fujitsu.setRaw(irsend.capture.state, irsend.capture.bits / 8); - EXPECT_EQ(FUJITSU_AC_STATE_LENGTH - 1, fujitsu.getStateLength()); + EXPECT_EQ(kFujitsuAcStateLength - 1, fujitsu.getStateLength()); EXPECT_EQ("Power: On, Mode: 1 (COOL), Temp: 18C, Fan: 4 (QUIET), " "Swing: Vert, Command: N/A", fujitsu.toString()); } @@ -391,11 +394,11 @@ TEST(TestDecodeFujitsuAC, RealShortARDB1OffExample) { irsend.makeDecodeResult(); EXPECT_TRUE(irrecv.decode(&irsend.capture)); ASSERT_EQ(FUJITSU_AC, irsend.capture.decode_type); - ASSERT_EQ(FUJITSU_AC_MIN_BITS, irsend.capture.bits); + ASSERT_EQ(kFujitsuAcMinBits, irsend.capture.bits); uint8_t expected[6] = {0x14, 0x63, 0x0, 0x10, 0x10, 0x02}; EXPECT_TRUE(ArraysMatch(expected, irsend.capture.state)); fujitsu.setRaw(irsend.capture.state, irsend.capture.bits / 8); - EXPECT_EQ(FUJITSU_AC_STATE_LENGTH_SHORT - 1, fujitsu.getStateLength()); + EXPECT_EQ(kFujitsuAcStateLengthShort - 1, fujitsu.getStateLength()); EXPECT_EQ("Power: Off, Mode: 0 (AUTO), Temp: 16C, Fan: 0 (AUTO), " "Swing: Off, Command: N/A", fujitsu.toString()); } @@ -433,13 +436,13 @@ TEST(TestDecodeFujitsuAC, RealLongARDB1Example) { irsend.makeDecodeResult(); EXPECT_TRUE(irrecv.decode(&irsend.capture)); ASSERT_EQ(FUJITSU_AC, irsend.capture.decode_type); - ASSERT_EQ(FUJITSU_AC_BITS - 8, irsend.capture.bits); - uint8_t expected1[FUJITSU_AC_STATE_LENGTH - 1] = { + ASSERT_EQ(kFujitsuAcBits - 8, irsend.capture.bits); + uint8_t expected1[kFujitsuAcStateLength - 1] = { 0x14, 0x63, 0x00, 0x10, 0x10, 0xFC, 0x08, 0x30, 0x21, 0x01, 0x04, 0x00, 0x00, 0x00, 0xAA}; EXPECT_TRUE(ArraysMatch(expected1, irsend.capture.state)); fujitsu.setRaw(irsend.capture.state, irsend.capture.bits / 8); - EXPECT_EQ(FUJITSU_AC_STATE_LENGTH - 1, fujitsu.getStateLength()); + EXPECT_EQ(kFujitsuAcStateLength - 1, fujitsu.getStateLength()); EXPECT_EQ("Power: On, Mode: 1 (COOL), Temp: 18C, Fan: 4 (QUIET), " "Swing: Off, Command: N/A", fujitsu.toString()); @@ -470,13 +473,13 @@ TEST(TestDecodeFujitsuAC, RealLongARDB1Example) { irsend.makeDecodeResult(); EXPECT_TRUE(irrecv.decode(&irsend.capture)); ASSERT_EQ(FUJITSU_AC, irsend.capture.decode_type); - ASSERT_EQ(FUJITSU_AC_BITS - 8, irsend.capture.bits); - uint8_t expected2[FUJITSU_AC_STATE_LENGTH - 1] = { + ASSERT_EQ(kFujitsuAcBits - 8, irsend.capture.bits); + uint8_t expected2[kFujitsuAcStateLength - 1] = { 0x14, 0x63, 0x00, 0x10, 0x10, 0xFC, 0x08, 0x30, 0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x9F}; EXPECT_TRUE(ArraysMatch(expected2, irsend.capture.state)); fujitsu.setRaw(irsend.capture.state, irsend.capture.bits / 8); - EXPECT_EQ(FUJITSU_AC_STATE_LENGTH - 1, fujitsu.getStateLength()); + EXPECT_EQ(kFujitsuAcStateLength - 1, fujitsu.getStateLength()); EXPECT_EQ("Power: On, Mode: 1 (COOL), Temp: 19C, Fan: 0 (AUTO), " "Swing: Off, Command: N/A", fujitsu.toString()); } @@ -515,10 +518,10 @@ TEST(TestDecodeFujitsuAC, Issue414) { irsend.makeDecodeResult(); EXPECT_TRUE(irrecv.decode(&irsend.capture)); ASSERT_EQ(FUJITSU_AC, irsend.capture.decode_type); - ASSERT_EQ(FUJITSU_AC_BITS, irsend.capture.bits); + ASSERT_EQ(kFujitsuAcBits, irsend.capture.bits); EXPECT_TRUE(ArraysMatch(state, irsend.capture.state)); fujitsu.setRaw(irsend.capture.state, irsend.capture.bits / 8); - EXPECT_EQ(FUJITSU_AC_STATE_LENGTH, fujitsu.getStateLength()); + EXPECT_EQ(kFujitsuAcStateLength, fujitsu.getStateLength()); EXPECT_EQ("Power: On, Mode: 4 (HEAT), Temp: 24C, Fan: 0 (AUTO), " "Swing: Off, Command: N/A", fujitsu.toString()); @@ -528,7 +531,7 @@ TEST(TestDecodeFujitsuAC, Issue414) { irsend.makeDecodeResult(); EXPECT_TRUE(irrecv.decode(&irsend.capture)); ASSERT_EQ(FUJITSU_AC, irsend.capture.decode_type); - ASSERT_EQ(FUJITSU_AC_BITS, irsend.capture.bits); + ASSERT_EQ(kFujitsuAcBits, irsend.capture.bits); EXPECT_TRUE(ArraysMatch(state, irsend.capture.state)); EXPECT_EQ( "m3324s1574" diff --git a/lib/IRremoteESP8266/test/ir_GICable_test.cpp b/lib/IRremoteESP8266/test/ir_GICable_test.cpp index 3eb5b67..b9bfce9 100644 --- a/lib/IRremoteESP8266/test/ir_GICable_test.cpp +++ b/lib/IRremoteESP8266/test/ir_GICable_test.cpp @@ -16,21 +16,24 @@ TEST(TestSendGICable, SendDataOnly) { "m550s2200m550s2200m550s2200m550s2200m550s2200m550s2200m550s2200m550s2200" "m550s2200m550s2200m550s2200m550s2200m550s2200m550s2200m550s2200m550s2200" "m550s41650" - "m9000s2200m550s87850", irsend.outputStr()); + "m9000s2200m550s87850", + irsend.outputStr()); irsend.sendGICable(0x8807); EXPECT_EQ( "m9000s4400" "m550s4400m550s2200m550s2200m550s2200m550s4400m550s2200m550s2200m550s2200" "m550s2200m550s2200m550s2200m550s2200m550s2200m550s4400m550s4400m550s4400" "m550s30650" - "m9000s2200m550s87850", irsend.outputStr()); + "m9000s2200m550s87850", + irsend.outputStr()); irsend.sendGICable(0xFFFF); EXPECT_EQ( "m9000s4400" "m550s4400m550s4400m550s4400m550s4400m550s4400m550s4400m550s4400m550s4400" "m550s4400m550s4400m550s4400m550s4400m550s4400m550s4400m550s4400m550s4400" "m550s6450" - "m9000s2200m550s87850", irsend.outputStr()); + "m9000s2200m550s87850", + irsend.outputStr()); } // Test sending with repeats. @@ -38,22 +41,24 @@ TEST(TestSendGICable, SendWithRepeats) { IRsendTest irsend(0); irsend.begin(); // Send a command with 0 repeats. - irsend.sendGICable(0x8807, GICABLE_BITS, 0); + irsend.sendGICable(0x8807, kGicableBits, 0); EXPECT_EQ( "m9000s4400" "m550s4400m550s2200m550s2200m550s2200m550s4400m550s2200m550s2200m550s2200" "m550s2200m550s2200m550s2200m550s2200m550s2200m550s4400m550s4400m550s4400" - "m550s30650", irsend.outputStr()); + "m550s30650", + irsend.outputStr()); // Send a command with 1 repeat. - irsend.sendGICable(0x8807, GICABLE_BITS, 1); + irsend.sendGICable(0x8807, kGicableBits, 1); EXPECT_EQ( "m9000s4400" "m550s4400m550s2200m550s2200m550s2200m550s4400m550s2200m550s2200m550s2200" "m550s2200m550s2200m550s2200m550s2200m550s2200m550s4400m550s4400m550s4400" "m550s30650" - "m9000s2200m550s87850", irsend.outputStr()); + "m9000s2200m550s87850", + irsend.outputStr()); // Send a command with 3 repeats. - irsend.sendGICable(0x8807, GICABLE_BITS, 3); + irsend.sendGICable(0x8807, kGicableBits, 3); EXPECT_EQ( "m9000s4400" "m550s4400m550s2200m550s2200m550s2200m550s4400m550s2200m550s2200m550s2200" @@ -61,7 +66,8 @@ TEST(TestSendGICable, SendWithRepeats) { "m550s30650" "m9000s2200m550s87850" "m9000s2200m550s87850" - "m9000s2200m550s87850", irsend.outputStr()); + "m9000s2200m550s87850", + irsend.outputStr()); } // Tests for decodeGICable(). @@ -77,7 +83,7 @@ TEST(TestDecodeGICable, SyntheticDecode) { irsend.makeDecodeResult(); EXPECT_TRUE(irrecv.decode(&irsend.capture)); EXPECT_EQ(GICABLE, irsend.capture.decode_type); - EXPECT_EQ(GICABLE_BITS, irsend.capture.bits); + EXPECT_EQ(kGicableBits, irsend.capture.bits); EXPECT_EQ(0x8807, irsend.capture.value); EXPECT_EQ(0x0, irsend.capture.address); EXPECT_EQ(0x0, irsend.capture.command); @@ -91,16 +97,17 @@ TEST(TestDecodeGICable, RealExampleDecodeOK) { // Real GICable "OK/Select" message. // Ref: https://github.com/markszabo/IRremoteESP8266/issues/447 - uint16_t rawData[39] = { - 9064, 4408, 580, 4408, 580, 2152, 578, 2150, 580, 2150, 580, 4408, 580, - 2150, 580, 2150, 580, 2150, 580, 2150, 580, 2150, 580, 2150, 580, 2150, - 580, 2150, 580, 4408, 580, 4408, 580, 4408, 580, 30622, 9066, 2148, 580}; + uint16_t rawData[39] = {9064, 4408, 580, 4408, 580, 2152, 578, 2150, + 580, 2150, 580, 4408, 580, 2150, 580, 2150, + 580, 2150, 580, 2150, 580, 2150, 580, 2150, + 580, 2150, 580, 2150, 580, 4408, 580, 4408, + 580, 4408, 580, 30622, 9066, 2148, 580}; irsend.reset(); irsend.sendRaw(rawData, 39, 39); irsend.makeDecodeResult(); EXPECT_TRUE(irrecv.decode(&irsend.capture)); EXPECT_EQ(GICABLE, irsend.capture.decode_type); - EXPECT_EQ(GICABLE_BITS, irsend.capture.bits); + EXPECT_EQ(kGicableBits, irsend.capture.bits); EXPECT_EQ(0x8807, irsend.capture.value); EXPECT_EQ(0x0, irsend.capture.address); EXPECT_EQ(0x0, irsend.capture.command); @@ -113,16 +120,17 @@ TEST(TestDecodeGICable, RealExampleDecodeLEFT) { // Real GICable "LEFT" message. // Ref: https://github.com/markszabo/IRremoteESP8266/issues/447 - uint16_t rawData[39] = { - 9040, 4434, 554, 2176, 580, 4408, 554, 4434, 582, 2148, 554, 4434, 580, - 4408, 556, 2174, 580, 2150, 580, 2150, 582, 2148, 556, 2176, 580, 2150, - 580, 4408, 580, 4408, 580, 4408, 582, 2150, 580, 26078, 9066, 2148, 580}; + uint16_t rawData[39] = {9040, 4434, 554, 2176, 580, 4408, 554, 4434, + 582, 2148, 554, 4434, 580, 4408, 556, 2174, + 580, 2150, 580, 2150, 582, 2148, 556, 2176, + 580, 2150, 580, 4408, 580, 4408, 580, 4408, + 582, 2150, 580, 26078, 9066, 2148, 580}; irsend.reset(); irsend.sendRaw(rawData, 39, 39); irsend.makeDecodeResult(); EXPECT_TRUE(irrecv.decode(&irsend.capture)); EXPECT_EQ(GICABLE, irsend.capture.decode_type); - EXPECT_EQ(GICABLE_BITS, irsend.capture.bits); + EXPECT_EQ(kGicableBits, irsend.capture.bits); EXPECT_EQ(0x6C0E, irsend.capture.value); EXPECT_EQ(0x0, irsend.capture.address); EXPECT_EQ(0x0, irsend.capture.command); @@ -136,16 +144,17 @@ TEST(TestDecodeGICable, RealExampleDecodeZEROKey) { // Real GICable "Zero Key" message. // Note: Zero key looks similar to a JVC message, hence this test. // Ref: https://github.com/markszabo/IRremoteESP8266/issues/447 - uint16_t rawData[39] = { - 9036, 4434, 552, 2178, 552, 2178, 552, 2180, 550, 2178, 552, 2178, 550, - 2180, 552, 2178, 552, 2178, 550, 2180, 552, 2178, 526, 2204, 552, 2178, - 552, 2178, 526, 2204, 526, 2204, 526, 2204, 526, 41932, 9036, 2176, 552}; + uint16_t rawData[39] = {9036, 4434, 552, 2178, 552, 2178, 552, 2180, + 550, 2178, 552, 2178, 550, 2180, 552, 2178, + 552, 2178, 550, 2180, 552, 2178, 526, 2204, + 552, 2178, 552, 2178, 526, 2204, 526, 2204, + 526, 2204, 526, 41932, 9036, 2176, 552}; irsend.reset(); irsend.sendRaw(rawData, 39, 39); irsend.makeDecodeResult(); EXPECT_TRUE(irrecv.decode(&irsend.capture)); EXPECT_EQ(GICABLE, irsend.capture.decode_type); - EXPECT_EQ(GICABLE_BITS, irsend.capture.bits); + EXPECT_EQ(kGicableBits, irsend.capture.bits); EXPECT_EQ(0x0, irsend.capture.value); EXPECT_EQ(0x0, irsend.capture.address); EXPECT_EQ(0x0, irsend.capture.command); diff --git a/lib/IRremoteESP8266/test/ir_GlobalCache_test.cpp b/lib/IRremoteESP8266/test/ir_GlobalCache_test.cpp index 68b0062..16a556b 100644 --- a/lib/IRremoteESP8266/test/ir_GlobalCache_test.cpp +++ b/lib/IRremoteESP8266/test/ir_GlobalCache_test.cpp @@ -13,27 +13,28 @@ TEST(TestSendGlobalCache, NonRepeatingCode) { irsend.begin(); irsend.reset(); - // Modified NEC TV "Power On" from Global Cache with no repeats - uint16_t gc_test[71] = {38000, 1, 1, 342, 172, 21, 22, 21, 21, 21, 65, 21, 21, - 21, 22, 21, 22, 21, 21, 21, 22, 21, 65, 21, 65, 21, - 22, 21, 65, 21, 65, 21, 65, 21, 65, 21, 65, 21, 65, - 21, 22, 21, 22, 21, 21, 21, 22, 21, 22, 21, 65, 21, - 22, 21, 21, 21, 65, 21, 65, 21, 65, 21, 64, 22, 65, - 21, 22, 21, 65, 21, 1519}; + // Modified NEC TV "Power On" from Global Cache with no repeats + uint16_t gc_test[71] = {38000, 1, 1, 342, 172, 21, 22, 21, 21, 21, 65, 21, + 21, 21, 22, 21, 22, 21, 21, 21, 22, 21, 65, 21, + 65, 21, 22, 21, 65, 21, 65, 21, 65, 21, 65, 21, + 65, 21, 65, 21, 22, 21, 22, 21, 21, 21, 22, 21, + 22, 21, 65, 21, 22, 21, 21, 21, 65, 21, 65, 21, + 65, 21, 64, 22, 65, 21, 22, 21, 65, 21, 1519}; irsend.sendGC(gc_test, 71); irsend.makeDecodeResult(); EXPECT_TRUE(irrecv.decodeNEC(&irsend.capture)); EXPECT_EQ(NEC, irsend.capture.decode_type); - EXPECT_EQ(NEC_BITS, irsend.capture.bits); + EXPECT_EQ(kNECBits, irsend.capture.bits); EXPECT_EQ(0x20DF827D, irsend.capture.value); EXPECT_EQ(0x4, irsend.capture.address); EXPECT_EQ(0x41, irsend.capture.command); - EXPECT_EQ("m8892s4472m546s572m546s546m546s1690m546s546m546s572m546s572" - "m546s546m546s572m546s1690m546s1690m546s572m546s1690m546s1690" - "m546s1690m546s1690m546s1690m546s1690m546s572m546s572m546s546" - "m546s572m546s572m546s1690m546s572m546s546m546s1690m546s1690" - "m546s1690m546s1664m572s1690m546s572m546s1690m546s39494", - irsend.outputStr()); + EXPECT_EQ( + "m8892s4472m546s572m546s546m546s1690m546s546m546s572m546s572" + "m546s546m546s572m546s1690m546s1690m546s572m546s1690m546s1690" + "m546s1690m546s1690m546s1690m546s1690m546s572m546s572m546s546" + "m546s572m546s572m546s1690m546s572m546s546m546s1690m546s1690" + "m546s1690m546s1664m572s1690m546s572m546s1690m546s39494", + irsend.outputStr()); } // Test sending typical command with repeats. @@ -43,26 +44,28 @@ TEST(TestSendGlobalCache, RepeatCode) { irsend.begin(); irsend.reset(); - // Sherwood (NEC-like) "Power On" from Global Cache with 2 repeats - uint16_t gc_test[75] = {38000, 2, 69, 341, 171, 21, 64, 21, 64, 21, 21, 21, - 21, 21, 21, 21, 21, 21, 21, 21, 64, 21, 64, 21, 21, - 21, 64, 21, 21, 21, 21, 21, 21, 21, 64, 21, 21, 21, - 64, 21, 21, 21, 21, 21, 21, 21, 64, 21, 21, 21, 21, - 21, 21, 21, 21, 21, 64, 21, 64, 21, 64, 21, 21, 21, - 64, 21, 64, 21, 64, 21, 1600, 341, 85, 21, 3647}; + // Sherwood (NEC-like) "Power On" from Global Cache with 2 repeats + uint16_t gc_test[75] = { + 38000, 2, 69, 341, 171, 21, 64, 21, 64, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 64, 21, 64, 21, 21, 21, 64, 21, 21, 21, + 21, 21, 21, 21, 64, 21, 21, 21, 64, 21, 21, 21, 21, 21, 21, + 21, 64, 21, 21, 21, 21, 21, 21, 21, 21, 21, 64, 21, 64, 21, + 64, 21, 21, 21, 64, 21, 64, 21, 64, 21, 1600, 341, 85, 21, 3647}; irsend.sendGC(gc_test, 75); irsend.makeDecodeResult(); EXPECT_TRUE(irrecv.decodeNEC(&irsend.capture)); EXPECT_EQ(NEC, irsend.capture.decode_type); - EXPECT_EQ(NEC_BITS, irsend.capture.bits); + EXPECT_EQ(kNECBits, irsend.capture.bits); EXPECT_EQ(0xC1A28877, irsend.capture.value); EXPECT_EQ(0x4583, irsend.capture.address); EXPECT_EQ(0x11, irsend.capture.command); - EXPECT_EQ("m8866s4446m546s1664m546s1664m546s546m546s546m546s546m546s546" - "m546s546m546s1664m546s1664m546s546m546s1664m546s546m546s546" - "m546s546m546s1664m546s546m546s1664m546s546m546s546m546s546" - "m546s1664m546s546m546s546m546s546m546s546m546s1664m546s1664" - "m546s1664m546s546m546s1664m546s1664m546s1664m546s41600" - "m8866s2210m546s94822" - "m8866s2210m546s94822", irsend.outputStr()); + EXPECT_EQ( + "m8866s4446m546s1664m546s1664m546s546m546s546m546s546m546s546" + "m546s546m546s1664m546s1664m546s546m546s1664m546s546m546s546" + "m546s546m546s1664m546s546m546s1664m546s546m546s546m546s546" + "m546s1664m546s546m546s546m546s546m546s546m546s1664m546s1664" + "m546s1664m546s546m546s1664m546s1664m546s1664m546s41600" + "m8866s2210m546s94822" + "m8866s2210m546s94822", + irsend.outputStr()); } diff --git a/lib/IRremoteESP8266/test/ir_Gree_test.cpp b/lib/IRremoteESP8266/test/ir_Gree_test.cpp index 811c9b7..6c7a1f6 100644 --- a/lib/IRremoteESP8266/test/ir_Gree_test.cpp +++ b/lib/IRremoteESP8266/test/ir_Gree_test.cpp @@ -1,11 +1,11 @@ // Copyright 2017 David Conran -#include "IRremoteESP8266.h" +#include "ir_Gree.h" #include "IRrecv.h" #include "IRrecv_test.h" +#include "IRremoteESP8266.h" #include "IRsend.h" #include "IRsend_test.h" -#include "ir_Gree.h" #include "gtest/gtest.h" // Tests for sendGree(). @@ -15,8 +15,8 @@ TEST(TestSendGreeChars, SendData) { IRsendTest irsend(4); irsend.begin(); - uint8_t gree_code[GREE_STATE_LENGTH] = { - 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF}; + uint8_t gree_code[kGreeStateLength] = {0x12, 0x34, 0x56, 0x78, + 0x90, 0xAB, 0xCD, 0xEF}; irsend.reset(); irsend.sendGree(gree_code); EXPECT_EQ( @@ -31,7 +31,8 @@ TEST(TestSendGreeChars, SendData) { "m620s1600m620s1600m620s540m620s1600m620s540m620s1600m620s540m620s1600" "m620s1600m620s540m620s1600m620s1600m620s540m620s540m620s1600m620s1600" "m620s1600m620s1600m620s1600m620s1600m620s540m620s1600m620s1600m620s1600" - "m620s19000", irsend.outputStr()); + "m620s19000", + irsend.outputStr()); } TEST(TestSendGreeUint64, SendData) { @@ -52,7 +53,8 @@ TEST(TestSendGreeUint64, SendData) { "m620s1600m620s1600m620s540m620s1600m620s540m620s1600m620s540m620s1600" "m620s1600m620s540m620s1600m620s1600m620s540m620s540m620s1600m620s1600" "m620s1600m620s1600m620s1600m620s1600m620s540m620s1600m620s1600m620s1600" - "m620s19000", irsend.outputStr()); + "m620s19000", + irsend.outputStr()); } // Test sending with repeats. @@ -61,36 +63,37 @@ TEST(TestSendGreeChars, SendWithRepeats) { irsend.begin(); irsend.reset(); - uint8_t gree_code[GREE_STATE_LENGTH] = { - 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF}; + uint8_t gree_code[kGreeStateLength] = {0x12, 0x34, 0x56, 0x78, + 0x90, 0xAB, 0xCD, 0xEF}; irsend.reset(); - irsend.sendGree(gree_code, GREE_STATE_LENGTH, 1); + irsend.sendGree(gree_code, kGreeStateLength, 1); EXPECT_EQ( - "m9000s4000" - "m620s540m620s1600m620s540m620s540m620s1600m620s540m620s540m620s540" - "m620s540m620s540m620s1600m620s540m620s1600m620s1600m620s540m620s540" - "m620s540m620s1600m620s1600m620s540m620s1600m620s540m620s1600m620s540" - "m620s540m620s540m620s540m620s1600m620s1600m620s1600m620s1600m620s540" - "m620s540m620s1600m620s540" - "m620s19000" - "m620s540m620s540m620s540m620s540m620s1600m620s540m620s540m620s1600" - "m620s1600m620s1600m620s540m620s1600m620s540m620s1600m620s540m620s1600" - "m620s1600m620s540m620s1600m620s1600m620s540m620s540m620s1600m620s1600" - "m620s1600m620s1600m620s1600m620s1600m620s540m620s1600m620s1600m620s1600" - "m620s19000" - "m9000s4000" - "m620s540m620s1600m620s540m620s540m620s1600m620s540m620s540m620s540" - "m620s540m620s540m620s1600m620s540m620s1600m620s1600m620s540m620s540" - "m620s540m620s1600m620s1600m620s540m620s1600m620s540m620s1600m620s540" - "m620s540m620s540m620s540m620s1600m620s1600m620s1600m620s1600m620s540" - "m620s540m620s1600m620s540" - "m620s19000" - "m620s540m620s540m620s540m620s540m620s1600m620s540m620s540m620s1600" - "m620s1600m620s1600m620s540m620s1600m620s540m620s1600m620s540m620s1600" - "m620s1600m620s540m620s1600m620s1600m620s540m620s540m620s1600m620s1600" - "m620s1600m620s1600m620s1600m620s1600m620s540m620s1600m620s1600m620s1600" - "m620s19000", irsend.outputStr()); + "m9000s4000" + "m620s540m620s1600m620s540m620s540m620s1600m620s540m620s540m620s540" + "m620s540m620s540m620s1600m620s540m620s1600m620s1600m620s540m620s540" + "m620s540m620s1600m620s1600m620s540m620s1600m620s540m620s1600m620s540" + "m620s540m620s540m620s540m620s1600m620s1600m620s1600m620s1600m620s540" + "m620s540m620s1600m620s540" + "m620s19000" + "m620s540m620s540m620s540m620s540m620s1600m620s540m620s540m620s1600" + "m620s1600m620s1600m620s540m620s1600m620s540m620s1600m620s540m620s1600" + "m620s1600m620s540m620s1600m620s1600m620s540m620s540m620s1600m620s1600" + "m620s1600m620s1600m620s1600m620s1600m620s540m620s1600m620s1600m620s1600" + "m620s19000" + "m9000s4000" + "m620s540m620s1600m620s540m620s540m620s1600m620s540m620s540m620s540" + "m620s540m620s540m620s1600m620s540m620s1600m620s1600m620s540m620s540" + "m620s540m620s1600m620s1600m620s540m620s1600m620s540m620s1600m620s540" + "m620s540m620s540m620s540m620s1600m620s1600m620s1600m620s1600m620s540" + "m620s540m620s1600m620s540" + "m620s19000" + "m620s540m620s540m620s540m620s540m620s1600m620s540m620s540m620s1600" + "m620s1600m620s1600m620s540m620s1600m620s540m620s1600m620s540m620s1600" + "m620s1600m620s540m620s1600m620s1600m620s540m620s540m620s1600m620s1600" + "m620s1600m620s1600m620s1600m620s1600m620s540m620s1600m620s1600m620s1600" + "m620s19000", + irsend.outputStr()); } TEST(TestSendGreeUint64, SendWithRepeats) { @@ -98,32 +101,33 @@ TEST(TestSendGreeUint64, SendWithRepeats) { irsend.begin(); irsend.reset(); - irsend.sendGree(0x1234567890ABCDEF, GREE_BITS, 1); + irsend.sendGree(0x1234567890ABCDEF, kGreeBits, 1); EXPECT_EQ( - "m9000s4000" - "m620s540m620s1600m620s540m620s540m620s1600m620s540m620s540m620s540" - "m620s540m620s540m620s1600m620s540m620s1600m620s1600m620s540m620s540" - "m620s540m620s1600m620s1600m620s540m620s1600m620s540m620s1600m620s540" - "m620s540m620s540m620s540m620s1600m620s1600m620s1600m620s1600m620s540" - "m620s540m620s1600m620s540" - "m620s19000" - "m620s540m620s540m620s540m620s540m620s1600m620s540m620s540m620s1600" - "m620s1600m620s1600m620s540m620s1600m620s540m620s1600m620s540m620s1600" - "m620s1600m620s540m620s1600m620s1600m620s540m620s540m620s1600m620s1600" - "m620s1600m620s1600m620s1600m620s1600m620s540m620s1600m620s1600m620s1600" - "m620s19000" - "m9000s4000" - "m620s540m620s1600m620s540m620s540m620s1600m620s540m620s540m620s540" - "m620s540m620s540m620s1600m620s540m620s1600m620s1600m620s540m620s540" - "m620s540m620s1600m620s1600m620s540m620s1600m620s540m620s1600m620s540" - "m620s540m620s540m620s540m620s1600m620s1600m620s1600m620s1600m620s540" - "m620s540m620s1600m620s540" - "m620s19000" - "m620s540m620s540m620s540m620s540m620s1600m620s540m620s540m620s1600" - "m620s1600m620s1600m620s540m620s1600m620s540m620s1600m620s540m620s1600" - "m620s1600m620s540m620s1600m620s1600m620s540m620s540m620s1600m620s1600" - "m620s1600m620s1600m620s1600m620s1600m620s540m620s1600m620s1600m620s1600" - "m620s19000", irsend.outputStr()); + "m9000s4000" + "m620s540m620s1600m620s540m620s540m620s1600m620s540m620s540m620s540" + "m620s540m620s540m620s1600m620s540m620s1600m620s1600m620s540m620s540" + "m620s540m620s1600m620s1600m620s540m620s1600m620s540m620s1600m620s540" + "m620s540m620s540m620s540m620s1600m620s1600m620s1600m620s1600m620s540" + "m620s540m620s1600m620s540" + "m620s19000" + "m620s540m620s540m620s540m620s540m620s1600m620s540m620s540m620s1600" + "m620s1600m620s1600m620s540m620s1600m620s540m620s1600m620s540m620s1600" + "m620s1600m620s540m620s1600m620s1600m620s540m620s540m620s1600m620s1600" + "m620s1600m620s1600m620s1600m620s1600m620s540m620s1600m620s1600m620s1600" + "m620s19000" + "m9000s4000" + "m620s540m620s1600m620s540m620s540m620s1600m620s540m620s540m620s540" + "m620s540m620s540m620s1600m620s540m620s1600m620s1600m620s540m620s540" + "m620s540m620s1600m620s1600m620s540m620s1600m620s540m620s1600m620s540" + "m620s540m620s540m620s540m620s1600m620s1600m620s1600m620s1600m620s540" + "m620s540m620s1600m620s540" + "m620s19000" + "m620s540m620s540m620s540m620s540m620s1600m620s540m620s540m620s1600" + "m620s1600m620s1600m620s540m620s1600m620s540m620s1600m620s540m620s1600" + "m620s1600m620s540m620s1600m620s1600m620s540m620s540m620s1600m620s1600" + "m620s1600m620s1600m620s1600m620s1600m620s540m620s1600m620s1600m620s1600" + "m620s19000", + irsend.outputStr()); } // Test sending atypical sizes. @@ -131,30 +135,31 @@ TEST(TestSendGreeChars, SendUnexpectedSizes) { IRsendTest irsend(4); irsend.begin(); - uint8_t gree_short_code[GREE_STATE_LENGTH - 1] = { - 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD}; - uint8_t gree_long_code[GREE_STATE_LENGTH + 1] = { - 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF, 0x12}; + uint8_t gree_short_code[kGreeStateLength - 1] = {0x12, 0x34, 0x56, 0x78, + 0x90, 0xAB, 0xCD}; + uint8_t gree_long_code[kGreeStateLength + 1] = {0x12, 0x34, 0x56, 0x78, 0x90, + 0xAB, 0xCD, 0xEF, 0x12}; irsend.reset(); - irsend.sendGree(gree_short_code, GREE_STATE_LENGTH - 1); + irsend.sendGree(gree_short_code, kGreeStateLength - 1); ASSERT_EQ("", irsend.outputStr()); irsend.reset(); - irsend.sendGree(gree_long_code, GREE_STATE_LENGTH + 1); + irsend.sendGree(gree_long_code, kGreeStateLength + 1); ASSERT_EQ( - "m9000s4000" - "m620s540m620s1600m620s540m620s540m620s1600m620s540m620s540m620s540" - "m620s540m620s540m620s1600m620s540m620s1600m620s1600m620s540m620s540" - "m620s540m620s1600m620s1600m620s540m620s1600m620s540m620s1600m620s540" - "m620s540m620s540m620s540m620s1600m620s1600m620s1600m620s1600m620s540" - "m620s540m620s1600m620s540" - "m620s19000" - "m620s540m620s540m620s540m620s540m620s1600m620s540m620s540m620s1600" - "m620s1600m620s1600m620s540m620s1600m620s540m620s1600m620s540m620s1600" - "m620s1600m620s540m620s1600m620s1600m620s540m620s540m620s1600m620s1600" - "m620s1600m620s1600m620s1600m620s1600m620s540m620s1600m620s1600m620s1600" - "m620s540m620s1600m620s540m620s540m620s1600m620s540m620s540m620s540" - "m620s19000", irsend.outputStr()); + "m9000s4000" + "m620s540m620s1600m620s540m620s540m620s1600m620s540m620s540m620s540" + "m620s540m620s540m620s1600m620s540m620s1600m620s1600m620s540m620s540" + "m620s540m620s1600m620s1600m620s540m620s1600m620s540m620s1600m620s540" + "m620s540m620s540m620s540m620s1600m620s1600m620s1600m620s1600m620s540" + "m620s540m620s1600m620s540" + "m620s19000" + "m620s540m620s540m620s540m620s540m620s1600m620s540m620s540m620s1600" + "m620s1600m620s1600m620s540m620s1600m620s540m620s1600m620s540m620s1600" + "m620s1600m620s540m620s1600m620s1600m620s540m620s540m620s1600m620s1600" + "m620s1600m620s1600m620s1600m620s1600m620s540m620s1600m620s1600m620s1600" + "m620s540m620s1600m620s540m620s540m620s1600m620s540m620s540m620s540" + "m620s19000", + irsend.outputStr()); } TEST(TestSendGreeUint64, SendUnexpectedSizes) { @@ -162,11 +167,11 @@ TEST(TestSendGreeUint64, SendUnexpectedSizes) { irsend.begin(); irsend.reset(); - irsend.sendGree(0x1234567890ABCDEF, GREE_BITS - 1); + irsend.sendGree(0x1234567890ABCDEF, kGreeBits - 1); ASSERT_EQ("", irsend.outputStr()); irsend.reset(); - irsend.sendGree(0x1234567890ABCDEF, GREE_BITS + 1); + irsend.sendGree(0x1234567890ABCDEF, kGreeBits + 1); ASSERT_EQ("", irsend.outputStr()); } @@ -174,8 +179,8 @@ TEST(TestSendGree, CompareUint64ToCharResults) { IRsendTest irsend_chars(4); IRsendTest irsend_uint64(0); - uint8_t gree_code[GREE_STATE_LENGTH] = { - 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF}; + uint8_t gree_code[kGreeStateLength] = {0x12, 0x34, 0x56, 0x78, + 0x90, 0xAB, 0xCD, 0xEF}; irsend_chars.begin(); irsend_uint64.begin(); @@ -186,12 +191,12 @@ TEST(TestSendGree, CompareUint64ToCharResults) { irsend_uint64.sendGree(0x1234567890ABCDEF); ASSERT_EQ(irsend_chars.outputStr(), irsend_uint64.outputStr()); - uint8_t gree_zero_code[GREE_STATE_LENGTH] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t gree_zero_code[kGreeStateLength] = {0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}; irsend_chars.reset(); irsend_uint64.reset(); irsend_chars.sendGree(gree_zero_code); - irsend_uint64.sendGree((uint64_t) 0x0); + irsend_uint64.sendGree((uint64_t)0x0); ASSERT_EQ(irsend_chars.outputStr(), irsend_uint64.outputStr()); } @@ -218,25 +223,25 @@ TEST(TestGreeClass, Temperature) { IRGreeAC irgree(0); irgree.begin(); - irgree.setMode(GREE_COOL); + irgree.setMode(kGreeCool); irgree.setTemp(0); - EXPECT_EQ(GREE_MIN_TEMP, irgree.getTemp()); + EXPECT_EQ(kGreeMinTemp, irgree.getTemp()); irgree.setTemp(255); - EXPECT_EQ(GREE_MAX_TEMP, irgree.getTemp()); + EXPECT_EQ(kGreeMaxTemp, irgree.getTemp()); - irgree.setTemp(GREE_MIN_TEMP); - EXPECT_EQ(GREE_MIN_TEMP, irgree.getTemp()); + irgree.setTemp(kGreeMinTemp); + EXPECT_EQ(kGreeMinTemp, irgree.getTemp()); - irgree.setTemp(GREE_MAX_TEMP); - EXPECT_EQ(GREE_MAX_TEMP, irgree.getTemp()); + irgree.setTemp(kGreeMaxTemp); + EXPECT_EQ(kGreeMaxTemp, irgree.getTemp()); - irgree.setTemp(GREE_MIN_TEMP - 1); - EXPECT_EQ(GREE_MIN_TEMP, irgree.getTemp()); + irgree.setTemp(kGreeMinTemp - 1); + EXPECT_EQ(kGreeMinTemp, irgree.getTemp()); - irgree.setTemp(GREE_MAX_TEMP + 1); - EXPECT_EQ(GREE_MAX_TEMP, irgree.getTemp()); + irgree.setTemp(kGreeMaxTemp + 1); + EXPECT_EQ(kGreeMaxTemp, irgree.getTemp()); irgree.setTemp(17); EXPECT_EQ(17, irgree.getTemp()); @@ -256,34 +261,34 @@ TEST(TestGreeClass, OperatingMode) { irgree.begin(); irgree.setTemp(17); - irgree.setMode(GREE_AUTO); // Auto should lock the temp to 25C. - EXPECT_EQ(GREE_AUTO, irgree.getMode()); + irgree.setMode(kGreeAuto); // Auto should lock the temp to 25C. + EXPECT_EQ(kGreeAuto, irgree.getMode()); EXPECT_EQ(25, irgree.getTemp()); irgree.setTemp(17); EXPECT_EQ(25, irgree.getTemp()); - irgree.setMode(GREE_COOL); - EXPECT_EQ(GREE_COOL, irgree.getMode()); + irgree.setMode(kGreeCool); + EXPECT_EQ(kGreeCool, irgree.getMode()); - irgree.setMode(GREE_HEAT); - EXPECT_EQ(GREE_HEAT, irgree.getMode()); + irgree.setMode(kGreeHeat); + EXPECT_EQ(kGreeHeat, irgree.getMode()); - ASSERT_NE(GREE_FAN_MAX, 1); - irgree.setFan(GREE_FAN_MAX); - irgree.setMode(GREE_DRY); // Dry should lock the fan to speed 1. - EXPECT_EQ(GREE_DRY, irgree.getMode()); + ASSERT_NE(kGreeFanMax, 1); + irgree.setFan(kGreeFanMax); + irgree.setMode(kGreeDry); // Dry should lock the fan to speed 1. + EXPECT_EQ(kGreeDry, irgree.getMode()); EXPECT_EQ(1, irgree.getFan()); - irgree.setFan(GREE_FAN_MAX); + irgree.setFan(kGreeFanMax); EXPECT_EQ(1, irgree.getFan()); - irgree.setMode(GREE_FAN); - EXPECT_EQ(GREE_FAN, irgree.getMode()); + irgree.setMode(kGreeFan); + EXPECT_EQ(kGreeFan, irgree.getMode()); - irgree.setMode(GREE_HEAT + 1); - EXPECT_EQ(GREE_AUTO, irgree.getMode()); + irgree.setMode(kGreeHeat + 1); + EXPECT_EQ(kGreeAuto, irgree.getMode()); irgree.setMode(255); - EXPECT_EQ(GREE_AUTO, irgree.getMode()); + EXPECT_EQ(kGreeAuto, irgree.getMode()); } TEST(TestGreeClass, Light) { @@ -350,16 +355,16 @@ TEST(TestGreeClass, FanSpeed) { EXPECT_EQ(0, irgree.getFan()); irgree.setFan(255); - EXPECT_EQ(GREE_FAN_MAX, irgree.getFan()); + EXPECT_EQ(kGreeFanMax, irgree.getFan()); - irgree.setFan(GREE_FAN_MAX); - EXPECT_EQ(GREE_FAN_MAX, irgree.getFan()); + irgree.setFan(kGreeFanMax); + EXPECT_EQ(kGreeFanMax, irgree.getFan()); - irgree.setFan(GREE_FAN_MAX + 1); - EXPECT_EQ(GREE_FAN_MAX, irgree.getFan()); + irgree.setFan(kGreeFanMax + 1); + EXPECT_EQ(kGreeFanMax, irgree.getFan()); - irgree.setFan(GREE_FAN_MAX - 1); - EXPECT_EQ(GREE_FAN_MAX - 1, irgree.getFan()); + irgree.setFan(kGreeFanMax - 1); + EXPECT_EQ(kGreeFanMax - 1, irgree.getFan()); irgree.setFan(1); EXPECT_EQ(1, irgree.getFan()); @@ -375,48 +380,48 @@ TEST(TestGreeClass, VerticalSwing) { IRGreeAC irgree(0); irgree.begin(); EXPECT_FALSE(irgree.getSwingVerticalAuto()); - EXPECT_EQ(GREE_SWING_LAST_POS, irgree.getSwingVerticalPosition()); + EXPECT_EQ(kGreeSwingLastPos, irgree.getSwingVerticalPosition()); - irgree.setSwingVertical(true, GREE_SWING_AUTO); + irgree.setSwingVertical(true, kGreeSwingAuto); EXPECT_TRUE(irgree.getSwingVerticalAuto()); - EXPECT_EQ(GREE_SWING_AUTO, irgree.getSwingVerticalPosition()); + EXPECT_EQ(kGreeSwingAuto, irgree.getSwingVerticalPosition()); - irgree.setSwingVertical(false, GREE_SWING_MIDDLE); + irgree.setSwingVertical(false, kGreeSwingMiddle); EXPECT_FALSE(irgree.getSwingVerticalAuto()); - EXPECT_EQ(GREE_SWING_MIDDLE, irgree.getSwingVerticalPosition()); + EXPECT_EQ(kGreeSwingMiddle, irgree.getSwingVerticalPosition()); - irgree.setSwingVertical(true, GREE_SWING_DOWN_AUTO); + irgree.setSwingVertical(true, kGreeSwingDownAuto); EXPECT_TRUE(irgree.getSwingVerticalAuto()); - EXPECT_EQ(GREE_SWING_DOWN_AUTO, irgree.getSwingVerticalPosition()); + EXPECT_EQ(kGreeSwingDownAuto, irgree.getSwingVerticalPosition()); // Out of bounds. irgree.setSwingVertical(false, 255); EXPECT_FALSE(irgree.getSwingVerticalAuto()); - EXPECT_EQ(GREE_SWING_LAST_POS, irgree.getSwingVerticalPosition()); - irgree.setSwingVertical(false, GREE_SWING_AUTO); + EXPECT_EQ(kGreeSwingLastPos, irgree.getSwingVerticalPosition()); + irgree.setSwingVertical(false, kGreeSwingAuto); EXPECT_FALSE(irgree.getSwingVerticalAuto()); - EXPECT_EQ(GREE_SWING_LAST_POS, irgree.getSwingVerticalPosition()); + EXPECT_EQ(kGreeSwingLastPos, irgree.getSwingVerticalPosition()); irgree.setSwingVertical(true, 255); EXPECT_TRUE(irgree.getSwingVerticalAuto()); - EXPECT_EQ(GREE_SWING_AUTO, irgree.getSwingVerticalPosition()); - irgree.setSwingVertical(true, GREE_SWING_DOWN); + EXPECT_EQ(kGreeSwingAuto, irgree.getSwingVerticalPosition()); + irgree.setSwingVertical(true, kGreeSwingDown); EXPECT_TRUE(irgree.getSwingVerticalAuto()); - EXPECT_EQ(GREE_SWING_AUTO, irgree.getSwingVerticalPosition()); + EXPECT_EQ(kGreeSwingAuto, irgree.getSwingVerticalPosition()); } TEST(TestGreeClass, SetAndGetRaw) { IRGreeAC irgree(0); - uint8_t initialState[GREE_STATE_LENGTH] = { - 0x00, 0x09, 0x20, 0x50, 0x00, 0x20, 0x00, 0x50}; - uint8_t expectedState[GREE_STATE_LENGTH] = { - 0xA9, 0x05, 0xD0, 0x50, 0x00, 0x20, 0x00, 0xA0}; + uint8_t initialState[kGreeStateLength] = {0x00, 0x09, 0x20, 0x50, + 0x00, 0x20, 0x00, 0x50}; + uint8_t expectedState[kGreeStateLength] = {0xA9, 0x05, 0xD0, 0x50, + 0x00, 0x20, 0x00, 0xA0}; - EXPECT_STATE_EQ(initialState, irgree.getRaw(), GREE_BITS); + EXPECT_STATE_EQ(initialState, irgree.getRaw(), kGreeBits); // toggle the power state. irgree.setPower(!irgree.getPower()); - irgree.setMode(GREE_COOL); + irgree.setMode(kGreeCool); irgree.setTemp(21); irgree.setFan(2); irgree.setLight(false); @@ -424,7 +429,7 @@ TEST(TestGreeClass, SetAndGetRaw) { irgree.setSleep(true); irgree.setXFan(true); - EXPECT_EQ(GREE_COOL, irgree.getMode()); + EXPECT_EQ(kGreeCool, irgree.getMode()); EXPECT_EQ(21, irgree.getTemp()); EXPECT_EQ(2, irgree.getFan()); EXPECT_FALSE(irgree.getLight()); @@ -432,31 +437,33 @@ TEST(TestGreeClass, SetAndGetRaw) { EXPECT_TRUE(irgree.getSleep()); EXPECT_TRUE(irgree.getXFan()); - EXPECT_STATE_EQ(expectedState, irgree.getRaw(), GREE_BITS); + EXPECT_STATE_EQ(expectedState, irgree.getRaw(), kGreeBits); irgree.setRaw(initialState); - EXPECT_STATE_EQ(initialState, irgree.getRaw(), GREE_BITS); + EXPECT_STATE_EQ(initialState, irgree.getRaw(), kGreeBits); } TEST(TestGreeClass, HumanReadable) { IRGreeAC irgree(0); - EXPECT_EQ("Power: Off, Mode: 0 (AUTO), Temp: 25C, Fan: 0 (AUTO), Turbo: Off, " - "XFan: Off, Light: On, Sleep: Off, Swing Vertical Mode: Manual, " - "Swing Vertical Pos: 0 (Last Pos)", - irgree.toString()); + EXPECT_EQ( + "Power: Off, Mode: 0 (AUTO), Temp: 25C, Fan: 0 (AUTO), Turbo: Off, " + "XFan: Off, Light: On, Sleep: Off, Swing Vertical Mode: Manual, " + "Swing Vertical Pos: 0 (Last Pos)", + irgree.toString()); irgree.on(); - irgree.setMode(GREE_COOL); - irgree.setTemp(GREE_MIN_TEMP); - irgree.setFan(GREE_FAN_MAX); + irgree.setMode(kGreeCool); + irgree.setTemp(kGreeMinTemp); + irgree.setFan(kGreeFanMax); irgree.setXFan(true); irgree.setSleep(true); irgree.setLight(false); irgree.setTurbo(true); - irgree.setSwingVertical(true, GREE_SWING_AUTO); - EXPECT_EQ("Power: On, Mode: 1 (COOL), Temp: 16C, Fan: 3 (MAX), Turbo: On, " - "XFan: On, Light: Off, Sleep: On, Swing Vertical Mode: Auto, " - "Swing Vertical Pos: 1 (Auto)", - irgree.toString()); + irgree.setSwingVertical(true, kGreeSwingAuto); + EXPECT_EQ( + "Power: On, Mode: 1 (COOL), Temp: 16C, Fan: 3 (MAX), Turbo: On, " + "XFan: On, Light: Off, Sleep: On, Swing Vertical Mode: Auto, " + "Swing Vertical Pos: 1 (Auto)", + irgree.toString()); } // Tests for decodeGree(). @@ -467,16 +474,16 @@ TEST(TestDecodeGree, NormalSynthetic) { IRrecv irrecv(4); irsend.begin(); - uint8_t gree_code[GREE_STATE_LENGTH] = { - 0x00, 0x09, 0x20, 0x50, 0x00, 0x20, 0x00, 0x50}; + uint8_t gree_code[kGreeStateLength] = {0x00, 0x09, 0x20, 0x50, + 0x00, 0x20, 0x00, 0x50}; irsend.reset(); irsend.sendGree(gree_code); irsend.makeDecodeResult(); EXPECT_TRUE(irrecv.decode(&irsend.capture)); EXPECT_EQ(GREE, irsend.capture.decode_type); - ASSERT_EQ(GREE_BITS, irsend.capture.bits); - EXPECT_STATE_EQ(gree_code, irsend.capture.state, GREE_BITS); + ASSERT_EQ(kGreeBits, irsend.capture.bits); + EXPECT_STATE_EQ(gree_code, irsend.capture.state, kGreeBits); } // Decode a synthetic Gree message. @@ -486,31 +493,35 @@ TEST(TestDecodeGree, NormalRealExample) { IRGreeAC irgree(4); irsend.begin(); - uint8_t gree_code[GREE_STATE_LENGTH] = { - 0x19, 0x0A, 0x60, 0x50, 0x02, 0x23, 0x00, 0xF0}; + uint8_t gree_code[kGreeStateLength] = {0x19, 0x0A, 0x60, 0x50, + 0x02, 0x23, 0x00, 0xF0}; // Ref: https://github.com/markszabo/IRremoteESP8266/issues/386 uint16_t rawData[139] = { - 9008, 4496, 644, 1660, 676, 530, 648, 558, 672, 1636, 646, 1660, 644, 556, - 650, 584, 626, 560, 644, 580, 628, 1680, 624, 560, 648, 1662, 644, 582, - 648, 536, 674, 530, 646, 580, 628, 560, 670, 532, 646, 562, 644, 556, 672, - 536, 648, 1662, 646, 1660, 652, 554, 644, 558, 672, 538, 644, 560, 668, - 560, 648, 1638, 668, 536, 644, 1660, 668, 532, 648, 560, 648, 1660, 674, - 554, 622, 19990, 646, 580, 624, 1660, 648, 556, 648, 558, 674, 556, 622, - 560, 644, 564, 668, 536, 646, 1662, 646, 1658, 672, 534, 648, 558, 644, - 562, 648, 1662, 644, 584, 622, 558, 648, 562, 668, 534, 670, 536, 670, - 532, 672, 536, 646, 560, 646, 558, 648, 558, 670, 534, 650, 558, 646, 560, - 646, 560, 668, 1638, 646, 1662, 646, 1660, 646, 1660, 648}; // Issue #386 + 9008, 4496, 644, 1660, 676, 530, 648, 558, 672, 1636, 646, 1660, + 644, 556, 650, 584, 626, 560, 644, 580, 628, 1680, 624, 560, + 648, 1662, 644, 582, 648, 536, 674, 530, 646, 580, 628, 560, + 670, 532, 646, 562, 644, 556, 672, 536, 648, 1662, 646, 1660, + 652, 554, 644, 558, 672, 538, 644, 560, 668, 560, 648, 1638, + 668, 536, 644, 1660, 668, 532, 648, 560, 648, 1660, 674, 554, + 622, 19990, 646, 580, 624, 1660, 648, 556, 648, 558, 674, 556, + 622, 560, 644, 564, 668, 536, 646, 1662, 646, 1658, 672, 534, + 648, 558, 644, 562, 648, 1662, 644, 584, 622, 558, 648, 562, + 668, 534, 670, 536, 670, 532, 672, 536, 646, 560, 646, 558, + 648, 558, 670, 534, 650, 558, 646, 560, 646, 560, 668, 1638, + 646, 1662, 646, 1660, 646, 1660, 648}; // Issue #386 irsend.reset(); irsend.sendRaw(rawData, 139, 38000); irsend.makeDecodeResult(); EXPECT_TRUE(irrecv.decode(&irsend.capture)); EXPECT_EQ(GREE, irsend.capture.decode_type); - ASSERT_EQ(GREE_BITS, irsend.capture.bits); - EXPECT_STATE_EQ(gree_code, irsend.capture.state, GREE_BITS); + ASSERT_EQ(kGreeBits, irsend.capture.bits); + EXPECT_STATE_EQ(gree_code, irsend.capture.state, kGreeBits); irgree.setRaw(irsend.capture.state); - EXPECT_EQ("Power: On, Mode: 1 (COOL), Temp: 26C, Fan: 1, Turbo: Off, " - "XFan: Off, Light: On, Sleep: Off, Swing Vertical Mode: Manual, " - "Swing Vertical Pos: 2", irgree.toString()); + EXPECT_EQ( + "Power: On, Mode: 1 (COOL), Temp: 26C, Fan: 1, Turbo: Off, " + "XFan: Off, Light: On, Sleep: Off, Swing Vertical Mode: Manual, " + "Swing Vertical Pos: 2", + irgree.toString()); } diff --git a/lib/IRremoteESP8266/test/ir_Haier_test.cpp b/lib/IRremoteESP8266/test/ir_Haier_test.cpp index 4fec483..11848e0 100644 --- a/lib/IRremoteESP8266/test/ir_Haier_test.cpp +++ b/lib/IRremoteESP8266/test/ir_Haier_test.cpp @@ -1,10 +1,10 @@ // Copyright 2018 David Conran +#include "ir_Haier.h" #include "IRrecv.h" #include "IRrecv_test.h" #include "IRsend.h" #include "IRsend_test.h" -#include "ir_Haier.h" #include "gtest/gtest.h" // Tests for sendHaierAC() @@ -13,8 +13,8 @@ TEST(TestSendHaierAC, SendDataOnly) { IRsendTest irsend(0); irsend.begin(); - uint8_t haier_zero[HAIER_AC_STATE_LENGTH] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t haier_zero[kHaierACStateLength] = {0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}; irsend.reset(); irsend.sendHaierAC(haier_zero); @@ -29,10 +29,11 @@ TEST(TestSendHaierAC, SendDataOnly) { "m520s650m520s650m520s650m520s650m520s650m520s650m520s650m520s650" "m520s650m520s650m520s650m520s650m520s650m520s650m520s650m520s650" "m520s650m520s650m520s650m520s650m520s650m520s650m520s650m520s650" - "m520s150000", irsend.outputStr()); + "m520s150000", + irsend.outputStr()); - uint8_t haier_test[HAIER_AC_STATE_LENGTH] = { - 0xA5, 0x01, 0x20, 0x01, 0x00, 0xC0, 0x20, 0x00, 0xA7}; + uint8_t haier_test[kHaierACStateLength] = {0xA5, 0x01, 0x20, 0x01, 0x00, + 0xC0, 0x20, 0x00, 0xA7}; irsend.reset(); irsend.sendHaierAC(haier_test); EXPECT_EQ( @@ -46,7 +47,8 @@ TEST(TestSendHaierAC, SendDataOnly) { "m520s650m520s650m520s1650m520s650m520s650m520s650m520s650m520s650" "m520s650m520s650m520s650m520s650m520s650m520s650m520s650m520s650" "m520s1650m520s650m520s1650m520s650m520s650m520s1650m520s1650m520s1650" - "m520s150000", irsend.outputStr()); + "m520s150000", + irsend.outputStr()); } // Test sending typical data with repeats. @@ -55,10 +57,10 @@ TEST(TestSendHaierAC, SendWithRepeats) { irsend.begin(); irsend.reset(); - uint8_t haier_test[HAIER_AC_STATE_LENGTH] = { - 0xA5, 0x01, 0x20, 0x01, 0x00, 0xC0, 0x20, 0x00, 0xA7}; + uint8_t haier_test[kHaierACStateLength] = {0xA5, 0x01, 0x20, 0x01, 0x00, + 0xC0, 0x20, 0x00, 0xA7}; irsend.reset(); - irsend.sendHaierAC(haier_test, HAIER_AC_STATE_LENGTH, 2); // two repeats. + irsend.sendHaierAC(haier_test, kHaierACStateLength, 2); // two repeats. EXPECT_EQ( "m3000s3000m3000s4300" "m520s1650m520s650m520s1650m520s650m520s650m520s1650m520s650m520s1650" @@ -92,7 +94,8 @@ TEST(TestSendHaierAC, SendWithRepeats) { "m520s650m520s650m520s1650m520s650m520s650m520s650m520s650m520s650" "m520s650m520s650m520s650m520s650m520s650m520s650m520s650m520s650" "m520s1650m520s650m520s1650m520s650m520s650m520s1650m520s1650m520s1650" - "m520s150000", irsend.outputStr()); + "m520s150000", + irsend.outputStr()); } // Tests for IRHaierAC class. @@ -101,156 +104,156 @@ TEST(TestHaierACClass, Command) { IRHaierAC haier(0); haier.begin(); - haier.setCommand(HAIER_AC_CMD_OFF); - EXPECT_EQ(HAIER_AC_CMD_OFF, haier.getCommand()); - haier.setCommand(HAIER_AC_CMD_ON); - EXPECT_EQ(HAIER_AC_CMD_ON, haier.getCommand()); - haier.setCommand(HAIER_AC_CMD_MODE); - EXPECT_EQ(HAIER_AC_CMD_MODE, haier.getCommand()); - haier.setCommand(HAIER_AC_CMD_FAN); - EXPECT_EQ(HAIER_AC_CMD_FAN, haier.getCommand()); - haier.setCommand(HAIER_AC_CMD_TEMP_UP); - EXPECT_EQ(HAIER_AC_CMD_TEMP_UP, haier.getCommand()); - haier.setCommand(HAIER_AC_CMD_TEMP_DOWN); - EXPECT_EQ(HAIER_AC_CMD_TEMP_DOWN, haier.getCommand()); - haier.setCommand(HAIER_AC_CMD_SLEEP); - EXPECT_EQ(HAIER_AC_CMD_SLEEP, haier.getCommand()); - haier.setCommand(HAIER_AC_CMD_TIMER_SET); - EXPECT_EQ(HAIER_AC_CMD_TIMER_SET, haier.getCommand()); - haier.setCommand(HAIER_AC_CMD_TIMER_CANCEL); - EXPECT_EQ(HAIER_AC_CMD_TIMER_CANCEL, haier.getCommand()); - haier.setCommand(HAIER_AC_CMD_HEALTH); - EXPECT_EQ(HAIER_AC_CMD_HEALTH, haier.getCommand()); - haier.setCommand(HAIER_AC_CMD_SWING); - EXPECT_EQ(HAIER_AC_CMD_SWING, haier.getCommand()); - haier.setCommand(HAIER_AC_CMD_ON); - EXPECT_EQ(HAIER_AC_CMD_ON, haier.getCommand()); + haier.setCommand(kHaierAcCmdOff); + EXPECT_EQ(kHaierAcCmdOff, haier.getCommand()); + haier.setCommand(kHaierAcCmdOn); + EXPECT_EQ(kHaierAcCmdOn, haier.getCommand()); + haier.setCommand(kHaierAcCmdMode); + EXPECT_EQ(kHaierAcCmdMode, haier.getCommand()); + haier.setCommand(kHaierAcCmdFan); + EXPECT_EQ(kHaierAcCmdFan, haier.getCommand()); + haier.setCommand(kHaierAcCmdTempUp); + EXPECT_EQ(kHaierAcCmdTempUp, haier.getCommand()); + haier.setCommand(kHaierAcCmdTempDown); + EXPECT_EQ(kHaierAcCmdTempDown, haier.getCommand()); + haier.setCommand(kHaierAcCmdSleep); + EXPECT_EQ(kHaierAcCmdSleep, haier.getCommand()); + haier.setCommand(kHaierAcCmdTimerSet); + EXPECT_EQ(kHaierAcCmdTimerSet, haier.getCommand()); + haier.setCommand(kHaierAcCmdTimerCancel); + EXPECT_EQ(kHaierAcCmdTimerCancel, haier.getCommand()); + haier.setCommand(kHaierAcCmdHealth); + EXPECT_EQ(kHaierAcCmdHealth, haier.getCommand()); + haier.setCommand(kHaierAcCmdSwing); + EXPECT_EQ(kHaierAcCmdSwing, haier.getCommand()); + haier.setCommand(kHaierAcCmdOn); + EXPECT_EQ(kHaierAcCmdOn, haier.getCommand()); // Test unexpected values. haier.setCommand(0b00001110); - EXPECT_EQ(HAIER_AC_CMD_OFF, haier.getCommand()); + EXPECT_EQ(kHaierAcCmdOff, haier.getCommand()); haier.setCommand(0b00001111); - EXPECT_EQ(HAIER_AC_CMD_OFF, haier.getCommand()); + EXPECT_EQ(kHaierAcCmdOff, haier.getCommand()); haier.setCommand(0b00000100); - EXPECT_EQ(HAIER_AC_CMD_OFF, haier.getCommand()); + EXPECT_EQ(kHaierAcCmdOff, haier.getCommand()); } TEST(TestHaierACClass, OperatingMode) { IRHaierAC haier(0); haier.begin(); - haier.setMode(HAIER_AC_AUTO); - EXPECT_EQ(HAIER_AC_AUTO, haier.getMode()); + haier.setMode(kHaierAcAuto); + EXPECT_EQ(kHaierAcAuto, haier.getMode()); - haier.setMode(HAIER_AC_COOL); - EXPECT_EQ(HAIER_AC_COOL, haier.getMode()); + haier.setMode(kHaierAcCool); + EXPECT_EQ(kHaierAcCool, haier.getMode()); - haier.setMode(HAIER_AC_HEAT); - EXPECT_EQ(HAIER_AC_HEAT, haier.getMode()); + haier.setMode(kHaierAcHeat); + EXPECT_EQ(kHaierAcHeat, haier.getMode()); - haier.setMode(HAIER_AC_FAN); - EXPECT_EQ(HAIER_AC_FAN, haier.getMode()); + haier.setMode(kHaierAcFan); + EXPECT_EQ(kHaierAcFan, haier.getMode()); - haier.setMode(HAIER_AC_DRY); - EXPECT_EQ(HAIER_AC_DRY, haier.getMode()); + haier.setMode(kHaierAcDry); + EXPECT_EQ(kHaierAcDry, haier.getMode()); - haier.setMode(HAIER_AC_AUTO - 1); - EXPECT_EQ(HAIER_AC_AUTO, haier.getMode()); + haier.setMode(kHaierAcAuto - 1); + EXPECT_EQ(kHaierAcAuto, haier.getMode()); - haier.setMode(HAIER_AC_COOL); - EXPECT_EQ(HAIER_AC_COOL, haier.getMode()); + haier.setMode(kHaierAcCool); + EXPECT_EQ(kHaierAcCool, haier.getMode()); - haier.setMode(HAIER_AC_FAN + 1); - EXPECT_EQ(HAIER_AC_AUTO, haier.getMode()); + haier.setMode(kHaierAcFan + 1); + EXPECT_EQ(kHaierAcAuto, haier.getMode()); haier.setMode(255); - EXPECT_EQ(HAIER_AC_AUTO, haier.getMode()); + EXPECT_EQ(kHaierAcAuto, haier.getMode()); } TEST(TestHaierACClass, Temperature) { IRHaierAC haier(0); haier.begin(); - haier.setTemp(HAIER_AC_MIN_TEMP); - EXPECT_EQ(HAIER_AC_MIN_TEMP, haier.getTemp()); + haier.setTemp(kHaierAcMinTemp); + EXPECT_EQ(kHaierAcMinTemp, haier.getTemp()); - haier.setCommand(HAIER_AC_CMD_ON); - haier.setTemp(HAIER_AC_MIN_TEMP + 1); - EXPECT_EQ(HAIER_AC_MIN_TEMP + 1, haier.getTemp()); - EXPECT_EQ(HAIER_AC_CMD_TEMP_UP, haier.getCommand()); + haier.setCommand(kHaierAcCmdOn); + haier.setTemp(kHaierAcMinTemp + 1); + EXPECT_EQ(kHaierAcMinTemp + 1, haier.getTemp()); + EXPECT_EQ(kHaierAcCmdTempUp, haier.getCommand()); - haier.setTemp(HAIER_AC_MAX_TEMP); - EXPECT_EQ(HAIER_AC_MAX_TEMP, haier.getTemp()); - EXPECT_EQ(HAIER_AC_CMD_TEMP_UP, haier.getCommand()); + haier.setTemp(kHaierAcMaxTemp); + EXPECT_EQ(kHaierAcMaxTemp, haier.getTemp()); + EXPECT_EQ(kHaierAcCmdTempUp, haier.getCommand()); - haier.setTemp(HAIER_AC_MIN_TEMP - 1); - EXPECT_EQ(HAIER_AC_MIN_TEMP, haier.getTemp()); - EXPECT_EQ(HAIER_AC_CMD_TEMP_DOWN, haier.getCommand()); + haier.setTemp(kHaierAcMinTemp - 1); + EXPECT_EQ(kHaierAcMinTemp, haier.getTemp()); + EXPECT_EQ(kHaierAcCmdTempDown, haier.getCommand()); - haier.setTemp(HAIER_AC_MAX_TEMP + 1); - EXPECT_EQ(HAIER_AC_MAX_TEMP, haier.getTemp()); - EXPECT_EQ(HAIER_AC_CMD_TEMP_UP, haier.getCommand()); + haier.setTemp(kHaierAcMaxTemp + 1); + EXPECT_EQ(kHaierAcMaxTemp, haier.getTemp()); + EXPECT_EQ(kHaierAcCmdTempUp, haier.getCommand()); haier.setTemp(23); EXPECT_EQ(23, haier.getTemp()); - EXPECT_EQ(HAIER_AC_CMD_TEMP_DOWN, haier.getCommand()); - haier.setCommand(HAIER_AC_CMD_ON); + EXPECT_EQ(kHaierAcCmdTempDown, haier.getCommand()); + haier.setCommand(kHaierAcCmdOn); haier.setTemp(23); EXPECT_EQ(23, haier.getTemp()); - EXPECT_EQ(HAIER_AC_CMD_ON, haier.getCommand()); + EXPECT_EQ(kHaierAcCmdOn, haier.getCommand()); haier.setTemp(0); - EXPECT_EQ(HAIER_AC_MIN_TEMP, haier.getTemp()); - EXPECT_EQ(HAIER_AC_CMD_TEMP_DOWN, haier.getCommand()); + EXPECT_EQ(kHaierAcMinTemp, haier.getTemp()); + EXPECT_EQ(kHaierAcCmdTempDown, haier.getCommand()); haier.setTemp(255); - EXPECT_EQ(HAIER_AC_MAX_TEMP, haier.getTemp()); - EXPECT_EQ(HAIER_AC_CMD_TEMP_UP, haier.getCommand()); + EXPECT_EQ(kHaierAcMaxTemp, haier.getTemp()); + EXPECT_EQ(kHaierAcCmdTempUp, haier.getCommand()); } TEST(TestHaierACClass, FanSpeed) { IRHaierAC haier(0); haier.begin(); - haier.setFan(HAIER_AC_FAN_LOW); - haier.setCommand(HAIER_AC_CMD_ON); + haier.setFan(kHaierAcFanLow); + haier.setCommand(kHaierAcCmdOn); - haier.setFan(HAIER_AC_FAN_AUTO); - EXPECT_EQ(HAIER_AC_FAN_AUTO, haier.getFan()); - EXPECT_EQ(HAIER_AC_CMD_FAN, haier.getCommand()); + haier.setFan(kHaierAcFanAuto); + EXPECT_EQ(kHaierAcFanAuto, haier.getFan()); + EXPECT_EQ(kHaierAcCmdFan, haier.getCommand()); - haier.setFan(HAIER_AC_FAN_LOW); - EXPECT_EQ(HAIER_AC_FAN_LOW, haier.getFan()); - haier.setFan(HAIER_AC_FAN_MED); - EXPECT_EQ(HAIER_AC_FAN_MED, haier.getFan()); - haier.setFan(HAIER_AC_FAN_HIGH); - EXPECT_EQ(HAIER_AC_FAN_HIGH, haier.getFan()); + haier.setFan(kHaierAcFanLow); + EXPECT_EQ(kHaierAcFanLow, haier.getFan()); + haier.setFan(kHaierAcFanMed); + EXPECT_EQ(kHaierAcFanMed, haier.getFan()); + haier.setFan(kHaierAcFanHigh); + EXPECT_EQ(kHaierAcFanHigh, haier.getFan()); - haier.setCommand(HAIER_AC_CMD_ON); - haier.setFan(HAIER_AC_FAN_HIGH); - EXPECT_EQ(HAIER_AC_FAN_HIGH, haier.getFan()); - EXPECT_EQ(HAIER_AC_CMD_ON, haier.getCommand()); + haier.setCommand(kHaierAcCmdOn); + haier.setFan(kHaierAcFanHigh); + EXPECT_EQ(kHaierAcFanHigh, haier.getFan()); + EXPECT_EQ(kHaierAcCmdOn, haier.getCommand()); } TEST(TestHaierACClass, Swing) { IRHaierAC haier(0); haier.begin(); - haier.setFan(HAIER_AC_FAN_LOW); - haier.setCommand(HAIER_AC_CMD_ON); + haier.setFan(kHaierAcFanLow); + haier.setCommand(kHaierAcCmdOn); - haier.setSwing(HAIER_AC_SWING_OFF); - EXPECT_EQ(HAIER_AC_SWING_OFF, haier.getSwing()); + haier.setSwing(kHaierAcSwingOff); + EXPECT_EQ(kHaierAcSwingOff, haier.getSwing()); - haier.setSwing(HAIER_AC_SWING_UP); - EXPECT_EQ(HAIER_AC_SWING_UP, haier.getSwing()); - EXPECT_EQ(HAIER_AC_CMD_SWING, haier.getCommand()); + haier.setSwing(kHaierAcSwingUp); + EXPECT_EQ(kHaierAcSwingUp, haier.getSwing()); + EXPECT_EQ(kHaierAcCmdSwing, haier.getCommand()); - haier.setSwing(HAIER_AC_SWING_DOWN); - EXPECT_EQ(HAIER_AC_SWING_DOWN, haier.getSwing()); - EXPECT_EQ(HAIER_AC_CMD_SWING, haier.getCommand()); + haier.setSwing(kHaierAcSwingDown); + EXPECT_EQ(kHaierAcSwingDown, haier.getSwing()); + EXPECT_EQ(kHaierAcCmdSwing, haier.getCommand()); - haier.setSwing(HAIER_AC_SWING_CHG); - EXPECT_EQ(HAIER_AC_SWING_CHG, haier.getSwing()); - EXPECT_EQ(HAIER_AC_CMD_SWING, haier.getCommand()); + haier.setSwing(kHaierAcSwingChg); + EXPECT_EQ(kHaierAcSwingChg, haier.getSwing()); + EXPECT_EQ(kHaierAcCmdSwing, haier.getCommand()); } TEST(TestHaierACClass, CurrentTime) { @@ -270,71 +273,71 @@ TEST(TestHaierACClass, CurrentTime) { haier.setCurrTime(18 * 60 + 34); // 18:34 EXPECT_EQ(1114, haier.getCurrTime()); - haier.setCurrTime(23 * 60 + 59); // 23:59 - EXPECT_EQ(HAIER_AC_MAX_TIME, haier.getCurrTime()); // 23:59 + haier.setCurrTime(23 * 60 + 59); // 23:59 + EXPECT_EQ(kHaierAcMaxTime, haier.getCurrTime()); // 23:59 - haier.setCurrTime(23 * 60 + 59 + 1); // 24:00 - EXPECT_EQ(HAIER_AC_MAX_TIME, haier.getCurrTime()); // 23:59 + haier.setCurrTime(23 * 60 + 59 + 1); // 24:00 + EXPECT_EQ(kHaierAcMaxTime, haier.getCurrTime()); // 23:59 haier.setCurrTime(UINT16_MAX); - EXPECT_EQ(HAIER_AC_MAX_TIME, haier.getCurrTime()); // 23:59 + EXPECT_EQ(kHaierAcMaxTime, haier.getCurrTime()); // 23:59 } TEST(TestHaierACClass, Timers) { IRHaierAC haier(0); haier.begin(); - haier.setCommand(HAIER_AC_CMD_ON); + haier.setCommand(kHaierAcCmdOn); // Off by default. EXPECT_GT(0, haier.getOnTimer()); EXPECT_GT(0, haier.getOffTimer()); - EXPECT_EQ(HAIER_AC_CMD_ON, haier.getCommand()); + EXPECT_EQ(kHaierAcCmdOn, haier.getCommand()); // On Timer. - haier.setOnTimer(6 * 60); // 6am + haier.setOnTimer(6 * 60); // 6am EXPECT_EQ(6 * 60, haier.getOnTimer()); // 6am EXPECT_GT(0, haier.getOffTimer()); - EXPECT_EQ(HAIER_AC_CMD_TIMER_SET, haier.getCommand()); + EXPECT_EQ(kHaierAcCmdTimerSet, haier.getCommand()); - haier.setCommand(HAIER_AC_CMD_ON); + haier.setCommand(kHaierAcCmdOn); EXPECT_EQ(6 * 60, haier.getOnTimer()); // 6am EXPECT_GT(0, haier.getOffTimer()); - EXPECT_EQ(HAIER_AC_CMD_ON, haier.getCommand()); + EXPECT_EQ(kHaierAcCmdOn, haier.getCommand()); haier.cancelTimers(); EXPECT_GT(0, haier.getOnTimer()); EXPECT_GT(0, haier.getOffTimer()); - EXPECT_EQ(HAIER_AC_CMD_TIMER_CANCEL, haier.getCommand()); + EXPECT_EQ(kHaierAcCmdTimerCancel, haier.getCommand()); // Off Timer. haier.setOffTimer(18 * 60 + 30); // 6:30pm EXPECT_GT(0, haier.getOnTimer()); EXPECT_EQ(18 * 60 + 30, haier.getOffTimer()); // 6:30pm - EXPECT_EQ(HAIER_AC_CMD_TIMER_SET, haier.getCommand()); + EXPECT_EQ(kHaierAcCmdTimerSet, haier.getCommand()); - haier.setCommand(HAIER_AC_CMD_ON); + haier.setCommand(kHaierAcCmdOn); EXPECT_GT(0, haier.getOnTimer()); EXPECT_EQ(18 * 60 + 30, haier.getOffTimer()); // 6:30pm - EXPECT_EQ(HAIER_AC_CMD_ON, haier.getCommand()); + EXPECT_EQ(kHaierAcCmdOn, haier.getCommand()); haier.cancelTimers(); EXPECT_GT(0, haier.getOnTimer()); EXPECT_GT(0, haier.getOffTimer()); - EXPECT_EQ(HAIER_AC_CMD_TIMER_CANCEL, haier.getCommand()); + EXPECT_EQ(kHaierAcCmdTimerCancel, haier.getCommand()); // Both Timers. haier.setOnTimer(6 * 60); // 6am - EXPECT_EQ(HAIER_AC_CMD_TIMER_SET, haier.getCommand()); + EXPECT_EQ(kHaierAcCmdTimerSet, haier.getCommand()); haier.setOffTimer(18 * 60 + 30); // 6:30pm - EXPECT_EQ(HAIER_AC_CMD_TIMER_SET, haier.getCommand()); - EXPECT_EQ(6 * 60, haier.getOnTimer()); // 6am + EXPECT_EQ(kHaierAcCmdTimerSet, haier.getCommand()); + EXPECT_EQ(6 * 60, haier.getOnTimer()); // 6am EXPECT_EQ(18 * 60 + 30, haier.getOffTimer()); // 6:30pm haier.cancelTimers(); EXPECT_GT(0, haier.getOnTimer()); EXPECT_GT(0, haier.getOffTimer()); - EXPECT_EQ(HAIER_AC_CMD_TIMER_CANCEL, haier.getCommand()); + EXPECT_EQ(kHaierAcCmdTimerCancel, haier.getCommand()); } TEST(TestHaierACClass, TimeToString) { @@ -353,67 +356,411 @@ TEST(TestHaierACClass, TimeToString) { TEST(TestHaierACClass, MessageConstuction) { IRHaierAC haier(0); - EXPECT_EQ("Command: 1 (On), Mode: 0 (AUTO), Temp: 25C, Fan: 0 (AUTO), " - "Swing: 0 (Off), Sleep: Off, Health: Off, " - "Current Time: 00:00, On Timer: Off, Off Timer: Off", - haier.toString()); - haier.setMode(HAIER_AC_COOL); + EXPECT_EQ( + "Command: 1 (On), Mode: 0 (AUTO), Temp: 25C, Fan: 0 (AUTO), " + "Swing: 0 (Off), Sleep: Off, Health: Off, " + "Current Time: 00:00, On Timer: Off, Off Timer: Off", + haier.toString()); + haier.setMode(kHaierAcCool); haier.setTemp(21); - haier.setFan(HAIER_AC_FAN_HIGH); - EXPECT_EQ("Command: 3 (Fan), Mode: 1 (COOL), Temp: 21C, Fan: 3 (MAX), " - "Swing: 0 (Off), Sleep: Off, Health: Off, " - "Current Time: 00:00, On Timer: Off, Off Timer: Off", - haier.toString()); - haier.setSwing(HAIER_AC_SWING_CHG); + haier.setFan(kHaierAcFanHigh); + EXPECT_EQ( + "Command: 3 (Fan), Mode: 1 (COOL), Temp: 21C, Fan: 3 (MAX), " + "Swing: 0 (Off), Sleep: Off, Health: Off, " + "Current Time: 00:00, On Timer: Off, Off Timer: Off", + haier.toString()); + haier.setSwing(kHaierAcSwingChg); haier.setHealth(true); haier.setSleep(true); haier.setCurrTime(615); // 10:15am - EXPECT_EQ("Command: 8 (Sleep), Mode: 3 (HEAT), Temp: 21C, Fan: 3 (MAX), " - "Swing: 3 (Chg), Sleep: On, Health: On, " - "Current Time: 10:15, On Timer: Off, Off Timer: Off", - haier.toString()); - haier.setOnTimer(800); // 1:20pm + EXPECT_EQ( + "Command: 8 (Sleep), Mode: 3 (HEAT), Temp: 21C, Fan: 3 (MAX), " + "Swing: 3 (Chg), Sleep: On, Health: On, " + "Current Time: 10:15, On Timer: Off, Off Timer: Off", + haier.toString()); + haier.setOnTimer(800); // 1:20pm haier.setOffTimer(1125); // 6:45pm - haier.setCommand(HAIER_AC_CMD_ON); + haier.setCommand(kHaierAcCmdOn); - EXPECT_EQ("Command: 1 (On), Mode: 2 (DRY), Temp: 21C, Fan: 2, " - "Swing: 3 (Chg), Sleep: On, Health: On, " - "Current Time: 10:15, On Timer: 13:20, Off Timer: 18:45", - haier.toString()); + EXPECT_EQ( + "Command: 1 (On), Mode: 2 (DRY), Temp: 21C, Fan: 2, " + "Swing: 3 (Chg), Sleep: On, Health: On, " + "Current Time: 10:15, On Timer: 13:20, Off Timer: 18:45", + haier.toString()); // Now change a few already set things. - haier.setMode(HAIER_AC_HEAT); - EXPECT_EQ("Command: 2 (Mode), Mode: 3 (HEAT), Temp: 21C, Fan: 2, " - "Swing: 3 (Chg), Sleep: On, Health: On, " - "Current Time: 10:15, On Timer: 13:52, Off Timer: 18:45", - haier.toString()); + haier.setMode(kHaierAcHeat); + EXPECT_EQ( + "Command: 2 (Mode), Mode: 3 (HEAT), Temp: 21C, Fan: 2, " + "Swing: 3 (Chg), Sleep: On, Health: On, " + "Current Time: 10:15, On Timer: 13:52, Off Timer: 18:45", + haier.toString()); haier.setTemp(25); - EXPECT_EQ("Command: 6 (Temp Up), Mode: 3 (HEAT), Temp: 25C, Fan: 2, " - "Swing: 3 (Chg), Sleep: On, Health: On, " - "Current Time: 10:15, On Timer: 13:52, Off Timer: 18:45", - haier.toString()); + EXPECT_EQ( + "Command: 6 (Temp Up), Mode: 3 (HEAT), Temp: 25C, Fan: 2, " + "Swing: 3 (Chg), Sleep: On, Health: On, " + "Current Time: 10:15, On Timer: 13:52, Off Timer: 18:45", + haier.toString()); - uint8_t expectedState[HAIER_AC_STATE_LENGTH] = { - 0xA5, 0x96, 0xEA, 0xCF, 0x32, 0x2D, 0x0D, 0x74, 0xD4}; - EXPECT_STATE_EQ(expectedState, haier.getRaw(), HAIER_AC_BITS); + uint8_t expectedState[kHaierACStateLength] = {0xA5, 0x96, 0xEA, 0xCF, 0x32, + 0x2D, 0x0D, 0x74, 0xD4}; + EXPECT_STATE_EQ(expectedState, haier.getRaw(), kHaierACBits); // Check that the checksum is valid. EXPECT_TRUE(IRHaierAC::validChecksum(haier.getRaw())); // Now load up some random data. - uint8_t randomState[HAIER_AC_STATE_LENGTH] = { - 0x52, 0x49, 0x50, 0x20, 0x54, 0x61, 0x6C, 0x69, 0x61}; + uint8_t randomState[kHaierACStateLength] = {0x52, 0x49, 0x50, 0x20, 0x54, + 0x61, 0x6C, 0x69, 0x61}; EXPECT_FALSE(IRHaierAC::validChecksum(randomState)); haier.setRaw(randomState); - EXPECT_EQ("Command: 9 (Timer Set), Mode: 3 (HEAT), Temp: 20C, Fan: 2, " - "Swing: 1 (Up), Sleep: On, Health: Off, " - "Current Time: 16:32, On Timer: Off, Off Timer: Off", - haier.toString()); + EXPECT_EQ( + "Command: 9 (Timer Set), Mode: 3 (HEAT), Temp: 20C, Fan: 2, " + "Swing: 1 (Up), Sleep: On, Health: Off, " + "Current Time: 16:32, On Timer: Off, Off Timer: Off", + haier.toString()); // getRaw() should correct the checksum. EXPECT_TRUE(IRHaierAC::validChecksum(haier.getRaw())); } +// Tests for the IRHaierACYRW02 class. + +TEST(TestHaierACYRW02Class, Button) { + IRHaierACYRW02 haier(0); + haier.begin(); + + haier.setButton(kHaierAcYrw02ButtonPower); + EXPECT_EQ(kHaierAcYrw02ButtonPower, haier.getButton()); + haier.setButton(kHaierAcYrw02ButtonMode); + EXPECT_EQ(kHaierAcYrw02ButtonMode, haier.getButton()); + haier.setButton(kHaierAcYrw02ButtonSleep); + EXPECT_EQ(kHaierAcYrw02ButtonSleep, haier.getButton()); + haier.setButton(kHaierAcYrw02ButtonFan); + + // Test unexpected values. + haier.setButton(0xFF); + EXPECT_EQ(kHaierAcYrw02ButtonFan, haier.getButton()); + haier.setButton(0x10); + EXPECT_EQ(kHaierAcYrw02ButtonFan, haier.getButton()); +} + +TEST(TestHaierACYRW02Class, OperatingMode) { + IRHaierACYRW02 haier(0); + haier.begin(); + + haier.setButton(kHaierAcYrw02ButtonPower); + haier.setMode(kHaierAcYrw02Auto); + EXPECT_EQ(kHaierAcYrw02Auto, haier.getMode()); + EXPECT_EQ(kHaierAcYrw02ButtonMode, haier.getButton()); + + haier.setMode(kHaierAcYrw02Cool); + EXPECT_EQ(kHaierAcYrw02Cool, haier.getMode()); + + haier.setMode(kHaierAcYrw02Heat); + EXPECT_EQ(kHaierAcYrw02Heat, haier.getMode()); + + haier.setMode(kHaierAcYrw02Fan); + EXPECT_EQ(kHaierAcYrw02Fan, haier.getMode()); + + haier.setMode(kHaierAcYrw02Dry); + EXPECT_EQ(kHaierAcYrw02Dry, haier.getMode()); + + haier.setMode(kHaierAcYrw02Auto - 1); + EXPECT_EQ(kHaierAcYrw02Auto, haier.getMode()); + + haier.setMode(kHaierAcYrw02Cool); + EXPECT_EQ(kHaierAcYrw02Cool, haier.getMode()); + + haier.setMode(kHaierAcYrw02Fan + 1); + EXPECT_EQ(kHaierAcYrw02Auto, haier.getMode()); + + haier.setMode(255); + EXPECT_EQ(kHaierAcYrw02Auto, haier.getMode()); +} + +TEST(TestHaierACYRW02Class, Temperature) { + IRHaierACYRW02 haier(0); + haier.begin(); + + haier.setTemp(kHaierAcMinTemp); + EXPECT_EQ(kHaierAcMinTemp, haier.getTemp()); + + haier.setButton(kHaierAcYrw02ButtonPower); + haier.setTemp(kHaierAcMinTemp + 1); + EXPECT_EQ(kHaierAcMinTemp + 1, haier.getTemp()); + EXPECT_EQ(kHaierAcYrw02ButtonTempUp, haier.getButton()); + + haier.setTemp(kHaierAcMaxTemp); + EXPECT_EQ(kHaierAcMaxTemp, haier.getTemp()); + EXPECT_EQ(kHaierAcYrw02ButtonTempUp, haier.getButton()); + + haier.setTemp(kHaierAcMinTemp - 1); + EXPECT_EQ(kHaierAcMinTemp, haier.getTemp()); + EXPECT_EQ(kHaierAcYrw02ButtonTempDown, haier.getButton()); + + haier.setTemp(kHaierAcMaxTemp + 1); + EXPECT_EQ(kHaierAcMaxTemp, haier.getTemp()); + EXPECT_EQ(kHaierAcYrw02ButtonTempUp, haier.getButton()); + + haier.setTemp(23); + EXPECT_EQ(23, haier.getTemp()); + EXPECT_EQ(kHaierAcYrw02ButtonTempDown, haier.getButton()); + haier.setButton(kHaierAcYrw02ButtonPower); + haier.setTemp(23); + EXPECT_EQ(23, haier.getTemp()); + EXPECT_EQ(kHaierAcYrw02ButtonPower, haier.getButton()); + + haier.setTemp(0); + EXPECT_EQ(kHaierAcMinTemp, haier.getTemp()); + EXPECT_EQ(kHaierAcYrw02ButtonTempDown, haier.getButton()); + + haier.setTemp(255); + EXPECT_EQ(kHaierAcMaxTemp, haier.getTemp()); + EXPECT_EQ(kHaierAcYrw02ButtonTempUp, haier.getButton()); +} + +TEST(TestHaierACYRW02Class, HealthMode) { + IRHaierACYRW02 haier(0); + haier.begin(); + + haier.setHealth(true); + EXPECT_TRUE(haier.getHealth()); + EXPECT_EQ(kHaierAcYrw02ButtonHealth, haier.getButton()); + + haier.setButton(kHaierAcYrw02ButtonTempUp); + haier.setHealth(false); + EXPECT_FALSE(haier.getHealth()); + EXPECT_EQ(kHaierAcYrw02ButtonHealth, haier.getButton()); + + haier.setHealth(true); + EXPECT_TRUE(haier.getHealth()); + EXPECT_EQ(kHaierAcYrw02ButtonHealth, haier.getButton()); +} + +TEST(TestHaierACYRW02Class, Power) { + IRHaierACYRW02 haier(0); + haier.begin(); + + haier.setPower(true); + EXPECT_TRUE(haier.getPower()); + EXPECT_EQ(kHaierAcYrw02ButtonPower, haier.getButton()); + + haier.setButton(kHaierAcYrw02ButtonTempUp); + haier.setPower(false); + EXPECT_FALSE(haier.getPower()); + EXPECT_EQ(kHaierAcYrw02ButtonPower, haier.getButton()); + + haier.setPower(true); + EXPECT_TRUE(haier.getPower()); + EXPECT_EQ(kHaierAcYrw02ButtonPower, haier.getButton()); + + haier.off(); + EXPECT_FALSE(haier.getPower()); + haier.on(); + EXPECT_TRUE(haier.getPower()); +} + +TEST(TestHaierACYRW02Class, SleepMode) { + IRHaierACYRW02 haier(0); + haier.begin(); + + haier.setSleep(true); + EXPECT_TRUE(haier.getSleep()); + EXPECT_EQ(kHaierAcYrw02ButtonSleep, haier.getButton()); + + haier.setButton(kHaierAcYrw02ButtonTempUp); + haier.setSleep(false); + EXPECT_FALSE(haier.getSleep()); + EXPECT_EQ(kHaierAcYrw02ButtonSleep, haier.getButton()); + + haier.setSleep(true); + EXPECT_TRUE(haier.getSleep()); + EXPECT_EQ(kHaierAcYrw02ButtonSleep, haier.getButton()); +} + +TEST(TestHaierACYRW02Class, TurboMode) { + IRHaierACYRW02 haier(0); + haier.begin(); + + haier.setTurbo(kHaierAcYrw02TurboOff); + EXPECT_EQ(kHaierAcYrw02TurboOff, haier.getTurbo()); + EXPECT_EQ(kHaierAcYrw02ButtonTurbo, haier.getButton()); + + haier.setButton(kHaierAcYrw02ButtonTempUp); + + haier.setTurbo(kHaierAcYrw02TurboLow); + EXPECT_EQ(kHaierAcYrw02TurboLow, haier.getTurbo()); + EXPECT_EQ(kHaierAcYrw02ButtonTurbo, haier.getButton()); + + haier.setTurbo(kHaierAcYrw02TurboHigh); + EXPECT_EQ(kHaierAcYrw02TurboHigh, haier.getTurbo()); + EXPECT_EQ(kHaierAcYrw02ButtonTurbo, haier.getButton()); + + haier.setTurbo(kHaierAcYrw02TurboOff); + EXPECT_EQ(kHaierAcYrw02TurboOff, haier.getTurbo()); + EXPECT_EQ(kHaierAcYrw02ButtonTurbo, haier.getButton()); +} + +TEST(TestHaierACYRW02Class, Fan) { + IRHaierACYRW02 haier(0); + haier.begin(); + + haier.setFan(kHaierAcYrw02FanAuto); + EXPECT_EQ(kHaierAcYrw02FanAuto, haier.getFan()); + EXPECT_EQ(kHaierAcYrw02ButtonFan, haier.getButton()); + + haier.setButton(kHaierAcYrw02ButtonTempUp); + + haier.setFan(kHaierAcYrw02FanLow); + EXPECT_EQ(kHaierAcYrw02FanLow, haier.getFan()); + EXPECT_EQ(kHaierAcYrw02ButtonFan, haier.getButton()); + + haier.setFan(kHaierAcYrw02FanHigh); + EXPECT_EQ(kHaierAcYrw02FanHigh, haier.getFan()); + EXPECT_EQ(kHaierAcYrw02ButtonFan, haier.getButton()); + + haier.setFan(kHaierAcYrw02FanMed); + EXPECT_EQ(kHaierAcYrw02FanMed, haier.getFan()); + EXPECT_EQ(kHaierAcYrw02ButtonFan, haier.getButton()); + + // Test unexpected values. + haier.setButton(kHaierAcYrw02ButtonTempUp); + haier.setFan(0x00); + EXPECT_EQ(kHaierAcYrw02FanMed, haier.getFan()); + EXPECT_EQ(kHaierAcYrw02ButtonTempUp, haier.getButton()); +} + +TEST(TestHaierACYRW02Class, Swing) { + IRHaierACYRW02 haier(0); + haier.begin(); + + haier.setSwing(kHaierAcYrw02SwingOff); + EXPECT_EQ(kHaierAcYrw02SwingOff, haier.getSwing()); + EXPECT_EQ(kHaierAcYrw02ButtonSwing, haier.getButton()); + + haier.setButton(kHaierAcYrw02ButtonTempUp); + + haier.setSwing(kHaierAcYrw02SwingAuto); + EXPECT_EQ(kHaierAcYrw02SwingAuto, haier.getSwing()); + EXPECT_EQ(kHaierAcYrw02ButtonSwing, haier.getButton()); + + haier.setSwing(kHaierAcYrw02SwingTop); + EXPECT_EQ(kHaierAcYrw02SwingTop, haier.getSwing()); + EXPECT_EQ(kHaierAcYrw02ButtonSwing, haier.getButton()); + + haier.setSwing(kHaierAcYrw02SwingDown); + EXPECT_EQ(kHaierAcYrw02SwingDown, haier.getSwing()); + EXPECT_EQ(kHaierAcYrw02ButtonSwing, haier.getButton()); + + // Test unexpected values. + haier.setButton(kHaierAcYrw02ButtonTempUp); + haier.setSwing(0xFF); + EXPECT_EQ(kHaierAcYrw02SwingDown, haier.getSwing()); + EXPECT_EQ(kHaierAcYrw02ButtonTempUp, haier.getButton()); + + // Test the mode-dependant positions. + haier.setMode(kHaierAcYrw02Auto); + haier.setSwing(kHaierAcYrw02SwingMiddle); + EXPECT_EQ(kHaierAcYrw02SwingMiddle, haier.getSwing()); + EXPECT_EQ(kHaierAcYrw02ButtonSwing, haier.getButton()); + haier.setMode(kHaierAcYrw02Heat); + haier.setSwing(kHaierAcYrw02SwingMiddle); + EXPECT_EQ(kHaierAcYrw02SwingBottom, haier.getSwing()); + haier.setSwing(kHaierAcYrw02SwingAuto); + EXPECT_EQ(kHaierAcYrw02SwingAuto, haier.getSwing()); + haier.setSwing(kHaierAcYrw02SwingBottom); + EXPECT_EQ(kHaierAcYrw02SwingBottom, haier.getSwing()); + haier.setMode(kHaierAcYrw02Cool); + haier.setSwing(kHaierAcYrw02SwingBottom); + EXPECT_EQ(kHaierAcYrw02SwingMiddle, haier.getSwing()); +} + +TEST(TestHaierACYRW02Class, MessageConstuction) { + IRHaierACYRW02 haier(0); + + EXPECT_EQ( + "Power: On, Button: 5 (Power), Mode: 0 (Auto), Temp: 25C," + " Fan: 10 (Auto), Turbo: 0 (Off), Swing: 0 (Off), Sleep: Off," + " Health: On", + haier.toString()); + haier.setMode(kHaierAcYrw02Cool); + haier.setTemp(21); + haier.setFan(kHaierAcYrw02FanHigh); + EXPECT_EQ( + "Power: On, Button: 4 (Fan), Mode: 2 (Cool), Temp: 21C," + " Fan: 2 (High), Turbo: 0 (Off), Swing: 0 (Off), Sleep: Off," + " Health: On", + haier.toString()); + + haier.setSwing(kHaierAcYrw02SwingMiddle); + haier.setHealth(false); + haier.setSleep(true); + haier.setTurbo(kHaierAcYrw02TurboHigh); + EXPECT_EQ( + "Power: On, Button: 8 (Turbo), Mode: 2 (Cool), Temp: 21C," + " Fan: 2 (High), Turbo: 1 (High), Swing: 2 (Middle)," + " Sleep: On, Health: Off", + haier.toString()); +} + +// Decode "real" state messages. +TEST(TestHaierACYRW02Class, RealStates) { + uint8_t expectedState1[kHaierACYRW02StateLength] = { + 0xA6, 0xE1, 0x00, 0x00, 0x40, 0x20, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x07, 0x6E}; + + IRHaierACYRW02 haier(0); + haier.setRaw(expectedState1); + EXPECT_EQ( + "Power: On, Button: 7 (Health), Mode: 8 (Heat), Temp: 30C," + " Fan: 2 (High), Turbo: 0 (Off), Swing: 1 (Top), Sleep: Off," + " Health: Off", + haier.toString()); + + uint8_t expectedState2[kHaierACYRW02StateLength] = { + 0xA6, 0xE0, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x05, 0x75}; + haier.setRaw(expectedState2); + EXPECT_EQ( + "Power: Off, Button: 5 (Power), Mode: 8 (Heat), Temp: 30C," + " Fan: 2 (High), Turbo: 0 (Off), Swing: 0 (Off), Sleep: Off," + " Health: Off", + haier.toString()); + + uint8_t expectedState3[kHaierACYRW02StateLength] = { + 0xA6, 0x02, 0x00, 0x02, 0x40, 0x20, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x01, 0x2B}; + haier.setRaw(expectedState3); + EXPECT_EQ( + "Power: On, Button: 1 (Temp Down), Mode: 2 (Cool), Temp: 16C," + " Fan: 2 (High), Turbo: 0 (Off), Swing: 2 (Middle), Sleep: Off," + " Health: On", + haier.toString()); + + // cool 25, health, fan auto, swing auto, sleep on + uint8_t expectedState4[kHaierACYRW02StateLength] = { + 0xA6, 0x9C, 0x00, 0x02, 0x40, 0xA8, 0x00, + 0x20, 0x80, 0x00, 0x00, 0x00, 0x0B, 0xD7}; + haier.setRaw(expectedState4); + EXPECT_EQ( + "Power: On, Button: 11 (Sleep), Mode: 2 (Cool), Temp: 25C," + " Fan: 10 (Auto), Turbo: 0 (Off), Swing: 12 (Auto), Sleep: On," + " Health: On", + haier.toString()); + + // cool 25, health, fan 3, swing auto, sleep on + uint8_t expectedState5[kHaierACYRW02StateLength] = { + 0xA6, 0x9C, 0x00, 0x02, 0x40, 0x27, 0x36, + 0x20, 0x80, 0x00, 0x00, 0x00, 0x04, 0x85}; + haier.setRaw(expectedState5); + EXPECT_EQ( + "Power: On, Button: 4 (Fan), Mode: 2 (Cool), Temp: 25C," + " Fan: 2 (High), Turbo: 0 (Off), Swing: 12 (Auto), Sleep: On," + " Health: On", + haier.toString()); +} + // Tests for decodeHaierAC(). // Decode normal "synthetic" messages. @@ -422,15 +769,16 @@ TEST(TestDecodeHaierAC, NormalDecodeWithStrict) { IRrecv irrecv(0); irsend.begin(); - uint8_t expectedState[HAIER_AC_STATE_LENGTH] = { - 0xA5, 0x01, 0x20, 0x01, 0x00, 0xC0, 0x20, 0x00, 0xA7}; + uint8_t expectedState[kHaierACStateLength] = {0xA5, 0x01, 0x20, 0x01, 0x00, + 0xC0, 0x20, 0x00, 0xA7}; + // With the specific decoder. irsend.reset(); irsend.sendHaierAC(expectedState); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodeHaierAC(&irsend.capture, HAIER_AC_BITS, true)); + ASSERT_TRUE(irrecv.decodeHaierAC(&irsend.capture, kHaierACBits, true)); EXPECT_EQ(HAIER_AC, irsend.capture.decode_type); - EXPECT_EQ(HAIER_AC_BITS, irsend.capture.bits); + EXPECT_EQ(kHaierACBits, irsend.capture.bits); EXPECT_FALSE(irsend.capture.repeat); EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); @@ -440,7 +788,7 @@ TEST(TestDecodeHaierAC, NormalDecodeWithStrict) { irsend.makeDecodeResult(); ASSERT_TRUE(irrecv.decode(&irsend.capture)); EXPECT_EQ(HAIER_AC, irsend.capture.decode_type); - EXPECT_EQ(HAIER_AC_BITS, irsend.capture.bits); + EXPECT_EQ(kHaierACBits, irsend.capture.bits); EXPECT_FALSE(irsend.capture.repeat); EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); } @@ -453,34 +801,37 @@ TEST(TestDecodeHaierAC, RealExample1) { irsend.reset(); // Data from Issue #404 captured by kuzin2006 - uint16_t rawData[149] = {3030, 3044, 3030, 4304, 576, 1694, 550, 582, 552, - 1704, 552, 714, 550, 582, 550, 1706, 552, 582, 550, 1836, 552, 582, 578, - 568, 550, 582, 550, 714, 550, 582, 550, 582, 552, 582, 550, 1836, 552, - 582, 552, 580, 580, 1692, 550, 712, 552, 582, 550, 582, 552, 580, 550, - 714, 552, 582, 550, 582, 552, 582, 578, 698, 552, 580, 552, 582, 552, - 582, 552, 1836, 552, 580, 552, 582, 552, 582, 550, 714, 578, 568, 550, - 582, 550, 582, 552, 714, 550, 1706, 550, 1706, 550, 582, 550, 714, 552, - 582, 580, 566, 552, 582, 550, 714, 552, 580, 552, 580, 552, 1706, 550, - 714, 550, 582, 552, 582, 578, 568, 552, 712, 552, 582, 550, 582, 550, - 582, 550, 712, 552, 582, 550, 582, 552, 582, 578, 722, 552, 1704, 550, - 582, 550, 1706, 550, 736, 550, 582, 550, 1706, 550, 1704, 552, 1704, 578}; - uint8_t expectedState[HAIER_AC_STATE_LENGTH] = { - 0xA5, 0x01, 0x20, 0x01, 0x00, 0xC0, 0x20, 0x00, 0xA7}; + uint16_t rawData[149] = { + 3030, 3044, 3030, 4304, 576, 1694, 550, 582, 552, 1704, 552, 714, 550, + 582, 550, 1706, 552, 582, 550, 1836, 552, 582, 578, 568, 550, 582, + 550, 714, 550, 582, 550, 582, 552, 582, 550, 1836, 552, 582, 552, + 580, 580, 1692, 550, 712, 552, 582, 550, 582, 552, 580, 550, 714, + 552, 582, 550, 582, 552, 582, 578, 698, 552, 580, 552, 582, 552, + 582, 552, 1836, 552, 580, 552, 582, 552, 582, 550, 714, 578, 568, + 550, 582, 550, 582, 552, 714, 550, 1706, 550, 1706, 550, 582, 550, + 714, 552, 582, 580, 566, 552, 582, 550, 714, 552, 580, 552, 580, + 552, 1706, 550, 714, 550, 582, 552, 582, 578, 568, 552, 712, 552, + 582, 550, 582, 550, 582, 550, 712, 552, 582, 550, 582, 552, 582, + 578, 722, 552, 1704, 550, 582, 550, 1706, 550, 736, 550, 582, 550, + 1706, 550, 1704, 552, 1704, 578}; + uint8_t expectedState[kHaierACStateLength] = {0xA5, 0x01, 0x20, 0x01, 0x00, + 0xC0, 0x20, 0x00, 0xA7}; irsend.sendRaw(rawData, 149, 38000); irsend.makeDecodeResult(); ASSERT_TRUE(irrecv.decode(&irsend.capture)); ASSERT_EQ(HAIER_AC, irsend.capture.decode_type); - EXPECT_EQ(HAIER_AC_BITS, irsend.capture.bits); + EXPECT_EQ(kHaierACBits, irsend.capture.bits); EXPECT_FALSE(irsend.capture.repeat); EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); IRHaierAC haier(0); haier.setRaw(irsend.capture.state); - EXPECT_EQ("Command: 1 (On), Mode: 0 (AUTO), Temp: 16C, Fan: 0 (AUTO), " - "Swing: 0 (Off), Sleep: Off, Health: Off, " - "Current Time: 00:01, On Timer: Off, Off Timer: Off", - haier.toString()); + EXPECT_EQ( + "Command: 1 (On), Mode: 0 (AUTO), Temp: 16C, Fan: 0 (AUTO), " + "Swing: 0 (Off), Sleep: Off, Health: Off, " + "Current Time: 00:01, On Timer: Off, Off Timer: Off", + haier.toString()); } // Decode a "real" example message. @@ -491,34 +842,38 @@ TEST(TestDecodeHaierAC, RealExample2) { irsend.reset(); // Data from Issue #404 captured by kuzin2006 - uint16_t rawData[149] = {3028, 3046, 3028, 4304, 576, 1694, 552, 582, 550, - 1704, 552, 714, 550, 582, 552, 1704, 550, 582, 550, 1836, 552, 582, 578, - 1690, 552, 1704, 552, 712, 550, 582, 550, 1706, 550, 1706, 552, 712, 550, - 582, 552, 582, 578, 1690, 552, 714, 552, 580, 552, 582, 552, 582, 550, - 712, 552, 582, 550, 582, 550, 582, 578, 698, 552, 582, 550, 584, 550, 582, - 552, 1836, 550, 582, 550, 582, 550, 582, 550, 712, 578, 568, 550, 582, - 550, 582, 550, 714, 552, 1706, 550, 1706, 552, 580, 550, 714, 550, 582, - 580, 568, 550, 582, 550, 714, 550, 582, 550, 582, 550, 1706, 552, 712, - 550, 582, 550, 582, 580, 568, 552, 712, 550, 584, 550, 582, 550, 584, 550, - 712, 550, 582, 550, 582, 550, 582, 578, 722, 550, 582, 552, 580, 552, 582, - 550, 738, 550, 1706, 550, 1704, 552, 582, 550, 582, 578}; - uint8_t expectedState[HAIER_AC_STATE_LENGTH] = { - 0xA5, 0x66, 0x20, 0x01, 0x00, 0xC0, 0x20, 0x00, 0x0C}; + uint16_t rawData[149] = { + 3028, 3046, 3028, 4304, 576, 1694, 552, 582, 550, 1704, 552, 714, + 550, 582, 552, 1704, 550, 582, 550, 1836, 552, 582, 578, 1690, + 552, 1704, 552, 712, 550, 582, 550, 1706, 550, 1706, 552, 712, + 550, 582, 552, 582, 578, 1690, 552, 714, 552, 580, 552, 582, + 552, 582, 550, 712, 552, 582, 550, 582, 550, 582, 578, 698, + 552, 582, 550, 584, 550, 582, 552, 1836, 550, 582, 550, 582, + 550, 582, 550, 712, 578, 568, 550, 582, 550, 582, 550, 714, + 552, 1706, 550, 1706, 552, 580, 550, 714, 550, 582, 580, 568, + 550, 582, 550, 714, 550, 582, 550, 582, 550, 1706, 552, 712, + 550, 582, 550, 582, 580, 568, 552, 712, 550, 584, 550, 582, + 550, 584, 550, 712, 550, 582, 550, 582, 550, 582, 578, 722, + 550, 582, 552, 580, 552, 582, 550, 738, 550, 1706, 550, 1704, + 552, 582, 550, 582, 578}; + uint8_t expectedState[kHaierACStateLength] = {0xA5, 0x66, 0x20, 0x01, 0x00, + 0xC0, 0x20, 0x00, 0x0C}; irsend.sendRaw(rawData, 149, 38000); irsend.makeDecodeResult(); ASSERT_TRUE(irrecv.decode(&irsend.capture)); ASSERT_EQ(HAIER_AC, irsend.capture.decode_type); - EXPECT_EQ(HAIER_AC_BITS, irsend.capture.bits); + EXPECT_EQ(kHaierACBits, irsend.capture.bits); EXPECT_FALSE(irsend.capture.repeat); EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); IRHaierAC haier(0); haier.setRaw(irsend.capture.state); - EXPECT_EQ("Command: 6 (Temp Up), Mode: 0 (AUTO), Temp: 22C, Fan: 0 (AUTO), " - "Swing: 0 (Off), Sleep: Off, Health: Off, " - "Current Time: 00:01, On Timer: Off, Off Timer: Off", - haier.toString()); + EXPECT_EQ( + "Command: 6 (Temp Up), Mode: 0 (AUTO), Temp: 22C, Fan: 0 (AUTO), " + "Swing: 0 (Off), Sleep: Off, Health: Off, " + "Current Time: 00:01, On Timer: Off, Off Timer: Off", + haier.toString()); } // Decode a "real" example message. @@ -529,32 +884,106 @@ TEST(TestDecodeHaierAC, RealExample3) { irsend.reset(); // Data from Issue #404 captured by kuzin2006 - uint16_t rawData[149] = {3030, 3044, 3030, 4302, 578, 1692, 550, 582, 550, - 1706, 550, 714, 550, 582, 552, 1706, 550, 582, 550, 1836, 552, 1706, 578, - 1690, 552, 1704, 552, 714, 550, 1706, 552, 1706, 550, 582, 550, 714, 552, - 582, 550, 582, 578, 1690, 550, 714, 552, 582, 552, 582, 550, 582, 550, - 714, 550, 584, 550, 582, 550, 582, 578, 700, 552, 1706, 550, 582, 550, - 582, 552, 1836, 550, 582, 550, 582, 552, 1706, 550, 714, 578, 568, 552, - 582, 552, 582, 550, 714, 550, 1706, 550, 1706, 550, 582, 552, 712, 552, - 582, 580, 568, 550, 582, 550, 714, 550, 582, 550, 582, 550, 1706, 550, - 714, 550, 582, 550, 582, 578, 568, 552, 712, 552, 582, 550, 582, 550, 582, - 550, 712, 550, 584, 550, 582, 552, 582, 578, 722, 552, 1704, 550, 582, - 550, 1706, 550, 1862, 550, 1706, 550, 582, 550, 1704, 552, 582, 578}; - uint8_t expectedState[HAIER_AC_STATE_LENGTH] = { - 0xA5, 0xEC, 0x20, 0x09, 0x20, 0xC0, 0x20, 0x00, 0xBA}; + uint16_t rawData[149] = { + 3030, 3044, 3030, 4302, 578, 1692, 550, 582, 550, 1706, 550, 714, + 550, 582, 552, 1706, 550, 582, 550, 1836, 552, 1706, 578, 1690, + 552, 1704, 552, 714, 550, 1706, 552, 1706, 550, 582, 550, 714, + 552, 582, 550, 582, 578, 1690, 550, 714, 552, 582, 552, 582, + 550, 582, 550, 714, 550, 584, 550, 582, 550, 582, 578, 700, + 552, 1706, 550, 582, 550, 582, 552, 1836, 550, 582, 550, 582, + 552, 1706, 550, 714, 578, 568, 552, 582, 552, 582, 550, 714, + 550, 1706, 550, 1706, 550, 582, 552, 712, 552, 582, 580, 568, + 550, 582, 550, 714, 550, 582, 550, 582, 550, 1706, 550, 714, + 550, 582, 550, 582, 578, 568, 552, 712, 552, 582, 550, 582, + 550, 582, 550, 712, 550, 584, 550, 582, 552, 582, 578, 722, + 552, 1704, 550, 582, 550, 1706, 550, 1862, 550, 1706, 550, 582, + 550, 1704, 552, 582, 578}; + uint8_t expectedState[kHaierACStateLength] = {0xA5, 0xEC, 0x20, 0x09, 0x20, + 0xC0, 0x20, 0x00, 0xBA}; irsend.sendRaw(rawData, 149, 38000); irsend.makeDecodeResult(); ASSERT_TRUE(irrecv.decode(&irsend.capture)); ASSERT_EQ(HAIER_AC, irsend.capture.decode_type); - EXPECT_EQ(HAIER_AC_BITS, irsend.capture.bits); + EXPECT_EQ(kHaierACBits, irsend.capture.bits); EXPECT_FALSE(irsend.capture.repeat); EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); IRHaierAC haier(0); haier.setRaw(irsend.capture.state); - EXPECT_EQ("Command: 12 (Health), Mode: 0 (AUTO), Temp: 30C, Fan: 0 (AUTO), " - "Swing: 0 (Off), Sleep: Off, Health: On, " - "Current Time: 00:09, On Timer: Off, Off Timer: Off", - haier.toString()); + EXPECT_EQ( + "Command: 12 (Health), Mode: 0 (AUTO), Temp: 30C, Fan: 0 (AUTO), " + "Swing: 0 (Off), Sleep: Off, Health: On, " + "Current Time: 00:09, On Timer: Off, Off Timer: Off", + haier.toString()); +} + +// Decode normal "synthetic" messages. +TEST(TestDecodeHaierAC_YRW02, NormalDecode) { + IRsendTest irsend(0); + IRrecv irrecv(0); + irsend.begin(); + + uint8_t expectedState[kHaierACYRW02StateLength] = { + 0xA6, 0x12, 0x00, 0x02, 0x40, 0x20, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x05, 0x3F}; + + irsend.reset(); + irsend.sendHaierACYRW02(expectedState); + irsend.makeDecodeResult(); + ASSERT_TRUE(irrecv.decode(&irsend.capture)); + EXPECT_EQ(HAIER_AC_YRW02, irsend.capture.decode_type); + EXPECT_EQ(kHaierACYRW02Bits, irsend.capture.bits); + EXPECT_FALSE(irsend.capture.repeat); + EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); +} + +// Decode a "real" example message. +TEST(TestDecodeHaierAC_YRW02, RealExample) { + IRsendTest irsend(0); + IRrecv irrecv(0); + irsend.begin(); + + irsend.reset(); + // Data from Issue #485 captured by non7top + uint16_t rawData[229] = { + 2998, 3086, 2998, 4460, 568, 1640, 596, 492, 514, 1690, 590, 496, + 566, 532, 592, 1596, 570, 1618, 518, 584, 590, 538, 524, 536, + 568, 532, 590, 1596, 516, 612, 568, 538, 522, 1638, 586, 500, + 512, 614, 568, 538, 520, 538, 586, 538, 566, 540, 520, 538, + 586, 538, 522, 538, 588, 538, 568, 538, 520, 538, 586, 538, + 566, 538, 520, 540, 588, 1596, 590, 536, 568, 538, 520, 1592, + 640, 538, 520, 540, 588, 538, 568, 538, 516, 562, 566, 538, + 518, 542, 586, 540, 566, 1596, 590, 538, 566, 538, 516, 544, + 586, 538, 516, 542, 588, 540, 564, 540, 468, 590, 588, 538, + 566, 540, 466, 590, 588, 538, 514, 544, 588, 538, 566, 538, + 468, 1692, 606, 526, 466, 592, 588, 538, 568, 490, 588, 538, + 566, 540, 466, 592, 588, 538, 566, 538, 466, 592, 588, 538, + 568, 492, 586, 540, 566, 540, 468, 590, 588, 538, 568, 516, + 488, 590, 588, 538, 568, 492, 588, 538, 566, 518, 488, 590, + 588, 540, 564, 518, 490, 590, 588, 538, 562, 496, 588, 538, + 566, 518, 488, 590, 588, 538, 562, 522, 488, 588, 590, 538, + 560, 498, 588, 540, 564, 522, 486, 590, 590, 538, 560, 524, + 488, 588, 588, 1598, 514, 608, 564, 1600, 548, 536, 586, 538, + 568, 1594, 590, 1618, 578, 1606, 606, 1582, 590, 1596, 590, 1616, + 580}; + uint8_t expectedState[kHaierACYRW02StateLength] = { + 0xA6, 0x12, 0x00, 0x02, 0x40, 0x20, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x05, 0x3F}; + + irsend.sendRaw(rawData, 229, 38000); + irsend.makeDecodeResult(); + ASSERT_TRUE(irrecv.decode(&irsend.capture)); + ASSERT_EQ(HAIER_AC_YRW02, irsend.capture.decode_type); + EXPECT_EQ(kHaierACYRW02Bits, irsend.capture.bits); + EXPECT_FALSE(irsend.capture.repeat); + EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); + + IRHaierACYRW02 haier(0); + haier.setRaw(irsend.capture.state); + EXPECT_EQ( + "Power: On, Button: 5 (Power), Mode: 2 (Cool), Temp: 17C," + " Fan: 2 (High), Turbo: 0 (Off), Swing: 2 (Middle), Sleep: Off," + " Health: On", + haier.toString()); } diff --git a/lib/IRremoteESP8266/test/ir_Hitachi_test.cpp b/lib/IRremoteESP8266/test/ir_Hitachi_test.cpp index 0173061..de0a4a2 100644 --- a/lib/IRremoteESP8266/test/ir_Hitachi_test.cpp +++ b/lib/IRremoteESP8266/test/ir_Hitachi_test.cpp @@ -1,8 +1,9 @@ // Copyright 2018 David Conran -#include "IRremoteESP8266.h" +#include "ir_Hitachi.h" #include "IRrecv.h" #include "IRrecv_test.h" +#include "IRremoteESP8266.h" #include "IRsend.h" #include "IRsend_test.h" #include "gtest/gtest.h" @@ -14,10 +15,10 @@ TEST(TestSendHitachiAC, SendData) { IRsendTest irsend(0); irsend.begin(); - uint8_t hitachi_code[HITACHI_AC_STATE_LENGTH] = { - 0x80, 0x08, 0x0C, 0x02, 0xFD, 0x80, 0x7F, 0x88, 0x48, 0x80, 0x20, 0x04, - 0x00, 0x80, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x80, 0x00, 0x00, 0xAC}; + uint8_t hitachi_code[kHitachiAcStateLength] = { + 0x80, 0x08, 0x0C, 0x02, 0xFD, 0x80, 0x7F, 0x88, 0x48, 0x80, + 0x20, 0x04, 0x00, 0x80, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0xAC}; irsend.reset(); irsend.sendHitachiAC(hitachi_code); EXPECT_EQ( @@ -50,7 +51,8 @@ TEST(TestSendHitachiAC, SendData) { "m400s500m400s500m400s500m400s500m400s500m400s500m400s500m400s500" "m400s500m400s500m400s500m400s500m400s500m400s500m400s500m400s500" "m400s1250m400s500m400s1250m400s500m400s1250m400s1250m400s500m400s500" - "m400s100000", irsend.outputStr()); + "m400s100000", + irsend.outputStr()); } // Test sending with repeats. @@ -58,74 +60,75 @@ TEST(TestSendHitachiAC, SendWithRepeats) { IRsendTest irsend(0); irsend.begin(); - uint8_t hitachi_code[HITACHI_AC_STATE_LENGTH] = { - 0x80, 0x08, 0x0C, 0x02, 0xFD, 0x80, 0x7F, 0x88, 0x48, 0x80, 0x20, 0x04, - 0x00, 0x80, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x80, 0x00, 0x00, 0xAC}; + uint8_t hitachi_code[kHitachiAcStateLength] = { + 0x80, 0x08, 0x0C, 0x02, 0xFD, 0x80, 0x7F, 0x88, 0x48, 0x80, + 0x20, 0x04, 0x00, 0x80, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0xAC}; irsend.reset(); - irsend.sendHitachiAC(hitachi_code, HITACHI_AC_STATE_LENGTH, 1); + irsend.sendHitachiAC(hitachi_code, kHitachiAcStateLength, 1); EXPECT_EQ( - "m3300s1700" - "m400s1250m400s500m400s500m400s500m400s500m400s500m400s500m400s500" - "m400s500m400s500m400s500m400s500m400s1250m400s500m400s500m400s500" - "m400s500m400s500m400s500m400s500m400s1250m400s1250m400s500m400s500" - "m400s500m400s500m400s500m400s500m400s500m400s500m400s1250m400s500" - "m400s1250m400s1250m400s1250m400s1250m400s1250m400s1250m400s500m400s1250" - "m400s1250m400s500m400s500m400s500m400s500m400s500m400s500m400s500" - "m400s500m400s1250m400s1250m400s1250m400s1250m400s1250m400s1250m400s1250" - "m400s1250m400s500m400s500m400s500m400s1250m400s500m400s500m400s500" - "m400s500m400s1250m400s500m400s500m400s1250m400s500m400s500m400s500" - "m400s1250m400s500m400s500m400s500m400s500m400s500m400s500m400s500" - "m400s500m400s500m400s1250m400s500m400s500m400s500m400s500m400s500" - "m400s500m400s500m400s500m400s500m400s500m400s1250m400s500m400s500" - "m400s500m400s500m400s500m400s500m400s500m400s500m400s500m400s500" - "m400s1250m400s500m400s500m400s500m400s500m400s500m400s500m400s500" - "m400s500m400s500m400s500m400s500m400s500m400s500m400s500m400s500" - "m400s500m400s500m400s500m400s500m400s500m400s500m400s500m400s500" - "m400s500m400s500m400s500m400s500m400s500m400s500m400s500m400s500" - "m400s500m400s500m400s500m400s500m400s500m400s500m400s500m400s1250" - "m400s500m400s500m400s500m400s500m400s500m400s500m400s500m400s500" - "m400s500m400s500m400s500m400s500m400s500m400s500m400s500m400s500" - "m400s500m400s500m400s500m400s500m400s500m400s500m400s500m400s500" - "m400s500m400s500m400s500m400s500m400s500m400s500m400s500m400s500" - "m400s500m400s500m400s500m400s500m400s500m400s500m400s500m400s500" - "m400s500m400s500m400s500m400s500m400s500m400s500m400s500m400s500" - "m400s1250m400s500m400s500m400s500m400s500m400s500m400s500m400s500" - "m400s500m400s500m400s500m400s500m400s500m400s500m400s500m400s500" - "m400s500m400s500m400s500m400s500m400s500m400s500m400s500m400s500" - "m400s1250m400s500m400s1250m400s500m400s1250m400s1250m400s500m400s500" - "m400s100000" - "m3300s1700" - "m400s1250m400s500m400s500m400s500m400s500m400s500m400s500m400s500" - "m400s500m400s500m400s500m400s500m400s1250m400s500m400s500m400s500" - "m400s500m400s500m400s500m400s500m400s1250m400s1250m400s500m400s500" - "m400s500m400s500m400s500m400s500m400s500m400s500m400s1250m400s500" - "m400s1250m400s1250m400s1250m400s1250m400s1250m400s1250m400s500m400s1250" - "m400s1250m400s500m400s500m400s500m400s500m400s500m400s500m400s500" - "m400s500m400s1250m400s1250m400s1250m400s1250m400s1250m400s1250m400s1250" - "m400s1250m400s500m400s500m400s500m400s1250m400s500m400s500m400s500" - "m400s500m400s1250m400s500m400s500m400s1250m400s500m400s500m400s500" - "m400s1250m400s500m400s500m400s500m400s500m400s500m400s500m400s500" - "m400s500m400s500m400s1250m400s500m400s500m400s500m400s500m400s500" - "m400s500m400s500m400s500m400s500m400s500m400s1250m400s500m400s500" - "m400s500m400s500m400s500m400s500m400s500m400s500m400s500m400s500" - "m400s1250m400s500m400s500m400s500m400s500m400s500m400s500m400s500" - "m400s500m400s500m400s500m400s500m400s500m400s500m400s500m400s500" - "m400s500m400s500m400s500m400s500m400s500m400s500m400s500m400s500" - "m400s500m400s500m400s500m400s500m400s500m400s500m400s500m400s500" - "m400s500m400s500m400s500m400s500m400s500m400s500m400s500m400s1250" - "m400s500m400s500m400s500m400s500m400s500m400s500m400s500m400s500" - "m400s500m400s500m400s500m400s500m400s500m400s500m400s500m400s500" - "m400s500m400s500m400s500m400s500m400s500m400s500m400s500m400s500" - "m400s500m400s500m400s500m400s500m400s500m400s500m400s500m400s500" - "m400s500m400s500m400s500m400s500m400s500m400s500m400s500m400s500" - "m400s500m400s500m400s500m400s500m400s500m400s500m400s500m400s500" - "m400s1250m400s500m400s500m400s500m400s500m400s500m400s500m400s500" - "m400s500m400s500m400s500m400s500m400s500m400s500m400s500m400s500" - "m400s500m400s500m400s500m400s500m400s500m400s500m400s500m400s500" - "m400s1250m400s500m400s1250m400s500m400s1250m400s1250m400s500m400s500" - "m400s100000", irsend.outputStr()); + "m3300s1700" + "m400s1250m400s500m400s500m400s500m400s500m400s500m400s500m400s500" + "m400s500m400s500m400s500m400s500m400s1250m400s500m400s500m400s500" + "m400s500m400s500m400s500m400s500m400s1250m400s1250m400s500m400s500" + "m400s500m400s500m400s500m400s500m400s500m400s500m400s1250m400s500" + "m400s1250m400s1250m400s1250m400s1250m400s1250m400s1250m400s500m400s1250" + "m400s1250m400s500m400s500m400s500m400s500m400s500m400s500m400s500" + "m400s500m400s1250m400s1250m400s1250m400s1250m400s1250m400s1250m400s1250" + "m400s1250m400s500m400s500m400s500m400s1250m400s500m400s500m400s500" + "m400s500m400s1250m400s500m400s500m400s1250m400s500m400s500m400s500" + "m400s1250m400s500m400s500m400s500m400s500m400s500m400s500m400s500" + "m400s500m400s500m400s1250m400s500m400s500m400s500m400s500m400s500" + "m400s500m400s500m400s500m400s500m400s500m400s1250m400s500m400s500" + "m400s500m400s500m400s500m400s500m400s500m400s500m400s500m400s500" + "m400s1250m400s500m400s500m400s500m400s500m400s500m400s500m400s500" + "m400s500m400s500m400s500m400s500m400s500m400s500m400s500m400s500" + "m400s500m400s500m400s500m400s500m400s500m400s500m400s500m400s500" + "m400s500m400s500m400s500m400s500m400s500m400s500m400s500m400s500" + "m400s500m400s500m400s500m400s500m400s500m400s500m400s500m400s1250" + "m400s500m400s500m400s500m400s500m400s500m400s500m400s500m400s500" + "m400s500m400s500m400s500m400s500m400s500m400s500m400s500m400s500" + "m400s500m400s500m400s500m400s500m400s500m400s500m400s500m400s500" + "m400s500m400s500m400s500m400s500m400s500m400s500m400s500m400s500" + "m400s500m400s500m400s500m400s500m400s500m400s500m400s500m400s500" + "m400s500m400s500m400s500m400s500m400s500m400s500m400s500m400s500" + "m400s1250m400s500m400s500m400s500m400s500m400s500m400s500m400s500" + "m400s500m400s500m400s500m400s500m400s500m400s500m400s500m400s500" + "m400s500m400s500m400s500m400s500m400s500m400s500m400s500m400s500" + "m400s1250m400s500m400s1250m400s500m400s1250m400s1250m400s500m400s500" + "m400s100000" + "m3300s1700" + "m400s1250m400s500m400s500m400s500m400s500m400s500m400s500m400s500" + "m400s500m400s500m400s500m400s500m400s1250m400s500m400s500m400s500" + "m400s500m400s500m400s500m400s500m400s1250m400s1250m400s500m400s500" + "m400s500m400s500m400s500m400s500m400s500m400s500m400s1250m400s500" + "m400s1250m400s1250m400s1250m400s1250m400s1250m400s1250m400s500m400s1250" + "m400s1250m400s500m400s500m400s500m400s500m400s500m400s500m400s500" + "m400s500m400s1250m400s1250m400s1250m400s1250m400s1250m400s1250m400s1250" + "m400s1250m400s500m400s500m400s500m400s1250m400s500m400s500m400s500" + "m400s500m400s1250m400s500m400s500m400s1250m400s500m400s500m400s500" + "m400s1250m400s500m400s500m400s500m400s500m400s500m400s500m400s500" + "m400s500m400s500m400s1250m400s500m400s500m400s500m400s500m400s500" + "m400s500m400s500m400s500m400s500m400s500m400s1250m400s500m400s500" + "m400s500m400s500m400s500m400s500m400s500m400s500m400s500m400s500" + "m400s1250m400s500m400s500m400s500m400s500m400s500m400s500m400s500" + "m400s500m400s500m400s500m400s500m400s500m400s500m400s500m400s500" + "m400s500m400s500m400s500m400s500m400s500m400s500m400s500m400s500" + "m400s500m400s500m400s500m400s500m400s500m400s500m400s500m400s500" + "m400s500m400s500m400s500m400s500m400s500m400s500m400s500m400s1250" + "m400s500m400s500m400s500m400s500m400s500m400s500m400s500m400s500" + "m400s500m400s500m400s500m400s500m400s500m400s500m400s500m400s500" + "m400s500m400s500m400s500m400s500m400s500m400s500m400s500m400s500" + "m400s500m400s500m400s500m400s500m400s500m400s500m400s500m400s500" + "m400s500m400s500m400s500m400s500m400s500m400s500m400s500m400s500" + "m400s500m400s500m400s500m400s500m400s500m400s500m400s500m400s500" + "m400s1250m400s500m400s500m400s500m400s500m400s500m400s500m400s500" + "m400s500m400s500m400s500m400s500m400s500m400s500m400s500m400s500" + "m400s500m400s500m400s500m400s500m400s500m400s500m400s500m400s500" + "m400s1250m400s500m400s1250m400s500m400s1250m400s1250m400s500m400s500" + "m400s100000", + irsend.outputStr()); } // Test sending atypical sizes. @@ -133,52 +136,208 @@ TEST(TestSendHitachiAC, SendUnexpectedSizes) { IRsendTest irsend(0); irsend.begin(); - uint8_t hitachi_short_code[HITACHI_AC_STATE_LENGTH - 1] = { - 0x80, 0x08, 0x0C, 0x02, 0xFD, 0x80, 0x7F, 0x88, 0x48, 0x80, 0x20, 0x04, - 0x00, 0x80, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x80, 0x00, 0x00}; - uint8_t hitachi_long_code[HITACHI_AC_STATE_LENGTH + 1] = { - 0x80, 0x08, 0x0C, 0x02, 0xFD, 0x80, 0x7F, 0x88, 0x48, 0x80, 0x20, 0x04, - 0x00, 0x80, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x80, 0x00, 0x00, 0xAC, 0xFF}; + uint8_t hitachi_short_code[kHitachiAcStateLength - 1] = { + 0x80, 0x08, 0x0C, 0x02, 0xFD, 0x80, 0x7F, 0x88, 0x48, + 0x80, 0x20, 0x04, 0x00, 0x80, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00}; + uint8_t hitachi_long_code[kHitachiAcStateLength + 1] = { + 0x80, 0x08, 0x0C, 0x02, 0xFD, 0x80, 0x7F, 0x88, 0x48, 0x80, + 0x20, 0x04, 0x00, 0x80, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0xAC, 0xFF}; irsend.reset(); - irsend.sendHitachiAC(hitachi_short_code, HITACHI_AC_STATE_LENGTH - 1); + irsend.sendHitachiAC(hitachi_short_code, kHitachiAcStateLength - 1); ASSERT_EQ("", irsend.outputStr()); irsend.reset(); - irsend.sendHitachiAC(hitachi_long_code, HITACHI_AC_STATE_LENGTH + 1); + irsend.sendHitachiAC(hitachi_long_code, kHitachiAcStateLength + 1); ASSERT_EQ( - "m3300s1700" - "m400s1250m400s500m400s500m400s500m400s500m400s500m400s500m400s500" - "m400s500m400s500m400s500m400s500m400s1250m400s500m400s500m400s500" - "m400s500m400s500m400s500m400s500m400s1250m400s1250m400s500m400s500" - "m400s500m400s500m400s500m400s500m400s500m400s500m400s1250m400s500" - "m400s1250m400s1250m400s1250m400s1250m400s1250m400s1250m400s500m400s1250" - "m400s1250m400s500m400s500m400s500m400s500m400s500m400s500m400s500" - "m400s500m400s1250m400s1250m400s1250m400s1250m400s1250m400s1250m400s1250" - "m400s1250m400s500m400s500m400s500m400s1250m400s500m400s500m400s500" - "m400s500m400s1250m400s500m400s500m400s1250m400s500m400s500m400s500" - "m400s1250m400s500m400s500m400s500m400s500m400s500m400s500m400s500" - "m400s500m400s500m400s1250m400s500m400s500m400s500m400s500m400s500" - "m400s500m400s500m400s500m400s500m400s500m400s1250m400s500m400s500" - "m400s500m400s500m400s500m400s500m400s500m400s500m400s500m400s500" - "m400s1250m400s500m400s500m400s500m400s500m400s500m400s500m400s500" - "m400s500m400s500m400s500m400s500m400s500m400s500m400s500m400s500" - "m400s500m400s500m400s500m400s500m400s500m400s500m400s500m400s500" - "m400s500m400s500m400s500m400s500m400s500m400s500m400s500m400s500" - "m400s500m400s500m400s500m400s500m400s500m400s500m400s500m400s1250" - "m400s500m400s500m400s500m400s500m400s500m400s500m400s500m400s500" - "m400s500m400s500m400s500m400s500m400s500m400s500m400s500m400s500" - "m400s500m400s500m400s500m400s500m400s500m400s500m400s500m400s500" - "m400s500m400s500m400s500m400s500m400s500m400s500m400s500m400s500" - "m400s500m400s500m400s500m400s500m400s500m400s500m400s500m400s500" - "m400s500m400s500m400s500m400s500m400s500m400s500m400s500m400s500" - "m400s1250m400s500m400s500m400s500m400s500m400s500m400s500m400s500" - "m400s500m400s500m400s500m400s500m400s500m400s500m400s500m400s500" - "m400s500m400s500m400s500m400s500m400s500m400s500m400s500m400s500" - "m400s1250m400s500m400s1250m400s500m400s1250m400s1250m400s500m400s500" - "m400s1250m400s1250m400s1250m400s1250m400s1250m400s1250m400s1250m400s1250" - "m400s100000", irsend.outputStr()); + "m3300s1700" + "m400s1250m400s500m400s500m400s500m400s500m400s500m400s500m400s500" + "m400s500m400s500m400s500m400s500m400s1250m400s500m400s500m400s500" + "m400s500m400s500m400s500m400s500m400s1250m400s1250m400s500m400s500" + "m400s500m400s500m400s500m400s500m400s500m400s500m400s1250m400s500" + "m400s1250m400s1250m400s1250m400s1250m400s1250m400s1250m400s500m400s1250" + "m400s1250m400s500m400s500m400s500m400s500m400s500m400s500m400s500" + "m400s500m400s1250m400s1250m400s1250m400s1250m400s1250m400s1250m400s1250" + "m400s1250m400s500m400s500m400s500m400s1250m400s500m400s500m400s500" + "m400s500m400s1250m400s500m400s500m400s1250m400s500m400s500m400s500" + "m400s1250m400s500m400s500m400s500m400s500m400s500m400s500m400s500" + "m400s500m400s500m400s1250m400s500m400s500m400s500m400s500m400s500" + "m400s500m400s500m400s500m400s500m400s500m400s1250m400s500m400s500" + "m400s500m400s500m400s500m400s500m400s500m400s500m400s500m400s500" + "m400s1250m400s500m400s500m400s500m400s500m400s500m400s500m400s500" + "m400s500m400s500m400s500m400s500m400s500m400s500m400s500m400s500" + "m400s500m400s500m400s500m400s500m400s500m400s500m400s500m400s500" + "m400s500m400s500m400s500m400s500m400s500m400s500m400s500m400s500" + "m400s500m400s500m400s500m400s500m400s500m400s500m400s500m400s1250" + "m400s500m400s500m400s500m400s500m400s500m400s500m400s500m400s500" + "m400s500m400s500m400s500m400s500m400s500m400s500m400s500m400s500" + "m400s500m400s500m400s500m400s500m400s500m400s500m400s500m400s500" + "m400s500m400s500m400s500m400s500m400s500m400s500m400s500m400s500" + "m400s500m400s500m400s500m400s500m400s500m400s500m400s500m400s500" + "m400s500m400s500m400s500m400s500m400s500m400s500m400s500m400s500" + "m400s1250m400s500m400s500m400s500m400s500m400s500m400s500m400s500" + "m400s500m400s500m400s500m400s500m400s500m400s500m400s500m400s500" + "m400s500m400s500m400s500m400s500m400s500m400s500m400s500m400s500" + "m400s1250m400s500m400s1250m400s500m400s1250m400s1250m400s500m400s500" + "m400s1250m400s1250m400s1250m400s1250m400s1250m400s1250m400s1250m400s1250" + "m400s100000", + irsend.outputStr()); +} + +// Tests for IRHitachiAc class. +TEST(TestIRHitachiAcClass, SetAndGetPower) { + IRHitachiAc ac(0); + ac.on(); + EXPECT_TRUE(ac.getPower()); + ac.off(); + EXPECT_FALSE(ac.getPower()); + ac.setPower(true); + EXPECT_TRUE(ac.getPower()); + ac.setPower(false); + EXPECT_FALSE(ac.getPower()); +} + +TEST(TestIRHitachiAcClass, SetAndGetSwing) { + IRHitachiAc ac(0); + ac.setSwingVertical(true); + ac.setSwingHorizontal(true); + EXPECT_TRUE(ac.getSwingVertical()); + EXPECT_TRUE(ac.getSwingHorizontal()); + ac.setSwingVertical(false); + EXPECT_FALSE(ac.getSwingVertical()); + EXPECT_TRUE(ac.getSwingHorizontal()); + ac.setSwingVertical(true); + EXPECT_TRUE(ac.getSwingVertical()); + EXPECT_TRUE(ac.getSwingHorizontal()); + ac.setSwingHorizontal(false); + EXPECT_TRUE(ac.getSwingVertical()); + EXPECT_FALSE(ac.getSwingHorizontal()); + ac.setSwingHorizontal(true); + EXPECT_TRUE(ac.getSwingHorizontal()); +} + +TEST(TestIRHitachiAcClass, SetAndGetTemp) { + IRHitachiAc ac(0); + ac.setTemp(25); + EXPECT_EQ(25, ac.getTemp()); + ac.setTemp(kHitachiAcMinTemp); + EXPECT_EQ(kHitachiAcMinTemp, ac.getTemp()); + ac.setTemp(kHitachiAcMinTemp - 1); + EXPECT_EQ(kHitachiAcMinTemp, ac.getTemp()); + ac.setTemp(kHitachiAcMaxTemp); + EXPECT_EQ(kHitachiAcMaxTemp, ac.getTemp()); + ac.setTemp(kHitachiAcMaxTemp + 1); + EXPECT_EQ(kHitachiAcMaxTemp, ac.getTemp()); + ac.setTemp(64); + EXPECT_EQ(64, ac.getTemp()); +} + +TEST(TestIRHitachiAcClass, SetAndGetMode) { + IRHitachiAc ac(0); + ac.setMode(kHitachiAcCool); + ac.setFan(kHitachiAcFanAuto); + EXPECT_EQ(kHitachiAcCool, ac.getMode()); + ac.setTemp(25); + EXPECT_EQ(25, ac.getTemp()); + EXPECT_EQ(kHitachiAcFanAuto, ac.getFan()); + ac.setMode(kHitachiAcFan); + EXPECT_EQ(kHitachiAcFan, ac.getMode()); + EXPECT_EQ(64, ac.getTemp()); + EXPECT_NE(kHitachiAcFanAuto, ac.getFan()); + ac.setMode(kHitachiAcHeat); + EXPECT_EQ(25, ac.getTemp()); + EXPECT_EQ(kHitachiAcHeat, ac.getMode()); + ac.setMode(kHitachiAcAuto); + ac.setFan(kHitachiAcFanAuto); + EXPECT_EQ(kHitachiAcAuto, ac.getMode()); + ac.setMode(kHitachiAcDry); + EXPECT_EQ(kHitachiAcDry, ac.getMode()); + EXPECT_NE(kHitachiAcFanAuto, ac.getFan()); +} + +TEST(TestIRHitachiAcClass, SetAndGetFan) { + IRHitachiAc ac(0); + ac.setMode(kHitachiAcCool); // All fan options are available in this mode. + ac.setFan(kHitachiAcFanAuto); + EXPECT_EQ(kHitachiAcFanAuto, ac.getFan()); + ac.setFan(kHitachiAcFanLow); + EXPECT_EQ(kHitachiAcFanLow, ac.getFan()); + ac.setFan(kHitachiAcFanHigh); + EXPECT_EQ(kHitachiAcFanHigh, ac.getFan()); + ac.setFan(kHitachiAcFanHigh + 1); + EXPECT_EQ(kHitachiAcFanHigh, ac.getFan()); + ac.setFan(0); + EXPECT_EQ(kHitachiAcFanAuto, ac.getFan()); + + ac.setMode(kHitachiAcFan); // No auto-fan in Fan mode. + EXPECT_EQ(kHitachiAcFanLow, ac.getFan()); + ac.setFan(kHitachiAcFanAuto); + EXPECT_EQ(kHitachiAcFanLow, ac.getFan()); + ac.setFan(kHitachiAcFanHigh); + EXPECT_EQ(kHitachiAcFanHigh, ac.getFan()); + + // Only Low and one higher fan settin in Dry mode. + ac.setMode(kHitachiAcDry); + EXPECT_EQ(kHitachiAcFanLow + 1, ac.getFan()); + ac.setFan(kHitachiAcFanHigh); + EXPECT_EQ(kHitachiAcFanLow + 1, ac.getFan()); + ac.setFan(kHitachiAcFanLow); + EXPECT_EQ(kHitachiAcFanLow, ac.getFan()); + ac.setFan(kHitachiAcFanAuto); + EXPECT_EQ(kHitachiAcFanLow, ac.getFan()); +} + +TEST(TestIRHitachiAcClass, HumanReadable) { + IRHitachiAc ac(0); + + ac.setMode(kHitachiAcHeat); + ac.setTemp(kHitachiAcMaxTemp); + ac.on(); + ac.setFan(kHitachiAcFanHigh); + ac.setSwingVertical(true); + EXPECT_EQ( + "Power: On, Mode: 3 (HEAT), Temp: 32C, Fan: 5 (HIGH), " + "Swing (Vertical): On, Swing (Horizontal): Off", + ac.toString()); + ac.setMode(kHitachiAcCool); + ac.setTemp(kHitachiAcMinTemp); + ac.setFan(kHitachiAcFanLow); + ac.setSwingVertical(false); + ac.setSwingHorizontal(true); + EXPECT_EQ( + "Power: On, Mode: 4 (COOL), Temp: 16C, Fan: 2 (LOW), " + "Swing (Vertical): Off, Swing (Horizontal): On", + ac.toString()); +} + +TEST(TestIRHitachiAcClass, ChecksumCalculation) { + IRHitachiAc ac(0); + + const uint8_t originalstate[kHitachiAcStateLength] = { + 0x80, 0x08, 0x0C, 0x02, 0xFD, 0x80, 0x7F, 0x88, 0x48, 0x80, + 0x20, 0x04, 0x00, 0x80, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0xAC}; + uint8_t examplestate[kHitachiAcStateLength] = { + 0x80, 0x08, 0x0C, 0x02, 0xFD, 0x80, 0x7F, 0x88, 0x48, 0x80, + 0x20, 0x04, 0x00, 0x80, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0xAC}; + + EXPECT_TRUE(IRHitachiAc::validChecksum(examplestate)); + EXPECT_EQ(0xAC, IRHitachiAc::calcChecksum(examplestate)); + + examplestate[kHitachiAcStateLength - 1] = + 0x12; // Make the existing checksum invalid + EXPECT_FALSE(IRHitachiAc::validChecksum(examplestate)); + EXPECT_EQ(0xAC, IRHitachiAc::calcChecksum(examplestate)); + ac.setRaw(examplestate); + // Extracting the state from the object should have a correct checksum. + EXPECT_TRUE(IRHitachiAc::validChecksum(ac.getRaw())); + EXPECT_STATE_EQ(originalstate, ac.getRaw(), kHitachiAcBits); + + examplestate[8] = 0x12; // Force a different checksum calc. + EXPECT_FALSE(IRHitachiAc::validChecksum(examplestate)); + EXPECT_EQ(0xFF, IRHitachiAc::calcChecksum(examplestate)); } // Tests for decodeHitachiAC(). @@ -189,18 +348,18 @@ TEST(TestDecodeHitachiAC, NormalSynthetic) { IRrecv irrecv(0); irsend.begin(); - uint8_t hitachi_code[HITACHI_AC_STATE_LENGTH] = { - 0x80, 0x08, 0x0C, 0x02, 0xFD, 0x80, 0x7F, 0x88, 0x48, 0x80, 0x20, 0x04, - 0x00, 0x80, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x80, 0x00, 0x00, 0xAC}; + uint8_t hitachi_code[kHitachiAcStateLength] = { + 0x80, 0x08, 0x0C, 0x02, 0xFD, 0x80, 0x7F, 0x88, 0x48, 0x80, + 0x20, 0x04, 0x00, 0x80, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0xAC}; irsend.reset(); irsend.sendHitachiAC(hitachi_code); irsend.makeDecodeResult(); EXPECT_TRUE(irrecv.decode(&irsend.capture)); EXPECT_EQ(HITACHI_AC, irsend.capture.decode_type); - ASSERT_EQ(HITACHI_AC_BITS, irsend.capture.bits); - EXPECT_STATE_EQ(hitachi_code, irsend.capture.state, HITACHI_AC_BITS); + ASSERT_EQ(kHitachiAcBits, irsend.capture.bits); + EXPECT_STATE_EQ(hitachi_code, irsend.capture.state, kHitachiAcBits); } // Decode a 'real' HitachiAC message. @@ -209,54 +368,66 @@ TEST(TestDecodeHitachiAC, NormalRealExample1) { IRrecv irrecv(0); irsend.begin(); - uint8_t hitachi_code[HITACHI_AC_STATE_LENGTH] = { - 0x80, 0x08, 0x0C, 0x02, 0xFD, 0x80, 0x7F, 0x88, 0x48, 0x80, 0x20, 0x04, - 0x00, 0x80, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x80, 0x00, 0x00, 0xAC}; + uint8_t hitachi_code[kHitachiAcStateLength] = { + 0x80, 0x08, 0x0C, 0x02, 0xFD, 0x80, 0x7F, 0x88, 0x48, 0x80, + 0x20, 0x04, 0x00, 0x80, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0xAC}; // Ref: https://github.com/markszabo/IRremoteESP8266/issues/417 // 'On' '16c' 'auto fan' 'cooling mode' uint16_t rawData[451] = { - 3318, 1720, 400, 1276, 400, 432, 398, 434, 398, 434, 400, 432, 398, 432, - 398, 432, 398, 434, 398, 432, 398, 434, 400, 432, 398, 434, 398, 1278, - 398, 434, 398, 434, 396, 434, 398, 434, 398, 432, 398, 434, 398, 432, 398, - 1276, 426, 1252, 424, 408, 424, 406, 424, 408, 426, 406, 398, 432, 398, - 434, 398, 432, 400, 432, 398, 1276, 426, 408, 424, 1252, 426, 1252, 424, - 1250, 426, 1252, 428, 1250, 426, 1252, 424, 406, 426, 1248, 428, 1252, - 426, 406, 426, 406, 424, 408, 400, 432, 400, 430, 400, 432, 400, 430, 400, - 432, 400, 1276, 400, 1276, 402, 1276, 400, 1276, 400, 1276, 400, 1278, - 400, 1276, 402, 1276, 402, 428, 402, 430, 400, 430, 402, 1276, 400, 430, - 402, 430, 400, 432, 402, 428, 402, 1278, 400, 430, 402, 430, 402, 1276, - 402, 428, 402, 430, 402, 430, 400, 1276, 402, 430, 402, 430, 402, 430, - 402, 430, 402, 428, 402, 430, 404, 430, 402, 428, 402, 430, 402, 1276, - 402, 430, 402, 428, 402, 430, 400, 428, 402, 430, 402, 430, 402, 430, 402, - 430, 402, 428, 402, 430, 402, 1274, 402, 428, 402, 430, 402, 430, 402, - 430, 402, 430, 402, 428, 402, 428, 402, 428, 404, 428, 404, 428, 402, - 1276, 400, 430, 402, 430, 400, 432, 400, 456, 374, 432, 400, 456, 404, - 428, 404, 426, 404, 428, 402, 428, 402, 430, 402, 430, 400, 432, 398, 434, - 376, 454, 378, 454, 380, 452, 378, 452, 404, 428, 406, 424, 432, 398, 406, - 426, 430, 402, 404, 428, 428, 402, 400, 430, 400, 432, 398, 434, 398, 432, - 398, 434, 372, 460, 374, 434, 398, 432, 398, 434, 396, 434, 376, 456, 376, - 456, 376, 456, 376, 1300, 378, 454, 378, 452, 378, 454, 378, 454, 378, - 454, 378, 452, 378, 454, 400, 432, 402, 430, 402, 430, 402, 430, 402, 428, - 402, 430, 402, 430, 400, 430, 402, 430, 400, 432, 400, 430, 400, 432, 400, - 430, 402, 430, 400, 432, 398, 432, 400, 430, 400, 432, 398, 432, 398, 434, - 398, 432, 398, 432, 400, 434, 398, 432, 398, 432, 398, 434, 398, 434, 396, - 434, 398, 434, 398, 432, 398, 434, 398, 432, 398, 456, 376, 454, 376, 436, - 396, 454, 376, 454, 378, 454, 376, 454, 376, 456, 374, 458, 374, 1302, - 374, 456, 374, 458, 374, 458, 376, 456, 374, 456, 374, 456, 374, 456, 376, - 456, 376, 456, 374, 458, 374, 458, 374, 458, 372, 458, 372, 460, 374, 458, - 372, 460, 372, 460, 372, 460, 370, 462, 372, 460, 372, 460, 370, 462, 370, - 462, 356, 1320, 368, 464, 346, 1332, 356, 476, 368, 1310, 366, 1312, 366, - 464, 366, 466, 366}; + 3318, 1720, 400, 1276, 400, 432, 398, 434, 398, 434, 400, 432, + 398, 432, 398, 432, 398, 434, 398, 432, 398, 434, 400, 432, + 398, 434, 398, 1278, 398, 434, 398, 434, 396, 434, 398, 434, + 398, 432, 398, 434, 398, 432, 398, 1276, 426, 1252, 424, 408, + 424, 406, 424, 408, 426, 406, 398, 432, 398, 434, 398, 432, + 400, 432, 398, 1276, 426, 408, 424, 1252, 426, 1252, 424, 1250, + 426, 1252, 428, 1250, 426, 1252, 424, 406, 426, 1248, 428, 1252, + 426, 406, 426, 406, 424, 408, 400, 432, 400, 430, 400, 432, + 400, 430, 400, 432, 400, 1276, 400, 1276, 402, 1276, 400, 1276, + 400, 1276, 400, 1278, 400, 1276, 402, 1276, 402, 428, 402, 430, + 400, 430, 402, 1276, 400, 430, 402, 430, 400, 432, 402, 428, + 402, 1278, 400, 430, 402, 430, 402, 1276, 402, 428, 402, 430, + 402, 430, 400, 1276, 402, 430, 402, 430, 402, 430, 402, 430, + 402, 428, 402, 430, 404, 430, 402, 428, 402, 430, 402, 1276, + 402, 430, 402, 428, 402, 430, 400, 428, 402, 430, 402, 430, + 402, 430, 402, 430, 402, 428, 402, 430, 402, 1274, 402, 428, + 402, 430, 402, 430, 402, 430, 402, 430, 402, 428, 402, 428, + 402, 428, 404, 428, 404, 428, 402, 1276, 400, 430, 402, 430, + 400, 432, 400, 456, 374, 432, 400, 456, 404, 428, 404, 426, + 404, 428, 402, 428, 402, 430, 402, 430, 400, 432, 398, 434, + 376, 454, 378, 454, 380, 452, 378, 452, 404, 428, 406, 424, + 432, 398, 406, 426, 430, 402, 404, 428, 428, 402, 400, 430, + 400, 432, 398, 434, 398, 432, 398, 434, 372, 460, 374, 434, + 398, 432, 398, 434, 396, 434, 376, 456, 376, 456, 376, 456, + 376, 1300, 378, 454, 378, 452, 378, 454, 378, 454, 378, 454, + 378, 452, 378, 454, 400, 432, 402, 430, 402, 430, 402, 430, + 402, 428, 402, 430, 402, 430, 400, 430, 402, 430, 400, 432, + 400, 430, 400, 432, 400, 430, 402, 430, 400, 432, 398, 432, + 400, 430, 400, 432, 398, 432, 398, 434, 398, 432, 398, 432, + 400, 434, 398, 432, 398, 432, 398, 434, 398, 434, 396, 434, + 398, 434, 398, 432, 398, 434, 398, 432, 398, 456, 376, 454, + 376, 436, 396, 454, 376, 454, 378, 454, 376, 454, 376, 456, + 374, 458, 374, 1302, 374, 456, 374, 458, 374, 458, 376, 456, + 374, 456, 374, 456, 374, 456, 376, 456, 376, 456, 374, 458, + 374, 458, 374, 458, 372, 458, 372, 460, 374, 458, 372, 460, + 372, 460, 372, 460, 370, 462, 372, 460, 372, 460, 370, 462, + 370, 462, 356, 1320, 368, 464, 346, 1332, 356, 476, 368, 1310, + 366, 1312, 366, 464, 366, 466, 366}; irsend.reset(); irsend.sendRaw(rawData, 451, 38000); irsend.makeDecodeResult(); EXPECT_TRUE(irrecv.decodeHitachiAC(&irsend.capture)); EXPECT_EQ(HITACHI_AC, irsend.capture.decode_type); - ASSERT_EQ(HITACHI_AC_BITS, irsend.capture.bits); - EXPECT_STATE_EQ(hitachi_code, irsend.capture.state, HITACHI_AC_BITS); + ASSERT_EQ(kHitachiAcBits, irsend.capture.bits); + EXPECT_STATE_EQ(hitachi_code, irsend.capture.state, kHitachiAcBits); + IRHitachiAc ac(0); + ac.setRaw(irsend.capture.state); + EXPECT_EQ( + "Power: On, Mode: 4 (COOL), Temp: 16C, Fan: 1 (AUTO), " + "Swing (Vertical): Off, Swing (Horizontal): Off", + ac.toString()); } // Decode another 'real' HitachiAC message. @@ -265,54 +436,66 @@ TEST(TestDecodeHitachiAC, NormalRealExample2) { IRrecv irrecv(0); irsend.begin(); - uint8_t hitachi_code[HITACHI_AC_STATE_LENGTH] = { - 0x80, 0x08, 0x0C, 0x02, 0xFD, 0x80, 0x7F, 0x88, 0x48, 0x10, 0xC0, 0x02, - 0x00, 0xA0, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x80, 0x00, 0x00, 0xD0}; + uint8_t hitachi_code[kHitachiAcStateLength] = { + 0x80, 0x08, 0x0C, 0x02, 0xFD, 0x80, 0x7F, 0x88, 0x48, 0x10, + 0xC0, 0x02, 0x00, 0xA0, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0xD0}; // Ref: https://github.com/markszabo/IRremoteESP8266/issues/417 // 'On' '32c' 'auto fan' 'heating mode' uint16_t rawData[451] = { - 3322, 1718, 400, 1278, 398, 432, 402, 430, 400, 430, 402, 430, 402, 430, - 400, 432, 400, 432, 402, 430, 400, 430, 402, 430, 400, 430, 402, 1276, - 402, 430, 400, 430, 402, 430, 402, 430, 402, 428, 402, 430, 400, 430, 402, - 1278, 400, 1274, 402, 430, 400, 432, 400, 430, 402, 430, 402, 430, 400, - 430, 400, 432, 402, 428, 402, 1276, 404, 428, 402, 1276, 402, 1274, 402, - 1274, 404, 1272, 402, 1274, 402, 1274, 404, 430, 402, 1274, 402, 1274, - 402, 430, 402, 430, 402, 430, 400, 430, 402, 430, 404, 428, 402, 430, 400, - 430, 402, 1274, 402, 1276, 402, 1276, 402, 1276, 400, 1276, 402, 1272, - 404, 1274, 402, 1272, 404, 430, 402, 430, 402, 430, 402, 1274, 404, 428, - 402, 428, 404, 430, 402, 430, 402, 1274, 402, 430, 402, 430, 402, 1274, - 402, 430, 402, 430, 402, 428, 404, 428, 402, 430, 402, 430, 402, 1272, - 406, 430, 402, 428, 402, 430, 402, 430, 400, 1276, 400, 1276, 402, 430, - 402, 430, 402, 430, 402, 430, 402, 428, 402, 430, 402, 430, 402, 430, 402, - 430, 402, 430, 402, 430, 400, 430, 402, 1272, 404, 430, 400, 430, 402, - 430, 402, 428, 404, 430, 400, 430, 402, 430, 402, 430, 402, 428, 402, - 1276, 402, 428, 402, 1276, 402, 430, 402, 428, 402, 430, 402, 430, 402, - 430, 402, 428, 402, 430, 402, 430, 402, 430, 402, 430, 402, 428, 402, 428, - 404, 430, 402, 428, 402, 430, 402, 428, 402, 430, 402, 432, 402, 428, 402, - 430, 402, 430, 402, 430, 400, 430, 400, 430, 402, 430, 402, 430, 402, 426, - 404, 430, 402, 430, 400, 428, 404, 428, 404, 432, 398, 432, 400, 456, 376, - 456, 376, 456, 376, 1276, 402, 454, 378, 456, 376, 454, 378, 454, 402, - 430, 376, 454, 376, 456, 400, 430, 378, 454, 400, 432, 402, 430, 376, 454, - 376, 456, 376, 454, 400, 432, 374, 458, 400, 430, 398, 434, 374, 456, 374, - 456, 374, 458, 374, 458, 374, 456, 352, 482, 372, 460, 374, 458, 364, 468, - 352, 480, 372, 460, 352, 480, 352, 480, 352, 480, 352, 480, 352, 454, 400, - 432, 376, 480, 374, 456, 374, 456, 378, 430, 404, 452, 376, 430, 404, 428, - 406, 426, 406, 426, 404, 426, 406, 428, 406, 426, 430, 400, 430, 1244, - 408, 424, 434, 398, 432, 400, 406, 424, 432, 400, 406, 426, 430, 400, 432, - 400, 432, 400, 430, 402, 428, 402, 404, 428, 404, 426, 406, 426, 406, 426, - 404, 428, 428, 402, 404, 428, 404, 428, 402, 428, 404, 428, 402, 428, 404, - 428, 404, 1274, 402, 1274, 404, 428, 400, 1276, 402, 430, 402, 430, 402, - 430, 402, 430, 400}; + 3322, 1718, 400, 1278, 398, 432, 402, 430, 400, 430, 402, 430, + 402, 430, 400, 432, 400, 432, 402, 430, 400, 430, 402, 430, + 400, 430, 402, 1276, 402, 430, 400, 430, 402, 430, 402, 430, + 402, 428, 402, 430, 400, 430, 402, 1278, 400, 1274, 402, 430, + 400, 432, 400, 430, 402, 430, 402, 430, 400, 430, 400, 432, + 402, 428, 402, 1276, 404, 428, 402, 1276, 402, 1274, 402, 1274, + 404, 1272, 402, 1274, 402, 1274, 404, 430, 402, 1274, 402, 1274, + 402, 430, 402, 430, 402, 430, 400, 430, 402, 430, 404, 428, + 402, 430, 400, 430, 402, 1274, 402, 1276, 402, 1276, 402, 1276, + 400, 1276, 402, 1272, 404, 1274, 402, 1272, 404, 430, 402, 430, + 402, 430, 402, 1274, 404, 428, 402, 428, 404, 430, 402, 430, + 402, 1274, 402, 430, 402, 430, 402, 1274, 402, 430, 402, 430, + 402, 428, 404, 428, 402, 430, 402, 430, 402, 1272, 406, 430, + 402, 428, 402, 430, 402, 430, 400, 1276, 400, 1276, 402, 430, + 402, 430, 402, 430, 402, 430, 402, 428, 402, 430, 402, 430, + 402, 430, 402, 430, 402, 430, 402, 430, 400, 430, 402, 1272, + 404, 430, 400, 430, 402, 430, 402, 428, 404, 430, 400, 430, + 402, 430, 402, 430, 402, 428, 402, 1276, 402, 428, 402, 1276, + 402, 430, 402, 428, 402, 430, 402, 430, 402, 430, 402, 428, + 402, 430, 402, 430, 402, 430, 402, 430, 402, 428, 402, 428, + 404, 430, 402, 428, 402, 430, 402, 428, 402, 430, 402, 432, + 402, 428, 402, 430, 402, 430, 402, 430, 400, 430, 400, 430, + 402, 430, 402, 430, 402, 426, 404, 430, 402, 430, 400, 428, + 404, 428, 404, 432, 398, 432, 400, 456, 376, 456, 376, 456, + 376, 1276, 402, 454, 378, 456, 376, 454, 378, 454, 402, 430, + 376, 454, 376, 456, 400, 430, 378, 454, 400, 432, 402, 430, + 376, 454, 376, 456, 376, 454, 400, 432, 374, 458, 400, 430, + 398, 434, 374, 456, 374, 456, 374, 458, 374, 458, 374, 456, + 352, 482, 372, 460, 374, 458, 364, 468, 352, 480, 372, 460, + 352, 480, 352, 480, 352, 480, 352, 480, 352, 454, 400, 432, + 376, 480, 374, 456, 374, 456, 378, 430, 404, 452, 376, 430, + 404, 428, 406, 426, 406, 426, 404, 426, 406, 428, 406, 426, + 430, 400, 430, 1244, 408, 424, 434, 398, 432, 400, 406, 424, + 432, 400, 406, 426, 430, 400, 432, 400, 432, 400, 430, 402, + 428, 402, 404, 428, 404, 426, 406, 426, 406, 426, 404, 428, + 428, 402, 404, 428, 404, 428, 402, 428, 404, 428, 402, 428, + 404, 428, 404, 1274, 402, 1274, 404, 428, 400, 1276, 402, 430, + 402, 430, 402, 430, 402, 430, 400}; irsend.reset(); irsend.sendRaw(rawData, 451, 38000); irsend.makeDecodeResult(); EXPECT_TRUE(irrecv.decode(&irsend.capture)); EXPECT_EQ(HITACHI_AC, irsend.capture.decode_type); - ASSERT_EQ(HITACHI_AC_BITS, irsend.capture.bits); - EXPECT_STATE_EQ(hitachi_code, irsend.capture.state, HITACHI_AC_BITS); + ASSERT_EQ(kHitachiAcBits, irsend.capture.bits); + EXPECT_STATE_EQ(hitachi_code, irsend.capture.state, kHitachiAcBits); + IRHitachiAc ac(0); + ac.setRaw(irsend.capture.state); + EXPECT_EQ( + "Power: On, Mode: 3 (HEAT), Temp: 32C, Fan: 5 (HIGH), " + "Swing (Vertical): Off, Swing (Horizontal): Off", + ac.toString()); } // Tests for sendHitachiAC1(). @@ -322,9 +505,9 @@ TEST(TestSendHitachiAC1, SendData) { IRsendTest irsend(0); irsend.begin(); - uint8_t hitachi_code[HITACHI_AC1_STATE_LENGTH] = { - 0xB2, 0xAE, 0x4D, 0x51, 0xF0, 0x61, 0x84, 0x00, 0x00, 0x00, 0x00, 0x30, - 0xB8}; + uint8_t hitachi_code[kHitachiAc1StateLength] = {0xB2, 0xAE, 0x4D, 0x51, 0xF0, + 0x61, 0x84, 0x00, 0x00, 0x00, + 0x00, 0x30, 0xB8}; irsend.reset(); irsend.sendHitachiAC1(hitachi_code); EXPECT_EQ( @@ -342,7 +525,8 @@ TEST(TestSendHitachiAC1, SendData) { "m400s500m400s500m400s500m400s500m400s500m400s500m400s500m400s500" "m400s500m400s500m400s1250m400s1250m400s500m400s500m400s500m400s500" "m400s1250m400s500m400s1250m400s1250m400s1250m400s500m400s500m400s500" - "m400s100000", irsend.outputStr()); + "m400s100000", + irsend.outputStr()); } // Decode a 'real' HitachiAC1 message. @@ -351,38 +535,40 @@ TEST(TestDecodeHitachiAC1, NormalRealExample) { IRrecv irrecv(0); irsend.begin(); - uint8_t hitachi_code[HITACHI_AC1_STATE_LENGTH] = { - 0xB2, 0xAE, 0x4D, 0x51, 0xF0, 0x61, 0x84, 0x00, 0x00, 0x00, 0x00, 0x10, - 0x98}; + uint8_t hitachi_code[kHitachiAc1StateLength] = {0xB2, 0xAE, 0x4D, 0x51, 0xF0, + 0x61, 0x84, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x98}; // Ref: https://github.com/markszabo/IRremoteESP8266/issues/453 uint16_t rawData[211] = { - 3400, 3350, 450, 1250, 450, 400, 400, 1300, 400, 1300, 400, 400, 450, 400, - 400, 1300, 400, 400, 400, 1300, 400, 400, 450, 1250, 400, 450, 400, 1300, - 400, 1250, 450, 1250, 450, 400, 400, 450, 400, 1250, 450, 400, 400, 400, - 400, 1300, 400, 1300, 400, 400, 450, 1250, 450, 400, 400, 1300, 400, 400, - 450, 1250, 400, 400, 450, 400, 400, 400, 450, 1250, 400, 1300, 450, 1250, - 450, 1250, 400, 1300, 400, 400, 450, 400, 400, 450, 350, 450, 400, 400, 400, - 1300, 400, 1300, 400, 400, 450, 400, 400, 400, 450, 400, 400, 1300, 400, - 1250, 450, 400, 400, 400, 450, 400, 400, 400, 450, 1250, 450, 400, 400, 400, - 450, 400, 400, 400, 450, 400, 400, 400, 450, 400, 400, 400, 450, 400, 400, - 400, 400, 450, 400, 400, 400, 400, 450, 400, 400, 400, 450, 400, 400, 450, - 400, 400, 400, 400, 450, 400, 400, 400, 450, 400, 400, 450, 400, 400, 400, - 400, 400, 450, 400, 400, 400, 400, 450, 400, 400, 400, 450, 400, 400, 400, - 450, 400, 400, 400, 450, 400, 400, 400, 450, 400, 400, 1300, 400, 400, 450, - 400, 400, 400, 400, 400, 450, 1250, 450, 400, 400, 400, 450, 1250, 450, - 1250, 450, 400, 400, 400, 450, 400, 400}; // UNKNOWN 828A89E1 + 3400, 3350, 450, 1250, 450, 400, 400, 1300, 400, 1300, 400, 400, + 450, 400, 400, 1300, 400, 400, 400, 1300, 400, 400, 450, 1250, + 400, 450, 400, 1300, 400, 1250, 450, 1250, 450, 400, 400, 450, + 400, 1250, 450, 400, 400, 400, 400, 1300, 400, 1300, 400, 400, + 450, 1250, 450, 400, 400, 1300, 400, 400, 450, 1250, 400, 400, + 450, 400, 400, 400, 450, 1250, 400, 1300, 450, 1250, 450, 1250, + 400, 1300, 400, 400, 450, 400, 400, 450, 350, 450, 400, 400, + 400, 1300, 400, 1300, 400, 400, 450, 400, 400, 400, 450, 400, + 400, 1300, 400, 1250, 450, 400, 400, 400, 450, 400, 400, 400, + 450, 1250, 450, 400, 400, 400, 450, 400, 400, 400, 450, 400, + 400, 400, 450, 400, 400, 400, 450, 400, 400, 400, 400, 450, + 400, 400, 400, 400, 450, 400, 400, 400, 450, 400, 400, 450, + 400, 400, 400, 400, 450, 400, 400, 400, 450, 400, 400, 450, + 400, 400, 400, 400, 400, 450, 400, 400, 400, 400, 450, 400, + 400, 400, 450, 400, 400, 400, 450, 400, 400, 400, 450, 400, + 400, 400, 450, 400, 400, 1300, 400, 400, 450, 400, 400, 400, + 400, 400, 450, 1250, 450, 400, 400, 400, 450, 1250, 450, 1250, + 450, 400, 400, 400, 450, 400, 400}; // UNKNOWN 828A89E1 irsend.reset(); irsend.sendRaw(rawData, 211, 38000); irsend.makeDecodeResult(); EXPECT_TRUE(irrecv.decode(&irsend.capture)); EXPECT_EQ(HITACHI_AC1, irsend.capture.decode_type); - ASSERT_EQ(HITACHI_AC1_BITS, irsend.capture.bits); - EXPECT_STATE_EQ(hitachi_code, irsend.capture.state, HITACHI_AC1_BITS); + ASSERT_EQ(kHitachiAc1Bits, irsend.capture.bits); + EXPECT_STATE_EQ(hitachi_code, irsend.capture.state, kHitachiAc1Bits); } - // Tests for sendHitachiAC2(). // Test sending typical data only. @@ -390,12 +576,12 @@ TEST(TestSendHitachiAC2, SendData) { IRsendTest irsend(0); irsend.begin(); - uint8_t hitachi_code[HITACHI_AC2_STATE_LENGTH] = { - 0x80, 0x08, 0x00, 0x02, 0xFD, 0xFF, 0x00, 0x33, 0xCC, 0x49, 0xB6, 0x22, - 0xDD, 0x01, 0xFE, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, - 0xFF, 0xCA, 0x35, 0x8F, 0x70, 0x00, 0xFF, 0x00, 0xFF, 0x01, 0xFE, 0xC0, - 0x3F, 0x80, 0x7F, 0x11, 0xEE, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, - 0x00, 0xFF, 0x00, 0xFF, 0x00}; + uint8_t hitachi_code[kHitachiAc2StateLength] = { + 0x80, 0x08, 0x00, 0x02, 0xFD, 0xFF, 0x00, 0x33, 0xCC, 0x49, 0xB6, + 0x22, 0xDD, 0x01, 0xFE, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, + 0xFF, 0x00, 0xFF, 0xCA, 0x35, 0x8F, 0x70, 0x00, 0xFF, 0x00, 0xFF, + 0x01, 0xFE, 0xC0, 0x3F, 0x80, 0x7F, 0x11, 0xEE, 0x00, 0xFF, 0x00, + 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00}; irsend.reset(); irsend.sendHitachiAC2(hitachi_code); EXPECT_EQ( @@ -453,7 +639,8 @@ TEST(TestSendHitachiAC2, SendData) { "m400s500m400s500m400s500m400s500m400s500m400s500m400s500m400s500" "m400s1250m400s1250m400s1250m400s1250m400s1250m400s1250m400s1250m400s1250" "m400s500m400s500m400s500m400s500m400s500m400s500m400s500m400s500" - "m400s100000", irsend.outputStr()); + "m400s100000", + irsend.outputStr()); } // Decode a synthetic HitachiAC2 message. @@ -464,20 +651,20 @@ TEST(TestDecodeHitachiAC2, NormalSyntheticExample) { irsend.begin(); // ON - 32c cool (fan auto) - uint8_t hitachi_code[HITACHI_AC2_STATE_LENGTH] = { - 0x80, 0x08, 0x00, 0x02, 0xFD, 0xFF, 0x00, 0x33, 0xCC, 0x49, 0xB6, 0x22, - 0xDD, 0x01, 0xFE, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, - 0xFF, 0xCA, 0x35, 0x8F, 0x70, 0x00, 0xFF, 0x00, 0xFF, 0x01, 0xFE, 0xC0, - 0x3F, 0x80, 0x7F, 0x11, 0xEE, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, - 0x00, 0xFF, 0x00, 0xFF, 0x00}; + uint8_t hitachi_code[kHitachiAc2StateLength] = { + 0x80, 0x08, 0x00, 0x02, 0xFD, 0xFF, 0x00, 0x33, 0xCC, 0x49, 0xB6, + 0x22, 0xDD, 0x01, 0xFE, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, + 0xFF, 0x00, 0xFF, 0xCA, 0x35, 0x8F, 0x70, 0x00, 0xFF, 0x00, 0xFF, + 0x01, 0xFE, 0xC0, 0x3F, 0x80, 0x7F, 0x11, 0xEE, 0x00, 0xFF, 0x00, + 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00}; irsend.reset(); irsend.sendHitachiAC2(hitachi_code); irsend.makeDecodeResult(); EXPECT_TRUE(irrecv.decode(&irsend.capture)); EXPECT_EQ(HITACHI_AC2, irsend.capture.decode_type); - ASSERT_EQ(HITACHI_AC2_BITS, irsend.capture.bits); - EXPECT_STATE_EQ(hitachi_code, irsend.capture.state, HITACHI_AC2_BITS); + ASSERT_EQ(kHitachiAc2Bits, irsend.capture.bits); + EXPECT_STATE_EQ(hitachi_code, irsend.capture.state, kHitachiAc2Bits); } // Decode a 'real' HitachiAC2 message. @@ -486,92 +673,93 @@ TEST(TestDecodeHitachiAC2, NormalRealExample) { IRrecv irrecv(0); irsend.begin(); - uint8_t hitachi_code[HITACHI_AC2_STATE_LENGTH] = { - 0x80, 0x08, 0x00, 0x02, 0xFD, 0xFF, 0x00, 0x33, 0xCC, 0x49, 0xB6, 0x22, - 0xDD, 0x01, 0xFE, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, - 0xFF, 0xCA, 0x35, 0x8F, 0x70, 0x00, 0xFF, 0x00, 0xFF, 0x01, 0xFE, 0xC0, - 0x3F, 0x80, 0x7F, 0x11, 0xEE, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, - 0x00, 0xFF, 0x00, 0xFF, 0x00}; + uint8_t hitachi_code[kHitachiAc2StateLength] = { + 0x80, 0x08, 0x00, 0x02, 0xFD, 0xFF, 0x00, 0x33, 0xCC, 0x49, 0xB6, + 0x22, 0xDD, 0x01, 0xFE, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, + 0xFF, 0x00, 0xFF, 0xCA, 0x35, 0x8F, 0x70, 0x00, 0xFF, 0x00, 0xFF, + 0x01, 0xFE, 0xC0, 0x3F, 0x80, 0x7F, 0x11, 0xEE, 0x00, 0xFF, 0x00, + 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00}; // Ref: https://github.com/markszabo/IRremoteESP8266/issues/417 - uint16_t rawData[851] = { // ON - 32c cool (fan auto) - 3432, 1654, 492, 1180, 488, 360, 486, 360, 486, 360, 486, 362, - 486, 362, 460, 360, 486, 362, 486, 362, 486, 360, 486, 362, - 486, 362, 486, 1184, 488, 362, 486, 360, 486, 362, 486, 362, - 486, 362, 460, 362, 486, 362, 486, 362, 484, 362, 486, 362, - 486, 362, 486, 362, 458, 362, 484, 362, 486, 362, 484, 364, - 484, 362, 486, 1184, 486, 362, 486, 1210, 488, 1210, 488, 1184, - 486, 1210, 488, 1210, 488, 1182, 488, 360, 488, 1208, 488, 1208, - 488, 1182, 488, 1208, 488, 1208, 488, 1208, 462, 1208, 490, 1208, - 488, 1208, 490, 332, 488, 360, 488, 360, 488, 360, 486, 360, - 486, 360, 486, 362, 460, 360, 486, 362, 486, 362, 486, 1210, - 488, 1210, 460, 362, 486, 362, 486, 1210, 488, 1210, 488, 1182, - 488, 1210, 488, 362, 486, 360, 488, 1182, 488, 1210, 488, 362, - 486, 362, 486, 360, 486, 1182, 488, 362, 486, 362, 486, 1210, - 488, 360, 486, 336, 486, 1210, 488, 1210, 488, 360, 486, 1182, - 488, 1210, 488, 360, 488, 1208, 488, 1182, 488, 362, 486, 362, - 486, 360, 486, 1210, 460, 362, 486, 360, 486, 362, 486, 1210, - 486, 362, 486, 1184, 488, 1208, 488, 360, 486, 1210, 488, 1184, - 488, 1208, 488, 362, 486, 1208, 462, 360, 486, 360, 486, 362, - 486, 360, 486, 362, 486, 360, 486, 334, 486, 1210, 488, 1208, - 488, 1210, 488, 1182, 488, 1208, 488, 1210, 488, 1182, 488, 1208, - 488, 360, 488, 360, 486, 360, 486, 334, 486, 362, 486, 362, - 486, 362, 486, 362, 486, 362, 486, 1182, 488, 1210, 486, 1210, - 488, 1210, 460, 1210, 488, 1210, 488, 1210, 488, 1184, 488, 360, - 486, 360, 486, 362, 486, 362, 486, 360, 460, 360, 486, 362, - 486, 362, 484, 1210, 488, 1182, 488, 1210, 488, 1210, 488, 1210, - 488, 1182, 488, 1208, 488, 1208, 488, 360, 460, 360, 486, 360, - 486, 360, 488, 360, 486, 362, 486, 362, 486, 334, 486, 1210, - 488, 1208, 488, 1210, 460, 1210, 488, 1208, 488, 1210, 488, 1182, - 488, 1208, 488, 360, 486, 362, 486, 360, 488, 334, 486, 360, - 486, 362, 486, 362, 486, 362, 486, 1210, 460, 1210, 488, 1210, - 488, 1210, 488, 1182, 488, 1210, 488, 1208, 488, 1182, 488, 360, - 486, 360, 486, 362, 486, 362, 486, 360, 486, 362, 460, 360, - 486, 362, 486, 1210, 486, 1212, 486, 1184, 488, 1210, 488, 1208, - 488, 1182, 488, 1208, 488, 1208, 488, 1208, 462, 1208, 488, 360, - 486, 362, 486, 1208, 488, 334, 486, 1208, 488, 360, 486, 360, - 486, 362, 486, 1182, 488, 1210, 488, 360, 486, 1210, 488, 334, - 486, 1208, 488, 1208, 488, 360, 486, 360, 486, 334, 486, 1210, - 488, 1210, 488, 1210, 460, 1210, 488, 360, 486, 1208, 488, 1182, - 490, 1208, 488, 360, 486, 360, 486, 360, 486, 360, 460, 360, - 486, 362, 486, 362, 486, 362, 486, 362, 486, 362, 486, 362, - 458, 362, 486, 1210, 488, 1210, 488, 1182, 488, 1210, 488, 1208, - 488, 1208, 462, 1208, 488, 1208, 488, 360, 486, 360, 486, 334, - 486, 360, 486, 362, 486, 362, 486, 362, 486, 362, 486, 1184, - 488, 1210, 488, 1210, 488, 1208, 462, 1210, 488, 1208, 488, 1208, - 488, 1182, 488, 360, 486, 360, 486, 360, 486, 362, 486, 360, - 460, 362, 486, 360, 488, 1208, 488, 1210, 488, 1184, 488, 1208, - 488, 1210, 488, 1182, 488, 1208, 488, 1208, 488, 360, 488, 1182, - 488, 1208, 488, 360, 488, 360, 488, 360, 486, 334, 486, 360, - 486, 362, 486, 362, 486, 360, 486, 1210, 488, 1182, 488, 1210, - 488, 1210, 488, 1182, 488, 1210, 488, 1210, 488, 360, 488, 334, - 486, 360, 488, 360, 486, 362, 486, 362, 486, 362, 486, 362, - 460, 1210, 488, 1210, 488, 1210, 488, 1184, 488, 1208, 488, 1208, - 490, 1182, 488, 360, 488, 360, 486, 362, 486, 1208, 488, 360, - 460, 362, 486, 362, 486, 1210, 488, 1210, 488, 1182, 488, 1208, - 488, 360, 488, 1208, 488, 1184, 486, 1210, 488, 360, 488, 360, - 486, 360, 460, 362, 486, 362, 486, 362, 486, 362, 484, 362, - 486, 362, 486, 1184, 488, 1210, 488, 1210, 488, 1182, 488, 1210, - 488, 1208, 488, 1208, 462, 1210, 488, 360, 486, 362, 486, 360, - 486, 362, 486, 334, 486, 362, 486, 360, 486, 362, 486, 1208, - 488, 1184, 488, 1208, 488, 1210, 488, 1182, 488, 1208, 488, 1208, - 488, 1208, 488, 1182, 488, 1208, 488, 1208, 488, 1182, 488, 1208, - 488, 1208, 488, 1182, 488, 1208, 488, 360, 488, 360, 486, 360, - 486, 362, 460, 362, 486, 362, 486, 362, 486, 360, 486, 1208, - 488, 1182, 488, 1208, 488, 1210, 488, 1182, 488, 1208, 490, 1208, - 488, 1208, 462, 360, 488, 360, 486, 360, 488, 360, 486, 360, - 486, 360, 486, 336, 486, 362, 486, 1210, 488, 1208, 488, 1182, - 488, 1208, 488, 1208, 488, 1208, 462, 1208, 490, 1206, 490, 360, - 488, 360, 488, 332, 486, 360, 488, 360, 486, 360, 488, 360, - 486, 360, 486, 1182, 488, 1208, 488, 1206, 492, 1208, 462, 1208, - 488, 1208, 488, 1208, 490, 1182, 490, 360, 486, 360, 486, 360, - 488, 360, 488, 360, 460, 360, 486, 362, 486, 360, 488}; + uint16_t rawData[851] = { + // ON - 32c cool (fan auto) + 3432, 1654, 492, 1180, 488, 360, 486, 360, 486, 360, 486, 362, + 486, 362, 460, 360, 486, 362, 486, 362, 486, 360, 486, 362, + 486, 362, 486, 1184, 488, 362, 486, 360, 486, 362, 486, 362, + 486, 362, 460, 362, 486, 362, 486, 362, 484, 362, 486, 362, + 486, 362, 486, 362, 458, 362, 484, 362, 486, 362, 484, 364, + 484, 362, 486, 1184, 486, 362, 486, 1210, 488, 1210, 488, 1184, + 486, 1210, 488, 1210, 488, 1182, 488, 360, 488, 1208, 488, 1208, + 488, 1182, 488, 1208, 488, 1208, 488, 1208, 462, 1208, 490, 1208, + 488, 1208, 490, 332, 488, 360, 488, 360, 488, 360, 486, 360, + 486, 360, 486, 362, 460, 360, 486, 362, 486, 362, 486, 1210, + 488, 1210, 460, 362, 486, 362, 486, 1210, 488, 1210, 488, 1182, + 488, 1210, 488, 362, 486, 360, 488, 1182, 488, 1210, 488, 362, + 486, 362, 486, 360, 486, 1182, 488, 362, 486, 362, 486, 1210, + 488, 360, 486, 336, 486, 1210, 488, 1210, 488, 360, 486, 1182, + 488, 1210, 488, 360, 488, 1208, 488, 1182, 488, 362, 486, 362, + 486, 360, 486, 1210, 460, 362, 486, 360, 486, 362, 486, 1210, + 486, 362, 486, 1184, 488, 1208, 488, 360, 486, 1210, 488, 1184, + 488, 1208, 488, 362, 486, 1208, 462, 360, 486, 360, 486, 362, + 486, 360, 486, 362, 486, 360, 486, 334, 486, 1210, 488, 1208, + 488, 1210, 488, 1182, 488, 1208, 488, 1210, 488, 1182, 488, 1208, + 488, 360, 488, 360, 486, 360, 486, 334, 486, 362, 486, 362, + 486, 362, 486, 362, 486, 362, 486, 1182, 488, 1210, 486, 1210, + 488, 1210, 460, 1210, 488, 1210, 488, 1210, 488, 1184, 488, 360, + 486, 360, 486, 362, 486, 362, 486, 360, 460, 360, 486, 362, + 486, 362, 484, 1210, 488, 1182, 488, 1210, 488, 1210, 488, 1210, + 488, 1182, 488, 1208, 488, 1208, 488, 360, 460, 360, 486, 360, + 486, 360, 488, 360, 486, 362, 486, 362, 486, 334, 486, 1210, + 488, 1208, 488, 1210, 460, 1210, 488, 1208, 488, 1210, 488, 1182, + 488, 1208, 488, 360, 486, 362, 486, 360, 488, 334, 486, 360, + 486, 362, 486, 362, 486, 362, 486, 1210, 460, 1210, 488, 1210, + 488, 1210, 488, 1182, 488, 1210, 488, 1208, 488, 1182, 488, 360, + 486, 360, 486, 362, 486, 362, 486, 360, 486, 362, 460, 360, + 486, 362, 486, 1210, 486, 1212, 486, 1184, 488, 1210, 488, 1208, + 488, 1182, 488, 1208, 488, 1208, 488, 1208, 462, 1208, 488, 360, + 486, 362, 486, 1208, 488, 334, 486, 1208, 488, 360, 486, 360, + 486, 362, 486, 1182, 488, 1210, 488, 360, 486, 1210, 488, 334, + 486, 1208, 488, 1208, 488, 360, 486, 360, 486, 334, 486, 1210, + 488, 1210, 488, 1210, 460, 1210, 488, 360, 486, 1208, 488, 1182, + 490, 1208, 488, 360, 486, 360, 486, 360, 486, 360, 460, 360, + 486, 362, 486, 362, 486, 362, 486, 362, 486, 362, 486, 362, + 458, 362, 486, 1210, 488, 1210, 488, 1182, 488, 1210, 488, 1208, + 488, 1208, 462, 1208, 488, 1208, 488, 360, 486, 360, 486, 334, + 486, 360, 486, 362, 486, 362, 486, 362, 486, 362, 486, 1184, + 488, 1210, 488, 1210, 488, 1208, 462, 1210, 488, 1208, 488, 1208, + 488, 1182, 488, 360, 486, 360, 486, 360, 486, 362, 486, 360, + 460, 362, 486, 360, 488, 1208, 488, 1210, 488, 1184, 488, 1208, + 488, 1210, 488, 1182, 488, 1208, 488, 1208, 488, 360, 488, 1182, + 488, 1208, 488, 360, 488, 360, 488, 360, 486, 334, 486, 360, + 486, 362, 486, 362, 486, 360, 486, 1210, 488, 1182, 488, 1210, + 488, 1210, 488, 1182, 488, 1210, 488, 1210, 488, 360, 488, 334, + 486, 360, 488, 360, 486, 362, 486, 362, 486, 362, 486, 362, + 460, 1210, 488, 1210, 488, 1210, 488, 1184, 488, 1208, 488, 1208, + 490, 1182, 488, 360, 488, 360, 486, 362, 486, 1208, 488, 360, + 460, 362, 486, 362, 486, 1210, 488, 1210, 488, 1182, 488, 1208, + 488, 360, 488, 1208, 488, 1184, 486, 1210, 488, 360, 488, 360, + 486, 360, 460, 362, 486, 362, 486, 362, 486, 362, 484, 362, + 486, 362, 486, 1184, 488, 1210, 488, 1210, 488, 1182, 488, 1210, + 488, 1208, 488, 1208, 462, 1210, 488, 360, 486, 362, 486, 360, + 486, 362, 486, 334, 486, 362, 486, 360, 486, 362, 486, 1208, + 488, 1184, 488, 1208, 488, 1210, 488, 1182, 488, 1208, 488, 1208, + 488, 1208, 488, 1182, 488, 1208, 488, 1208, 488, 1182, 488, 1208, + 488, 1208, 488, 1182, 488, 1208, 488, 360, 488, 360, 486, 360, + 486, 362, 460, 362, 486, 362, 486, 362, 486, 360, 486, 1208, + 488, 1182, 488, 1208, 488, 1210, 488, 1182, 488, 1208, 490, 1208, + 488, 1208, 462, 360, 488, 360, 486, 360, 488, 360, 486, 360, + 486, 360, 486, 336, 486, 362, 486, 1210, 488, 1208, 488, 1182, + 488, 1208, 488, 1208, 488, 1208, 462, 1208, 490, 1206, 490, 360, + 488, 360, 488, 332, 486, 360, 488, 360, 486, 360, 488, 360, + 486, 360, 486, 1182, 488, 1208, 488, 1206, 492, 1208, 462, 1208, + 488, 1208, 488, 1208, 490, 1182, 490, 360, 486, 360, 486, 360, + 488, 360, 488, 360, 460, 360, 486, 362, 486, 360, 488}; irsend.reset(); irsend.sendRaw(rawData, 851, 38000); irsend.makeDecodeResult(); EXPECT_TRUE(irrecv.decode(&irsend.capture)); EXPECT_EQ(HITACHI_AC2, irsend.capture.decode_type); - ASSERT_EQ(HITACHI_AC2_BITS, irsend.capture.bits); - EXPECT_STATE_EQ(hitachi_code, irsend.capture.state, HITACHI_AC2_BITS); + ASSERT_EQ(kHitachiAc2Bits, irsend.capture.bits); + EXPECT_STATE_EQ(hitachi_code, irsend.capture.state, kHitachiAc2Bits); } diff --git a/lib/IRremoteESP8266/test/ir_JVC_test.cpp b/lib/IRremoteESP8266/test/ir_JVC_test.cpp index a9caf85..c899fa8 100644 --- a/lib/IRremoteESP8266/test/ir_JVC_test.cpp +++ b/lib/IRremoteESP8266/test/ir_JVC_test.cpp @@ -17,7 +17,8 @@ TEST(TestSendJVC, SendDataOnly) { "m8400s4200" "m525s1725m525s1725m525s525m525s525m525s525m525s525m525s1725m525s525" "m525s1725m525s525m525s1725m525s1725m525s1725m525s525m525s525m525s525" - "m525s21675", irsend.outputStr()); + "m525s21675", + irsend.outputStr()); } // Test sending with different repeats. @@ -26,7 +27,7 @@ TEST(TestSendJVC, SendWithRepeats) { irsend.begin(); irsend.reset(); - irsend.sendJVC(0xC2B8, JVC_BITS, 1); // 1 repeat. + irsend.sendJVC(0xC2B8, kJvcBits, 1); // 1 repeat. EXPECT_EQ( "m8400s4200" "m525s1725m525s1725m525s525m525s525m525s525m525s525m525s1725m525s525" @@ -34,8 +35,9 @@ TEST(TestSendJVC, SendWithRepeats) { "m525s21675" "m525s1725m525s1725m525s525m525s525m525s525m525s525m525s1725m525s525" "m525s1725m525s525m525s1725m525s1725m525s1725m525s525m525s525m525s525" - "m525s34275", irsend.outputStr()); - irsend.sendJVC(0xC2B8, JVC_BITS, 2); // 2 repeats. + "m525s34275", + irsend.outputStr()); + irsend.sendJVC(0xC2B8, kJvcBits, 2); // 2 repeats. EXPECT_EQ( "m8400s4200" "m525s1725m525s1725m525s525m525s525m525s525m525s525m525s1725m525s525" @@ -46,7 +48,8 @@ TEST(TestSendJVC, SendWithRepeats) { "m525s34275" "m525s1725m525s1725m525s525m525s525m525s525m525s525m525s1725m525s525" "m525s1725m525s525m525s1725m525s1725m525s1725m525s525m525s525m525s525" - "m525s34275", irsend.outputStr()); + "m525s34275", + irsend.outputStr()); } // Test sending an atypical data size. @@ -59,7 +62,8 @@ TEST(TestSendJVC, SendUnusualSize) { EXPECT_EQ( "m8400s4200" "m525s525m525s525m525s525m525s525m525s525m525s525m525s525m525s525" - "m525s38475", irsend.outputStr()); + "m525s38475", + irsend.outputStr()); irsend.reset(); irsend.sendJVC(0x1234567890ABCDEF, 64); @@ -73,7 +77,8 @@ TEST(TestSendJVC, SendUnusualSize) { "m525s1725m525s525m525s1725m525s525m525s1725m525s525m525s1725m525s1725" "m525s1725m525s1725m525s525m525s525m525s1725m525s1725m525s525m525s1725" "m525s1725m525s1725m525s1725m525s525m525s1725m525s1725m525s1725m525s1725" - "m525s10875", irsend.outputStr()); + "m525s10875", + irsend.outputStr()); } // Tests for encodeJVC(). @@ -100,9 +105,9 @@ TEST(TestDecodeJVC, NormalDecodeWithStrict) { irsend.reset(); irsend.sendJVC(0xC2B8); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodeJVC(&irsend.capture, JVC_BITS, true)); + ASSERT_TRUE(irrecv.decodeJVC(&irsend.capture, kJvcBits, true)); EXPECT_EQ(JVC, irsend.capture.decode_type); - EXPECT_EQ(JVC_BITS, irsend.capture.bits); + EXPECT_EQ(kJvcBits, irsend.capture.bits); EXPECT_EQ(0xC2B8, irsend.capture.value); EXPECT_EQ(0x43, irsend.capture.address); EXPECT_EQ(0x1D, irsend.capture.command); @@ -112,9 +117,9 @@ TEST(TestDecodeJVC, NormalDecodeWithStrict) { irsend.reset(); irsend.sendJVC(irsend.encodeJVC(0x07, 0x99)); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodeJVC(&irsend.capture, JVC_BITS, true)); + ASSERT_TRUE(irrecv.decodeJVC(&irsend.capture, kJvcBits, true)); EXPECT_EQ(JVC, irsend.capture.decode_type); - EXPECT_EQ(JVC_BITS, irsend.capture.bits); + EXPECT_EQ(kJvcBits, irsend.capture.bits); EXPECT_EQ(0xE099, irsend.capture.value); EXPECT_EQ(0x07, irsend.capture.address); EXPECT_EQ(0x99, irsend.capture.command); @@ -124,9 +129,9 @@ TEST(TestDecodeJVC, NormalDecodeWithStrict) { irsend.reset(); irsend.sendJVC(irsend.encodeJVC(0x1, 0x1)); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodeJVC(&irsend.capture, JVC_BITS, true)); + ASSERT_TRUE(irrecv.decodeJVC(&irsend.capture, kJvcBits, true)); EXPECT_EQ(JVC, irsend.capture.decode_type); - EXPECT_EQ(JVC_BITS, irsend.capture.bits); + EXPECT_EQ(kJvcBits, irsend.capture.bits); EXPECT_EQ(0x8080, irsend.capture.value); EXPECT_EQ(0x1, irsend.capture.address); EXPECT_EQ(0x1, irsend.capture.command); @@ -141,42 +146,42 @@ TEST(TestDecodeJVC, NormalDecodeWithRepeatAndStrict) { // Normal JVC 16-bit message with 2 repeats. irsend.reset(); - irsend.sendJVC(0xC2B8, JVC_BITS, 2); + irsend.sendJVC(0xC2B8, kJvcBits, 2); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodeJVC(&irsend.capture, JVC_BITS, true)); + ASSERT_TRUE(irrecv.decodeJVC(&irsend.capture, kJvcBits, true)); EXPECT_EQ(JVC, irsend.capture.decode_type); - EXPECT_EQ(JVC_BITS, irsend.capture.bits); + EXPECT_EQ(kJvcBits, irsend.capture.bits); EXPECT_EQ(0xC2B8, irsend.capture.value); EXPECT_EQ(0x43, irsend.capture.address); EXPECT_EQ(0x1D, irsend.capture.command); EXPECT_FALSE(irsend.capture.repeat); - irsend.makeDecodeResult(2 * JVC_BITS + 4); - ASSERT_TRUE(irrecv.decodeJVC(&irsend.capture, JVC_BITS, true)); + irsend.makeDecodeResult(2 * kJvcBits + 4); + ASSERT_TRUE(irrecv.decodeJVC(&irsend.capture, kJvcBits, true)); EXPECT_EQ(JVC, irsend.capture.decode_type); - EXPECT_EQ(JVC_BITS, irsend.capture.bits); + EXPECT_EQ(kJvcBits, irsend.capture.bits); EXPECT_EQ(0xC2B8, irsend.capture.value); EXPECT_TRUE(irsend.capture.repeat); - irsend.makeDecodeResult(2 * JVC_BITS + 4 + 2 * JVC_BITS + 2); - ASSERT_TRUE(irrecv.decodeJVC(&irsend.capture, JVC_BITS, true)); + irsend.makeDecodeResult(2 * kJvcBits + 4 + 2 * kJvcBits + 2); + ASSERT_TRUE(irrecv.decodeJVC(&irsend.capture, kJvcBits, true)); EXPECT_EQ(JVC, irsend.capture.decode_type); - EXPECT_EQ(JVC_BITS, irsend.capture.bits); + EXPECT_EQ(kJvcBits, irsend.capture.bits); EXPECT_EQ(0xC2B8, irsend.capture.value); EXPECT_TRUE(irsend.capture.repeat); // Simulate 'just' a JVC repeat command. // JVC VCR Power On from Global Cache, but modified to be a repeat message. - uint16_t gc_test[37] = {38000, 1, 1, 20, 61, 20, 61, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 61, 20, 20, 20, 61, 20, 20, 20, - 61, 20, 61, 20, 61, 20, 20, 20, 20, 20, 20, 20, 884}; + uint16_t gc_test[37] = {38000, 1, 1, 20, 61, 20, 61, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 61, 20, 20, 20, 61, 20, 20, 20, 61, 20, + 61, 20, 61, 20, 20, 20, 20, 20, 20, 20, 884}; irsend.reset(); irsend.sendGC(gc_test, 37); irsend.makeDecodeResult(); ASSERT_TRUE(irrecv.decodeJVC(&irsend.capture)); EXPECT_EQ(JVC, irsend.capture.decode_type); - EXPECT_EQ(JVC_BITS, irsend.capture.bits); + EXPECT_EQ(kJvcBits, irsend.capture.bits); EXPECT_EQ(0xC2B8, irsend.capture.value); EXPECT_EQ(0x43, irsend.capture.address); EXPECT_EQ(0x1D, irsend.capture.command); @@ -193,7 +198,7 @@ TEST(TestDecodeJVC, DecodeWithNonStrictValues) { irsend.sendJVC(0x0, 8); // Illegal value JVC 8-bit message. irsend.makeDecodeResult(); // Should fail with strict on. - ASSERT_FALSE(irrecv.decodeJVC(&irsend.capture, JVC_BITS, true)); + ASSERT_FALSE(irrecv.decodeJVC(&irsend.capture, kJvcBits, true)); // Should pass if strict off. ASSERT_TRUE(irrecv.decodeJVC(&irsend.capture, 8, false)); EXPECT_EQ(JVC, irsend.capture.decode_type); @@ -206,7 +211,7 @@ TEST(TestDecodeJVC, DecodeWithNonStrictValues) { irsend.sendJVC(0x12345678, 32); // Illegal value JVC 32-bit message. irsend.makeDecodeResult(); // Should not pass with strict when we ask for less bits than we got. - ASSERT_FALSE(irrecv.decodeJVC(&irsend.capture, JVC_BITS, true)); + ASSERT_FALSE(irrecv.decodeJVC(&irsend.capture, kJvcBits, true)); irsend.makeDecodeResult(); // Should fail with strict when we ask for the wrong bit size. @@ -225,7 +230,7 @@ TEST(TestDecodeJVC, DecodeWithNonStrictValues) { irsend.makeDecodeResult(); // Shouldn't pass if strict off and the wrong expected bits. - ASSERT_FALSE(irrecv.decodeJVC(&irsend.capture, JVC_BITS, false)); + ASSERT_FALSE(irrecv.decodeJVC(&irsend.capture, kJvcBits, false)); // Re-decode with correct bit size. ASSERT_FALSE(irrecv.decodeJVC(&irsend.capture, 36, true)); @@ -264,16 +269,17 @@ TEST(TestDecodeJVC, DecodeGlobalCacheExample) { irsend.reset(); // JVC VCR Power On from Global Cache. - uint16_t gc_test[39] = {38000, 1, 1, 322, 162, 20, 61, 20, 61, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 61, 20, 20, 20, 61, 20, 20, 20, - 61, 20, 61, 20, 61, 20, 20, 20, 20, 20, 20, 20, 884}; - // 38000,1,37,320,161,21,59,21,59,21,19,21,19,21,19,21,19,21,59,21,19,21,59,21,59,21,19,21,59,21,19,21,19,21,19,21,19,21,838,21,59,21,59,21,19,21,19,21,19,21,19,21,59,21,19,21,59,21,19,21,59,21,59,21,59,21,19,21,19,21,19,21,850}; + uint16_t gc_test[39] = {38000, 1, 1, 322, 162, 20, 61, 20, 61, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 61, 20, + 20, 20, 61, 20, 20, 20, 61, 20, 61, 20, + 61, 20, 20, 20, 20, 20, 20, 20, 884}; + // 38000,1,37,320,161,21,59,21,59,21,19,21,19,21,19,21,19,21,59,21,19,21,59,21,59,21,19,21,59,21,19,21,19,21,19,21,19,21,838,21,59,21,59,21,19,21,19,21,19,21,19,21,59,21,19,21,59,21,19,21,59,21,59,21,59,21,19,21,19,21,19,21,850}; irsend.sendGC(gc_test, 39); irsend.makeDecodeResult(); ASSERT_TRUE(irrecv.decodeJVC(&irsend.capture)); EXPECT_EQ(JVC, irsend.capture.decode_type); - EXPECT_EQ(JVC_BITS, irsend.capture.bits); + EXPECT_EQ(kJvcBits, irsend.capture.bits); EXPECT_EQ(0xC2B8, irsend.capture.value); EXPECT_EQ(0x43, irsend.capture.address); EXPECT_EQ(0x1D, irsend.capture.command); @@ -288,12 +294,13 @@ TEST(TestDecodeJVC, FailToDecodeNonJVCExample) { irsend.reset(); // Modified a few entries to unexpected values, based on previous test case. - uint16_t gc_test[39] = {38000, 1, 1, 322, 162, 20, 61, 20, 61, 20, 20, 20, 20, - 20, 20, 20, 127, 20, 61, 9, 20, 20, 61, 20, 20, 20, - 61, 20, 61, 20, 61, 20, 20, 20, 20, 20, 20, 20, 884}; + uint16_t gc_test[39] = {38000, 1, 1, 322, 162, 20, 61, 20, 61, 20, + 20, 20, 20, 20, 20, 20, 127, 20, 61, 9, + 20, 20, 61, 20, 20, 20, 61, 20, 61, 20, + 61, 20, 20, 20, 20, 20, 20, 20, 884}; irsend.sendGC(gc_test, 39); irsend.makeDecodeResult(); ASSERT_FALSE(irrecv.decodeJVC(&irsend.capture)); - ASSERT_FALSE(irrecv.decodeJVC(&irsend.capture, JVC_BITS, false)); + ASSERT_FALSE(irrecv.decodeJVC(&irsend.capture, kJvcBits, false)); } diff --git a/lib/IRremoteESP8266/test/ir_Kelvinator_test.cpp b/lib/IRremoteESP8266/test/ir_Kelvinator_test.cpp index 9ece663..001f8bc 100644 --- a/lib/IRremoteESP8266/test/ir_Kelvinator_test.cpp +++ b/lib/IRremoteESP8266/test/ir_Kelvinator_test.cpp @@ -1,11 +1,11 @@ // Copyright 2017 David Conran -#include "IRremoteESP8266.h" +#include "ir_Kelvinator.h" #include "IRrecv.h" #include "IRrecv_test.h" +#include "IRremoteESP8266.h" #include "IRsend.h" #include "IRsend_test.h" -#include "ir_Kelvinator.h" #include "gtest/gtest.h" // Tests for sendKelvinator(). @@ -15,7 +15,7 @@ TEST(TestSendKelvinator, SendDataOnly) { IRsendTest irsend(4); irsend.begin(); - uint8_t kelv_code[KELVINATOR_STATE_LENGTH] = { + uint8_t kelv_code[kKelvinatorStateLength] = { 0x19, 0x0B, 0x80, 0x50, 0x00, 0x00, 0x00, 0xE0, 0x19, 0x0B, 0x80, 0x70, 0x00, 0x00, 0x10, 0xf0}; irsend.reset(); @@ -44,7 +44,8 @@ TEST(TestSendKelvinator, SendDataOnly) { "m680s510m680s510m680s510m680s510m680s510m680s510m680s510m680s510" "m680s510m680s510m680s510m680s510m680s1530m680s510m680s510m680s510" "m680s510m680s510m680s510m680s510m680s1530m680s1530m680s1530m680s1530" - "m680s39950", irsend.outputStr()); + "m680s39950", + irsend.outputStr()); } // Test sending with repeats. @@ -53,12 +54,12 @@ TEST(TestSendKelvinator, SendWithRepeats) { irsend.begin(); irsend.reset(); - uint8_t kelv_code[KELVINATOR_STATE_LENGTH] = { + uint8_t kelv_code[kKelvinatorStateLength] = { 0x19, 0x0B, 0x80, 0x50, 0x00, 0x00, 0x00, 0xE0, 0x19, 0x0B, 0x80, 0x70, 0x00, 0x00, 0x10, 0xf0}; irsend.reset(); - irsend.sendKelvinator(kelv_code, KELVINATOR_STATE_LENGTH, 1); + irsend.sendKelvinator(kelv_code, kKelvinatorStateLength, 1); EXPECT_EQ( "m9010s4505" "m680s1530m680s510m680s510m680s1530m680s1530m680s510m680s510m680s510" @@ -107,7 +108,8 @@ TEST(TestSendKelvinator, SendWithRepeats) { "m680s510m680s510m680s510m680s510m680s510m680s510m680s510m680s510" "m680s510m680s510m680s510m680s510m680s1530m680s510m680s510m680s510" "m680s510m680s510m680s510m680s510m680s1530m680s1530m680s1530m680s1530" - "m680s39950", irsend.outputStr()); + "m680s39950", + irsend.outputStr()); } // Test sending atypical sizes. @@ -117,9 +119,9 @@ TEST(TestSendKelvinator, SendUnexpectedSizes) { uint8_t kelv_short_code[15] = {0x19, 0x0B, 0x80, 0x50, 0x00, 0x00, 0x00, 0xE0, 0x19, 0x0B, 0x80, 0x70, 0x00, 0x00, 0x10}; - uint8_t kelv_long_code[17] = {0x19, 0x0B, 0x80, 0x50, 0x00, 0x00, 0x00, 0xE0, - 0x19, 0x0B, 0x80, 0x70, 0x00, 0x00, 0x10, 0xf0, - 0x00}; + uint8_t kelv_long_code[17] = {0x19, 0x0B, 0x80, 0x50, 0x00, 0x00, + 0x00, 0xE0, 0x19, 0x0B, 0x80, 0x70, + 0x00, 0x00, 0x10, 0xf0, 0x00}; irsend.reset(); irsend.sendKelvinator(kelv_short_code, 15); ASSERT_EQ("", irsend.outputStr()); @@ -152,10 +154,10 @@ TEST(TestSendKelvinator, SendUnexpectedSizes) { "m680s510m680s510m680s510m680s510m680s510m680s510m680s510m680s510" "m680s510m680s510m680s510m680s510m680s1530m680s510m680s510m680s510" "m680s510m680s510m680s510m680s510m680s1530m680s1530m680s1530m680s1530" - "m680s39950", irsend.outputStr()); + "m680s39950", + irsend.outputStr()); } - // Tests for IRKelvinatorAC class. TEST(TestKelvinatorClass, Power) { @@ -180,22 +182,22 @@ TEST(TestKelvinatorClass, Temperature) { irkelv.begin(); irkelv.setTemp(0); - EXPECT_EQ(KELVINATOR_MIN_TEMP, irkelv.getTemp()); + EXPECT_EQ(kKelvinatorMinTemp, irkelv.getTemp()); irkelv.setTemp(255); - EXPECT_EQ(KELVINATOR_MAX_TEMP, irkelv.getTemp()); + EXPECT_EQ(kKelvinatorMaxTemp, irkelv.getTemp()); - irkelv.setTemp(KELVINATOR_MIN_TEMP); - EXPECT_EQ(KELVINATOR_MIN_TEMP, irkelv.getTemp()); + irkelv.setTemp(kKelvinatorMinTemp); + EXPECT_EQ(kKelvinatorMinTemp, irkelv.getTemp()); - irkelv.setTemp(KELVINATOR_MAX_TEMP); - EXPECT_EQ(KELVINATOR_MAX_TEMP, irkelv.getTemp()); + irkelv.setTemp(kKelvinatorMaxTemp); + EXPECT_EQ(kKelvinatorMaxTemp, irkelv.getTemp()); - irkelv.setTemp(KELVINATOR_MIN_TEMP - 1); - EXPECT_EQ(KELVINATOR_MIN_TEMP, irkelv.getTemp()); + irkelv.setTemp(kKelvinatorMinTemp - 1); + EXPECT_EQ(kKelvinatorMinTemp, irkelv.getTemp()); - irkelv.setTemp(KELVINATOR_MAX_TEMP + 1); - EXPECT_EQ(KELVINATOR_MAX_TEMP, irkelv.getTemp()); + irkelv.setTemp(kKelvinatorMaxTemp + 1); + EXPECT_EQ(kKelvinatorMaxTemp, irkelv.getTemp()); irkelv.setTemp(17); EXPECT_EQ(17, irkelv.getTemp()); @@ -215,29 +217,29 @@ TEST(TestKelvinatorClass, OperatingMode) { irkelv.begin(); irkelv.setTemp(24); - irkelv.setMode(KELVINATOR_AUTO); - EXPECT_EQ(KELVINATOR_AUTO, irkelv.getMode()); - EXPECT_EQ(KELVINATOR_AUTO_TEMP, irkelv.getTemp()); + irkelv.setMode(kKelvinatorAuto); + EXPECT_EQ(kKelvinatorAuto, irkelv.getMode()); + EXPECT_EQ(kKelvinatorAutoTemp, irkelv.getTemp()); - irkelv.setMode(KELVINATOR_COOL); - EXPECT_EQ(KELVINATOR_COOL, irkelv.getMode()); + irkelv.setMode(kKelvinatorCool); + EXPECT_EQ(kKelvinatorCool, irkelv.getMode()); - irkelv.setMode(KELVINATOR_HEAT); - EXPECT_EQ(KELVINATOR_HEAT, irkelv.getMode()); + irkelv.setMode(kKelvinatorHeat); + EXPECT_EQ(kKelvinatorHeat, irkelv.getMode()); irkelv.setTemp(24); - irkelv.setMode(KELVINATOR_DRY); - EXPECT_EQ(KELVINATOR_DRY, irkelv.getMode()); - EXPECT_EQ(KELVINATOR_AUTO_TEMP, irkelv.getTemp()); + irkelv.setMode(kKelvinatorDry); + EXPECT_EQ(kKelvinatorDry, irkelv.getMode()); + EXPECT_EQ(kKelvinatorAutoTemp, irkelv.getTemp()); - irkelv.setMode(KELVINATOR_FAN); - EXPECT_EQ(KELVINATOR_FAN, irkelv.getMode()); + irkelv.setMode(kKelvinatorFan); + EXPECT_EQ(kKelvinatorFan, irkelv.getMode()); - irkelv.setMode(KELVINATOR_HEAT + 1); - EXPECT_EQ(KELVINATOR_AUTO, irkelv.getMode()); + irkelv.setMode(kKelvinatorHeat + 1); + EXPECT_EQ(kKelvinatorAuto, irkelv.getMode()); irkelv.setMode(255); - EXPECT_EQ(KELVINATOR_AUTO, irkelv.getMode()); + EXPECT_EQ(kKelvinatorAuto, irkelv.getMode()); } TEST(TestKelvinatorClass, VaneSwing) { @@ -352,16 +354,16 @@ TEST(TestKelvinatorClass, FanSpeed) { EXPECT_EQ(0, irkelv.getFan()); irkelv.setFan(255); - EXPECT_EQ(KELVINATOR_FAN_MAX, irkelv.getFan()); + EXPECT_EQ(kKelvinatorFanMax, irkelv.getFan()); - irkelv.setFan(KELVINATOR_FAN_MAX); - EXPECT_EQ(KELVINATOR_FAN_MAX, irkelv.getFan()); + irkelv.setFan(kKelvinatorFanMax); + EXPECT_EQ(kKelvinatorFanMax, irkelv.getFan()); - irkelv.setFan(KELVINATOR_FAN_MAX + 1); - EXPECT_EQ(KELVINATOR_FAN_MAX, irkelv.getFan()); + irkelv.setFan(kKelvinatorFanMax + 1); + EXPECT_EQ(kKelvinatorFanMax, irkelv.getFan()); - irkelv.setFan(KELVINATOR_FAN_MAX - 1); - EXPECT_EQ(KELVINATOR_FAN_MAX - 1, irkelv.getFan()); + irkelv.setFan(kKelvinatorFanMax - 1); + EXPECT_EQ(kKelvinatorFanMax - 1, irkelv.getFan()); irkelv.setFan(1); EXPECT_EQ(1, irkelv.getFan()); @@ -374,7 +376,7 @@ TEST(TestKelvinatorClass, FanSpeed) { } TEST(TestKelvinatorClass, Checksums) { - uint8_t kelv_code[KELVINATOR_STATE_LENGTH] = { + uint8_t kelv_code[kKelvinatorStateLength] = { 0x19, 0x0B, 0x80, 0x50, 0x00, 0x00, 0x00, 0xE0, 0x19, 0x0B, 0x80, 0x70, 0x00, 0x00, 0x10, 0xf0}; @@ -396,42 +398,44 @@ TEST(TestKelvinatorClass, Checksums) { TEST(TestKelvinatorClass, SetAndGetRaw) { IRKelvinatorAC irkelv(0); - uint8_t initialState[KELVINATOR_STATE_LENGTH] = { + uint8_t initialState[kKelvinatorStateLength] = { 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0xA0, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0xA0}; - uint8_t expectedState[KELVINATOR_STATE_LENGTH] = { + uint8_t expectedState[kKelvinatorStateLength] = { 0x08, 0x05, 0x20, 0x50, 0x00, 0x00, 0x00, 0x70, 0x08, 0x05, 0x20, 0x70, 0x00, 0x00, 0x00, 0x70}; - EXPECT_STATE_EQ(initialState, irkelv.getRaw(), KELVINATOR_BITS); + EXPECT_STATE_EQ(initialState, irkelv.getRaw(), kKelvinatorBits); // toggle the power state. irkelv.setPower(!irkelv.getPower()); irkelv.setTemp(21); irkelv.setLight(true); - EXPECT_STATE_EQ(expectedState, irkelv.getRaw(), KELVINATOR_BITS); + EXPECT_STATE_EQ(expectedState, irkelv.getRaw(), kKelvinatorBits); irkelv.setRaw(initialState); - EXPECT_STATE_EQ(initialState, irkelv.getRaw(), KELVINATOR_BITS); + EXPECT_STATE_EQ(initialState, irkelv.getRaw(), kKelvinatorBits); } TEST(TestKelvinatorClass, HumanReadable) { IRKelvinatorAC irkelv(0); - EXPECT_EQ("Power: Off, Mode: 0 (AUTO), Temp: 16C, Fan: 0 (AUTO), Turbo: Off, " - "Quiet: Off, XFan: Off, IonFilter: Off, Light: Off, " - "Swing (Horizontal): Off, Swing (Vertical): Off", - irkelv.toString()); + EXPECT_EQ( + "Power: Off, Mode: 0 (AUTO), Temp: 16C, Fan: 0 (AUTO), Turbo: Off, " + "Quiet: Off, XFan: Off, IonFilter: Off, Light: Off, " + "Swing (Horizontal): Off, Swing (Vertical): Off", + irkelv.toString()); irkelv.on(); - irkelv.setMode(KELVINATOR_COOL); + irkelv.setMode(kKelvinatorCool); irkelv.setTemp(25); - irkelv.setFan(KELVINATOR_FAN_MAX); + irkelv.setFan(kKelvinatorFanMax); irkelv.setXFan(true); irkelv.setIonFilter(true); irkelv.setLight(true); irkelv.setSwingHorizontal(true); - EXPECT_EQ("Power: On, Mode: 1 (COOL), Temp: 25C, Fan: 5 (MAX), Turbo: Off, " - "Quiet: Off, XFan: On, IonFilter: On, Light: On, " - "Swing (Horizontal): On, Swing (Vertical): Off", - irkelv.toString()); + EXPECT_EQ( + "Power: On, Mode: 1 (COOL), Temp: 25C, Fan: 5 (MAX), Turbo: Off, " + "Quiet: Off, XFan: On, IonFilter: On, Light: On, " + "Swing (Horizontal): On, Swing (Vertical): Off", + irkelv.toString()); } TEST(TestKelvinatorClass, MessageConstuction) { @@ -441,7 +445,7 @@ TEST(TestKelvinatorClass, MessageConstuction) { irsend.begin(); irkelv.setFan(1); - irkelv.setMode(KELVINATOR_COOL); + irkelv.setMode(kKelvinatorCool); irkelv.setTemp(27); irkelv.setSwingVertical(false); irkelv.setSwingHorizontal(true); @@ -454,7 +458,7 @@ TEST(TestKelvinatorClass, MessageConstuction) { // Check everything for kicks. EXPECT_EQ(1, irkelv.getFan()); - EXPECT_EQ(KELVINATOR_COOL, irkelv.getMode()); + EXPECT_EQ(kKelvinatorCool, irkelv.getMode()); EXPECT_EQ(27, irkelv.getTemp()); EXPECT_FALSE(irkelv.getSwingVertical()); EXPECT_TRUE(irkelv.getSwingHorizontal()); @@ -491,7 +495,8 @@ TEST(TestKelvinatorClass, MessageConstuction) { "m680s510m680s510m680s510m680s510m680s510m680s510m680s510m680s510" "m680s510m680s510m680s510m680s510m680s1530m680s510m680s510m680s510" "m680s510m680s510m680s510m680s510m680s1530m680s1530m680s1530m680s1530" - "m680s39950", irsend.outputStr()); + "m680s39950", + irsend.outputStr()); } // Decode a synthetic Kelvinator message. @@ -500,7 +505,7 @@ TEST(TestDecodeKelvinator, NormalSynthetic) { IRrecv irrecv(4); irsend.begin(); - uint8_t kelv_code[KELVINATOR_STATE_LENGTH] = { + uint8_t kelv_code[kKelvinatorStateLength] = { 0x19, 0x0B, 0x80, 0x50, 0x00, 0x00, 0x00, 0xE0, 0x19, 0x0B, 0x80, 0x70, 0x00, 0x00, 0x10, 0xf0}; irsend.reset(); @@ -508,6 +513,6 @@ TEST(TestDecodeKelvinator, NormalSynthetic) { irsend.makeDecodeResult(); EXPECT_TRUE(irrecv.decode(&irsend.capture)); EXPECT_EQ(KELVINATOR, irsend.capture.decode_type); - ASSERT_EQ(KELVINATOR_BITS, irsend.capture.bits); - EXPECT_STATE_EQ(kelv_code, irsend.capture.state, KELVINATOR_BITS); + ASSERT_EQ(kKelvinatorBits, irsend.capture.bits); + EXPECT_STATE_EQ(kelv_code, irsend.capture.state, kKelvinatorBits); } diff --git a/lib/IRremoteESP8266/test/ir_LG_test.cpp b/lib/IRremoteESP8266/test/ir_LG_test.cpp index 19a93c9..8ab24a7 100644 --- a/lib/IRremoteESP8266/test/ir_LG_test.cpp +++ b/lib/IRremoteESP8266/test/ir_LG_test.cpp @@ -1,8 +1,8 @@ // Copyright 2017 David Conran +#include "ir_LG.h" #include "IRsend.h" #include "IRsend_test.h" -#include "ir_LG.h" #include "gtest/gtest.h" // Tests for calcLGChecksum() @@ -30,15 +30,16 @@ TEST(TestSendLG, SendDataOnly) { irsend.reset(); irsend.sendLG(0x4B4AE51); EXPECT_EQ( - "m8000s4000" + "m8500s4250" "m550s550m550s1600m550s550m550s550" "m550s1600m550s550m550s1600m550s1600m550s550m550s1600m550s550m550s550" "m550s1600m550s550m550s1600m550s550m550s1600m550s1600m550s1600m550s550" "m550s550m550s1600m550s550m550s1600m550s550m550s550m550s550m550s1600" - "m550s51050", irsend.outputStr()); + "m550s50300", + irsend.outputStr()); irsend.reset(); - irsend.sendLG(0xB4B4AE51, LG32_BITS); + irsend.sendLG(0xB4B4AE51, kLg32Bits); EXPECT_EQ( "m4480s4480" "m560s1680m560s560m560s1680m560s1680m560s560m560s1680m560s560m560s560" @@ -46,7 +47,8 @@ TEST(TestSendLG, SendDataOnly) { "m560s1680m560s560m560s1680m560s560m560s1680m560s1680m560s1680m560s560" "m560s560m560s1680m560s560m560s1680m560s560m560s560m560s560m560s1680" "m560s44800" - "m8950s2250m550s96300", irsend.outputStr()); + "m8950s2250m550s96300", + irsend.outputStr()); } // Test sending with different repeats. @@ -55,18 +57,19 @@ TEST(TestSendLG, SendWithRepeats) { irsend.begin(); irsend.reset(); - irsend.sendLG(0x4B4AE51, LG_BITS, 1); + irsend.sendLG(0x4B4AE51, kLgBits, 1); EXPECT_EQ( - "m8000s4000" + "m8500s4250" "m550s550m550s1600m550s550m550s550" "m550s1600m550s550m550s1600m550s1600m550s550m550s1600m550s550m550s550" "m550s1600m550s550m550s1600m550s550m550s1600m550s1600m550s1600m550s550" "m550s550m550s1600m550s550m550s1600m550s550m550s550m550s550m550s1600" - "m550s51050" - "m8000s2250m550s97250", irsend.outputStr()); + "m550s50300" + "m8500s2250m550s96750", + irsend.outputStr()); irsend.reset(); - irsend.sendLG(0xB4B4AE51, LG32_BITS, 1); + irsend.sendLG(0xB4B4AE51, kLg32Bits, 1); EXPECT_EQ( "m4480s4480" "m560s1680m560s560m560s1680m560s1680m560s560m560s1680m560s560m560s560" @@ -75,7 +78,8 @@ TEST(TestSendLG, SendWithRepeats) { "m560s560m560s1680m560s560m560s1680m560s560m560s560m560s560m560s1680" "m560s44800" "m8950s2250m550s96300" - "m8950s2250m550s96300", irsend.outputStr()); + "m8950s2250m550s96300", + irsend.outputStr()); } // Test sending an atypical data size. @@ -86,12 +90,13 @@ TEST(TestSendLG, SendUnusualSize) { irsend.reset(); irsend.sendLG(0x0, 31); EXPECT_EQ( - "m8000s4000" + "m8500s4250" "m550s550m550s550m550s550m550s550m550s550m550s550m550s550m550s550" "m550s550m550s550m550s550m550s550m550s550m550s550m550s550m550s550" "m550s550m550s550m550s550m550s550m550s550m550s550m550s550m550s550" "m550s550m550s550m550s550m550s550m550s550m550s550m550s550" - "m550s61400", irsend.outputStr()); + "m550s60650", + irsend.outputStr()); irsend.reset(); irsend.sendLG(0x0, 64); @@ -106,7 +111,8 @@ TEST(TestSendLG, SendUnusualSize) { "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560" "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560" "m560s26880" - "m8950s2250m550s96300", irsend.outputStr()); + "m8950s2250m550s96300", + irsend.outputStr()); } // Tests for encodeLG(). @@ -132,11 +138,11 @@ TEST(TestDecodeLG, NormalDecodeWithStrict) { // Normal LG 28-bit message. irsend.reset(); - irsend.sendLG(0x4B4AE51, LG_BITS); + irsend.sendLG(0x4B4AE51, kLgBits); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodeLG(&irsend.capture, LG_BITS, true)); + ASSERT_TRUE(irrecv.decodeLG(&irsend.capture, kLgBits, true)); EXPECT_EQ(LG, irsend.capture.decode_type); - EXPECT_EQ(LG_BITS, irsend.capture.bits); + EXPECT_EQ(kLgBits, irsend.capture.bits); EXPECT_EQ(0x4B4AE51, irsend.capture.value); EXPECT_EQ(0x4B, irsend.capture.address); EXPECT_EQ(0x4AE5, irsend.capture.command); @@ -144,11 +150,11 @@ TEST(TestDecodeLG, NormalDecodeWithStrict) { // Normal LG 32-bit message. irsend.reset(); - irsend.sendLG(0xB4B4AE51, LG32_BITS); + irsend.sendLG(0xB4B4AE51, kLg32Bits); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodeLG(&irsend.capture, LG32_BITS, false)); + ASSERT_TRUE(irrecv.decodeLG(&irsend.capture, kLg32Bits, false)); EXPECT_EQ(LG, irsend.capture.decode_type); - EXPECT_EQ(LG32_BITS, irsend.capture.bits); + EXPECT_EQ(kLg32Bits, irsend.capture.bits); EXPECT_EQ(0xB4B4AE51, irsend.capture.value); EXPECT_EQ(0xB4B, irsend.capture.address); EXPECT_EQ(0x4AE5, irsend.capture.command); @@ -158,9 +164,9 @@ TEST(TestDecodeLG, NormalDecodeWithStrict) { irsend.reset(); irsend.sendLG(irsend.encodeLG(0x07, 0x99)); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodeLG(&irsend.capture, LG_BITS, true)); + ASSERT_TRUE(irrecv.decodeLG(&irsend.capture, kLgBits, true)); EXPECT_EQ(LG, irsend.capture.decode_type); - EXPECT_EQ(LG_BITS, irsend.capture.bits); + EXPECT_EQ(kLgBits, irsend.capture.bits); EXPECT_EQ(0x700992, irsend.capture.value); EXPECT_EQ(0x07, irsend.capture.address); EXPECT_EQ(0x99, irsend.capture.command); @@ -168,11 +174,11 @@ TEST(TestDecodeLG, NormalDecodeWithStrict) { // Synthesised Normal LG 32-bit message. irsend.reset(); - irsend.sendLG(irsend.encodeLG(0x800, 0x8000), LG32_BITS); + irsend.sendLG(irsend.encodeLG(0x800, 0x8000), kLg32Bits); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodeLG(&irsend.capture, LG32_BITS, true)); + ASSERT_TRUE(irrecv.decodeLG(&irsend.capture, kLg32Bits, true)); EXPECT_EQ(LG, irsend.capture.decode_type); - EXPECT_EQ(LG32_BITS, irsend.capture.bits); + EXPECT_EQ(kLg32Bits, irsend.capture.bits); EXPECT_EQ(0x80080008, irsend.capture.value); EXPECT_EQ(0x800, irsend.capture.address); EXPECT_EQ(0x8000, irsend.capture.command); @@ -187,11 +193,11 @@ TEST(TestDecodeLG, NormalDecodeWithRepeatAndStrict) { // Normal LG 28-bit message with 2 repeats. irsend.reset(); - irsend.sendLG(irsend.encodeLG(0x07, 0x99), LG_BITS, 2); + irsend.sendLG(irsend.encodeLG(0x07, 0x99), kLgBits, 2); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodeLG(&irsend.capture, LG_BITS, true)); + ASSERT_TRUE(irrecv.decodeLG(&irsend.capture, kLgBits, true)); EXPECT_EQ(LG, irsend.capture.decode_type); - EXPECT_EQ(LG_BITS, irsend.capture.bits); + EXPECT_EQ(kLgBits, irsend.capture.bits); EXPECT_EQ(0x700992, irsend.capture.value); EXPECT_EQ(0x07, irsend.capture.address); EXPECT_EQ(0x99, irsend.capture.command); @@ -199,11 +205,11 @@ TEST(TestDecodeLG, NormalDecodeWithRepeatAndStrict) { // Normal LG 32-bit message with 2 repeats. irsend.reset(); - irsend.sendLG(irsend.encodeLG(0x07, 0x99), LG32_BITS, 2); + irsend.sendLG(irsend.encodeLG(0x07, 0x99), kLg32Bits, 2); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodeLG(&irsend.capture, LG32_BITS, true)); + ASSERT_TRUE(irrecv.decodeLG(&irsend.capture, kLg32Bits, true)); EXPECT_EQ(LG, irsend.capture.decode_type); - EXPECT_EQ(LG32_BITS, irsend.capture.bits); + EXPECT_EQ(kLg32Bits, irsend.capture.bits); EXPECT_EQ(0x700992, irsend.capture.value); EXPECT_EQ(0x07, irsend.capture.address); EXPECT_EQ(0x99, irsend.capture.command); @@ -221,30 +227,30 @@ TEST(TestDecodeLG, DecodeWithNonStrictValues) { irsend.reset(); irsend.sendLG(0x1); irsend.makeDecodeResult(); - ASSERT_FALSE(irrecv.decodeLG(&irsend.capture, LG_BITS, true)); - ASSERT_FALSE(irrecv.decodeLG(&irsend.capture, LG32_BITS, true)); - ASSERT_FALSE(irrecv.decodeLG(&irsend.capture, LG32_BITS, false)); - ASSERT_TRUE(irrecv.decodeLG(&irsend.capture, LG_BITS, false)); + ASSERT_FALSE(irrecv.decodeLG(&irsend.capture, kLgBits, true)); + ASSERT_FALSE(irrecv.decodeLG(&irsend.capture, kLg32Bits, true)); + ASSERT_FALSE(irrecv.decodeLG(&irsend.capture, kLg32Bits, false)); + ASSERT_TRUE(irrecv.decodeLG(&irsend.capture, kLgBits, false)); // Illegal LG 32-bit message value. irsend.reset(); - irsend.sendLG(0x1111111, LG32_BITS); + irsend.sendLG(0x1111111, kLg32Bits); irsend.makeDecodeResult(); - ASSERT_FALSE(irrecv.decodeLG(&irsend.capture, LG32_BITS, true)); - ASSERT_FALSE(irrecv.decodeLG(&irsend.capture, LG_BITS, true)); + ASSERT_FALSE(irrecv.decodeLG(&irsend.capture, kLg32Bits, true)); + ASSERT_FALSE(irrecv.decodeLG(&irsend.capture, kLgBits, true)); - ASSERT_TRUE(irrecv.decodeLG(&irsend.capture, LG32_BITS, false)); + ASSERT_TRUE(irrecv.decodeLG(&irsend.capture, kLg32Bits, false)); EXPECT_EQ(LG, irsend.capture.decode_type); - EXPECT_EQ(LG32_BITS, irsend.capture.bits); + EXPECT_EQ(kLg32Bits, irsend.capture.bits); EXPECT_EQ(0x1111111, irsend.capture.value); EXPECT_EQ(0x11, irsend.capture.address); EXPECT_EQ(0x1111, irsend.capture.command); EXPECT_FALSE(irsend.capture.repeat); irsend.reset(); - irsend.sendLG(0x1111111, LG32_BITS); + irsend.sendLG(0x1111111, kLg32Bits); irsend.makeDecodeResult(); - ASSERT_FALSE(irrecv.decodeLG(&irsend.capture, LG_BITS, false)); + ASSERT_FALSE(irrecv.decodeLG(&irsend.capture, kLgBits, false)); } // Decode unsupported LG message sizes. @@ -259,10 +265,10 @@ TEST(TestDecodeLG, DecodeWithNonStrictSizes) { irsend.sendLG(irsend.encodeLG(0x07, 0x99), 16); irsend.makeDecodeResult(); // Should fail when unexpected against different bit sizes. - ASSERT_FALSE(irrecv.decodeLG(&irsend.capture, LG_BITS, true)); - ASSERT_FALSE(irrecv.decodeLG(&irsend.capture, LG32_BITS, true)); - ASSERT_FALSE(irrecv.decodeLG(&irsend.capture, LG_BITS, false)); - ASSERT_FALSE(irrecv.decodeLG(&irsend.capture, LG32_BITS, false)); + ASSERT_FALSE(irrecv.decodeLG(&irsend.capture, kLgBits, true)); + ASSERT_FALSE(irrecv.decodeLG(&irsend.capture, kLg32Bits, true)); + ASSERT_FALSE(irrecv.decodeLG(&irsend.capture, kLgBits, false)); + ASSERT_FALSE(irrecv.decodeLG(&irsend.capture, kLg32Bits, false)); // Should pass if strict off. ASSERT_TRUE(irrecv.decodeLG(&irsend.capture, 16, false)); @@ -277,10 +283,10 @@ TEST(TestDecodeLG, DecodeWithNonStrictSizes) { irsend.sendLG(0x123456789, 36); // Illegal value LG 36-bit message. irsend.makeDecodeResult(); // Should fail when unexpected against different bit sizes. - ASSERT_FALSE(irrecv.decodeLG(&irsend.capture, LG_BITS, true)); - ASSERT_FALSE(irrecv.decodeLG(&irsend.capture, LG_BITS, false)); - ASSERT_FALSE(irrecv.decodeLG(&irsend.capture, LG32_BITS, true)); - ASSERT_FALSE(irrecv.decodeLG(&irsend.capture, LG32_BITS, false)); + ASSERT_FALSE(irrecv.decodeLG(&irsend.capture, kLgBits, true)); + ASSERT_FALSE(irrecv.decodeLG(&irsend.capture, kLgBits, false)); + ASSERT_FALSE(irrecv.decodeLG(&irsend.capture, kLg32Bits, true)); + ASSERT_FALSE(irrecv.decodeLG(&irsend.capture, kLg32Bits, false)); ASSERT_TRUE(irrecv.decodeLG(&irsend.capture, 36, false)); EXPECT_EQ(LG, irsend.capture.decode_type); @@ -317,22 +323,21 @@ TEST(TestDecodeLG, DecodeGlobalCacheExample) { IRrecv irrecv(4); irsend.begin(); -// TODO(anyone): Find a Global Cache example of the LG 28-bit message. + // TODO(anyone): Find a Global Cache example of the LG 28-bit message. irsend.reset(); // LG (32-bit) code from Global Cache. - uint16_t gc_test[75] = {38000, 1, 69, 341, 170, 21, 64, 21, 21, 21, 64, - 21, 64, 21, 21, 21, 64, 21, 21, 21, 21, 21, 64, - 21, 21, 21, 64, 21, 64, 21, 21, 21, 64, 21, 21, - 21, 21, 21, 64, 21, 21, 21, 64, 21, 21, 21, 64, - 21, 64, 21, 64, 21, 21, 21, 21, 21, 64, 21, 21, - 21, 64, 21, 21, 21, 21, 21, 21, 21, 64, 21, 1517, - 341, 85, 21, 3655}; + uint16_t gc_test[75] = { + 38000, 1, 69, 341, 170, 21, 64, 21, 21, 21, 64, 21, 64, 21, 21, + 21, 64, 21, 21, 21, 21, 21, 64, 21, 21, 21, 64, 21, 64, 21, + 21, 21, 64, 21, 21, 21, 21, 21, 64, 21, 21, 21, 64, 21, 21, + 21, 64, 21, 64, 21, 64, 21, 21, 21, 21, 21, 64, 21, 21, 21, + 64, 21, 21, 21, 21, 21, 21, 21, 64, 21, 1517, 341, 85, 21, 3655}; irsend.sendGC(gc_test, 75); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodeLG(&irsend.capture, LG32_BITS, true)); + ASSERT_TRUE(irrecv.decodeLG(&irsend.capture, kLg32Bits, true)); EXPECT_EQ(LG, irsend.capture.decode_type); - EXPECT_EQ(LG32_BITS, irsend.capture.bits); + EXPECT_EQ(kLg32Bits, irsend.capture.bits); EXPECT_EQ(0xB4B4AE51, irsend.capture.value); EXPECT_EQ(0xB4B, irsend.capture.address); EXPECT_EQ(0x4AE5, irsend.capture.command); @@ -347,12 +352,71 @@ TEST(TestDecodeLG, FailToDecodeNonLGExample) { irsend.reset(); // Modified a few entries to unexpected values, based on previous test case. - uint16_t gc_test[39] = {38000, 1, 1, 322, 162, 20, 61, 20, 61, 20, 20, 20, 20, - 20, 20, 20, 127, 20, 61, 9, 20, 20, 61, 20, 20, 20, - 61, 20, 61, 20, 61, 20, 20, 20, 20, 20, 20, 20, 884}; + uint16_t gc_test[39] = {38000, 1, 1, 322, 162, 20, 61, 20, 61, 20, + 20, 20, 20, 20, 20, 20, 127, 20, 61, 9, + 20, 20, 61, 20, 20, 20, 61, 20, 61, 20, + 61, 20, 20, 20, 20, 20, 20, 20, 884}; irsend.sendGC(gc_test, 39); irsend.makeDecodeResult(); ASSERT_FALSE(irrecv.decodeLG(&irsend.capture)); - ASSERT_FALSE(irrecv.decodeLG(&irsend.capture, LG_BITS, false)); + ASSERT_FALSE(irrecv.decodeLG(&irsend.capture, kLgBits, false)); +} + +// Tests for sendLG2(). + +// Test sending typical data only. +TEST(TestSendLG2, SendDataOnly) { + IRsendTest irsend(0); + irsend.begin(); + + irsend.reset(); + irsend.sendLG2(0x880094D); + EXPECT_EQ( + "m3200s9850" + "m550s1600m550s550m550s550m550s550m550s1600m550s550m550s550m550s550" + "m550s550m550s550m550s550m550s550m550s550m550s550m550s550m550s550" + "m550s1600m550s550m550s550m550s1600m550s550m550s1600m550s550m550s550" + "m550s1600m550s1600m550s550m550s1600" + "m550s55250", + irsend.outputStr()); +} + +TEST(TestDecodeLG2, SyntheticExample) { + IRsendTest irsend(0); + IRrecv irrecv(0); + irsend.begin(); + + irsend.reset(); + irsend.sendLG2(0x880094D); + irsend.makeDecodeResult(); + + ASSERT_TRUE(irrecv.decodeLG(&irsend.capture)); + ASSERT_EQ(LG2, irsend.capture.decode_type); + EXPECT_EQ(kLgBits, irsend.capture.bits); + EXPECT_EQ(0x880094D, irsend.capture.value); +} + +// Verify decoding of LG variant 2 messages. +TEST(TestDecodeLG2, RealLG2Example) { + IRsendTest irsend(0); + IRrecv irrecv(0); + irsend.begin(); + + irsend.reset(); + // From issue #548 + uint16_t rawData[59] = { + 3154, 9834, 520, 1634, 424, 606, 424, 568, 462, 570, 462, 1564, + 508, 568, 458, 544, 500, 546, 508, 530, 508, 532, 506, 566, + 464, 568, 460, 578, 464, 568, 464, 532, 506, 552, 474, 1592, + 506, 568, 460, 570, 462, 1564, 506, 606, 424, 1640, 424, 616, + 422, 570, 462, 1616, 460, 1584, 500, 544, 506, 1598, 490}; // UNKNOWN + // F6D13AE8 + irsend.sendRaw(rawData, 59, 38000); + irsend.makeDecodeResult(); + + ASSERT_TRUE(irrecv.decodeLG(&irsend.capture)); + ASSERT_EQ(LG2, irsend.capture.decode_type); + EXPECT_EQ(kLgBits, irsend.capture.bits); + EXPECT_EQ(0x880094D, irsend.capture.value); } diff --git a/lib/IRremoteESP8266/test/ir_Lasertag_test.cpp b/lib/IRremoteESP8266/test/ir_Lasertag_test.cpp index 8bcb88f..041109f 100644 --- a/lib/IRremoteESP8266/test/ir_Lasertag_test.cpp +++ b/lib/IRremoteESP8266/test/ir_Lasertag_test.cpp @@ -10,7 +10,6 @@ // LL AAAAAAA SS EE RR RR TTT AAAAAAA GG GG // LLLLLLL AA AA SSSSS EEEEEEE RR RR TTT AA AA GGGGGG - // Tests for sendLasertag(). // Test sending simplest case data only. @@ -22,31 +21,34 @@ TEST(TestSendLasertag, SendDataOnly) { irsend.sendLasertag(0x1); // Red 1 EXPECT_EQ( "m333s333m333s333m333s333m333s333m333s333m333s333m333s333m333s333m333" - "s333m333s333m333s333m333s666m333s100000", irsend.outputStr()); + "s333m333s333m333s333m333s666m333s100000", + irsend.outputStr()); irsend.reset(); irsend.sendLasertag(0x2); // Red 2 EXPECT_EQ( "m333s333m333s333m333s333m333s333m333s333m333s333m333s333" - "m333s333m333s333m333s333m333s666m666s100333", irsend.outputStr()); + "m333s333m333s333m333s333m333s666m666s100333", + irsend.outputStr()); irsend.reset(); irsend.sendLasertag(0x51); // Green 1 // Raw: (21) // m364s364m332s336m384s276m332s364m332s304m416s584m692s724m640s360m304s332m392s612m380, EXPECT_EQ( - // m364s364m332s336m384s276m332s364m332s304m416s584 - // m692s724m640s360m304s332m392s612m380 + // m364s364m332s336m384s276m332s364m332s304m416s584 + // m692s724m640s360m304s332m392s612m380 "m333s333m333s333m333s333m333s333m333s333m333s666" - "m666s666m666s333m333s333m333s666m333s100000", irsend.outputStr()); + "m666s666m666s333m333s333m333s666m333s100000", + irsend.outputStr()); irsend.reset(); // Raw: (19) // m332s308m412s280m360s336m332s304m444s248m332s644m744s612m696s692m668s636m360 irsend.sendLasertag(0x55); // Green 5 EXPECT_EQ( - // m332s308m412s280m360s336m332s304m444s248m332s644 - // m744s612m696s692m668s636m360 + // m332s308m412s280m360s336m332s304m444s248m332s644 + // m744s612m696s692m668s636m360 "m333s333m333s333m333s333m333s333m333s333m333s666" "m666s666m666s666m666s666m333s100000", irsend.outputStr()); @@ -57,22 +59,24 @@ TEST(TestSendLasertag, SendDataWithRepeat) { irsend.begin(); irsend.reset(); - irsend.sendLasertag(0x1, LASERTAG_BITS, 1); // Red 1, one repeat. + irsend.sendLasertag(0x1, kLasertagBits, 1); // Red 1, one repeat. EXPECT_EQ( "m333s333m333s333m333s333m333s333m333s333m333s333m333s333m333s333" "m333s333m333s333m333s333m333s666m333s100000" "m333s333m333s333m333s333m333s333m333s333m333s333m333s333m333s333" - "m333s333m333s333m333s333m333s666m333s100000", irsend.outputStr()); + "m333s333m333s333m333s333m333s666m333s100000", + irsend.outputStr()); irsend.reset(); - irsend.sendLasertag(0x52, LASERTAG_BITS, 2); // Green 2, two repeats. + irsend.sendLasertag(0x52, kLasertagBits, 2); // Green 2, two repeats. EXPECT_EQ( "m333s333m333s333m333s333m333s333m333s333m333s666m666s666m666s333" "m333s666m666s100333" "m333s333m333s333m333s333m333s333m333s333m333s666m666s666m666s333" "m333s666m666s100333" "m333s333m333s333m333s333m333s333m333s333m333s666m666s666m666s333" - "m333s666m666s100333", irsend.outputStr()); + "m333s666m666s100333", + irsend.outputStr()); } TEST(TestSendLasertag, SmallestMessageSize) { @@ -100,7 +104,7 @@ TEST(TestDecodeLasertag, NormalSyntheticDecodeWithStrict) { irsend.makeDecodeResult(); ASSERT_TRUE(irrecv.decode(&irsend.capture)); EXPECT_EQ(LASERTAG, irsend.capture.decode_type); - EXPECT_EQ(LASERTAG_BITS, irsend.capture.bits); + EXPECT_EQ(kLasertagBits, irsend.capture.bits); EXPECT_EQ(0x01, irsend.capture.value); EXPECT_EQ(0x1, irsend.capture.address); // Unit 1 EXPECT_EQ(0x0, irsend.capture.command); // Team Red @@ -111,7 +115,7 @@ TEST(TestDecodeLasertag, NormalSyntheticDecodeWithStrict) { irsend.makeDecodeResult(); ASSERT_TRUE(irrecv.decode(&irsend.capture)); EXPECT_EQ(LASERTAG, irsend.capture.decode_type); - EXPECT_EQ(LASERTAG_BITS, irsend.capture.bits); + EXPECT_EQ(kLasertagBits, irsend.capture.bits); EXPECT_EQ(0x02, irsend.capture.value); EXPECT_EQ(0x2, irsend.capture.address); // Unit 2 EXPECT_EQ(0x0, irsend.capture.command); // Team Red @@ -122,7 +126,7 @@ TEST(TestDecodeLasertag, NormalSyntheticDecodeWithStrict) { irsend.makeDecodeResult(); ASSERT_TRUE(irrecv.decode(&irsend.capture)); EXPECT_EQ(LASERTAG, irsend.capture.decode_type); - EXPECT_EQ(LASERTAG_BITS, irsend.capture.bits); + EXPECT_EQ(kLasertagBits, irsend.capture.bits); EXPECT_EQ(0x06, irsend.capture.value); EXPECT_EQ(0x6, irsend.capture.address); // Unit 6 EXPECT_EQ(0x0, irsend.capture.command); // Team Red @@ -133,7 +137,7 @@ TEST(TestDecodeLasertag, NormalSyntheticDecodeWithStrict) { irsend.makeDecodeResult(); ASSERT_TRUE(irrecv.decode(&irsend.capture)); EXPECT_EQ(LASERTAG, irsend.capture.decode_type); - EXPECT_EQ(LASERTAG_BITS, irsend.capture.bits); + EXPECT_EQ(kLasertagBits, irsend.capture.bits); EXPECT_EQ(0x51, irsend.capture.value); EXPECT_EQ(0x1, irsend.capture.address); // Unit 1 EXPECT_EQ(0x5, irsend.capture.command); // Team Green @@ -144,7 +148,7 @@ TEST(TestDecodeLasertag, NormalSyntheticDecodeWithStrict) { irsend.makeDecodeResult(); ASSERT_TRUE(irrecv.decode(&irsend.capture)); EXPECT_EQ(LASERTAG, irsend.capture.decode_type); - EXPECT_EQ(LASERTAG_BITS, irsend.capture.bits); + EXPECT_EQ(kLasertagBits, irsend.capture.bits); EXPECT_EQ(0x56, irsend.capture.value); EXPECT_EQ(0x6, irsend.capture.address); // Unit EXPECT_EQ(0x5, irsend.capture.command); // Team @@ -158,183 +162,180 @@ TEST(TestDecodeLasertag, RealExamples) { irsend.begin(); irsend.reset(); - uint16_t green3[21] = { - 360, 364, 272, 360, 420, 248, 360, 360, 332, 308, 388, 612, 692, 696, - 636, 360, 332, 700, 300, 308, 416}; + uint16_t green3[21] = {360, 364, 272, 360, 420, 248, 360, 360, 332, 308, 388, + 612, 692, 696, 636, 360, 332, 700, 300, 308, 416}; irsend.sendRaw(green3, 21, 36000); irsend.makeDecodeResult(); ASSERT_TRUE(irrecv.decode(&irsend.capture)); EXPECT_EQ(LASERTAG, irsend.capture.decode_type); - EXPECT_EQ(LASERTAG_BITS, irsend.capture.bits); + EXPECT_EQ(kLasertagBits, irsend.capture.bits); EXPECT_EQ(0x53, irsend.capture.value); EXPECT_EQ(0x3, irsend.capture.address); // Unit EXPECT_EQ(0x5, irsend.capture.command); // Team irsend.reset(); - uint16_t green1[21] = { - 364, 364, 332, 336, 384, 276, 332, 364, 332, 304, 416, 584, 692, 724, - 640, 360, 304, 332, 392, 612, 380}; + uint16_t green1[21] = {364, 364, 332, 336, 384, 276, 332, 364, 332, 304, 416, + 584, 692, 724, 640, 360, 304, 332, 392, 612, 380}; irsend.sendRaw(green1, 21, 36000); irsend.makeDecodeResult(); ASSERT_TRUE(irrecv.decode(&irsend.capture)); EXPECT_EQ(LASERTAG, irsend.capture.decode_type); - EXPECT_EQ(LASERTAG_BITS, irsend.capture.bits); + EXPECT_EQ(kLasertagBits, irsend.capture.bits); EXPECT_EQ(0x51, irsend.capture.value); EXPECT_EQ(0x1, irsend.capture.address); // Unit EXPECT_EQ(0x5, irsend.capture.command); // Team irsend.reset(); - uint16_t green4[19] = { - 336, 304, 412, 280, 360, 360, 304, 308, 420, 276, 332, 636, 744, 620, - 688, 724, 640, 360, 304}; + uint16_t green4[19] = {336, 304, 412, 280, 360, 360, 304, 308, 420, 276, + 332, 636, 744, 620, 688, 724, 640, 360, 304}; irsend.sendRaw(green4, 19, 36000); irsend.makeDecodeResult(); ASSERT_TRUE(irrecv.decode(&irsend.capture)); EXPECT_EQ(LASERTAG, irsend.capture.decode_type); - EXPECT_EQ(LASERTAG_BITS, irsend.capture.bits); + EXPECT_EQ(kLasertagBits, irsend.capture.bits); EXPECT_EQ(0x54, irsend.capture.value); EXPECT_EQ(0x4, irsend.capture.address); // Unit EXPECT_EQ(0x5, irsend.capture.command); // Team irsend.reset(); - uint16_t unit15[25] = { - 280, 360, 360, 308, 332, 388, 308, 332, 360, 308, 360, 360, 304, 304, - 412, 284, 304, 692, 364, 360, 276, 336, 416, 276, 328}; + uint16_t unit15[25] = {280, 360, 360, 308, 332, 388, 308, 332, 360, + 308, 360, 360, 304, 304, 412, 284, 304, 692, + 364, 360, 276, 336, 416, 276, 328}; irsend.sendRaw(unit15, 25, 36000); irsend.makeDecodeResult(); ASSERT_TRUE(irrecv.decode(&irsend.capture)); EXPECT_EQ(LASERTAG, irsend.capture.decode_type); - EXPECT_EQ(LASERTAG_BITS, irsend.capture.bits); + EXPECT_EQ(kLasertagBits, irsend.capture.bits); EXPECT_EQ(0x0F, irsend.capture.value); EXPECT_EQ(0xF, irsend.capture.address); // Unit EXPECT_EQ(0x0, irsend.capture.command); // Team irsend.reset(); - uint16_t red_unit2_1[23] = { - 406, 262, 384, 374, 256, 354, 306, 366, 252, 442, 256, 374, - 358, 336, 278, 438, 246, 340, 380, 292, 304, 688, 746}; + uint16_t red_unit2_1[23] = {406, 262, 384, 374, 256, 354, 306, 366, + 252, 442, 256, 374, 358, 336, 278, 438, + 246, 340, 380, 292, 304, 688, 746}; irsend.sendRaw(red_unit2_1, 23, 36000); irsend.makeDecodeResult(); ASSERT_TRUE(irrecv.decode(&irsend.capture)); ASSERT_EQ(LASERTAG, irsend.capture.decode_type); - EXPECT_EQ(LASERTAG_BITS, irsend.capture.bits); + EXPECT_EQ(kLasertagBits, irsend.capture.bits); EXPECT_EQ(0x02, irsend.capture.value); EXPECT_EQ(0x2, irsend.capture.address); // Unit EXPECT_EQ(0x0, irsend.capture.command); // Team irsend.reset(); - uint16_t red_unit2_2[23] = { - 302, 306, 302, 392, 196, 476, 278, 352, 304, 348, 278, 438, - 226, 382, 328, 366, 252, 458, 196, 392, 302, 688, 644}; + uint16_t red_unit2_2[23] = {302, 306, 302, 392, 196, 476, 278, 352, + 304, 348, 278, 438, 226, 382, 328, 366, + 252, 458, 196, 392, 302, 688, 644}; irsend.sendRaw(red_unit2_2, 23, 36000); irsend.makeDecodeResult(); ASSERT_TRUE(irrecv.decode(&irsend.capture)); ASSERT_EQ(LASERTAG, irsend.capture.decode_type); - EXPECT_EQ(LASERTAG_BITS, irsend.capture.bits); + EXPECT_EQ(kLasertagBits, irsend.capture.bits); EXPECT_EQ(0x02, irsend.capture.value); EXPECT_EQ(0x2, irsend.capture.address); // Unit EXPECT_EQ(0x0, irsend.capture.command); // Team irsend.reset(); - uint16_t red_unit2_3[23] = { - 196, 432, 304, 348, 328, 386, 304, 326, 302, 370, 252, 442, - 272, 356, 278, 374, 276, 438, 274, 352, 302, 668, 622}; + uint16_t red_unit2_3[23] = {196, 432, 304, 348, 328, 386, 304, 326, + 302, 370, 252, 442, 272, 356, 278, 374, + 276, 438, 274, 352, 302, 668, 622}; irsend.sendRaw(red_unit2_3, 23, 36000); irsend.makeDecodeResult(); ASSERT_TRUE(irrecv.decode(&irsend.capture)); ASSERT_EQ(LASERTAG, irsend.capture.decode_type); - EXPECT_EQ(LASERTAG_BITS, irsend.capture.bits); + EXPECT_EQ(kLasertagBits, irsend.capture.bits); EXPECT_EQ(0x02, irsend.capture.value); EXPECT_EQ(0x2, irsend.capture.address); // Unit EXPECT_EQ(0x0, irsend.capture.command); // Team irsend.reset(); - uint16_t red_unit2_4[23] = { - 304, 390, 328, 324, 324, 346, 350, 364, 300, 330, 320, 310, - 324, 388, 242, 366, 354, 318, 354, 340, 244, 726, 670}; + uint16_t red_unit2_4[23] = {304, 390, 328, 324, 324, 346, 350, 364, + 300, 330, 320, 310, 324, 388, 242, 366, + 354, 318, 354, 340, 244, 726, 670}; irsend.sendRaw(red_unit2_4, 23, 36000); irsend.makeDecodeResult(); ASSERT_TRUE(irrecv.decode(&irsend.capture)); ASSERT_EQ(LASERTAG, irsend.capture.decode_type); - EXPECT_EQ(LASERTAG_BITS, irsend.capture.bits); + EXPECT_EQ(kLasertagBits, irsend.capture.bits); EXPECT_EQ(0x02, irsend.capture.value); EXPECT_EQ(0x2, irsend.capture.address); // Unit EXPECT_EQ(0x0, irsend.capture.command); // Team irsend.reset(); uint16_t red_unit1_1_issue532[25] = { - 368, 352, 336, 308, 388, 276, 364, 356, 280, 360, 332, 336, 360, 360, 308, - 300, 416, 280, 356, 360, 312, 328, 336, 636, 424}; + 368, 352, 336, 308, 388, 276, 364, 356, 280, 360, 332, 336, 360, + 360, 308, 300, 416, 280, 356, 360, 312, 328, 336, 636, 424}; irsend.sendRaw(red_unit1_1_issue532, 25, 36000); irsend.makeDecodeResult(); ASSERT_TRUE(irrecv.decode(&irsend.capture)); ASSERT_EQ(LASERTAG, irsend.capture.decode_type); - EXPECT_EQ(LASERTAG_BITS, irsend.capture.bits); + EXPECT_EQ(kLasertagBits, irsend.capture.bits); EXPECT_EQ(0x01, irsend.capture.value); EXPECT_EQ(0x1, irsend.capture.address); // Unit EXPECT_EQ(0x0, irsend.capture.command); // Team irsend.reset(); uint16_t red_unit1_2_issue532[25] = { - 328, 400, 272, 360, 388, 280, 360, 364, 272, 364, 332, 336, 332, 388, 304, - 308, 388, 280, 356, 364, 272, 368, 384, 612, 408}; + 328, 400, 272, 360, 388, 280, 360, 364, 272, 364, 332, 336, 332, + 388, 304, 308, 388, 280, 356, 364, 272, 368, 384, 612, 408}; irsend.sendRaw(red_unit1_2_issue532, 25, 36000); irsend.makeDecodeResult(); ASSERT_TRUE(irrecv.decode(&irsend.capture)); ASSERT_EQ(LASERTAG, irsend.capture.decode_type); - EXPECT_EQ(LASERTAG_BITS, irsend.capture.bits); + EXPECT_EQ(kLasertagBits, irsend.capture.bits); EXPECT_EQ(0x01, irsend.capture.value); EXPECT_EQ(0x1, irsend.capture.address); // Unit EXPECT_EQ(0x0, irsend.capture.command); // Team irsend.reset(); uint16_t red_unit1_3_issue532[25] = { - 416, 284, 356, 336, 328, 336, 384, 308, 328, 368, 304, 308, 412, 280, 328, - 368, 272, 368, 376, 312, 332, 392, 276, 700, 272}; + 416, 284, 356, 336, 328, 336, 384, 308, 328, 368, 304, 308, 412, + 280, 328, 368, 272, 368, 376, 312, 332, 392, 276, 700, 272}; irsend.sendRaw(red_unit1_3_issue532, 25, 36000); irsend.makeDecodeResult(); ASSERT_TRUE(irrecv.decode(&irsend.capture)); ASSERT_EQ(LASERTAG, irsend.capture.decode_type); - EXPECT_EQ(LASERTAG_BITS, irsend.capture.bits); + EXPECT_EQ(kLasertagBits, irsend.capture.bits); EXPECT_EQ(0x01, irsend.capture.value); EXPECT_EQ(0x1, irsend.capture.address); // Unit EXPECT_EQ(0x0, irsend.capture.command); // Team irsend.reset(); - uint16_t red_unit2_1_issue532[23] = { - 308, 340, 408, 284, 332, 388, 276, 336, 356, 340, 332, 360, 300, 364, 360, - 304, 280, 444, 276, 336, 384, 640, 696}; + uint16_t red_unit2_1_issue532[23] = {308, 340, 408, 284, 332, 388, 276, 336, + 356, 340, 332, 360, 300, 364, 360, 304, + 280, 444, 276, 336, 384, 640, 696}; irsend.sendRaw(red_unit2_1_issue532, 23, 36000); irsend.makeDecodeResult(); ASSERT_TRUE(irrecv.decode(&irsend.capture)); ASSERT_EQ(LASERTAG, irsend.capture.decode_type); - EXPECT_EQ(LASERTAG_BITS, irsend.capture.bits); + EXPECT_EQ(kLasertagBits, irsend.capture.bits); EXPECT_EQ(0x02, irsend.capture.value); EXPECT_EQ(0x2, irsend.capture.address); // Unit EXPECT_EQ(0x0, irsend.capture.command); // Team irsend.reset(); - uint16_t red_unit2_2_issue532[23] = { - 332, 308, 388, 280, 328, 420, 308, 304, 384, 308, 332, 364, 272, 368, 384, - 276, 364, 360, 308, 332, 384, 612, 696}; + uint16_t red_unit2_2_issue532[23] = {332, 308, 388, 280, 328, 420, 308, 304, + 384, 308, 332, 364, 272, 368, 384, 276, + 364, 360, 308, 332, 384, 612, 696}; irsend.sendRaw(red_unit2_2_issue532, 23, 36000); irsend.makeDecodeResult(); ASSERT_TRUE(irrecv.decode(&irsend.capture)); ASSERT_EQ(LASERTAG, irsend.capture.decode_type); - EXPECT_EQ(LASERTAG_BITS, irsend.capture.bits); + EXPECT_EQ(kLasertagBits, irsend.capture.bits); EXPECT_EQ(0x02, irsend.capture.value); EXPECT_EQ(0x2, irsend.capture.address); // Unit EXPECT_EQ(0x0, irsend.capture.command); // Team irsend.reset(); - uint16_t red_unit2_3_issue532[23] = { - 392, 332, 340, 272, 448, 276, 364, 328, 340, 272, 396, 296, 340, 380, 312, - 296, 400, 272, 364, 352, 284, 720, 672}; + uint16_t red_unit2_3_issue532[23] = {392, 332, 340, 272, 448, 276, 364, 328, + 340, 272, 396, 296, 340, 380, 312, 296, + 400, 272, 364, 352, 284, 720, 672}; irsend.sendRaw(red_unit2_3_issue532, 23, 36000); irsend.makeDecodeResult(); ASSERT_TRUE(irrecv.decode(&irsend.capture)); ASSERT_EQ(LASERTAG, irsend.capture.decode_type); - EXPECT_EQ(LASERTAG_BITS, irsend.capture.bits); + EXPECT_EQ(kLasertagBits, irsend.capture.bits); EXPECT_EQ(0x02, irsend.capture.value); EXPECT_EQ(0x2, irsend.capture.address); // Unit EXPECT_EQ(0x0, irsend.capture.command); // Team diff --git a/lib/IRremoteESP8266/test/ir_Lutron_test.cpp b/lib/IRremoteESP8266/test/ir_Lutron_test.cpp new file mode 100644 index 0000000..6c99b99 --- /dev/null +++ b/lib/IRremoteESP8266/test/ir_Lutron_test.cpp @@ -0,0 +1,143 @@ +// Copyright 2018 David Conran + +#include "IRsend.h" +#include "IRsend_test.h" +#include "gtest/gtest.h" + +// Tests for sendLutron(). + +// Test sending typical data only. +TEST(TestSendLutron, SendDataOnly) { + IRsendTest irsend(0); + irsend.begin(); + irsend.sendLutron(0); + EXPECT_EQ("m2288s230080", irsend.outputStr()); + irsend.sendLutron(0xAAAAAAAAA); // Longest possible sequence. (I think) + EXPECT_EQ( + "m2288s2288m2288s2288m2288s2288m2288s2288m2288s2288m2288s2288m2288s2288" + "m2288s2288m2288s2288m2288s2288m2288s2288m2288s2288m2288s2288m2288s2288" + "m2288s2288m2288s2288m2288s2288m2288s152288", + irsend.outputStr()); + irsend.sendLutron(0x7FFFFFFFF); + EXPECT_EQ("m82368s150000", irsend.outputStr()); + irsend.sendLutron(0x7F88BD120); + EXPECT_EQ( + "m20592s6864m2288s6864m2288s2288m9152s2288m2288s6864m2288s4576m2288" + "s161440", + irsend.outputStr()); +} + +// Test sending with repeats. +TEST(TestSendLutron, SendWithRepeats) { + IRsendTest irsend(0); + irsend.begin(); + // Send a command with 0 repeats. + irsend.sendLutron(0x7F88BD120, kLutronBits, 0); + EXPECT_EQ( + "m20592s6864m2288s6864m2288s2288m9152s2288m2288s6864m2288s4576m2288" + "s161440", + irsend.outputStr()); + // Send a command with 1 repeat. + irsend.sendLutron(0x7F88BD120, kLutronBits, 1); + EXPECT_EQ( + "m20592s6864m2288s6864m2288s2288m9152s2288m2288s6864m2288s4576m2288" + "s161440" + "m20592s6864m2288s6864m2288s2288m9152s2288m2288s6864m2288s4576m2288" + "s161440", + irsend.outputStr()); + // Send a command with 3 repeats. + irsend.sendLutron(0x7F88BD120, kLutronBits, 3); + EXPECT_EQ( + "m20592s6864m2288s6864m2288s2288m9152s2288m2288s6864m2288s4576m2288" + "s161440" + "m20592s6864m2288s6864m2288s2288m9152s2288m2288s6864m2288s4576m2288" + "s161440" + "m20592s6864m2288s6864m2288s2288m9152s2288m2288s6864m2288s4576m2288" + "s161440" + "m20592s6864m2288s6864m2288s2288m9152s2288m2288s6864m2288s4576m2288" + "s161440", + irsend.outputStr()); +} + +// Tests for decodeLutron(). +// Decode normal Lutron messages. +TEST(TestDecodeLutron, SyntheticDecode) { + IRsendTest irsend(0); + IRrecv irrecv(0); + irsend.begin(); + + // Synthesised Normal Lutron messages. + irsend.reset(); + irsend.sendLutron(0x7F88BD120); + irsend.makeDecodeResult(); + EXPECT_TRUE(irrecv.decode(&irsend.capture)); + EXPECT_EQ(LUTRON, irsend.capture.decode_type); + EXPECT_EQ(kLutronBits, irsend.capture.bits); + EXPECT_EQ(0x7F88BD120, irsend.capture.value); + EXPECT_EQ(0x0, irsend.capture.address); + EXPECT_EQ(0x0, irsend.capture.command); + + irsend.reset(); + irsend.sendLutron(0x0DEADBEEF); + irsend.makeDecodeResult(); + EXPECT_TRUE(irrecv.decode(&irsend.capture)); + EXPECT_EQ(LUTRON, irsend.capture.decode_type); + EXPECT_EQ(kLutronBits, irsend.capture.bits); + EXPECT_EQ(0x0DEADBEEF, irsend.capture.value); + EXPECT_EQ(0x0, irsend.capture.address); + EXPECT_EQ(0x0, irsend.capture.command); + + irsend.reset(); + irsend.sendLutron(0x0); + irsend.makeDecodeResult(); + EXPECT_TRUE(irrecv.decode(&irsend.capture)); + EXPECT_EQ(LUTRON, irsend.capture.decode_type); + EXPECT_EQ(kLutronBits, irsend.capture.bits); + EXPECT_EQ(0x0, irsend.capture.value); + EXPECT_EQ(0x0, irsend.capture.address); + EXPECT_EQ(0x0, irsend.capture.command); + + irsend.reset(); + irsend.sendLutron(0x7FFFFFFFF); + irsend.makeDecodeResult(); + EXPECT_TRUE(irrecv.decode(&irsend.capture)); + EXPECT_EQ(LUTRON, irsend.capture.decode_type); + EXPECT_EQ(kLutronBits, irsend.capture.bits); + EXPECT_EQ(0x7FFFFFFFF, irsend.capture.value); + EXPECT_EQ(0x0, irsend.capture.address); + EXPECT_EQ(0x0, irsend.capture.command); +} + +// Decode a documented example +TEST(TestDecodeLutron, DocumentedExampleFullOff) { + IRsendTest irsend(0); + IRrecv irrecv(0); + irsend.begin(); + + // Full Off code. + // Ref: https://github.com/markszabo/IRremoteESP8266/issues/515 + uint16_t rawData[14] = {20518, 6839, 2280, 6839, 2280, 2280, 9119, + 2280, 2280, 6839, 2280, 4560, 2280, 11399}; + irsend.reset(); + irsend.sendRaw(rawData, 14, 40); + irsend.makeDecodeResult(); + EXPECT_TRUE(irrecv.decode(&irsend.capture)); + EXPECT_EQ(LUTRON, irsend.capture.decode_type); + EXPECT_EQ(kLutronBits, irsend.capture.bits); + EXPECT_EQ(0x7F88BD120, irsend.capture.value); + EXPECT_EQ(0x0, irsend.capture.address); + EXPECT_EQ(0x0, irsend.capture.command); + + uint16_t pronto[18] = {0x0000, 0x0069, 0x0007, 0x0000, 0x032a, 0x010e, + 0x005a, 0x010e, 0x005a, 0x005a, 0x0168, 0x005a, + 0x005a, 0x010e, 0x005a, 0x00b4, 0x005a, 0x01c2}; + irsend.reset(); + irsend.sendPronto(pronto, 18); + irsend.makeDecodeResult(); + EXPECT_TRUE(irrecv.decode(&irsend.capture)); + EXPECT_EQ(LUTRON, irsend.capture.decode_type); + EXPECT_EQ(kLutronBits, irsend.capture.bits); + EXPECT_EQ(0x7F88BD120, irsend.capture.value); + EXPECT_EQ(0x0, irsend.capture.address); + EXPECT_EQ(0x0, irsend.capture.command); +} diff --git a/lib/IRremoteESP8266/test/ir_MWM_test.cpp b/lib/IRremoteESP8266/test/ir_MWM_test.cpp new file mode 100644 index 0000000..9ecd0ea --- /dev/null +++ b/lib/IRremoteESP8266/test/ir_MWM_test.cpp @@ -0,0 +1,124 @@ +// Copyright 2017 David Conran +// Copyright 2018 Brett T. Warden + +#include "IRrecv.h" +#include "IRrecv_test.h" +#include "IRsend.h" +#include "IRsend_test.h" +#include "gtest/gtest.h" + +// MM MM WW WW MM MM +// MMM MMM WW WW MMM MMM +// MM M MM WW W WW MM M MM +// MM MM WWW WWW MM MM +// MM MM WW WW MM MM + +// Tests for sendMWM(). + +// Test sending simplest case data only. +TEST(TestSendMWM, SendDataOnly) { + IRsendTest irsend(4); + irsend.begin(); + + irsend.reset(); + unsigned char test1[] = {0x96, 0x19, 0x10, 0x24, 0x0A, + 0x6B, 0x20, 0x03, 0x82}; + /* + ++--+-++-- + +-++--+++- + +++++-+++- + +++-++-++- + ++-+-++++- + +--+-+--+- + ++++++-++- + +--++++++- + ++-+++++-- + */ + irsend.sendMWM(test1, sizeof(test1), 0); + EXPECT_EQ( + "m834s834m417s417m834s834" + "m417s417m834s834m1251s417" + "m2085s417m1251s417" + "m1251s417m834s417m834s417" + "m834s417m417s417m1668s417" + "m417s834m417s417m417s834m417s417" + "m2502s417m834s417" + "m417s834m2502s417" + "m834s417m2085s30834", irsend.outputStr()); + + irsend.reset(); + unsigned char test2[] = { + 0x99, 0x26, 0x66, 0x6E, 0xD1, 0x42, 0x06, + 0x20, 0xD0, 0x32, 0xF0, 0x0B + // +-++--++-- + // ++--++-++- + // ++--++--+- + // ++---+--+- + // +-+++-+--- + // ++-++++-+- + // ++--+++++- + // ++++++-++- + // +++++-+--- + // ++-++--++- + // +++++----- + // +--+-++++- + }; + irsend.sendMWM(test2, sizeof(test2), 0); + EXPECT_EQ( + "m417s417m834s834m834s834" + "m834s834m834s417m834s417" + "m834s834m834s834m417s417" + "m834s1251m417s834m417s417" + "m417s417m1251s417m417s1251" + "m834s417m1668s417m417s417" + "m834s834m2085s417" + "m2502s417m834s417" + "m2085s417m417s1251" + "m834s417m834s834m834s417" + "m2085s2085" + "m417s834m417s417m1668s30417", irsend.outputStr()); +} + +// Tests for decodeMWM(). + +// Example data +TEST(TestDecodeMWM, RealExamples) { + IRsendTest irsend(0); + IRrecv irrecv(0); + irsend.begin(); + + irsend.reset(); + uint16_t short_code[] = { + 915, 793, 488, 366, 915, 793, 427, 366, 915, 793, 1281, 427, + 2136, 366, 1281, 366, 915, 793, 427, 854, 854, 366, 1281, 854, + 1708, 366, 488, 793, 854, 427, 427, 427, 427, 366, 854, 427, + 2563, 366, 488, 793, 2563, 366, 488, 2075, 427, 34057}; + unsigned char short_expected[] = {0x96, 0x19, 0x10, 0x36, 0x0C, + 0x53, 0x02, 0x03, 0xDF}; + irsend.sendRaw(short_code, sizeof(short_code) / sizeof(short_code[0]), 38000); + irsend.makeDecodeResult(); + ASSERT_TRUE(irrecv.decode(&irsend.capture)); + EXPECT_EQ(MWM, irsend.capture.decode_type); + EXPECT_EQ(8 * sizeof(short_expected) / sizeof(short_expected[0]), + irsend.capture.bits); + EXPECT_STATE_EQ(short_expected, irsend.capture.state, irsend.capture.bits); + + irsend.reset(); + uint16_t long_code[] = { + 427, 427, 854, 854, 854, 793, 915, 793, 854, 366, 915, 366, 854, + 854, 854, 793, 488, 366, 915, 1220, 427, 793, 488, 366, 488, 366, + 1281, 427, 427, 1220, 915, 366, 1708, 366, 488, 366, 854, 854, 2136, + 366, 2563, 366, 854, 427, 2136, 366, 488, 1220, 854, 427, 854, 793, + 915, 366, 2136, 2075, 427, 793, 488, 366, 1708, 30517}; + unsigned char long_expected[] = {0x99, 0x26, 0x66, 0x6E, 0xD1, 0x42, + 0x06, 0x20, 0xD0, 0x32, 0xF0, 0x0B}; + irsend.sendRaw(long_code, sizeof(long_code) / sizeof(long_code[0]), 38000); + irsend.makeDecodeResult(); + ASSERT_TRUE(irrecv.decode(&irsend.capture)); + EXPECT_EQ(MWM, irsend.capture.decode_type); + EXPECT_EQ(8 * sizeof(long_expected) / sizeof(long_expected[0]), + irsend.capture.bits); + EXPECT_STATE_EQ(long_expected, irsend.capture.state, irsend.capture.bits); +} + +// vim: et:ts=2:sw=2 diff --git a/lib/IRremoteESP8266/test/ir_Magiquest_test.cpp b/lib/IRremoteESP8266/test/ir_Magiquest_test.cpp index ef5ede8..e1c3da8 100644 --- a/lib/IRremoteESP8266/test/ir_Magiquest_test.cpp +++ b/lib/IRremoteESP8266/test/ir_Magiquest_test.cpp @@ -1,9 +1,9 @@ // Copyright 2017 David Conran +#include "ir_Magiquest.h" #include "IRrecv.h" #include "IRsend.h" #include "IRsend_test.h" -#include "ir_Magiquest.h" #include "gtest/gtest.h" // Tests for encodeMagiQuest() @@ -53,7 +53,7 @@ TEST(TestSendMagiQuest, SendWithRepeats) { irsend.begin(); irsend.reset(); - irsend.sendMagiQuest(0x12345678ABCD, MAGIQUEST_BITS, 2); // two repeats. + irsend.sendMagiQuest(0x12345678ABCD, kMagiquestBits, 2); // two repeats. EXPECT_EQ( "m280s850m280s850m280s850m280s850m280s850m280s850m280s850m280s850" "m280s850m280s850m280s850m580s600m280s850m280s850m580s600m280s850" @@ -90,9 +90,9 @@ TEST(TestDecodeMagiQuest, NormalDecodeWithStrict) { irsend.reset(); irsend.sendMagiQuest(0x0); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodeMagiQuest(&irsend.capture, MAGIQUEST_BITS, true)); + ASSERT_TRUE(irrecv.decodeMagiQuest(&irsend.capture, kMagiquestBits, true)); EXPECT_EQ(MAGIQUEST, irsend.capture.decode_type); - EXPECT_EQ(MAGIQUEST_BITS, irsend.capture.bits); + EXPECT_EQ(kMagiquestBits, irsend.capture.bits); EXPECT_EQ(0x0, irsend.capture.value); EXPECT_EQ(0x0, irsend.capture.address); EXPECT_EQ(0x0, irsend.capture.command); @@ -101,9 +101,9 @@ TEST(TestDecodeMagiQuest, NormalDecodeWithStrict) { irsend.reset(); irsend.sendMagiQuest(irsend.encodeMagiQuest(0x1, 0x1)); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodeMagiQuest(&irsend.capture, MAGIQUEST_BITS, true)); + ASSERT_TRUE(irrecv.decodeMagiQuest(&irsend.capture, kMagiquestBits, true)); EXPECT_EQ(MAGIQUEST, irsend.capture.decode_type); - EXPECT_EQ(MAGIQUEST_BITS, irsend.capture.bits); + EXPECT_EQ(kMagiquestBits, irsend.capture.bits); EXPECT_EQ(0x10001, irsend.capture.value); EXPECT_EQ(0x1, irsend.capture.address); EXPECT_EQ(0x1, irsend.capture.command); @@ -112,9 +112,9 @@ TEST(TestDecodeMagiQuest, NormalDecodeWithStrict) { irsend.reset(); irsend.sendMagiQuest(irsend.encodeMagiQuest(0x12345678, 0xABCD)); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodeMagiQuest(&irsend.capture, MAGIQUEST_BITS, true)); + ASSERT_TRUE(irrecv.decodeMagiQuest(&irsend.capture, kMagiquestBits, true)); EXPECT_EQ(MAGIQUEST, irsend.capture.decode_type); - EXPECT_EQ(MAGIQUEST_BITS, irsend.capture.bits); + EXPECT_EQ(kMagiquestBits, irsend.capture.bits); EXPECT_EQ(0x12345678ABCD, irsend.capture.value); EXPECT_EQ(0x12345678, irsend.capture.address); EXPECT_EQ(0xABCD, irsend.capture.command); @@ -126,7 +126,7 @@ TEST(TestDecodeMagiQuest, NormalDecodeWithStrict) { irsend.makeDecodeResult(); ASSERT_TRUE(irrecv.decode(&irsend.capture)); EXPECT_EQ(MAGIQUEST, irsend.capture.decode_type); - EXPECT_EQ(MAGIQUEST_BITS, irsend.capture.bits); + EXPECT_EQ(kMagiquestBits, irsend.capture.bits); EXPECT_EQ(0x12345678ABCD, irsend.capture.value); } @@ -137,25 +137,26 @@ TEST(TestDecodeMagiQuest, RealExamples) { irsend.begin(); irsend.reset(); - uint16_t rawData[111] = { - 262, 842, 298, 858, 238, 866, 240, 890, 238, 866, 240, 862, - 244, 886, 242, 860, 246, 858, 554, 604, 264, 840, 560, 622, - 266, 836, 552, 604, 556, 626, 262, 866, 240, 864, 264, 838, - 268, 862, 244, 886, 536, 620, 530, 628, 554, 628, 532, 624, - 244, 858, 552, 604, 264, 840, 268, 862, 266, 838, 268, 888, - 240, 864, 242, 860, 268, 862, 244, 860, 236, 868, 272, 832, - 264, 866, 240, 890, 532, 598, 268, 834, 294, 836, 270, 834, - 262, 866, 272, 858, 238, 866, 534, 622, 268, 836, 270, 860, - 268, 862, 526, 604, 264, 892, 530, 600, 268, 836, 586, 598, - 270, 834, 556}; // Data from PR #365 captured by coolacid + uint16_t rawData[111] = {262, 842, 298, 858, 238, 866, 240, 890, 238, 866, + 240, 862, 244, 886, 242, 860, 246, 858, 554, 604, + 264, 840, 560, 622, 266, 836, 552, 604, 556, 626, + 262, 866, 240, 864, 264, 838, 268, 862, 244, 886, + 536, 620, 530, 628, 554, 628, 532, 624, 244, 858, + 552, 604, 264, 840, 268, 862, 266, 838, 268, 888, + 240, 864, 242, 860, 268, 862, 244, 860, 236, 868, + 272, 832, 264, 866, 240, 890, 532, 598, 268, 834, + 294, 836, 270, 834, 262, 866, 272, 858, 238, 866, + 534, 622, 268, 836, 270, 860, 268, 862, 526, 604, + 264, 892, 530, 600, 268, 836, 586, 598, 270, 834, + 556}; // Data from PR #365 captured by coolacid irsend.sendRaw(rawData, 111, 36000); irsend.makeDecodeResult(); ASSERT_TRUE(irrecv.decode(&irsend.capture)); EXPECT_EQ(MAGIQUEST, irsend.capture.decode_type); - EXPECT_EQ(MAGIQUEST_BITS, irsend.capture.bits); + EXPECT_EQ(kMagiquestBits, irsend.capture.bits); EXPECT_EQ(0x560F40020455, irsend.capture.value); EXPECT_EQ(0x560F4002, irsend.capture.address); // Wand ID - EXPECT_EQ(0x0455, irsend.capture.command); // Magnitude + EXPECT_EQ(0x0455, irsend.capture.command); // Magnitude EXPECT_FALSE(irsend.capture.repeat); } diff --git a/lib/IRremoteESP8266/test/ir_Midea_test.cpp b/lib/IRremoteESP8266/test/ir_Midea_test.cpp index 9c17967..5d5f5e9 100644 --- a/lib/IRremoteESP8266/test/ir_Midea_test.cpp +++ b/lib/IRremoteESP8266/test/ir_Midea_test.cpp @@ -1,8 +1,8 @@ // Copyright 2017 David Conran +#include "ir_Midea.h" #include "IRsend.h" #include "IRsend_test.h" -#include "ir_Midea.h" #include "gtest/gtest.h" // Tests for sendMidea(). @@ -30,7 +30,8 @@ TEST(TestSendMidea, SendDataOnly) { "m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680" "m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680" "m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680" - "m560s5600", irsend.outputStr()); + "m560s5600", + irsend.outputStr()); irsend.reset(); irsend.sendMidea(0x55AA55AA55AA); @@ -50,7 +51,8 @@ TEST(TestSendMidea, SendDataOnly) { "m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680" "m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560" "m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680" - "m560s5600", irsend.outputStr()); + "m560s5600", + irsend.outputStr()); irsend.reset(); irsend.sendMidea(0xFFFFFFFFFFFF); @@ -70,7 +72,8 @@ TEST(TestSendMidea, SendDataOnly) { "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560" "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560" "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560" - "m560s5600", irsend.outputStr()); + "m560s5600", + irsend.outputStr()); } // Test sending with different repeats. @@ -79,7 +82,7 @@ TEST(TestSendMidea, SendWithRepeats) { irsend.begin(); irsend.reset(); - irsend.sendMidea(0x55AA55AA55AA, MIDEA_BITS, 1); // 1 repeat. + irsend.sendMidea(0x55AA55AA55AA, kMideaBits, 1); // 1 repeat. EXPECT_EQ( "m4480s4480" "m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680" @@ -112,57 +115,59 @@ TEST(TestSendMidea, SendWithRepeats) { "m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680" "m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560" "m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680" - "m560s5600", irsend.outputStr()); - irsend.sendMidea(0x55AA55AA55AA, MIDEA_BITS, 2); // 2 repeats. + "m560s5600", + irsend.outputStr()); + irsend.sendMidea(0x55AA55AA55AA, kMideaBits, 2); // 2 repeats. EXPECT_EQ( - "m4480s4480" - "m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680" - "m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560" - "m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680" - "m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560" - "m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680" - "m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560" - "m560s5600" - "m4480s4480" - "m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560" - "m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680" - "m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560" - "m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680" - "m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560" - "m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680" - "m560s5600" - "m4480s4480" - "m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680" - "m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560" - "m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680" - "m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560" - "m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680" - "m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560" - "m560s5600" - "m4480s4480" - "m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560" - "m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680" - "m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560" - "m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680" - "m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560" - "m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680" - "m560s5600" - "m4480s4480" - "m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680" - "m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560" - "m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680" - "m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560" - "m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680" - "m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560" - "m560s5600" - "m4480s4480" - "m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560" - "m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680" - "m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560" - "m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680" - "m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560" - "m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680" - "m560s5600", irsend.outputStr()); + "m4480s4480" + "m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680" + "m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560" + "m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680" + "m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560" + "m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680" + "m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560" + "m560s5600" + "m4480s4480" + "m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560" + "m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680" + "m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560" + "m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680" + "m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560" + "m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680" + "m560s5600" + "m4480s4480" + "m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680" + "m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560" + "m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680" + "m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560" + "m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680" + "m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560" + "m560s5600" + "m4480s4480" + "m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560" + "m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680" + "m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560" + "m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680" + "m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560" + "m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680" + "m560s5600" + "m4480s4480" + "m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680" + "m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560" + "m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680" + "m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560" + "m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680" + "m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560" + "m560s5600" + "m4480s4480" + "m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560" + "m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680" + "m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560" + "m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680" + "m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560" + "m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680" + "m560s5600", + irsend.outputStr()); } // Test sending an atypical data size. @@ -178,7 +183,8 @@ TEST(TestSendMidea, SendUnusualSize) { "m560s5600" "m4480s4480" "m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680" - "m560s5600", irsend.outputStr()); + "m560s5600", + irsend.outputStr()); irsend.reset(); irsend.sendMidea(0x1234567890ABCDEF, 64); @@ -202,12 +208,13 @@ TEST(TestSendMidea, SendUnusualSize) { "m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s560" "m560s560m560s560m560s1680m560s1680m560s560m560s560m560s1680m560s560" "m560s560m560s560m560s560m560s1680m560s560m560s560m560s560m560s560" - "m560s5600", irsend.outputStr()); + "m560s5600", + irsend.outputStr()); // Bit sizes must be a multiple of 8. irsend.reset(); irsend.sendMidea(0x0, 17); - EXPECT_EQ("" , irsend.outputStr()); + EXPECT_EQ("", irsend.outputStr()); } // Tests for IRMideaAC class. @@ -228,7 +235,6 @@ TEST(TestMideaACClass, Power) { EXPECT_FALSE(midea.getPower()); EXPECT_EQ(0xA1026FFFFFE2, midea.getRaw()); - midea.setPower(true); EXPECT_TRUE(midea.getPower()); EXPECT_EQ(0xA1826FFFFF62, midea.getRaw()); @@ -272,32 +278,32 @@ TEST(TestMideaACClass, OperatingMode) { midea.begin(); midea.setRaw(0xA1826FFFFF62); // Auto mode already set. - midea.setMode(MIDEA_AC_AUTO); - EXPECT_EQ(MIDEA_AC_AUTO, midea.getMode()); + midea.setMode(kMideaACAuto); + EXPECT_EQ(kMideaACAuto, midea.getMode()); EXPECT_EQ(0xA1826FFFFF62, midea.getRaw()); // State shouldn't have changed. - midea.setMode(MIDEA_AC_COOL); - EXPECT_EQ(MIDEA_AC_COOL, midea.getMode()); + midea.setMode(kMideaACCool); + EXPECT_EQ(kMideaACCool, midea.getMode()); EXPECT_EQ(0xA1806FFFFF61, midea.getRaw()); - midea.setMode(MIDEA_AC_AUTO); - EXPECT_EQ(MIDEA_AC_AUTO, midea.getMode()); + midea.setMode(kMideaACAuto); + EXPECT_EQ(kMideaACAuto, midea.getMode()); EXPECT_EQ(0xA1826FFFFF62, midea.getRaw()); - midea.setMode(MIDEA_AC_HEAT); - EXPECT_EQ(MIDEA_AC_HEAT, midea.getMode()); + midea.setMode(kMideaACHeat); + EXPECT_EQ(kMideaACHeat, midea.getMode()); EXPECT_EQ(0xA1836FFFFF63, midea.getRaw()); - midea.setMode(MIDEA_AC_DRY); - EXPECT_EQ(MIDEA_AC_DRY, midea.getMode()); + midea.setMode(kMideaACDry); + EXPECT_EQ(kMideaACDry, midea.getMode()); EXPECT_EQ(0xA1816FFFFF60, midea.getRaw()); - midea.setMode(MIDEA_AC_FAN); - EXPECT_EQ(MIDEA_AC_FAN, midea.getMode()); + midea.setMode(kMideaACFan); + EXPECT_EQ(kMideaACFan, midea.getMode()); EXPECT_EQ(0xA1846FFFFF66, midea.getRaw()); midea.setMode(255); - EXPECT_EQ(MIDEA_AC_AUTO, midea.getMode()); + EXPECT_EQ(kMideaACAuto, midea.getMode()); EXPECT_EQ(0xA1826FFFFF62, midea.getRaw()); } @@ -306,26 +312,26 @@ TEST(TestMideaACClass, FanSpeed) { midea.begin(); midea.setRaw(0xA1826FFFFF62); // Auto mode already set. - EXPECT_EQ(MIDEA_AC_FAN_AUTO, midea.getFan()); + EXPECT_EQ(kMideaACFanAuto, midea.getFan()); - midea.setFan(MIDEA_AC_FAN_LOW); - EXPECT_EQ(MIDEA_AC_FAN_LOW, midea.getFan()); + midea.setFan(kMideaACFanLow); + EXPECT_EQ(kMideaACFanLow, midea.getFan()); EXPECT_EQ(0xA18A6FFFFF6C, midea.getRaw()); midea.setFan(255); // Setting an unexpected value defaults to auto. - EXPECT_EQ(MIDEA_AC_FAN_AUTO, midea.getFan()); + EXPECT_EQ(kMideaACFanAuto, midea.getFan()); EXPECT_EQ(0xA1826FFFFF62, midea.getRaw()); - midea.setFan(MIDEA_AC_FAN_MED); - EXPECT_EQ(MIDEA_AC_FAN_MED, midea.getFan()); + midea.setFan(kMideaACFanMed); + EXPECT_EQ(kMideaACFanMed, midea.getFan()); EXPECT_EQ(0xA1926FFFFF7C, midea.getRaw()); - midea.setFan(MIDEA_AC_FAN_HI); - EXPECT_EQ(MIDEA_AC_FAN_HI, midea.getFan()); + midea.setFan(kMideaACFanHigh); + EXPECT_EQ(kMideaACFanHigh, midea.getFan()); EXPECT_EQ(0xA19A6FFFFF74, midea.getRaw()); - midea.setFan(MIDEA_AC_FAN_AUTO); - EXPECT_EQ(MIDEA_AC_FAN_AUTO, midea.getFan()); + midea.setFan(kMideaACFanAuto); + EXPECT_EQ(kMideaACFanAuto, midea.getFan()); EXPECT_EQ(0xA1826FFFFF62, midea.getRaw()); } @@ -333,81 +339,81 @@ TEST(TestMideaACClass, Temperature) { IRMideaAC midea(0); midea.begin(); - midea.setRaw(0xA1826FFFFF62); // 77F / 25C - EXPECT_EQ(77, midea.getTemp()); // F + midea.setRaw(0xA1826FFFFF62); // 77F / 25C + EXPECT_EQ(77, midea.getTemp()); // F EXPECT_EQ(77, midea.getTemp(false)); // F - EXPECT_EQ(25, midea.getTemp(true)); // F + EXPECT_EQ(25, midea.getTemp(true)); // F midea.setTemp(0); - EXPECT_EQ(MIDEA_AC_MIN_TEMP_F, midea.getTemp()); + EXPECT_EQ(kMideaACMinTempF, midea.getTemp()); EXPECT_EQ(0xA18260FFFF6C, midea.getRaw()); midea.setTemp(255); - EXPECT_EQ(MIDEA_AC_MAX_TEMP_F, midea.getTemp()); + EXPECT_EQ(kMideaACMaxTempF, midea.getTemp()); EXPECT_EQ(0xA18278FFFF78, midea.getRaw()); midea.setTemp(0, true); - EXPECT_EQ(MIDEA_AC_MIN_TEMP_F, midea.getTemp()); + EXPECT_EQ(kMideaACMinTempF, midea.getTemp()); EXPECT_EQ(0xA18260FFFF6C, midea.getRaw()); midea.setTemp(255, true); - EXPECT_EQ(MIDEA_AC_MAX_TEMP_F, midea.getTemp()); + EXPECT_EQ(kMideaACMaxTempF, midea.getTemp()); EXPECT_EQ(0xA18278FFFF78, midea.getRaw()); // fahrenheit min/max etc. - midea.setTemp(MIDEA_AC_MIN_TEMP_F); - EXPECT_EQ(MIDEA_AC_MIN_TEMP_F, midea.getTemp()); + midea.setTemp(kMideaACMinTempF); + EXPECT_EQ(kMideaACMinTempF, midea.getTemp()); - midea.setTemp(MIDEA_AC_MAX_TEMP_F); - EXPECT_EQ(MIDEA_AC_MAX_TEMP_F, midea.getTemp()); + midea.setTemp(kMideaACMaxTempF); + EXPECT_EQ(kMideaACMaxTempF, midea.getTemp()); - midea.setTemp(MIDEA_AC_MIN_TEMP_F - 1); - EXPECT_EQ(MIDEA_AC_MIN_TEMP_F, midea.getTemp()); + midea.setTemp(kMideaACMinTempF - 1); + EXPECT_EQ(kMideaACMinTempF, midea.getTemp()); - midea.setTemp(MIDEA_AC_MAX_TEMP_F + 1); - EXPECT_EQ(MIDEA_AC_MAX_TEMP_F, midea.getTemp()); + midea.setTemp(kMideaACMaxTempF + 1); + EXPECT_EQ(kMideaACMaxTempF, midea.getTemp()); // celsius min/max etc. - midea.setTemp(MIDEA_AC_MIN_TEMP_C, true); - EXPECT_EQ(MIDEA_AC_MIN_TEMP_C, midea.getTemp(true)); - EXPECT_EQ(MIDEA_AC_MIN_TEMP_F, midea.getTemp(false)); + midea.setTemp(kMideaACMinTempC, true); + EXPECT_EQ(kMideaACMinTempC, midea.getTemp(true)); + EXPECT_EQ(kMideaACMinTempF, midea.getTemp(false)); - midea.setTemp(MIDEA_AC_MAX_TEMP_C, true); - EXPECT_EQ(MIDEA_AC_MAX_TEMP_C, midea.getTemp(true)); - EXPECT_EQ(MIDEA_AC_MAX_TEMP_F, midea.getTemp(false)); + midea.setTemp(kMideaACMaxTempC, true); + EXPECT_EQ(kMideaACMaxTempC, midea.getTemp(true)); + EXPECT_EQ(kMideaACMaxTempF, midea.getTemp(false)); - midea.setTemp(MIDEA_AC_MIN_TEMP_C - 1, true); - EXPECT_EQ(MIDEA_AC_MIN_TEMP_C, midea.getTemp(true)); + midea.setTemp(kMideaACMinTempC - 1, true); + EXPECT_EQ(kMideaACMinTempC, midea.getTemp(true)); - midea.setTemp(MIDEA_AC_MAX_TEMP_C + 1, true); - EXPECT_EQ(MIDEA_AC_MAX_TEMP_C, midea.getTemp(true)); - EXPECT_EQ(MIDEA_AC_MAX_TEMP_F, midea.getTemp(false)); + midea.setTemp(kMideaACMaxTempC + 1, true); + EXPECT_EQ(kMideaACMaxTempC, midea.getTemp(true)); + EXPECT_EQ(kMideaACMaxTempF, midea.getTemp(false)); // General changes. - midea.setTemp(17, true); // C - EXPECT_EQ(17, midea.getTemp(true)); // C + midea.setTemp(17, true); // C + EXPECT_EQ(17, midea.getTemp(true)); // C EXPECT_EQ(63, midea.getTemp(false)); // F - midea.setTemp(21, true); // C - EXPECT_EQ(21, midea.getTemp(true)); // C + midea.setTemp(21, true); // C + EXPECT_EQ(21, midea.getTemp(true)); // C EXPECT_EQ(70, midea.getTemp(false)); // F - midea.setTemp(25, true); // C - EXPECT_EQ(25, midea.getTemp(true)); // C + midea.setTemp(25, true); // C + EXPECT_EQ(25, midea.getTemp(true)); // C EXPECT_EQ(77, midea.getTemp(false)); // F - midea.setTemp(30, true); // C - EXPECT_EQ(30, midea.getTemp(true)); // C + midea.setTemp(30, true); // C + EXPECT_EQ(30, midea.getTemp(true)); // C EXPECT_EQ(86, midea.getTemp(false)); // F - midea.setTemp(80, false); // F - EXPECT_EQ(26, midea.getTemp(true)); // C + midea.setTemp(80, false); // F + EXPECT_EQ(26, midea.getTemp(true)); // C EXPECT_EQ(80, midea.getTemp(false)); // F - midea.setTemp(70); // F - EXPECT_EQ(21, midea.getTemp(true)); // C + midea.setTemp(70); // F + EXPECT_EQ(21, midea.getTemp(true)); // C EXPECT_EQ(70, midea.getTemp(false)); // F - EXPECT_EQ(70, midea.getTemp()); // F + EXPECT_EQ(70, midea.getTemp()); // F } // Tests for controlling the sleep state. @@ -431,12 +437,14 @@ TEST(TestMideaACClass, HumanReadableOutput) { midea.begin(); midea.setRaw(0xA1826FFFFF62); - EXPECT_EQ("Power: On, Mode: 2 (AUTO), Temp: 25C/77F, Fan: 0 (AUTO), " - "Sleep: Off", midea.toString()); + EXPECT_EQ( + "Power: On, Mode: 2 (AUTO), Temp: 25C/77F, Fan: 0 (AUTO), " + "Sleep: Off", + midea.toString()); midea.off(); midea.setTemp(25); - midea.setFan(MIDEA_AC_FAN_HI); - midea.setMode(MIDEA_AC_DRY); + midea.setFan(kMideaACFanHigh); + midea.setMode(kMideaACDry); midea.setSleep(true); EXPECT_EQ("Power: Off, Mode: 1 (DRY), Temp: 16C/62F, Fan: 3 (HI), Sleep: On", midea.toString()); @@ -458,9 +466,9 @@ TEST(TestDecodeMidea, NormalDecodeWithStrict) { irsend.reset(); irsend.sendMidea(0x1234567890DF); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodeMidea(&irsend.capture, MIDEA_BITS, true)); + ASSERT_TRUE(irrecv.decodeMidea(&irsend.capture, kMideaBits, true)); EXPECT_EQ(MIDEA, irsend.capture.decode_type); - EXPECT_EQ(MIDEA_BITS, irsend.capture.bits); + EXPECT_EQ(kMideaBits, irsend.capture.bits); EXPECT_EQ(0x1234567890DF, irsend.capture.value); EXPECT_EQ(0x0, irsend.capture.address); EXPECT_EQ(0x0, irsend.capture.command); @@ -470,9 +478,9 @@ TEST(TestDecodeMidea, NormalDecodeWithStrict) { irsend.reset(); irsend.sendMidea(0x0); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodeMidea(&irsend.capture, MIDEA_BITS, true)); + ASSERT_TRUE(irrecv.decodeMidea(&irsend.capture, kMideaBits, true)); EXPECT_EQ(MIDEA, irsend.capture.decode_type); - EXPECT_EQ(MIDEA_BITS, irsend.capture.bits); + EXPECT_EQ(kMideaBits, irsend.capture.bits); EXPECT_EQ(0x0, irsend.capture.value); EXPECT_EQ(0x0, irsend.capture.address); EXPECT_EQ(0x0, irsend.capture.command); @@ -482,9 +490,9 @@ TEST(TestDecodeMidea, NormalDecodeWithStrict) { irsend.reset(); irsend.sendMidea(0xFFFFFFFFFFA0); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodeMidea(&irsend.capture, MIDEA_BITS, true)); + ASSERT_TRUE(irrecv.decodeMidea(&irsend.capture, kMideaBits, true)); EXPECT_EQ(MIDEA, irsend.capture.decode_type); - EXPECT_EQ(MIDEA_BITS, irsend.capture.bits); + EXPECT_EQ(kMideaBits, irsend.capture.bits); EXPECT_EQ(0xFFFFFFFFFFA0, irsend.capture.value); EXPECT_EQ(0x0, irsend.capture.address); EXPECT_EQ(0x0, irsend.capture.command); @@ -497,7 +505,7 @@ TEST(TestDecodeMidea, NormalDecodeWithStrict) { irsend.makeDecodeResult(); ASSERT_TRUE(irrecv.decode(&irsend.capture)); EXPECT_EQ(MIDEA, irsend.capture.decode_type); - EXPECT_EQ(MIDEA_BITS, irsend.capture.bits); + EXPECT_EQ(kMideaBits, irsend.capture.bits); EXPECT_EQ(0xA18263FFFF6E, irsend.capture.value); EXPECT_EQ(0x0, irsend.capture.address); EXPECT_EQ(0x0, irsend.capture.command); @@ -512,24 +520,24 @@ TEST(TestDecodeMidea, NormalDecodeWithRepeatAndStrict) { // Normal Midea 48-bit message with 2 repeats. irsend.reset(); - irsend.sendMidea(0xA18263FFFF6E, MIDEA_BITS, 2); + irsend.sendMidea(0xA18263FFFF6E, kMideaBits, 2); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodeMidea(&irsend.capture, MIDEA_BITS, true)); + ASSERT_TRUE(irrecv.decodeMidea(&irsend.capture, kMideaBits, true)); EXPECT_EQ(MIDEA, irsend.capture.decode_type); - EXPECT_EQ(MIDEA_BITS, irsend.capture.bits); + EXPECT_EQ(kMideaBits, irsend.capture.bits); EXPECT_EQ(0xA18263FFFF6E, irsend.capture.value); EXPECT_FALSE(irsend.capture.repeat); - irsend.makeDecodeResult(2 * (2 * MIDEA_BITS + 4)); - ASSERT_TRUE(irrecv.decodeMidea(&irsend.capture, MIDEA_BITS, true)); + irsend.makeDecodeResult(2 * (2 * kMideaBits + 4)); + ASSERT_TRUE(irrecv.decodeMidea(&irsend.capture, kMideaBits, true)); EXPECT_EQ(MIDEA, irsend.capture.decode_type); - EXPECT_EQ(MIDEA_BITS, irsend.capture.bits); + EXPECT_EQ(kMideaBits, irsend.capture.bits); EXPECT_EQ(0xA18263FFFF6E, irsend.capture.value); - irsend.makeDecodeResult(4 * (2 * MIDEA_BITS + 4)); - ASSERT_TRUE(irrecv.decodeMidea(&irsend.capture, MIDEA_BITS, true)); + irsend.makeDecodeResult(4 * (2 * kMideaBits + 4)); + ASSERT_TRUE(irrecv.decodeMidea(&irsend.capture, kMideaBits, true)); EXPECT_EQ(MIDEA, irsend.capture.decode_type); - EXPECT_EQ(MIDEA_BITS, irsend.capture.bits); + EXPECT_EQ(kMideaBits, irsend.capture.bits); EXPECT_EQ(0xA18263FFFF6E, irsend.capture.value); } @@ -543,7 +551,7 @@ TEST(TestDecodeMidea, DecodeWithNonStrictSizes) { irsend.sendMidea(0x12, 8); // Illegal value Midea 8-bit message. irsend.makeDecodeResult(); // Should fail with strict on. - ASSERT_FALSE(irrecv.decodeMidea(&irsend.capture, MIDEA_BITS, true)); + ASSERT_FALSE(irrecv.decodeMidea(&irsend.capture, kMideaBits, true)); // Should pass if strict off. ASSERT_TRUE(irrecv.decodeMidea(&irsend.capture, 8, false)); EXPECT_EQ(MIDEA, irsend.capture.decode_type); @@ -554,7 +562,7 @@ TEST(TestDecodeMidea, DecodeWithNonStrictSizes) { irsend.sendMidea(0x12345678, 32); // Illegal value Midea 32-bit message. irsend.makeDecodeResult(); // Shouldn't pass with strict when we ask for less bits than we got. - ASSERT_FALSE(irrecv.decodeMidea(&irsend.capture, MIDEA_BITS, true)); + ASSERT_FALSE(irrecv.decodeMidea(&irsend.capture, kMideaBits, true)); irsend.makeDecodeResult(); // Should fail with strict when we ask for the wrong bit size. @@ -567,7 +575,7 @@ TEST(TestDecodeMidea, DecodeWithNonStrictSizes) { // Decode should fail if asked to decode non-multiples of 8 bits. irsend.reset(); - irsend.sendMidea(0x123456, MIDEA_BITS, 2); + irsend.sendMidea(0x123456, kMideaBits, 2); irsend.makeDecodeResult(); ASSERT_FALSE(irrecv.decodeMidea(&irsend.capture, 9, false)); } @@ -597,14 +605,15 @@ TEST(TestDecodeMidea, FailToDecodeNonMideaExample) { irsend.reset(); // Modified a few entries to unexpected values, based on previous test case. - uint16_t gc_test[39] = {38000, 1, 1, 322, 162, 20, 61, 20, 61, 20, 20, 20, 20, - 20, 20, 20, 127, 20, 61, 9, 20, 20, 61, 20, 20, 20, - 61, 20, 61, 20, 61, 20, 20, 20, 20, 20, 20, 20, 884}; + uint16_t gc_test[39] = {38000, 1, 1, 322, 162, 20, 61, 20, 61, 20, + 20, 20, 20, 20, 20, 20, 127, 20, 61, 9, + 20, 20, 61, 20, 20, 20, 61, 20, 61, 20, + 61, 20, 20, 20, 20, 20, 20, 20, 884}; irsend.sendGC(gc_test, 39); irsend.makeDecodeResult(); ASSERT_FALSE(irrecv.decodeMidea(&irsend.capture)); - ASSERT_FALSE(irrecv.decodeMidea(&irsend.capture, MIDEA_BITS, false)); + ASSERT_FALSE(irrecv.decodeMidea(&irsend.capture, kMideaBits, false)); } // Decode against a real capture reported by a user. See issue #354 @@ -615,26 +624,28 @@ TEST(TestDecodeMidea, DecodeRealExample) { irsend.reset(); uint16_t rawData[199] = { - 4366, 4470, 498, 1658, 522, 554, 498, 1658, 496, 580, 498, 580, 498, 578, - 498, 580, 498, 1658, 498, 1658, 498, 578, 498, 578, 498, 580, 496, 582, - 496, 578, 498, 1658, 498, 580, 498, 580, 498, 1656, 498, 1656, 500, 580, - 498, 578, 502, 576, 500, 1656, 498, 1656, 500, 1654, 500, 1656, 500, 1656, - 498, 1658, 498, 1656, 500, 1658, 498, 1656, 498, 1656, 500, 1656, 500, - 1654, 500, 1578, 578, 1658, 498, 1656, 500, 1658, 498, 1656, 498, 1656, - 500, 578, 498, 1638, 516, 1656, 500, 578, 500, 1656, 500, 1656, 498, 1658, - 522, 554, 500, 5258, 4366, 4472, 498, 580, 498, 1658, 498, 580, 498, 1656, - 500, 1600, 556, 1658, 500, 1656, 500, 578, 498, 578, 522, 1634, 498, 1588, - 568, 1658, 498, 1656, 500, 1654, 498, 580, 498, 1658, 498, 1658, 498, 580, - 496, 578, 500, 1654, 500, 1636, 518, 1656, 500, 578, 520, 558, 498, 578, - 498, 580, 498, 576, 500, 578, 498, 580, 498, 578, 498, 578, 498, 580, 498, - 578, 498, 580, 498, 580, 520, 556, 498, 580, 496, 580, 498, 578, 500, 578, - 498, 1658, 498, 580, 498, 578, 498, 1656, 500, 578, 498, 580, 498, 580, - 498, 1656, 522}; + 4366, 4470, 498, 1658, 522, 554, 498, 1658, 496, 580, 498, 580, + 498, 578, 498, 580, 498, 1658, 498, 1658, 498, 578, 498, 578, + 498, 580, 496, 582, 496, 578, 498, 1658, 498, 580, 498, 580, + 498, 1656, 498, 1656, 500, 580, 498, 578, 502, 576, 500, 1656, + 498, 1656, 500, 1654, 500, 1656, 500, 1656, 498, 1658, 498, 1656, + 500, 1658, 498, 1656, 498, 1656, 500, 1656, 500, 1654, 500, 1578, + 578, 1658, 498, 1656, 500, 1658, 498, 1656, 498, 1656, 500, 578, + 498, 1638, 516, 1656, 500, 578, 500, 1656, 500, 1656, 498, 1658, + 522, 554, 500, 5258, 4366, 4472, 498, 580, 498, 1658, 498, 580, + 498, 1656, 500, 1600, 556, 1658, 500, 1656, 500, 578, 498, 578, + 522, 1634, 498, 1588, 568, 1658, 498, 1656, 500, 1654, 498, 580, + 498, 1658, 498, 1658, 498, 580, 496, 578, 500, 1654, 500, 1636, + 518, 1656, 500, 578, 520, 558, 498, 578, 498, 580, 498, 576, + 500, 578, 498, 580, 498, 578, 498, 578, 498, 580, 498, 578, + 498, 580, 498, 580, 520, 556, 498, 580, 496, 580, 498, 578, + 500, 578, 498, 1658, 498, 580, 498, 578, 498, 1656, 500, 578, + 498, 580, 498, 580, 498, 1656, 522}; irsend.sendRaw(rawData, 199, 38000); irsend.makeDecodeResult(); ASSERT_TRUE(irrecv.decode(&irsend.capture)); EXPECT_EQ(MIDEA, irsend.capture.decode_type); - EXPECT_EQ(MIDEA_BITS, irsend.capture.bits); + EXPECT_EQ(kMideaBits, irsend.capture.bits); EXPECT_EQ(0xA18263FFFF6E, irsend.capture.value); } diff --git a/lib/IRremoteESP8266/test/ir_Mitsubishi_test.cpp b/lib/IRremoteESP8266/test/ir_Mitsubishi_test.cpp index 861a1ce..7b8eb21 100644 --- a/lib/IRremoteESP8266/test/ir_Mitsubishi_test.cpp +++ b/lib/IRremoteESP8266/test/ir_Mitsubishi_test.cpp @@ -1,8 +1,10 @@ // Copyright 2017 David Conran +// Copyright 2018 denxhun +#include "ir_Mitsubishi.h" +#include "IRrecv_test.h" #include "IRsend.h" #include "IRsend_test.h" -#include "ir_Mitsubishi.h" #include "gtest/gtest.h" // Tests for sendMitsubishi(). @@ -20,7 +22,8 @@ TEST(TestSendMitsubishi, SendDataOnly) { "m300s28080" "m300s2100m300s2100m300s2100m300s900m300s900m300s900m300s2100m300s900" "m300s900m300s2100m300s900m300s900m300s900m300s900m300s2100m300s900" - "m300s28080", irsend.outputStr()); + "m300s28080", + irsend.outputStr()); irsend.reset(); irsend.sendMitsubishi(0x0); @@ -30,7 +33,8 @@ TEST(TestSendMitsubishi, SendDataOnly) { "m300s34080" "m300s900m300s900m300s900m300s900m300s900m300s900m300s900m300s900" "m300s900m300s900m300s900m300s900m300s900m300s900m300s900m300s900" - "m300s34080", irsend.outputStr()); + "m300s34080", + irsend.outputStr()); irsend.reset(); irsend.sendMitsubishi(0x4321); @@ -40,7 +44,8 @@ TEST(TestSendMitsubishi, SendDataOnly) { "m300s28080" "m300s900m300s2100m300s900m300s900m300s900m300s900m300s2100m300s2100" "m300s900m300s900m300s2100m300s900m300s900m300s900m300s900m300s2100" - "m300s28080", irsend.outputStr()); + "m300s28080", + irsend.outputStr()); } // Test sending with different repeats. @@ -49,22 +54,24 @@ TEST(TestSendMitsubishi, SendWithRepeats) { irsend.begin(); irsend.reset(); - irsend.sendMitsubishi(0xE242, MITSUBISHI_BITS, 0); // 0 repeat. + irsend.sendMitsubishi(0xE242, kMitsubishiBits, 0); // 0 repeat. EXPECT_EQ( "m300s2100m300s2100m300s2100m300s900m300s900m300s900m300s2100m300s900" "m300s900m300s2100m300s900m300s900m300s900m300s900m300s2100m300s900" - "m300s28080", irsend.outputStr()); + "m300s28080", + irsend.outputStr()); irsend.reset(); - irsend.sendMitsubishi(0xE242, MITSUBISHI_BITS, 1); // 1 repeat. + irsend.sendMitsubishi(0xE242, kMitsubishiBits, 1); // 1 repeat. EXPECT_EQ( "m300s2100m300s2100m300s2100m300s900m300s900m300s900m300s2100m300s900" "m300s900m300s2100m300s900m300s900m300s900m300s900m300s2100m300s900" "m300s28080" "m300s2100m300s2100m300s2100m300s900m300s900m300s900m300s2100m300s900" "m300s900m300s2100m300s900m300s900m300s900m300s900m300s2100m300s900" - "m300s28080", irsend.outputStr()); - irsend.sendMitsubishi(0xE242, MITSUBISHI_BITS, 2); // 2 repeats. + "m300s28080", + irsend.outputStr()); + irsend.sendMitsubishi(0xE242, kMitsubishiBits, 2); // 2 repeats. EXPECT_EQ( "m300s2100m300s2100m300s2100m300s900m300s900m300s900m300s2100m300s900" "m300s900m300s2100m300s900m300s900m300s900m300s900m300s2100m300s900" @@ -74,7 +81,8 @@ TEST(TestSendMitsubishi, SendWithRepeats) { "m300s28080" "m300s2100m300s2100m300s2100m300s900m300s900m300s900m300s2100m300s900" "m300s900m300s2100m300s900m300s900m300s900m300s900m300s2100m300s900" - "m300s28080", irsend.outputStr()); + "m300s28080", + irsend.outputStr()); } // Test sending an atypical data size. @@ -88,7 +96,8 @@ TEST(TestSendMitsubishi, SendUnusualSize) { "m300s900m300s900m300s900m300s900m300s900m300s900m300s900m300s900" "m300s43680" "m300s900m300s900m300s900m300s900m300s900m300s900m300s900m300s900" - "m300s43680", irsend.outputStr()); + "m300s43680", + irsend.outputStr()); irsend.reset(); irsend.sendMitsubishi(0x1234567890ABCDEF, 64); @@ -110,7 +119,8 @@ TEST(TestSendMitsubishi, SendUnusualSize) { "m300s2100m300s900m300s2100m300s900m300s2100m300s900m300s2100m300s2100" "m300s2100m300s2100m300s900m300s900m300s2100m300s2100m300s900m300s2100" "m300s2100m300s2100m300s2100m300s900m300s2100m300s2100m300s2100m300s2100" - "m300s28080", irsend.outputStr()); + "m300s28080", + irsend.outputStr()); } // Decode normal Mitsubishi messages. @@ -123,9 +133,9 @@ TEST(TestDecodeMitsubishi, NormalDecodeWithStrict) { irsend.reset(); irsend.sendMitsubishi(0xC2B8); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodeMitsubishi(&irsend.capture, MITSUBISHI_BITS, true)); + ASSERT_TRUE(irrecv.decodeMitsubishi(&irsend.capture, kMitsubishiBits, true)); EXPECT_EQ(MITSUBISHI, irsend.capture.decode_type); - EXPECT_EQ(MITSUBISHI_BITS, irsend.capture.bits); + EXPECT_EQ(kMitsubishiBits, irsend.capture.bits); EXPECT_EQ(0xC2B8, irsend.capture.value); EXPECT_EQ(0x0, irsend.capture.address); EXPECT_EQ(0x0, irsend.capture.command); @@ -134,9 +144,9 @@ TEST(TestDecodeMitsubishi, NormalDecodeWithStrict) { irsend.reset(); irsend.sendMitsubishi(0x0); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodeMitsubishi(&irsend.capture, MITSUBISHI_BITS, true)); + ASSERT_TRUE(irrecv.decodeMitsubishi(&irsend.capture, kMitsubishiBits, true)); EXPECT_EQ(MITSUBISHI, irsend.capture.decode_type); - EXPECT_EQ(MITSUBISHI_BITS, irsend.capture.bits); + EXPECT_EQ(kMitsubishiBits, irsend.capture.bits); EXPECT_EQ(0x0, irsend.capture.value); EXPECT_EQ(0x0, irsend.capture.address); EXPECT_EQ(0x0, irsend.capture.command); @@ -145,9 +155,9 @@ TEST(TestDecodeMitsubishi, NormalDecodeWithStrict) { irsend.reset(); irsend.sendMitsubishi(0xFFFF); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodeMitsubishi(&irsend.capture, MITSUBISHI_BITS, true)); + ASSERT_TRUE(irrecv.decodeMitsubishi(&irsend.capture, kMitsubishiBits, true)); EXPECT_EQ(MITSUBISHI, irsend.capture.decode_type); - EXPECT_EQ(MITSUBISHI_BITS, irsend.capture.bits); + EXPECT_EQ(kMitsubishiBits, irsend.capture.bits); EXPECT_EQ(0xFFFF, irsend.capture.value); EXPECT_EQ(0x0, irsend.capture.address); EXPECT_EQ(0x0, irsend.capture.command); @@ -158,14 +168,14 @@ TEST(TestDecodeMitsubishi, NormalDecodeWithStrict) { // 12 bits. irsend.sendMitsubishi(0xFFF, 12); irsend.makeDecodeResult(); - ASSERT_FALSE(irrecv.decodeMitsubishi(&irsend.capture, MITSUBISHI_BITS, true)); + ASSERT_FALSE(irrecv.decodeMitsubishi(&irsend.capture, kMitsubishiBits, true)); ASSERT_FALSE(irrecv.decodeMitsubishi(&irsend.capture, 12, true)); ASSERT_FALSE(irrecv.decodeMitsubishi(&irsend.capture, 64, true)); // 32 bits. irsend.sendMitsubishi(0xFFF, 32); irsend.makeDecodeResult(); - ASSERT_FALSE(irrecv.decodeMitsubishi(&irsend.capture, MITSUBISHI_BITS, true)); + ASSERT_FALSE(irrecv.decodeMitsubishi(&irsend.capture, kMitsubishiBits, true)); ASSERT_FALSE(irrecv.decodeMitsubishi(&irsend.capture, 12, true)); ASSERT_FALSE(irrecv.decodeMitsubishi(&irsend.capture, 32, true)); ASSERT_FALSE(irrecv.decodeMitsubishi(&irsend.capture, 64, true)); @@ -179,11 +189,11 @@ TEST(TestDecodeMitsubishi, NormalDecodeWithRepeatAndStrict) { // Normal Mitsubishi 16-bit message with 2 repeats. irsend.reset(); - irsend.sendMitsubishi(0xC2B8, MITSUBISHI_BITS, 2); + irsend.sendMitsubishi(0xC2B8, kMitsubishiBits, 2); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodeMitsubishi(&irsend.capture, MITSUBISHI_BITS, true)); + ASSERT_TRUE(irrecv.decodeMitsubishi(&irsend.capture, kMitsubishiBits, true)); EXPECT_EQ(MITSUBISHI, irsend.capture.decode_type); - EXPECT_EQ(MITSUBISHI_BITS, irsend.capture.bits); + EXPECT_EQ(kMitsubishiBits, irsend.capture.bits); EXPECT_EQ(0xC2B8, irsend.capture.value); EXPECT_EQ(0x0, irsend.capture.address); EXPECT_EQ(0x0, irsend.capture.command); @@ -191,11 +201,11 @@ TEST(TestDecodeMitsubishi, NormalDecodeWithRepeatAndStrict) { // Normal Mitsubishi 16-bit message with 0 repeats. irsend.reset(); - irsend.sendMitsubishi(0xC2B8, MITSUBISHI_BITS, 0); + irsend.sendMitsubishi(0xC2B8, kMitsubishiBits, 0); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodeMitsubishi(&irsend.capture, MITSUBISHI_BITS, true)); + ASSERT_TRUE(irrecv.decodeMitsubishi(&irsend.capture, kMitsubishiBits, true)); EXPECT_EQ(MITSUBISHI, irsend.capture.decode_type); - EXPECT_EQ(MITSUBISHI_BITS, irsend.capture.bits); + EXPECT_EQ(kMitsubishiBits, irsend.capture.bits); EXPECT_EQ(0xC2B8, irsend.capture.value); EXPECT_EQ(0x0, irsend.capture.address); EXPECT_EQ(0x0, irsend.capture.command); @@ -212,7 +222,7 @@ TEST(TestDecodeMitsubishi, DecodeWithNonStrictValues) { irsend.sendMitsubishi(0x0, 8); // Illegal sized Mitsubishi 8-bit message. irsend.makeDecodeResult(); // Should fail with strict on. - ASSERT_FALSE(irrecv.decodeMitsubishi(&irsend.capture, MITSUBISHI_BITS, true)); + ASSERT_FALSE(irrecv.decodeMitsubishi(&irsend.capture, kMitsubishiBits, true)); // Should pass if strict off. ASSERT_TRUE(irrecv.decodeMitsubishi(&irsend.capture, 8, false)); EXPECT_EQ(MITSUBISHI, irsend.capture.decode_type); @@ -227,7 +237,7 @@ TEST(TestDecodeMitsubishi, DecodeWithNonStrictValues) { irsend.sendMitsubishi(0xFEDCBA9876543210, 64); irsend.makeDecodeResult(); // Should fail with strict on. - ASSERT_FALSE(irrecv.decodeMitsubishi(&irsend.capture, MITSUBISHI_BITS, true)); + ASSERT_FALSE(irrecv.decodeMitsubishi(&irsend.capture, kMitsubishiBits, true)); // Should pass if strict off. ASSERT_TRUE(irrecv.decodeMitsubishi(&irsend.capture, 64, false)); EXPECT_EQ(MITSUBISHI, irsend.capture.decode_type); @@ -247,15 +257,15 @@ TEST(TestDecodeMitsubishi, DecodeGlobalCacheExample) { irsend.reset(); // Mitsubishi "Power On" (16-bit) code from Global Cache. - uint16_t gc_test[37] = {33000, 1, 1, 10, 70, 10, 70, 10, 70, 10, 30, 10, 30, - 10, 30, 10, 70, 10, 30, 10, 30, 10, 70, 10, 30, - 10, 30, 10, 30, 10, 30, 10, 70, 10, 30, 10, 936}; + uint16_t gc_test[37] = {33000, 1, 1, 10, 70, 10, 70, 10, 70, 10, 30, 10, 30, + 10, 30, 10, 70, 10, 30, 10, 30, 10, 70, 10, 30, 10, + 30, 10, 30, 10, 30, 10, 70, 10, 30, 10, 936}; irsend.sendGC(gc_test, 37); irsend.makeDecodeResult(); ASSERT_TRUE(irrecv.decodeMitsubishi(&irsend.capture)); EXPECT_EQ(MITSUBISHI, irsend.capture.decode_type); - EXPECT_EQ(MITSUBISHI_BITS, irsend.capture.bits); + EXPECT_EQ(kMitsubishiBits, irsend.capture.bits); EXPECT_EQ(0xE242, irsend.capture.value); EXPECT_EQ(0x0, irsend.capture.address); EXPECT_EQ(0x0, irsend.capture.command); @@ -270,15 +280,16 @@ TEST(TestDecodeMitsubishi, FailToDecodeNonMitsubishiExample) { irsend.reset(); // Modified a few entries to unexpected values, based on previous test case. - uint16_t gc_test[39] = {38000, 1, 1, 322, 162, 20, 61, 20, 61, 20, 20, 20, 20, - 20, 20, 20, 127, 20, 61, 9, 20, 20, 61, 20, 20, 20, - 61, 20, 61, 20, 61, 20, 20, 20, 20, 20, 20, 20, 884}; + uint16_t gc_test[39] = {38000, 1, 1, 322, 162, 20, 61, 20, 61, 20, + 20, 20, 20, 20, 20, 20, 127, 20, 61, 9, + 20, 20, 61, 20, 20, 20, 61, 20, 61, 20, + 61, 20, 20, 20, 20, 20, 20, 20, 884}; irsend.sendGC(gc_test, 39); irsend.makeDecodeResult(); ASSERT_FALSE(irrecv.decodeMitsubishi(&irsend.capture)); - ASSERT_FALSE(irrecv.decodeMitsubishi(&irsend.capture, MITSUBISHI_BITS, - false)); + ASSERT_FALSE( + irrecv.decodeMitsubishi(&irsend.capture, kMitsubishiBits, false)); } // Tests for Mitsubishi A/C methods. @@ -288,7 +299,7 @@ TEST(TestSendMitsubishiAC, SendDataOnly) { IRsendTest irsend(4); irsend.begin(); - uint8_t mitsub_code[MITSUBISHI_AC_STATE_LENGTH] = { + uint8_t mitsub_code[kMitsubishiACStateLength] = { 0x23, 0xCB, 0x26, 0x01, 0x00, 0x20, 0x08, 0x06, 0x30, 0x45, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F}; irsend.reset(); @@ -333,7 +344,8 @@ TEST(TestSendMitsubishiAC, SendDataOnly) { "m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420" "m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420" "m450s1300m450s1300m450s1300m450s1300m450s1300m450s420m450s420m450s420" - "m440s17100", irsend.outputStr()); + "m440s17100", + irsend.outputStr()); } // Test sending with repeats. @@ -342,11 +354,11 @@ TEST(TestSendMitsubishiAC, SendWithRepeats) { irsend.begin(); irsend.reset(); - uint8_t mitsub_code[MITSUBISHI_AC_STATE_LENGTH] = { + uint8_t mitsub_code[kMitsubishiACStateLength] = { 0x23, 0xCB, 0x26, 0x01, 0x00, 0x20, 0x08, 0x06, 0x30, 0x45, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F}; - irsend.sendMitsubishiAC(mitsub_code, MITSUBISHI_AC_STATE_LENGTH, 0); + irsend.sendMitsubishiAC(mitsub_code, kMitsubishiACStateLength, 0); EXPECT_EQ( "m3400s1750" "m450s1300m450s1300m450s420m450s420m450s420m450s1300m450s420m450s420" @@ -367,10 +379,11 @@ TEST(TestSendMitsubishiAC, SendWithRepeats) { "m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420" "m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420" "m450s1300m450s1300m450s1300m450s1300m450s1300m450s420m450s420m450s420" - "m440s17100", irsend.outputStr()); + "m440s17100", + irsend.outputStr()); irsend.reset(); - irsend.sendMitsubishiAC(mitsub_code, MITSUBISHI_AC_STATE_LENGTH, 2); + irsend.sendMitsubishiAC(mitsub_code, kMitsubishiACStateLength, 2); EXPECT_EQ( "m3400s1750" "m450s1300m450s1300m450s420m450s420m450s420m450s1300m450s420m450s420" @@ -431,7 +444,8 @@ TEST(TestSendMitsubishiAC, SendWithRepeats) { "m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420" "m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420" "m450s1300m450s1300m450s1300m450s1300m450s1300m450s420m450s420m450s420" - "m440s17100", irsend.outputStr()); + "m440s17100", + irsend.outputStr()); } // Test sending atypical sizes. @@ -442,10 +456,9 @@ TEST(TestSendMitsubishiAC, SendUnexpectedSizes) { uint8_t mitsub_short_code[17] = {0x23, 0xCB, 0x26, 0x01, 0x00, 0x20, 0x08, 0x06, 0x30, 0x45, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - uint8_t mitsub_long_code[19] = {0x23, 0xCB, 0x26, 0x01, 0x00, 0x20, - 0x08, 0x06, 0x30, 0x45, 0x67, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, - 0x00}; + uint8_t mitsub_long_code[19] = {0x23, 0xCB, 0x26, 0x01, 0x00, 0x20, 0x08, + 0x06, 0x30, 0x45, 0x67, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1F, 0x00}; irsend.reset(); irsend.sendMitsubishiAC(mitsub_short_code, 17); ASSERT_EQ("", irsend.outputStr()); @@ -494,7 +507,8 @@ TEST(TestSendMitsubishiAC, SendUnexpectedSizes) { "m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420" "m450s1300m450s1300m450s1300m450s1300m450s1300m450s420m450s420m450s420" "m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420" - "m440s17100", irsend.outputStr()); + "m440s17100", + irsend.outputStr()); } // Tests for IRMitsubishiAC class. @@ -521,22 +535,22 @@ TEST(TestMitsubishiACClass, Temperature) { mitsub.begin(); mitsub.setTemp(0); - EXPECT_EQ(MITSUBISHI_AC_MIN_TEMP, mitsub.getTemp()); + EXPECT_EQ(kMitsubishiAcMinTemp, mitsub.getTemp()); mitsub.setTemp(255); - EXPECT_EQ(MITSUBISHI_AC_MAX_TEMP, mitsub.getTemp()); + EXPECT_EQ(kMitsubishiAcMaxTemp, mitsub.getTemp()); - mitsub.setTemp(MITSUBISHI_AC_MIN_TEMP); - EXPECT_EQ(MITSUBISHI_AC_MIN_TEMP, mitsub.getTemp()); + mitsub.setTemp(kMitsubishiAcMinTemp); + EXPECT_EQ(kMitsubishiAcMinTemp, mitsub.getTemp()); - mitsub.setTemp(MITSUBISHI_AC_MAX_TEMP); - EXPECT_EQ(MITSUBISHI_AC_MAX_TEMP, mitsub.getTemp()); + mitsub.setTemp(kMitsubishiAcMaxTemp); + EXPECT_EQ(kMitsubishiAcMaxTemp, mitsub.getTemp()); - mitsub.setTemp(MITSUBISHI_AC_MIN_TEMP - 1); - EXPECT_EQ(MITSUBISHI_AC_MIN_TEMP, mitsub.getTemp()); + mitsub.setTemp(kMitsubishiAcMinTemp - 1); + EXPECT_EQ(kMitsubishiAcMinTemp, mitsub.getTemp()); - mitsub.setTemp(MITSUBISHI_AC_MAX_TEMP + 1); - EXPECT_EQ(MITSUBISHI_AC_MAX_TEMP, mitsub.getTemp()); + mitsub.setTemp(kMitsubishiAcMaxTemp + 1); + EXPECT_EQ(kMitsubishiAcMaxTemp, mitsub.getTemp()); mitsub.setTemp(17); EXPECT_EQ(17, mitsub.getTemp()); @@ -555,60 +569,60 @@ TEST(TestMitsubishiACClass, OperatingMode) { IRMitsubishiAC mitsub(0); mitsub.begin(); - mitsub.setMode(MITSUBISHI_AC_AUTO); - EXPECT_EQ(MITSUBISHI_AC_AUTO, mitsub.getMode()); + mitsub.setMode(kMitsubishiAcAuto); + EXPECT_EQ(kMitsubishiAcAuto, mitsub.getMode()); - mitsub.setMode(MITSUBISHI_AC_COOL); - EXPECT_EQ(MITSUBISHI_AC_COOL, mitsub.getMode()); + mitsub.setMode(kMitsubishiAcCool); + EXPECT_EQ(kMitsubishiAcCool, mitsub.getMode()); - mitsub.setMode(MITSUBISHI_AC_HEAT); - EXPECT_EQ(MITSUBISHI_AC_HEAT, mitsub.getMode()); + mitsub.setMode(kMitsubishiAcHeat); + EXPECT_EQ(kMitsubishiAcHeat, mitsub.getMode()); - mitsub.setMode(MITSUBISHI_AC_DRY); - EXPECT_EQ(MITSUBISHI_AC_DRY, mitsub.getMode()); + mitsub.setMode(kMitsubishiAcDry); + EXPECT_EQ(kMitsubishiAcDry, mitsub.getMode()); - mitsub.setMode(MITSUBISHI_AC_AUTO + 1); - EXPECT_EQ(MITSUBISHI_AC_AUTO, mitsub.getMode()); + mitsub.setMode(kMitsubishiAcAuto + 1); + EXPECT_EQ(kMitsubishiAcAuto, mitsub.getMode()); mitsub.setMode(255); - EXPECT_EQ(MITSUBISHI_AC_AUTO, mitsub.getMode()); + EXPECT_EQ(kMitsubishiAcAuto, mitsub.getMode()); } TEST(TestMitsubishiACClass, VaneMode) { IRMitsubishiAC mitsub(0); mitsub.begin(); - mitsub.setVane(MITSUBISHI_AC_VANE_AUTO); - EXPECT_EQ(MITSUBISHI_AC_VANE_AUTO, mitsub.getVane()); + mitsub.setVane(kMitsubishiAcVaneAuto); + EXPECT_EQ(kMitsubishiAcVaneAuto, mitsub.getVane()); - mitsub.setVane(MITSUBISHI_AC_VANE_AUTO + 1); - EXPECT_EQ(MITSUBISHI_AC_VANE_AUTO + 1, mitsub.getVane()); + mitsub.setVane(kMitsubishiAcVaneAuto + 1); + EXPECT_EQ(kMitsubishiAcVaneAuto + 1, mitsub.getVane()); - mitsub.setVane(MITSUBISHI_AC_VANE_AUTO_MOVE); - EXPECT_EQ(MITSUBISHI_AC_VANE_AUTO_MOVE, mitsub.getVane()); + mitsub.setVane(kMitsubishiAcVaneAutoMove); + EXPECT_EQ(kMitsubishiAcVaneAutoMove, mitsub.getVane()); - mitsub.setVane(MITSUBISHI_AC_VANE_AUTO_MOVE + 1); - EXPECT_EQ(MITSUBISHI_AC_VANE_AUTO_MOVE, mitsub.getVane()); + mitsub.setVane(kMitsubishiAcVaneAutoMove + 1); + EXPECT_EQ(kMitsubishiAcVaneAutoMove, mitsub.getVane()); - mitsub.setVane(MITSUBISHI_AC_VANE_AUTO_MOVE - 1); - EXPECT_EQ(MITSUBISHI_AC_VANE_AUTO_MOVE - 1, mitsub.getVane()); + mitsub.setVane(kMitsubishiAcVaneAutoMove - 1); + EXPECT_EQ(kMitsubishiAcVaneAutoMove - 1, mitsub.getVane()); } TEST(TestMitsubishiACClass, FanSpeed) { IRMitsubishiAC mitsub(0); mitsub.begin(); - mitsub.setFan(MITSUBISHI_AC_FAN_AUTO); - EXPECT_EQ(MITSUBISHI_AC_FAN_AUTO, mitsub.getFan()); + mitsub.setFan(kMitsubishiAcFanAuto); + EXPECT_EQ(kMitsubishiAcFanAuto, mitsub.getFan()); mitsub.setFan(255); - EXPECT_EQ(MITSUBISHI_AC_FAN_REAL_MAX, mitsub.getFan()); + EXPECT_EQ(kMitsubishiAcFanRealMax, mitsub.getFan()); - mitsub.setFan(MITSUBISHI_AC_FAN_MAX); - EXPECT_EQ(MITSUBISHI_AC_FAN_REAL_MAX, mitsub.getFan()); + mitsub.setFan(kMitsubishiAcFanMax); + EXPECT_EQ(kMitsubishiAcFanRealMax, mitsub.getFan()); - mitsub.setFan(MITSUBISHI_AC_FAN_MAX - 1); - EXPECT_EQ(MITSUBISHI_AC_FAN_MAX - 1, mitsub.getFan()); + mitsub.setFan(kMitsubishiAcFanMax - 1); + EXPECT_EQ(kMitsubishiAcFanMax - 1, mitsub.getFan()); mitsub.setFan(1); EXPECT_EQ(1, mitsub.getFan()); @@ -622,11 +636,11 @@ TEST(TestMitsubishiACClass, FanSpeed) { mitsub.setFan(4); EXPECT_EQ(4, mitsub.getFan()); - mitsub.setFan(MITSUBISHI_AC_FAN_SILENT); - EXPECT_EQ(MITSUBISHI_AC_FAN_SILENT, mitsub.getFan()); + mitsub.setFan(kMitsubishiAcFanSilent); + EXPECT_EQ(kMitsubishiAcFanSilent, mitsub.getFan()); - mitsub.setFan(MITSUBISHI_AC_FAN_SILENT + 1); - EXPECT_EQ(MITSUBISHI_AC_FAN_REAL_MAX, mitsub.getFan()); + mitsub.setFan(kMitsubishiAcFanSilent + 1); + EXPECT_EQ(kMitsubishiAcFanRealMax, mitsub.getFan()); } TEST(TestMitsubishiACClass, MessageConstuction) { @@ -636,14 +650,14 @@ TEST(TestMitsubishiACClass, MessageConstuction) { irsend.begin(); mitsub.setFan(1); - mitsub.setMode(MITSUBISHI_AC_COOL); + mitsub.setMode(kMitsubishiAcCool); mitsub.setTemp(27); mitsub.setVane(3); mitsub.on(); // Check everything for kicks. EXPECT_EQ(1, mitsub.getFan()); - EXPECT_EQ(MITSUBISHI_AC_COOL, mitsub.getMode()); + EXPECT_EQ(kMitsubishiAcCool, mitsub.getMode()); EXPECT_EQ(27, mitsub.getTemp()); EXPECT_EQ(3, mitsub.getVane()); EXPECT_TRUE(mitsub.getPower()); @@ -660,7 +674,7 @@ TEST(TestMitsubishiACClass, MessageConstuction) { "m450s420m450s420m450s420m450s420m450s420m450s1300m450s420m450s420" "m450s420m450s420m450s420m450s1300m450s1300m450s420m450s420m450s420" "m450s1300m450s1300m450s420m450s1300m450s420m450s420m450s420m450s420" - "m450s420m450s420m450s420m450s420m450s1300m450s1300m450s420m450s420" + "m450s420m450s1300m450s1300m450s420m450s1300m450s1300m450s420m450s420" "m450s1300m450s420m450s420m450s1300m450s1300m450s420m450s1300m450s420" "m450s1300m450s1300m450s1300m450s420m450s420m450s1300m450s1300m450s420" "m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420" @@ -669,7 +683,7 @@ TEST(TestMitsubishiACClass, MessageConstuction) { "m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420" "m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420" "m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420" - "m450s420m450s420m450s420m450s1300m450s420m450s420m450s1300m450s420" + "m450s420m450s1300m450s1300m450s1300m450s420m450s420m450s1300m450s420" "m440s17100" "m3400s1750" "m450s1300m450s1300m450s420m450s420m450s420m450s1300m450s420m450s420" @@ -680,7 +694,7 @@ TEST(TestMitsubishiACClass, MessageConstuction) { "m450s420m450s420m450s420m450s420m450s420m450s1300m450s420m450s420" "m450s420m450s420m450s420m450s1300m450s1300m450s420m450s420m450s420" "m450s1300m450s1300m450s420m450s1300m450s420m450s420m450s420m450s420" - "m450s420m450s420m450s420m450s420m450s1300m450s1300m450s420m450s420" + "m450s420m450s1300m450s1300m450s420m450s1300m450s1300m450s420m450s420" "m450s1300m450s420m450s420m450s1300m450s1300m450s420m450s1300m450s420" "m450s1300m450s1300m450s1300m450s420m450s420m450s1300m450s1300m450s420" "m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420" @@ -689,11 +703,278 @@ TEST(TestMitsubishiACClass, MessageConstuction) { "m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420" "m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420" "m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420" - "m450s420m450s420m450s420m450s1300m450s420m450s420m450s1300m450s420" - "m440s17100", irsend.outputStr()); + "m450s420m450s1300m450s1300m450s1300m450s420m450s420m450s1300m450s420" + "m440s17100", + irsend.outputStr()); } -// Tests for sendMitsubishi2(). +// Tests for decodeMitsubishiAC() with real captured example. +TEST(TestDecodeMitsubishiAC, DecodeRealExample) { + IRsendTest irsend(4); + IRrecv irrecv(4); + irsend.begin(); + + irsend.reset(); + // Mitsubishi AC "Power On, 16C, low fan, vane auto move". + uint16_t rawData[583] = { + 3476, 1708, 416, 1264, 420, 1260, 414, 400, 448, 390, 446, 392, + 444, 1236, 440, 400, 446, 392, 446, 1234, 440, 1266, 418, 396, + 442, 1264, 420, 394, 444, 394, 442, 1264, 422, 1260, 414, 398, + 440, 1266, 418, 1264, 420, 392, 446, 392, 444, 1264, 422, 392, + 446, 392, 446, 1260, 414, 400, 448, 390, 446, 392, 444, 394, + 442, 396, 442, 398, 440, 424, 412, 400, 448, 390, 446, 392, + 446, 392, 444, 394, 442, 396, 442, 396, 440, 398, 438, 400, + 448, 390, 446, 392, 446, 392, 444, 396, 442, 396, 440, 398, + 440, 400, 438, 400, 448, 390, 446, 392, 444, 1236, 440, 1266, + 418, 394, 442, 396, 440, 398, 438, 402, 446, 1232, 444, 396, + 440, 1268, 418, 394, 442, 396, 440, 398, 440, 400, 448, 390, + 448, 1232, 442, 1266, 420, 394, 444, 1264, 422, 1260, 416, 396, + 440, 398, 450, 1230, 444, 396, 442, 398, 440, 1266, 418, 1264, + 422, 1258, 416, 1266, 418, 394, 442, 396, 440, 398, 440, 398, + 438, 400, 446, 392, 446, 392, 446, 392, 444, 396, 442, 396, + 440, 398, 438, 398, 438, 400, 448, 392, 446, 392, 444, 394, + 444, 396, 442, 396, 440, 398, 438, 400, 448, 390, 448, 392, + 444, 394, 444, 394, 442, 396, 442, 396, 440, 398, 438, 400, + 448, 390, 446, 392, 446, 392, 444, 394, 442, 396, 442, 396, + 440, 398, 438, 400, 448, 390, 446, 392, 444, 394, 444, 394, + 442, 396, 440, 398, 440, 398, 438, 400, 448, 390, 446, 392, + 444, 394, 444, 394, 442, 396, 440, 398, 438, 400, 438, 400, + 448, 392, 446, 392, 444, 394, 442, 396, 442, 396, 440, 398, + 438, 1240, 444, 1264, 422, 390, 446, 392, 446, 1260, 414, 1268, + 418, 1264, 422, 12984, 3478, 1708, 418, 1264, 422, 1234, 442, 398, + 448, 390, 446, 392, 446, 1234, 440, 400, 448, 390, 446, 1234, + 442, 1266, 420, 392, 444, 1264, 420, 392, 446, 394, 444, 1236, + 448, 1260, 416, 398, 440, 1266, 418, 1262, 422, 390, 446, 392, + 444, 1234, 440, 400, 448, 392, 446, 1234, 440, 398, 450, 390, + 446, 392, 444, 394, 444, 394, 442, 396, 442, 398, 440, 400, + 438, 400, 448, 390, 446, 392, 444, 394, 442, 396, 442, 396, + 440, 398, 438, 400, 448, 390, 446, 392, 446, 392, 444, 394, + 442, 396, 442, 396, 440, 398, 438, 400, 448, 416, 420, 392, + 444, 1234, 440, 1240, 446, 394, 442, 396, 440, 398, 438, 400, + 448, 1232, 444, 396, 440, 1240, 446, 394, 442, 396, 440, 398, + 440, 400, 448, 390, 446, 1232, 444, 1238, 446, 394, 444, 1236, + 448, 1232, 442, 396, 440, 398, 448, 1232, 444, 396, 440, 398, + 438, 1242, 444, 1238, 448, 1234, 442, 1240, 444, 394, 442, 396, + 440, 398, 438, 400, 448, 390, 446, 394, 444, 420, 416, 394, + 444, 396, 440, 398, 440, 398, 438, 400, 448, 418, 420, 418, + 418, 394, 442, 396, 442, 396, 440, 424, 412, 400, 448, 390, + 446, 392, 446, 420, 418, 420, 416, 396, 440, 398, 440, 424, + 412, 426, 420, 418, 420, 392, 444, 394, 444, 422, 416, 422, + 414, 398, 440, 426, 422, 388, 448, 416, 420, 418, 418, 422, + 416, 422, 414, 424, 414, 398, 438, 426, 422, 418, 420, 390, + 446, 418, 418, 420, 416, 396, 440, 424, 412, 426, 412, 400, + 446, 418, 420, 420, 418, 420, 416, 422, 414, 422, 414, 424, + 412, 426, 422, 390, 446, 1232, 442, 1240, 446, 394, 444, 394, + 442, 1238, 446, 1234, 440, 1240, 444}; // UNKNOWN F6FDB82B + + irsend.sendRaw(rawData, 583, 33); + irsend.makeDecodeResult(); + + ASSERT_TRUE(irrecv.decode(&irsend.capture)); + EXPECT_EQ(MITSUBISHI_AC, irsend.capture.decode_type); + EXPECT_EQ(kMitsubishiACBits, irsend.capture.bits); + uint8_t expected[kMitsubishiACStateLength] = { + 0x23, 0xCB, 0x26, 0x01, 0x00, 0x00, 0x18, 0x0A, 0x36, + 0x79, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE6}; + EXPECT_STATE_EQ(expected, irsend.capture.state, kMitsubishiACBits); +} + +// Tests for decodeMitsubishiAC() when the first payload has an error. +TEST(TestDecodeMitsubishiAC, DecodeRealExampleRepeatNeeded) { + IRsendTest irsend(4); + IRrecv irrecv(4); + irsend.begin(); + + irsend.reset(); + // Mitsubishi AC "Power On, 16C, low fan, vane auto move". + uint16_t rawData[583] = { + 3476, 1708, 416, 1264, 420, 1260, 414, 400, 448, 390, 446, 392, 444, 1236, + 440, 400, 446, 392, 446, 1234, 440, 1266, 418, 396, 442, 1264, 420, 394, + 444, 394, 442, 1264, 422, 1260, 414, 398, 440, 1266, 418, 1264, 420, 392, + 446, 392, 444, 1264, 422, 392, 446, 392, 446, 1260, 414, 400, 448, 390, + 446, 392, 444, 394, 442, 396, 442, 398, 440, 424, 412, 400, 448, 390, 446, + 392, 446, 392, 444, 394, 442, 396, 442, 396, 440, 398, 438, 400, 448, 390, + 446, 392, 446, 392, 444, 396, 442, 396, 440, 398, 440, 400, 438, 400, 448, + 390, 446, 392, 444, 1236, 440, 1266, 418, 394, 442, 396, 440, 398, 438, + 402, 446, 1232, 444, 396, 440, 1268, 418, 394, 442, 396, 440, 398, + // space 699 is not recognizable: + 440, 400, 448, 390, 448, 1232, 442, 1266, 420, 394, 444, 1264, 699, 1260, + 416, 396, 440, 398, 450, 1230, 444, 396, 442, 398, 440, 1266, 418, 1264, + 422, 1258, 416, 1266, 418, 394, 442, 396, 440, 398, 440, 398, 438, 400, + 446, 392, 446, 392, 446, 392, 444, 396, 442, 396, 440, 398, 438, 398, 438, + 400, 448, 392, 446, 392, 444, 394, 444, 396, 442, 396, 440, 398, 438, 400, + 448, 390, 448, 392, 444, 394, 444, 394, 442, 396, 442, 396, 440, 398, 438, + 400, 448, 390, 446, 392, 446, 392, 444, 394, 442, 396, 442, 396, 440, 398, + 438, 400, 448, 390, 446, 392, 444, 394, 444, 394, 442, 396, 440, 398, 440, + 398, 438, 400, 448, 390, 446, 392, 444, 394, 444, 394, 442, 396, 440, 398, + 438, 400, 438, 400, 448, 392, 446, 392, 444, 394, 442, 396, 442, 396, 440, + 398, 438, 1240, 444, 1264, 422, 390, 446, 392, 446, 1260, 414, 1268, 418, + 1264, 422, 12984, 3478, 1708, 418, 1264, 422, 1234, 442, 398, 448, 390, + 446, 392, 446, 1234, 440, 400, 448, 390, 446, 1234, 442, 1266, 420, 392, + 444, 1264, 420, 392, 446, 394, 444, 1236, 448, 1260, 416, 398, 440, 1266, + 418, 1262, 422, 390, 446, 392, 444, 1234, 440, 400, 448, 392, 446, 1234, + 440, 398, 450, 390, 446, 392, 444, 394, 444, 394, 442, 396, 442, 398, 440, + 400, 438, 400, 448, 390, 446, 392, 444, 394, 442, 396, 442, 396, 440, 398, + 438, 400, 448, 390, 446, 392, 446, 392, 444, 394, 442, 396, 442, 396, 440, + 398, 438, 400, 448, 416, 420, 392, 444, 1234, 440, 1240, 446, 394, 442, + 396, 440, 398, 438, 400, 448, 1232, 444, 396, 440, 1240, 446, 394, 442, + 396, 440, 398, 440, 400, 448, 390, 446, 1232, 444, 1238, 446, 394, 444, + 1236, 448, 1232, 442, 396, 440, 398, 448, 1232, 444, 396, 440, 398, 438, + 1242, 444, 1238, 448, 1234, 442, 1240, 444, 394, 442, 396, 440, 398, 438, + 400, 448, 390, 446, 394, 444, 420, 416, 394, 444, 396, 440, 398, 440, 398, + 438, 400, 448, 418, 420, 418, 418, 394, 442, 396, 442, 396, 440, 424, 412, + 400, 448, 390, 446, 392, 446, 420, 418, 420, 416, 396, 440, 398, 440, 424, + 412, 426, 420, 418, 420, 392, 444, 394, 444, 422, 416, 422, 414, 398, 440, + 426, 422, 388, 448, 416, 420, 418, 418, 422, 416, 422, 414, 424, 414, 398, + 438, 426, 422, 418, 420, 390, 446, 418, 418, 420, 416, 396, 440, 424, 412, + 426, 412, 400, 446, 418, 420, 420, 418, 420, 416, 422, 414, 422, 414, 424, + 412, 426, 422, 390, 446, 1232, 442, 1240, 446, 394, 444, 394, 442, 1238, + 446, 1234, 440, 1240, 444}; // UNKNOWN F6FDB82B + + irsend.sendRaw(rawData, 583, 33); + irsend.makeDecodeResult(); + + ASSERT_TRUE(irrecv.decode(&irsend.capture)); + EXPECT_EQ(MITSUBISHI_AC, irsend.capture.decode_type); + EXPECT_EQ(kMitsubishiACBits, irsend.capture.bits); + uint8_t expected[kMitsubishiACStateLength] = { + 0x23, 0xCB, 0x26, 0x01, 0x00, 0x00, 0x18, 0x0A, 0x36, + 0x79, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE6}; + EXPECT_STATE_EQ(expected, irsend.capture.state, kMitsubishiACBits); +} + +// Tests for decodeMitsubishiAC() when the repeat mark is wrong. +TEST(TestDecodeMitsubishiAC, DecodeRealExampleRepeatMarkError) { + IRsendTest irsend(4); + IRrecv irrecv(4); + irsend.begin(); + + irsend.reset(); + // Mitsubishi AC "Power On, 16C, low fan, vane auto move". + uint16_t rawData[583] = { + 3476, 1708, 416, 1264, 420, 1260, 414, 400, 448, 390, 446, 392, 444, 1236, + 440, 400, 446, 392, 446, 1234, 440, 1266, 418, 396, 442, 1264, 420, 394, + 444, 394, 442, 1264, 422, 1260, 414, 398, 440, 1266, 418, 1264, 420, 392, + 446, 392, 444, 1264, 422, 392, 446, 392, 446, 1260, 414, 400, 448, 390, + 446, 392, 444, 394, 442, 396, 442, 398, 440, 424, 412, 400, 448, 390, 446, + 392, 446, 392, 444, 394, 442, 396, 442, 396, 440, 398, 438, 400, 448, 390, + 446, 392, 446, 392, 444, 396, 442, 396, 440, 398, 440, 400, 438, 400, 448, + 390, 446, 392, 444, 1236, 440, 1266, 418, 394, 442, 396, 440, 398, 438, + 402, 446, 1232, 444, 396, 440, 1268, 418, 394, 442, 396, 440, 398, 440, + 400, 448, 390, 448, 1232, 442, 1266, 420, 394, 444, 1264, 422, 1260, 416, + 396, 440, 398, 450, 1230, 444, 396, 442, 398, 440, 1266, 418, 1264, 422, + 1258, 416, 1266, 418, 394, 442, 396, 440, 398, 440, 398, 438, 400, 446, + 392, 446, 392, 446, 392, 444, 396, 442, 396, 440, 398, 438, 398, 438, 400, + 448, 392, 446, 392, 444, 394, 444, 396, 442, 396, 440, 398, 438, 400, 448, + 390, 448, 392, 444, 394, 444, 394, 442, 396, 442, 396, 440, 398, 438, 400, + 448, 390, 446, 392, 446, 392, 444, 394, 442, 396, 442, 396, 440, 398, 438, + 400, 448, 390, 446, 392, 444, 394, 444, 394, 442, 396, 440, 398, 440, 398, + 438, 400, 448, 390, 446, 392, 444, 394, 444, 394, 442, 396, 440, 398, 438, + 400, 438, 400, 448, 392, 446, 392, 444, 394, 442, 396, 442, 396, 440, 398, + 438, 1240, 444, 1264, 422, 390, 446, 392, 446, + // Repeat mark (1111) wrong: + 1260, 414, 1268, 418, 1264, 422, 1111, 347, 1708, 418, 1264, 422, 1234, + 442, 398, 448, 390, 446, 392, 446, 1234, 440, 400, 448, 390, 446, 1234, + 442, 1266, 420, 392, 444, 1264, 420, 392, 446, 394, 444, 1236, 448, 1260, + 416, 398, 440, 1266, 418, 1262, 422, 390, 446, 392, 444, 1234, 440, 400, + 448, 392, 446, 1234, 440, 398, 450, 390, 446, 392, 444, 394, 444, 394, + 442, 396, 442, 398, 440, 400, 438, 400, 448, 390, 446, 392, 444, 394, 442, + 396, 442, 396, 440, 398, 438, 400, 448, 390, 446, 392, 446, 392, 444, 394, + 442, 396, 442, 396, 440, 398, 438, 400, 448, 416, 420, 392, 444, 1234, + 440, 1240, 446, 394, 442, 396, 440, 398, 438, 400, 448, 1232, 444, 396, + 440, 1240, 446, 394, 442, 396, 440, 398, 440, 400, 448, 390, 446, 1232, + 444, 1238, 446, 394, 444, 1236, 448, 1232, 442, 396, 440, 398, 448, 1232, + 444, 396, 440, 398, 438, 1242, 444, 1238, 448, 1234, 442, 1240, 444, 394, + 442, 396, 440, 398, 438, 400, 448, 390, 446, 394, 444, 420, 416, 394, 444, + 396, 440, 398, 440, 398, 438, 400, 448, 418, 420, 418, 418, 394, 442, 396, + 442, 396, 440, 424, 412, 400, 448, 390, 446, 392, 446, 420, 418, 420, 416, + 396, 440, 398, 440, 424, 412, 426, 420, 418, 420, 392, 444, 394, 444, 422, + 416, 422, 414, 398, 440, 426, 422, 388, 448, 416, 420, 418, 418, 422, 416, + 422, 414, 424, 414, 398, 438, 426, 422, 418, 420, 390, 446, 418, 418, 420, + 416, 396, 440, 424, 412, 426, 412, 400, 446, 418, 420, 420, 418, 420, 416, + 422, 414, 422, 414, 424, 412, 426, 422, 390, 446, 1232, 442, 1240, 446, + 394, 444, 394, 442, 1238, 446, 1234, 440, 1240, 444}; // UNKNOWN F6FDB82B + + irsend.sendRaw(rawData, 583, 33); + irsend.makeDecodeResult(); + + ASSERT_TRUE(irrecv.decode(&irsend.capture)); + EXPECT_EQ(MITSUBISHI_AC, irsend.capture.decode_type); + EXPECT_EQ(kMitsubishiACBits, irsend.capture.bits); + uint8_t expected[kMitsubishiACStateLength] = { + 0x23, 0xCB, 0x26, 0x01, 0x00, 0x00, 0x18, 0x0A, 0x36, + 0x79, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE6}; + EXPECT_STATE_EQ(expected, irsend.capture.state, kMitsubishiACBits); +} + +// Tests for decodeMitsubishiAC() when first payload has an error and the +// repeat mark is wrong. +TEST(TestDecodeMitsubishiAC, DecodeRealExampleRepeatNeededButError) { + IRsendTest irsend(4); + IRrecv irrecv(4); + irsend.begin(); + + irsend.reset(); + // Mitsubishi AC "Power On, 16C, low fan, vane auto move". + uint16_t rawData[583] = { + 3476, 1708, 416, 1264, 420, 1260, 414, 400, 448, 390, 446, 392, 444, 1236, + 440, 400, 446, 392, 446, 1234, 440, 1266, 418, 396, 442, 1264, 420, 394, + 444, 394, 442, 1264, 422, 1260, 414, 398, 440, 1266, 418, 1264, 420, 392, + 446, 392, 444, 1264, 422, 392, 446, 392, 446, 1260, 414, 400, 448, 390, + 446, 392, 444, 394, 442, 396, 442, 398, 440, 424, 412, 400, 448, 390, 446, + 392, 446, 392, 444, 394, 442, 396, 442, 396, 440, 398, 438, 400, 448, 390, + 446, 392, 446, 392, 444, 396, 442, 396, 440, 398, 440, 400, 438, 400, 448, + 390, 446, 392, 444, 1236, 440, 1266, 418, 394, 442, 396, 440, 398, 438, + 402, 446, 1232, 444, 396, 440, 1268, 418, 394, 442, 396, 440, 398, + // space 699 is not recognizable: + 440, 400, 448, 390, 448, 1232, 442, 1266, 420, 394, 444, 1264, 699, 1260, + 416, 396, 440, 398, 450, 1230, 444, 396, 442, 398, 440, 1266, 418, 1264, + 422, 1258, 416, 1266, 418, 394, 442, 396, 440, 398, 440, 398, 438, 400, + 446, 392, 446, 392, 446, 392, 444, 396, 442, 396, 440, 398, 438, 398, 438, + 400, 448, 392, 446, 392, 444, 394, 444, 396, 442, 396, 440, 398, 438, 400, + 448, 390, 448, 392, 444, 394, 444, 394, 442, 396, 442, 396, 440, 398, 438, + 400, 448, 390, 446, 392, 446, 392, 444, 394, 442, 396, 442, 396, 440, 398, + 438, 400, 448, 390, 446, 392, 444, 394, 444, 394, 442, 396, 440, 398, 440, + 398, 438, 400, 448, 390, 446, 392, 444, 394, 444, 394, 442, 396, 440, 398, + 438, 400, 438, 400, 448, 392, 446, 392, 444, 394, 442, 396, 442, 396, 440, + 398, 438, 1240, 444, 1264, 422, 390, 446, 392, 446, + // 1111 is not a valid repeat mark: + 1260, 414, 1268, 418, 1264, 422, 1111, 3478, 1708, 418, 1264, 422, 1234, + 442, 398, 448, 390, 446, 392, 446, 1234, 440, 400, 448, 390, 446, 1234, + 442, 1266, 420, 392, 444, 1264, 420, 392, 446, 394, 444, 1236, 448, 1260, + 416, 398, 440, 1266, 418, 1262, 422, 390, 446, 392, 444, 1234, 440, 400, + 448, 392, 446, 1234, 440, 398, 450, 390, 446, 392, 444, 394, 444, 394, + 442, 396, 442, 398, 440, 400, 438, 400, 448, 390, 446, 392, 444, 394, 442, + 396, 442, 396, 440, 398, 438, 400, 448, 390, 446, 392, 446, 392, 444, 394, + 442, 396, 442, 396, 440, 398, 438, 400, 448, 416, 420, 392, 444, 1234, + 440, 1240, 446, 394, 442, 396, 440, 398, 438, 400, 448, 1232, 444, 396, + 440, 1240, 446, 394, 442, 396, 440, 398, 440, 400, 448, 390, 446, 1232, + 444, 1238, 446, 394, 444, 1236, 448, 1232, 442, 396, 440, 398, 448, 1232, + 444, 396, 440, 398, 438, 1242, 444, 1238, 448, 1234, 442, 1240, 444, 394, + 442, 396, 440, 398, 438, 400, 448, 390, 446, 394, 444, 420, 416, 394, 444, + 396, 440, 398, 440, 398, 438, 400, 448, 418, 420, 418, 418, 394, 442, 396, + 442, 396, 440, 424, 412, 400, 448, 390, 446, 392, 446, 420, 418, 420, 416, + 396, 440, 398, 440, 424, 412, 426, 420, 418, 420, 392, 444, 394, 444, 422, + 416, 422, 414, 398, 440, 426, 422, 388, 448, 416, 420, 418, 418, 422, 416, + 422, 414, 424, 414, 398, 438, 426, 422, 418, 420, 390, 446, 418, 418, 420, + 416, 396, 440, 424, 412, 426, 412, 400, 446, 418, 420, 420, 418, 420, 416, + 422, 414, 422, 414, 424, 412, 426, 422, 390, 446, 1232, 442, 1240, 446, + 394, 444, 394, 442, 1238, 446, 1234, 440, 1240, 444}; // UNKNOWN F6FDB82B + + irsend.sendRaw(rawData, 583, 33); + irsend.makeDecodeResult(); + + ASSERT_TRUE(irrecv.decode(&irsend.capture)); + EXPECT_EQ(UNKNOWN, irsend.capture.decode_type); +} + +TEST(TestMitsubishiACClass, HumanReadable) { + IRMitsubishiAC irMitsu(0); + EXPECT_EQ( + "Power: On (HEAT), Temp: 22C, FAN: SILENT, VANE: AUTO, " + "Time: 17:10, On timer: 00:00, Off timer: 00:00, Timer: -", + irMitsu.toString()); +} // Test sending typical data only. TEST(TestSendMitsubishi2, SendDataOnly) { @@ -712,7 +993,8 @@ TEST(TestSendMitsubishi2, SendDataOnly) { "m560s520m560s520m560s520m560s520m560s1560m560s1560m560s1560m560s1560" "m560s4200" "m560s1560m560s520m560s520m560s520m560s520m560s520m560s1560m560s520" - "m560s28500", irsend.outputStr()); + "m560s28500", + irsend.outputStr()); irsend.reset(); irsend.sendMitsubishi2(0x0); @@ -726,7 +1008,8 @@ TEST(TestSendMitsubishi2, SendDataOnly) { "m560s520m560s520m560s520m560s520m560s520m560s520m560s520m560s520" "m560s4200" "m560s520m560s520m560s520m560s520m560s520m560s520m560s520m560s520" - "m560s28500", irsend.outputStr()); + "m560s28500", + irsend.outputStr()); } // Test sending odd repeats. @@ -735,32 +1018,34 @@ TEST(TestSendMitsubishi2, Repeats) { irsend.begin(); irsend.reset(); - irsend.sendMitsubishi2(0xF82, MITSUBISHI_BITS, 0); + irsend.sendMitsubishi2(0xF82, kMitsubishiBits, 0); EXPECT_EQ( "m8400s4200" "m560s520m560s520m560s520m560s520m560s1560m560s1560m560s1560m560s1560" "m560s4200" "m560s1560m560s520m560s520m560s520m560s520m560s520m560s1560m560s520" - "m560s28500", irsend.outputStr()); + "m560s28500", + irsend.outputStr()); irsend.reset(); - irsend.sendMitsubishi2(0xF82, MITSUBISHI_BITS, 2); + irsend.sendMitsubishi2(0xF82, kMitsubishiBits, 2); EXPECT_EQ( - "m8400s4200" - "m560s520m560s520m560s520m560s520m560s1560m560s1560m560s1560m560s1560" - "m560s4200" - "m560s1560m560s520m560s520m560s520m560s520m560s520m560s1560m560s520" - "m560s28500" - "m8400s4200" - "m560s520m560s520m560s520m560s520m560s1560m560s1560m560s1560m560s1560" - "m560s4200" - "m560s1560m560s520m560s520m560s520m560s520m560s520m560s1560m560s520" - "m560s28500" - "m8400s4200" - "m560s520m560s520m560s520m560s520m560s1560m560s1560m560s1560m560s1560" - "m560s4200" - "m560s1560m560s520m560s520m560s520m560s520m560s520m560s1560m560s520" - "m560s28500", irsend.outputStr()); + "m8400s4200" + "m560s520m560s520m560s520m560s520m560s1560m560s1560m560s1560m560s1560" + "m560s4200" + "m560s1560m560s520m560s520m560s520m560s520m560s520m560s1560m560s520" + "m560s28500" + "m8400s4200" + "m560s520m560s520m560s520m560s520m560s1560m560s1560m560s1560m560s1560" + "m560s4200" + "m560s1560m560s520m560s520m560s520m560s520m560s520m560s1560m560s520" + "m560s28500" + "m8400s4200" + "m560s520m560s520m560s520m560s520m560s1560m560s1560m560s1560m560s1560" + "m560s4200" + "m560s1560m560s520m560s520m560s520m560s520m560s520m560s1560m560s520" + "m560s28500", + irsend.outputStr()); } // Tests for decodeMitsubishi2(). @@ -778,7 +1063,7 @@ TEST(TestDecodeMitsubishi2, DecodeSyntheticExamples) { ASSERT_TRUE(irrecv.decode(&irsend.capture)); EXPECT_EQ(MITSUBISHI2, irsend.capture.decode_type); - EXPECT_EQ(MITSUBISHI_BITS, irsend.capture.bits); + EXPECT_EQ(kMitsubishiBits, irsend.capture.bits); EXPECT_EQ(0xF82, irsend.capture.value); EXPECT_EQ(0xF, irsend.capture.address); EXPECT_EQ(0x82, irsend.capture.command); @@ -788,7 +1073,7 @@ TEST(TestDecodeMitsubishi2, DecodeSyntheticExamples) { irsend.makeDecodeResult(); ASSERT_TRUE(irrecv.decode(&irsend.capture)); EXPECT_EQ(MITSUBISHI2, irsend.capture.decode_type); - EXPECT_EQ(MITSUBISHI_BITS, irsend.capture.bits); + EXPECT_EQ(kMitsubishiBits, irsend.capture.bits); EXPECT_EQ(0x0, irsend.capture.value); EXPECT_EQ(0x0, irsend.capture.address); EXPECT_EQ(0x0, irsend.capture.command); @@ -798,7 +1083,7 @@ TEST(TestDecodeMitsubishi2, DecodeSyntheticExamples) { irsend.makeDecodeResult(); ASSERT_TRUE(irrecv.decode(&irsend.capture)); EXPECT_EQ(MITSUBISHI2, irsend.capture.decode_type); - EXPECT_EQ(MITSUBISHI_BITS, irsend.capture.bits); + EXPECT_EQ(kMitsubishiBits, irsend.capture.bits); EXPECT_EQ(0x1234, irsend.capture.value); EXPECT_EQ(0x12, irsend.capture.address); EXPECT_EQ(0x34, irsend.capture.command); @@ -813,21 +1098,20 @@ TEST(TestDecodeMitsubishi2, DecodeRealExample) { irsend.reset(); // Mitsubishi Projector "Power On" (16-bit). uint16_t rawData[75] = { - 8402, 4172, 554, 490, 562, 484, 560, 514, 532, 512, 534, 1566, - 526, 1572, 526, 1542, 560, 1568, 532, 4192, - 534, 1564, 532, 484, 560, 512, 532, 512, 532, 514, 530, 514, - 526, 1570, 524, 520, 526, 28506, - 8454, 4170, 560, 514, 528, 516, 526, 520, 524, 490, 556, 1572, - 534, 1534, 560, 1568, 530, 1538, 558, 4166, - 560, 1538, 558, 490, 560, 512, 530, 514, 532, 484, 558, 514, - 532, 1566, 530, 486, 554}; // UNKNOWN 96A1512F + 8402, 4172, 554, 490, 562, 484, 560, 514, 532, 512, 534, + 1566, 526, 1572, 526, 1542, 560, 1568, 532, 4192, 534, 1564, + 532, 484, 560, 512, 532, 512, 532, 514, 530, 514, 526, + 1570, 524, 520, 526, 28506, 8454, 4170, 560, 514, 528, 516, + 526, 520, 524, 490, 556, 1572, 534, 1534, 560, 1568, 530, + 1538, 558, 4166, 560, 1538, 558, 490, 560, 512, 530, 514, + 532, 484, 558, 514, 532, 1566, 530, 486, 554}; // UNKNOWN 96A1512F irsend.sendRaw(rawData, 75, 33); irsend.makeDecodeResult(); ASSERT_TRUE(irrecv.decode(&irsend.capture)); EXPECT_EQ(MITSUBISHI2, irsend.capture.decode_type); - EXPECT_EQ(MITSUBISHI_BITS, irsend.capture.bits); + EXPECT_EQ(kMitsubishiBits, irsend.capture.bits); EXPECT_EQ(0xF82, irsend.capture.value); EXPECT_EQ(0xF, irsend.capture.address); EXPECT_EQ(0x82, irsend.capture.command); diff --git a/lib/IRremoteESP8266/test/ir_NEC_test.cpp b/lib/IRremoteESP8266/test/ir_NEC_test.cpp index a3b915d..6b84b0e 100644 --- a/lib/IRremoteESP8266/test/ir_NEC_test.cpp +++ b/lib/IRremoteESP8266/test/ir_NEC_test.cpp @@ -11,18 +11,21 @@ TEST(TestSendNEC, SendDataOnly) { IRsendTest irsend(4); irsend.begin(); irsend.sendNEC(0); - EXPECT_EQ("m8960s4480m560s560m560s560m560s560m560s560m560s560m560s560m560s560" - "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560" - "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560" - "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560" - "m560s560m560s58240", irsend.outputStr()); + EXPECT_EQ( + "m8960s4480m560s560m560s560m560s560m560s560m560s560m560s560m560s560" + "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560" + "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560" + "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560" + "m560s560m560s58240", + irsend.outputStr()); irsend.sendNEC(0xAA00FF55); - EXPECT_EQ("m8960s4480m560s1680m560s560m560s1680m560s560m560s1680m560s560" - "m560s1680m560s560m560s560m560s560m560s560m560s560m560s560m560s560" - "m560s560m560s560m560s1680m560s1680m560s1680m560s1680m560s1680" - "m560s1680m560s1680m560s1680m560s560m560s1680m560s560m560s1680" - "m560s560m560s1680m560s560m560s1680m560s40320", - irsend.outputStr()); + EXPECT_EQ( + "m8960s4480m560s1680m560s560m560s1680m560s560m560s1680m560s560" + "m560s1680m560s560m560s560m560s560m560s560m560s560m560s560m560s560" + "m560s560m560s560m560s1680m560s1680m560s1680m560s1680m560s1680" + "m560s1680m560s1680m560s1680m560s560m560s1680m560s560m560s1680" + "m560s560m560s1680m560s560m560s1680m560s40320", + irsend.outputStr()); } // Test sending different bit lengths. @@ -33,19 +36,23 @@ TEST(TestSendNEC, SendSmallData) { EXPECT_EQ("m8960s4480m560s1680m560s560m560s1680m560s560m560s87360", irsend.outputStr()); irsend.sendNEC(0, 8); // Send only 8 data bits. - EXPECT_EQ("m8960s4480m560s560m560s560m560s560m560s560m560s560m560s560m560s560" - "m560s560m560s85120", irsend.outputStr()); + EXPECT_EQ( + "m8960s4480m560s560m560s560m560s560m560s560m560s560m560s560m560s560" + "m560s560m560s85120", + irsend.outputStr()); irsend.sendNEC(0x1234567890ABCDEF, 64); // Send 64 data bits. - EXPECT_EQ("m8960s4480m560s560m560s560m560s560m560s1680m560s560m560s560" - "m560s1680m560s560m560s560m560s560m560s1680m560s1680m560s560" - "m560s1680m560s560m560s560m560s560m560s1680m560s560m560s1680" - "m560s560m560s1680m560s1680m560s560m560s560m560s1680m560s1680" - "m560s1680m560s1680m560s560m560s560m560s560m560s1680m560s560" - "m560s560m560s1680m560s560m560s560m560s560m560s560m560s1680m560s560" - "m560s1680m560s560m560s1680m560s560m560s1680m560s1680m560s1680" - "m560s1680m560s560m560s560m560s1680m560s1680m560s560m560s1680" - "m560s1680m560s1680m560s1680m560s560m560s1680m560s1680m560s1680" - "m560s1680m560s22400", irsend.outputStr()); + EXPECT_EQ( + "m8960s4480m560s560m560s560m560s560m560s1680m560s560m560s560" + "m560s1680m560s560m560s560m560s560m560s1680m560s1680m560s560" + "m560s1680m560s560m560s560m560s560m560s1680m560s560m560s1680" + "m560s560m560s1680m560s1680m560s560m560s560m560s1680m560s1680" + "m560s1680m560s1680m560s560m560s560m560s560m560s1680m560s560" + "m560s560m560s1680m560s560m560s560m560s560m560s560m560s1680m560s560" + "m560s1680m560s560m560s1680m560s560m560s1680m560s1680m560s1680" + "m560s1680m560s560m560s560m560s1680m560s1680m560s560m560s1680" + "m560s1680m560s1680m560s1680m560s560m560s1680m560s1680m560s1680" + "m560s1680m560s22400", + irsend.outputStr()); } // Test sending with repeats. @@ -53,20 +60,24 @@ TEST(TestSendNEC, SendWithRepeats) { IRsendTest irsend(4); irsend.begin(); irsend.sendNEC(0, 8, 0); // Send a command with 0 repeats. - EXPECT_EQ("m8960s4480m560s560m560s560m560s560m560s560m560s560m560s560m560s560" - "m560s560m560s85120", irsend.outputStr()); + EXPECT_EQ( + "m8960s4480m560s560m560s560m560s560m560s560m560s560m560s560m560s560" + "m560s560m560s85120", + irsend.outputStr()); irsend.sendNEC(0xAA, 8, 1); // Send a command with 1 repeat. - EXPECT_EQ("m8960s4480m560s1680m560s560m560s1680m560s560m560s1680m560s560" - "m560s1680m560s560m560s80640" - "m8960s2240m560s96320", - irsend.outputStr()); + EXPECT_EQ( + "m8960s4480m560s1680m560s560m560s1680m560s560m560s1680m560s560" + "m560s1680m560s560m560s80640" + "m8960s2240m560s96320", + irsend.outputStr()); irsend.sendNEC(0xAA, 8, 3); // Send a command with 3 repeats. - EXPECT_EQ("m8960s4480m560s1680m560s560m560s1680m560s560m560s1680m560s560" - "m560s1680m560s560m560s80640" - "m8960s2240m560s96320" - "m8960s2240m560s96320" - "m8960s2240m560s96320", - irsend.outputStr()); + EXPECT_EQ( + "m8960s4480m560s1680m560s560m560s1680m560s560m560s1680m560s560" + "m560s1680m560s560m560s80640" + "m8960s2240m560s96320" + "m8960s2240m560s96320" + "m8960s2240m560s96320", + irsend.outputStr()); } // Tests for encodeNEC(). @@ -101,7 +112,7 @@ TEST(TestDecodeNEC, NormalNECDecodeWithStrict) { irsend.makeDecodeResult(); EXPECT_TRUE(irrecv.decodeNEC(&irsend.capture)); EXPECT_EQ(NEC, irsend.capture.decode_type); - EXPECT_EQ(NEC_BITS, irsend.capture.bits); + EXPECT_EQ(kNECBits, irsend.capture.bits); EXPECT_EQ(0x807F40BF, irsend.capture.value); EXPECT_EQ(0x1, irsend.capture.address); EXPECT_EQ(0x2, irsend.capture.command); @@ -112,7 +123,7 @@ TEST(TestDecodeNEC, NormalNECDecodeWithStrict) { irsend.makeDecodeResult(); EXPECT_TRUE(irrecv.decodeNEC(&irsend.capture)); EXPECT_EQ(NEC, irsend.capture.decode_type); - EXPECT_EQ(NEC_BITS, irsend.capture.bits); + EXPECT_EQ(kNECBits, irsend.capture.bits); EXPECT_EQ(0xC1A28877, irsend.capture.value); EXPECT_EQ(0x4583, irsend.capture.address); EXPECT_EQ(0x11, irsend.capture.command); @@ -129,7 +140,7 @@ TEST(TestDecodeNEC, NormalNECDecodeWithStrict) { irsend.makeDecodeResult(); EXPECT_TRUE(irrecv.decodeNEC(&irsend.capture)); EXPECT_EQ(NEC, irsend.capture.decode_type); - EXPECT_EQ(NEC_BITS, irsend.capture.bits); + EXPECT_EQ(kNECBits, irsend.capture.bits); EXPECT_EQ(0x807F40BF, irsend.capture.value); EXPECT_EQ(0x1, irsend.capture.address); EXPECT_EQ(0x2, irsend.capture.command); @@ -146,7 +157,7 @@ TEST(TestDecodeNEC, NormalNECDecodeWithoutStrict) { irsend.makeDecodeResult(); EXPECT_TRUE(irrecv.decodeNEC(&irsend.capture, 32, false)); EXPECT_EQ(NEC, irsend.capture.decode_type); - EXPECT_EQ(NEC_BITS, irsend.capture.bits); + EXPECT_EQ(kNECBits, irsend.capture.bits); EXPECT_EQ(0, irsend.capture.value); EXPECT_EQ(0, irsend.capture.address); EXPECT_EQ(0, irsend.capture.command); @@ -156,7 +167,7 @@ TEST(TestDecodeNEC, NormalNECDecodeWithoutStrict) { irsend.makeDecodeResult(); EXPECT_TRUE(irrecv.decodeNEC(&irsend.capture, 32, false)); EXPECT_EQ(NEC, irsend.capture.decode_type); - EXPECT_EQ(NEC_BITS, irsend.capture.bits); + EXPECT_EQ(kNECBits, irsend.capture.bits); EXPECT_EQ(0x12345678, irsend.capture.value); EXPECT_EQ(0x2C48, irsend.capture.address); EXPECT_EQ(0, irsend.capture.command); @@ -225,18 +236,18 @@ TEST(TestDecodeNEC, NoTrailingGap_Issue243) { irsend.begin(); irsend.reset(); - uint16_t rawData[67] = {9000, 4500, 650, 550, 650, 1650, 600, 550, 650, 550, - 600, 1650, 650, 550, 600, 1650, 650, 1650, 650, 1650, - 600, 550, 650, 1650, 650, 1650, 650, 550, 600, 1650, - 650, 1650, 650, 550, 650, 550, 650, 1650, 650, 550, - 650, 550, 650, 550, 600, 550, 650, 550, 650, 550, - 650, 1650, 600, 550, 650, 1650, 650, 1650, 650, 1650, - 650, 1650, 650, 1650, 650, 1650, 600}; + uint16_t rawData[67] = { + 9000, 4500, 650, 550, 650, 1650, 600, 550, 650, 550, 600, 1650, + 650, 550, 600, 1650, 650, 1650, 650, 1650, 600, 550, 650, 1650, + 650, 1650, 650, 550, 600, 1650, 650, 1650, 650, 550, 650, 550, + 650, 1650, 650, 550, 650, 550, 650, 550, 600, 550, 650, 550, + 650, 550, 650, 1650, 600, 550, 650, 1650, 650, 1650, 650, 1650, + 650, 1650, 650, 1650, 650, 1650, 600}; irsend.sendRaw(rawData, 67, 38); irsend.makeDecodeResult(); EXPECT_TRUE(irrecv.decodeNEC(&irsend.capture)); EXPECT_EQ(NEC, irsend.capture.decode_type); - EXPECT_EQ(NEC_BITS, irsend.capture.bits); + EXPECT_EQ(kNECBits, irsend.capture.bits); EXPECT_EQ(0x4BB640BF, irsend.capture.value); EXPECT_EQ(0x6DD2, irsend.capture.address); EXPECT_EQ(0x2, irsend.capture.command); @@ -246,7 +257,7 @@ TEST(TestDecodeNEC, NoTrailingGap_Issue243) { irsend.makeDecodeResult(); ASSERT_TRUE(irrecv.decode(&irsend.capture)); EXPECT_EQ(NEC, irsend.capture.decode_type); - EXPECT_EQ(NEC_BITS, irsend.capture.bits); + EXPECT_EQ(kNECBits, irsend.capture.bits); EXPECT_EQ(0x4BB640BF, irsend.capture.value); // Add a zero length space to the message to test how it handles that as @@ -255,7 +266,7 @@ TEST(TestDecodeNEC, NoTrailingGap_Issue243) { irsend.makeDecodeResult(); ASSERT_TRUE(irrecv.decode(&irsend.capture)); EXPECT_EQ(NEC, irsend.capture.decode_type); - EXPECT_EQ(NEC_BITS, irsend.capture.bits); + EXPECT_EQ(kNECBits, irsend.capture.bits); EXPECT_EQ(0x4BB640BF, irsend.capture.value); } @@ -270,18 +281,18 @@ TEST(TestDecodeNEC, NonStrictNECDecode_Issue264) { irsend.reset(); // Slightly modified example than reported due to poor timings that are too // far out of spec. - uint16_t rawData[67] = {9150, 4650, 550, 600, 550, 1800, 600, 1750, 600, 1800, - 550, 600, 550, 1800, 550, 1750, 600, 1750, 600, 1750, - 600, 1750, 600, 1700, 600, 600, 600, 600, 550, 600, - 600, 600, 600, 1750, 600, 1750, 600, 600, 550, 1800, - 600, 600, 600, 600, 600, 600, 500, 600, 600, 600, - 600, 600, 600, 1750, 600, 600, 600, 550, 600, 600, - 600, 600, 600, 600, 600, 550, 600}; + uint16_t rawData[67] = { + 9150, 4650, 550, 600, 550, 1800, 600, 1750, 600, 1800, 550, 600, + 550, 1800, 550, 1750, 600, 1750, 600, 1750, 600, 1750, 600, 1700, + 600, 600, 600, 600, 550, 600, 600, 600, 600, 1750, 600, 1750, + 600, 600, 550, 1800, 600, 600, 600, 600, 600, 600, 500, 600, + 600, 600, 600, 600, 600, 1750, 600, 600, 600, 550, 600, 600, + 600, 600, 600, 600, 600, 550, 600}; irsend.sendRaw(rawData, 67, 38); irsend.makeDecodeResult(); EXPECT_FALSE(irrecv.decodeNEC(&irsend.capture)); // Not strictly NEC - EXPECT_TRUE(irrecv.decodeNEC(&irsend.capture, NEC_BITS, false)); + EXPECT_TRUE(irrecv.decodeNEC(&irsend.capture, kNECBits, false)); EXPECT_EQ(0x77E1A040, irsend.capture.value); // Do it all again, but with a normal decode. @@ -290,7 +301,7 @@ TEST(TestDecodeNEC, NonStrictNECDecode_Issue264) { irsend.makeDecodeResult(); ASSERT_TRUE(irrecv.decode(&irsend.capture)); EXPECT_EQ(NEC_LIKE, irsend.capture.decode_type); - EXPECT_EQ(NEC_BITS, irsend.capture.bits); + EXPECT_EQ(kNECBits, irsend.capture.bits); EXPECT_EQ(0x77E1A040, irsend.capture.value); } @@ -303,18 +314,18 @@ TEST(TestDecodeNEC, AutoReceiveCalibration) { // Data from Issue #264, for a remote that is slightly off spec. // Should be matched as a NEC-like message however without self-calibrating // the timings of the short spaces is out. - uint16_t rawData[67] = {9150, 4600, 650, 600, 650, 1650, 650, 1700, 650, 1750, - 650, 600, 650, 1700, 650, 1750, 650, 1750, 650, 1700, - 650, 1700, 650, 1700, 650, 600, 650, 600, 650, 600, - 600, 600, 650, 1750, 650, 1750, 650, 600, 650, 1700, - 600, 600, 700, 550, 650, 550, 650, 600, 650, 600, - 650, 600, 650, 1750, 600, 600, 650, 600, 650, 550, - 650, 600, 650, 600, 650, 600, 600}; + uint16_t rawData[67] = { + 9150, 4600, 650, 600, 650, 1650, 650, 1700, 650, 1750, 650, 600, + 650, 1700, 650, 1750, 650, 1750, 650, 1700, 650, 1700, 650, 1700, + 650, 600, 650, 600, 650, 600, 600, 600, 650, 1750, 650, 1750, + 650, 600, 650, 1700, 600, 600, 700, 550, 650, 550, 650, 600, + 650, 600, 650, 600, 650, 1750, 600, 600, 650, 600, 650, 550, + 650, 600, 650, 600, 650, 600, 600}; irsend.sendRaw(rawData, 67, 38); irsend.makeDecodeResult(); - EXPECT_TRUE(irrecv.decodeNEC(&irsend.capture, NEC_BITS, false)); + EXPECT_TRUE(irrecv.decodeNEC(&irsend.capture, kNECBits, false)); EXPECT_EQ(NEC, irsend.capture.decode_type); - EXPECT_EQ(NEC_BITS, irsend.capture.bits); + EXPECT_EQ(kNECBits, irsend.capture.bits); EXPECT_EQ(0x77E1A040, irsend.capture.value); } diff --git a/lib/IRremoteESP8266/test/ir_Nikai_test.cpp b/lib/IRremoteESP8266/test/ir_Nikai_test.cpp index 0eea2bc..4a4ea05 100644 --- a/lib/IRremoteESP8266/test/ir_Nikai_test.cpp +++ b/lib/IRremoteESP8266/test/ir_Nikai_test.cpp @@ -12,12 +12,13 @@ TEST(TestSendNikai, SendDataOnly) { irsend.reset(); irsend.sendNikai(0xD5F2A); // Nikai TV Power Off. - EXPECT_EQ("m4000s4000" - "m500s2000m500s2000m500s2000m500s2000m500s1000m500s1000m500s2000" - "m500s1000m500s2000m500s1000m500s2000m500s1000m500s1000m500s1000" - "m500s1000m500s1000m500s2000m500s2000m500s1000m500s2000m500s1000" - "m500s2000m500s1000m500s2000m500s8500", - irsend.outputStr()); + EXPECT_EQ( + "m4000s4000" + "m500s2000m500s2000m500s2000m500s2000m500s1000m500s1000m500s2000" + "m500s1000m500s2000m500s1000m500s2000m500s1000m500s1000m500s1000" + "m500s1000m500s1000m500s2000m500s2000m500s1000m500s2000m500s1000" + "m500s2000m500s1000m500s2000m500s8500", + irsend.outputStr()); irsend.reset(); } @@ -28,35 +29,37 @@ TEST(TestSendNikai, SendWithRepeats) { irsend.begin(); irsend.reset(); - irsend.sendNikai(0xD5F2A, NIKAI_BITS, 1); // 1 repeat. - EXPECT_EQ("m4000s4000" - "m500s2000m500s2000m500s2000m500s2000m500s1000m500s1000m500s2000" - "m500s1000m500s2000m500s1000m500s2000m500s1000m500s1000m500s1000" - "m500s1000m500s1000m500s2000m500s2000m500s1000m500s2000m500s1000" - "m500s2000m500s1000m500s2000m500s8500" - "m4000s4000" - "m500s2000m500s2000m500s2000m500s2000m500s1000m500s1000m500s2000" - "m500s1000m500s2000m500s1000m500s2000m500s1000m500s1000m500s1000" - "m500s1000m500s1000m500s2000m500s2000m500s1000m500s2000m500s1000" - "m500s2000m500s1000m500s2000m500s8500", - irsend.outputStr()); - irsend.sendNikai(0xD5F2A, NIKAI_BITS, 2); // 2 repeat. - EXPECT_EQ("m4000s4000" - "m500s2000m500s2000m500s2000m500s2000m500s1000m500s1000m500s2000" - "m500s1000m500s2000m500s1000m500s2000m500s1000m500s1000m500s1000" - "m500s1000m500s1000m500s2000m500s2000m500s1000m500s2000m500s1000" - "m500s2000m500s1000m500s2000m500s8500" - "m4000s4000" - "m500s2000m500s2000m500s2000m500s2000m500s1000m500s1000m500s2000" - "m500s1000m500s2000m500s1000m500s2000m500s1000m500s1000m500s1000" - "m500s1000m500s1000m500s2000m500s2000m500s1000m500s2000m500s1000" - "m500s2000m500s1000m500s2000m500s8500" - "m4000s4000" - "m500s2000m500s2000m500s2000m500s2000m500s1000m500s1000m500s2000" - "m500s1000m500s2000m500s1000m500s2000m500s1000m500s1000m500s1000" - "m500s1000m500s1000m500s2000m500s2000m500s1000m500s2000m500s1000" - "m500s2000m500s1000m500s2000m500s8500", - irsend.outputStr()); + irsend.sendNikai(0xD5F2A, kNikaiBits, 1); // 1 repeat. + EXPECT_EQ( + "m4000s4000" + "m500s2000m500s2000m500s2000m500s2000m500s1000m500s1000m500s2000" + "m500s1000m500s2000m500s1000m500s2000m500s1000m500s1000m500s1000" + "m500s1000m500s1000m500s2000m500s2000m500s1000m500s2000m500s1000" + "m500s2000m500s1000m500s2000m500s8500" + "m4000s4000" + "m500s2000m500s2000m500s2000m500s2000m500s1000m500s1000m500s2000" + "m500s1000m500s2000m500s1000m500s2000m500s1000m500s1000m500s1000" + "m500s1000m500s1000m500s2000m500s2000m500s1000m500s2000m500s1000" + "m500s2000m500s1000m500s2000m500s8500", + irsend.outputStr()); + irsend.sendNikai(0xD5F2A, kNikaiBits, 2); // 2 repeat. + EXPECT_EQ( + "m4000s4000" + "m500s2000m500s2000m500s2000m500s2000m500s1000m500s1000m500s2000" + "m500s1000m500s2000m500s1000m500s2000m500s1000m500s1000m500s1000" + "m500s1000m500s1000m500s2000m500s2000m500s1000m500s2000m500s1000" + "m500s2000m500s1000m500s2000m500s8500" + "m4000s4000" + "m500s2000m500s2000m500s2000m500s2000m500s1000m500s1000m500s2000" + "m500s1000m500s2000m500s1000m500s2000m500s1000m500s1000m500s1000" + "m500s1000m500s1000m500s2000m500s2000m500s1000m500s2000m500s1000" + "m500s2000m500s1000m500s2000m500s8500" + "m4000s4000" + "m500s2000m500s2000m500s2000m500s2000m500s1000m500s1000m500s2000" + "m500s1000m500s2000m500s1000m500s2000m500s1000m500s1000m500s1000" + "m500s1000m500s1000m500s2000m500s2000m500s1000m500s2000m500s1000" + "m500s2000m500s1000m500s2000m500s8500", + irsend.outputStr()); } // Tests for decodeNikai(). @@ -71,17 +74,17 @@ TEST(TestDecodeNikai, NormalDecodeWithStrict) { irsend.reset(); irsend.sendNikai(0x123456); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodeNikai(&irsend.capture, NIKAI_BITS, true)); + ASSERT_TRUE(irrecv.decodeNikai(&irsend.capture, kNikaiBits, true)); EXPECT_EQ(NIKAI, irsend.capture.decode_type); - EXPECT_EQ(NIKAI_BITS, irsend.capture.bits); + EXPECT_EQ(kNikaiBits, irsend.capture.bits); EXPECT_EQ(0x123456, irsend.capture.value); irsend.reset(); irsend.sendNikai(0x101); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodeNikai(&irsend.capture, NIKAI_BITS, true)); + ASSERT_TRUE(irrecv.decodeNikai(&irsend.capture, kNikaiBits, true)); EXPECT_EQ(NIKAI, irsend.capture.decode_type); - EXPECT_EQ(NIKAI_BITS, irsend.capture.bits); + EXPECT_EQ(kNikaiBits, irsend.capture.bits); EXPECT_EQ(0x101, irsend.capture.value); } @@ -93,11 +96,11 @@ TEST(TestDecodeNikai, NormalDecodeWithRepeatAndStrict) { // Normal Nikai 24-bit message. irsend.reset(); - irsend.sendNikai(0xD5F2A, NIKAI_BITS, 2); + irsend.sendNikai(0xD5F2A, kNikaiBits, 2); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodeNikai(&irsend.capture, NIKAI_BITS, true)); + ASSERT_TRUE(irrecv.decodeNikai(&irsend.capture, kNikaiBits, true)); EXPECT_EQ(NIKAI, irsend.capture.decode_type); - EXPECT_EQ(NIKAI_BITS, irsend.capture.bits); + EXPECT_EQ(kNikaiBits, irsend.capture.bits); EXPECT_EQ(0xD5F2A, irsend.capture.value); } @@ -111,9 +114,9 @@ TEST(TestDecodeNikai, NormalDecodeWithNonStrict) { irsend.sendNikai(0x0, 16); irsend.makeDecodeResult(); // Should fail with strict on. - ASSERT_FALSE(irrecv.decodeNikai(&irsend.capture, NIKAI_BITS, true)); + ASSERT_FALSE(irrecv.decodeNikai(&irsend.capture, kNikaiBits, true)); // And it should fail when we expect more bits. - ASSERT_FALSE(irrecv.decodeNikai(&irsend.capture, NIKAI_BITS, false)); + ASSERT_FALSE(irrecv.decodeNikai(&irsend.capture, kNikaiBits, false)); // Should pass if strict off if we ask for correct nr. of bits sent. ASSERT_TRUE(irrecv.decodeNikai(&irsend.capture, 16, false)); @@ -136,7 +139,7 @@ TEST(TestDecodeNikai, Decode64BitMessages) { // Illegal size Nikai 64-bit message. irsend.sendNikai(0xFFFFFFFFFFFFFFFF, 64); irsend.makeDecodeResult(); - ASSERT_FALSE(irrecv.decodeNikai(&irsend.capture, NIKAI_BITS, true)); + ASSERT_FALSE(irrecv.decodeNikai(&irsend.capture, kNikaiBits, true)); // Should work with a 'normal' match (not strict) ASSERT_TRUE(irrecv.decodeNikai(&irsend.capture, 64, false)); EXPECT_EQ(NIKAI, irsend.capture.decode_type); @@ -152,32 +155,31 @@ TEST(TestDecodeNikai, DecodeExamples) { irsend.reset(); // Nikai TV Power Off from Issue #309 - uint16_t rawdata_off[100] = {4060, 3918, - 508, 2004, 508, 2002, 510, 2002, 508, 2004, 506, 1050, 508, 1048, - 510, 2004, 508, 1048, 508, 2002, 510, 1050, 508, 2004, 510, 1048, - 508, 1050, 508, 1048, 508, 1050, 508, 1050, 508, 2004, 508, 2002, - 510, 1048, 508, 2004, 508, 1050, 506, 2004, 508, 1048, 510, 2002, - 456, 8446, - 3956, 3998, - 508, 2004, 508, 2002, 508, 2004, 508, 1978, 532, 1050, 508, 1050, - 508, 2002, 508, 1050, 508, 2004, 508, 1050, 508, 2002, 510, 1050, - 508, 1050, 508, 1048, 508, 1050, 508, 1050, 508, 2002, 510, 2002, - 508, 1050, 508, 2002, 510, 1050, 508, 2002, 508}; + uint16_t rawdata_off[100] = { + 4060, 3918, 508, 2004, 508, 2002, 510, 2002, 508, 2004, 506, + 1050, 508, 1048, 510, 2004, 508, 1048, 508, 2002, 510, 1050, + 508, 2004, 510, 1048, 508, 1050, 508, 1048, 508, 1050, 508, + 1050, 508, 2004, 508, 2002, 510, 1048, 508, 2004, 508, 1050, + 506, 2004, 508, 1048, 510, 2002, 456, 8446, 3956, 3998, 508, + 2004, 508, 2002, 508, 2004, 508, 1978, 532, 1050, 508, 1050, + 508, 2002, 508, 1050, 508, 2004, 508, 1050, 508, 2002, 510, + 1050, 508, 1050, 508, 1048, 508, 1050, 508, 1050, 508, 2002, + 510, 2002, 508, 1050, 508, 2002, 510, 1050, 508, 2002, 508}; irsend.sendRaw(rawdata_off, 100, 38); irsend.makeDecodeResult(); ASSERT_TRUE(irrecv.decode(&irsend.capture)); EXPECT_EQ(NIKAI, irsend.capture.decode_type); - EXPECT_EQ(NIKAI_BITS, irsend.capture.bits); + EXPECT_EQ(kNikaiBits, irsend.capture.bits); EXPECT_EQ(0xD5F2A, irsend.capture.value); // Nikai TV Volume Up from Issue #309 - uint16_t rawdata_volup[52] = {3972, 4002, - 504, 1982, 526, 2010, 502, 2010, 502, 2010, 500, 1056, 502, 1056, - 502, 2010, 500, 1056, 502, 2010, 502, 2010, 500, 2010, 502, 2010, - 502, 1056, 502, 1056, 502, 1056, 500, 1056, 502, 2010, 502, 2010, - 500, 1056, 502, 2008, 502, 1054, 504, 1054, 504, 1054, 500, 1056, - 450}; + uint16_t rawdata_volup[52] = { + 3972, 4002, 504, 1982, 526, 2010, 502, 2010, 502, 2010, 500, + 1056, 502, 1056, 502, 2010, 500, 1056, 502, 2010, 502, 2010, + 500, 2010, 502, 2010, 502, 1056, 502, 1056, 502, 1056, 500, + 1056, 502, 2010, 502, 2010, 500, 1056, 502, 2008, 502, 1054, + 504, 1054, 504, 1054, 500, 1056, 450}; irsend.reset(); irsend.sendRaw(rawdata_volup, 52, 38); @@ -185,7 +187,7 @@ TEST(TestDecodeNikai, DecodeExamples) { ASSERT_TRUE(irrecv.decode(&irsend.capture)); EXPECT_EQ(NIKAI, irsend.capture.decode_type); - EXPECT_EQ(NIKAI_BITS, irsend.capture.bits); + EXPECT_EQ(kNikaiBits, irsend.capture.bits); EXPECT_EQ(0xD0F2F, irsend.capture.value); } @@ -196,15 +198,15 @@ TEST(TestDecodeNikai, FailToDecodeNonNikaiExample) { irsend.begin(); irsend.reset(); - uint16_t gc_test[71] = {38000, 1, 1, 172, 172, 22, 64, 22, 64, 22, 64, 22, 21, - 22, 21, 22, 21, 22, 11, 22, 21, 22, 128, 22, 64, 22, - 64, 22, 21, 22, 21, 22, 21, 22, 21, 22, 21, 22, 64, - 22, 21, 22, 21, 22, 64, 22, 64, 22, 21, 22, 21, 22, - 64, 22, 21, 22, 64, 22, 64, 22, 21, 22, 21, 22, 64, - 22, 64, 22, 21, 22, 1820}; + uint16_t gc_test[71] = {38000, 1, 1, 172, 172, 22, 64, 22, 64, 22, 64, 22, + 21, 22, 21, 22, 21, 22, 11, 22, 21, 22, 128, 22, + 64, 22, 64, 22, 21, 22, 21, 22, 21, 22, 21, 22, + 21, 22, 64, 22, 21, 22, 21, 22, 64, 22, 64, 22, + 21, 22, 21, 22, 64, 22, 21, 22, 64, 22, 64, 22, + 21, 22, 21, 22, 64, 22, 64, 22, 21, 22, 1820}; irsend.sendGC(gc_test, 71); irsend.makeDecodeResult(); ASSERT_FALSE(irrecv.decodeNikai(&irsend.capture)); - ASSERT_FALSE(irrecv.decodeNikai(&irsend.capture, NIKAI_BITS, false)); + ASSERT_FALSE(irrecv.decodeNikai(&irsend.capture, kNikaiBits, false)); } diff --git a/lib/IRremoteESP8266/test/ir_Panasonic_test.cpp b/lib/IRremoteESP8266/test/ir_Panasonic_test.cpp index 6e6c62d..a1d8a79 100644 --- a/lib/IRremoteESP8266/test/ir_Panasonic_test.cpp +++ b/lib/IRremoteESP8266/test/ir_Panasonic_test.cpp @@ -1,7 +1,11 @@ -// Copyright 2017 David Conran +// Copyright 2017, 2018 David Conran +#include "ir_Panasonic.h" +#include "IRrecv.h" +#include "IRrecv_test.h" #include "IRsend.h" #include "IRsend_test.h" +#include "IRutils.h" #include "gtest/gtest.h" // Tests for encodePanasonic(). @@ -18,7 +22,6 @@ TEST(TestEncodePanasonic, General) { EXPECT_EQ(0x40040190ED7C, irsend.encodePanasonic(0x4004, 0x01, 0x90, 0xED)); } - // Tests for sendPanasonic64(). // Test sending typical data only. @@ -36,7 +39,8 @@ TEST(TestSendPanasonic64, SendDataOnly) { "m432s432m432s432m432s432m432s432m432s432m432s432m432s432m432s432" "m432s432m432s432m432s432m432s432m432s432m432s432m432s432m432s432" "m432s432m432s432m432s432m432s432m432s432m432s432m432s432m432s432" - "m432s116208", irsend.outputStr()); + "m432s116208", + irsend.outputStr()); irsend.reset(); irsend.sendPanasonic64(0x40040190ED7C); @@ -48,7 +52,8 @@ TEST(TestSendPanasonic64, SendDataOnly) { "m432s1296m432s432m432s432m432s1296m432s432m432s432m432s432m432s432" "m432s1296m432s1296m432s1296m432s432m432s1296m432s1296m432s432m432s1296" "m432s432m432s1296m432s1296m432s1296m432s1296m432s1296m432s432m432s432" - "m432s102384", irsend.outputStr()); + "m432s102384", + irsend.outputStr()); irsend.reset(); irsend.sendPanasonic64(0xFFFFFFFFFFFF); @@ -60,7 +65,8 @@ TEST(TestSendPanasonic64, SendDataOnly) { "m432s1296m432s1296m432s1296m432s1296m432s1296m432s1296m432s1296m432s1296" "m432s1296m432s1296m432s1296m432s1296m432s1296m432s1296m432s1296m432s1296" "m432s1296m432s1296m432s1296m432s1296m432s1296m432s1296m432s1296m432s1296" - "m432s74736", irsend.outputStr()); + "m432s74736", + irsend.outputStr()); } // Test sending with different repeats. @@ -69,7 +75,7 @@ TEST(TestSendPanasonic64, SendWithRepeats) { irsend.begin(); irsend.reset(); - irsend.sendPanasonic64(0x40040190ED7C, PANASONIC_BITS, 0); // 0 repeats. + irsend.sendPanasonic64(0x40040190ED7C, kPanasonicBits, 0); // 0 repeats. EXPECT_EQ( "m3456s1728" "m432s432m432s1296m432s432m432s432m432s432m432s432m432s432m432s432" @@ -78,10 +84,11 @@ TEST(TestSendPanasonic64, SendWithRepeats) { "m432s1296m432s432m432s432m432s1296m432s432m432s432m432s432m432s432" "m432s1296m432s1296m432s1296m432s432m432s1296m432s1296m432s432m432s1296" "m432s432m432s1296m432s1296m432s1296m432s1296m432s1296m432s432m432s432" - "m432s102384", irsend.outputStr()); + "m432s102384", + irsend.outputStr()); irsend.reset(); - irsend.sendPanasonic64(0x40040190ED7C, PANASONIC_BITS, 1); // 1 repeat. + irsend.sendPanasonic64(0x40040190ED7C, kPanasonicBits, 1); // 1 repeat. EXPECT_EQ( "m3456s1728" "m432s432m432s1296m432s432m432s432m432s432m432s432m432s432m432s432" @@ -98,9 +105,10 @@ TEST(TestSendPanasonic64, SendWithRepeats) { "m432s1296m432s432m432s432m432s1296m432s432m432s432m432s432m432s432" "m432s1296m432s1296m432s1296m432s432m432s1296m432s1296m432s432m432s1296" "m432s432m432s1296m432s1296m432s1296m432s1296m432s1296m432s432m432s432" - "m432s102384", irsend.outputStr()); + "m432s102384", + irsend.outputStr()); - irsend.sendPanasonic64(0x40040190ED7C, PANASONIC_BITS, 2); // 2 repeats. + irsend.sendPanasonic64(0x40040190ED7C, kPanasonicBits, 2); // 2 repeats. EXPECT_EQ( "m3456s1728" "m432s432m432s1296m432s432m432s432m432s432m432s432m432s432m432s432" @@ -125,7 +133,8 @@ TEST(TestSendPanasonic64, SendWithRepeats) { "m432s1296m432s432m432s432m432s1296m432s432m432s432m432s432m432s432" "m432s1296m432s1296m432s1296m432s432m432s1296m432s1296m432s432m432s1296" "m432s432m432s1296m432s1296m432s1296m432s1296m432s1296m432s432m432s432" - "m432s102384", irsend.outputStr()); + "m432s102384", + irsend.outputStr()); } // Test sending an atypical data size. @@ -138,7 +147,8 @@ TEST(TestSendPanasonic64, SendUnusualSize) { EXPECT_EQ( "m3456s1728" "m432s432m432s432m432s432m432s432m432s432m432s432m432s432m432s432" - "m432s150768", irsend.outputStr()); + "m432s150768", + irsend.outputStr()); irsend.reset(); irsend.sendPanasonic64(0x1234567890ABCDEF, 64); @@ -152,7 +162,8 @@ TEST(TestSendPanasonic64, SendUnusualSize) { "m432s1296m432s432m432s1296m432s432m432s1296m432s432m432s1296m432s1296" "m432s1296m432s1296m432s432m432s432m432s1296m432s1296m432s432m432s1296" "m432s1296m432s1296m432s1296m432s432m432s1296m432s1296m432s1296m432s1296" - "m432s74736", irsend.outputStr()); + "m432s74736", + irsend.outputStr()); } // Tests for sendPanasonic(). @@ -183,8 +194,8 @@ TEST(TestSendPanasonic, CompareToSendPanasonic64) { panasonic64.sendPanasonic64(0x1234567890AB, 64); EXPECT_EQ(panasonic64.outputStr(), panasonic.outputStr()); - panasonic.sendPanasonic(0x1234, 0x567890AB, PANASONIC_BITS, 2); - panasonic64.sendPanasonic64(0x1234567890AB, PANASONIC_BITS, 2); + panasonic.sendPanasonic(0x1234, 0x567890AB, kPanasonicBits, 2); + panasonic64.sendPanasonic64(0x1234567890AB, kPanasonicBits, 2); EXPECT_EQ(panasonic64.outputStr(), panasonic.outputStr()); } @@ -200,9 +211,9 @@ TEST(TestDecodePanasonic, NormalDecodeWithStrict) { irsend.reset(); irsend.sendPanasonic64(0x40040190ED7C); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodePanasonic(&irsend.capture, PANASONIC_BITS, true)); + ASSERT_TRUE(irrecv.decodePanasonic(&irsend.capture, kPanasonicBits, true)); EXPECT_EQ(PANASONIC, irsend.capture.decode_type); - EXPECT_EQ(PANASONIC_BITS, irsend.capture.bits); + EXPECT_EQ(kPanasonicBits, irsend.capture.bits); EXPECT_EQ(0x40040190ED7C, irsend.capture.value); EXPECT_EQ(0x4004, irsend.capture.address); EXPECT_EQ(0x0190ED7C, irsend.capture.command); @@ -212,9 +223,9 @@ TEST(TestDecodePanasonic, NormalDecodeWithStrict) { irsend.reset(); irsend.sendPanasonic64(irsend.encodePanasonic(0x4004, 0x12, 0x34, 0x56)); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodePanasonic(&irsend.capture, PANASONIC_BITS, true)); + ASSERT_TRUE(irrecv.decodePanasonic(&irsend.capture, kPanasonicBits, true)); EXPECT_EQ(PANASONIC, irsend.capture.decode_type); - EXPECT_EQ(PANASONIC_BITS, irsend.capture.bits); + EXPECT_EQ(kPanasonicBits, irsend.capture.bits); EXPECT_EQ(0x400412345670, irsend.capture.value); EXPECT_EQ(0x4004, irsend.capture.address); EXPECT_EQ(0x12345670, irsend.capture.command); @@ -224,9 +235,9 @@ TEST(TestDecodePanasonic, NormalDecodeWithStrict) { irsend.reset(); irsend.sendPanasonic64(irsend.encodePanasonic(0x4004, 0x1, 0x1, 0x1)); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodePanasonic(&irsend.capture, PANASONIC_BITS, true)); + ASSERT_TRUE(irrecv.decodePanasonic(&irsend.capture, kPanasonicBits, true)); EXPECT_EQ(PANASONIC, irsend.capture.decode_type); - EXPECT_EQ(PANASONIC_BITS, irsend.capture.bits); + EXPECT_EQ(kPanasonicBits, irsend.capture.bits); EXPECT_EQ(0x400401010101, irsend.capture.value); EXPECT_EQ(0x4004, irsend.capture.address); EXPECT_EQ(0x1010101, irsend.capture.command); @@ -241,26 +252,26 @@ TEST(TestDecodePanasonic, NormalDecodeWithRepeatAndStrict) { // Normal Panasonic 48-bit message with 2 repeats. irsend.reset(); - irsend.sendPanasonic64(0x40040190ED7C, PANASONIC_BITS, 2); + irsend.sendPanasonic64(0x40040190ED7C, kPanasonicBits, 2); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodePanasonic(&irsend.capture, PANASONIC_BITS, true)); + ASSERT_TRUE(irrecv.decodePanasonic(&irsend.capture, kPanasonicBits, true)); EXPECT_EQ(PANASONIC, irsend.capture.decode_type); - EXPECT_EQ(PANASONIC_BITS, irsend.capture.bits); + EXPECT_EQ(kPanasonicBits, irsend.capture.bits); EXPECT_EQ(0x40040190ED7C, irsend.capture.value); EXPECT_EQ(0x4004, irsend.capture.address); EXPECT_EQ(0x190ED7C, irsend.capture.command); EXPECT_FALSE(irsend.capture.repeat); - irsend.makeDecodeResult(2 * PANASONIC_BITS + 4); - ASSERT_TRUE(irrecv.decodePanasonic(&irsend.capture, PANASONIC_BITS, true)); + irsend.makeDecodeResult(2 * kPanasonicBits + 4); + ASSERT_TRUE(irrecv.decodePanasonic(&irsend.capture, kPanasonicBits, true)); EXPECT_EQ(PANASONIC, irsend.capture.decode_type); - EXPECT_EQ(PANASONIC_BITS, irsend.capture.bits); + EXPECT_EQ(kPanasonicBits, irsend.capture.bits); EXPECT_EQ(0x40040190ED7C, irsend.capture.value); - irsend.makeDecodeResult(2 * (2 * PANASONIC_BITS + 4)); - ASSERT_TRUE(irrecv.decodePanasonic(&irsend.capture, PANASONIC_BITS, true)); + irsend.makeDecodeResult(2 * (2 * kPanasonicBits + 4)); + ASSERT_TRUE(irrecv.decodePanasonic(&irsend.capture, kPanasonicBits, true)); EXPECT_EQ(PANASONIC, irsend.capture.decode_type); - EXPECT_EQ(PANASONIC_BITS, irsend.capture.bits); + EXPECT_EQ(kPanasonicBits, irsend.capture.bits); EXPECT_EQ(0x40040190ED7C, irsend.capture.value); } @@ -274,11 +285,11 @@ TEST(TestDecodePanasonic, DecodeWithNonStrictValues) { irsend.sendPanasonic64(0x0); // Illegal value Panasonic 48-bit message. irsend.makeDecodeResult(); // Should fail with strict on. - ASSERT_FALSE(irrecv.decodePanasonic(&irsend.capture, PANASONIC_BITS, true)); + ASSERT_FALSE(irrecv.decodePanasonic(&irsend.capture, kPanasonicBits, true)); // Should pass if strict off. - ASSERT_TRUE(irrecv.decodePanasonic(&irsend.capture, PANASONIC_BITS, false)); + ASSERT_TRUE(irrecv.decodePanasonic(&irsend.capture, kPanasonicBits, false)); EXPECT_EQ(PANASONIC, irsend.capture.decode_type); - EXPECT_EQ(PANASONIC_BITS, irsend.capture.bits); + EXPECT_EQ(kPanasonicBits, irsend.capture.bits); EXPECT_EQ(0x0, irsend.capture.value); EXPECT_EQ(0x0, irsend.capture.address); EXPECT_EQ(0x0, irsend.capture.command); @@ -288,11 +299,11 @@ TEST(TestDecodePanasonic, DecodeWithNonStrictValues) { irsend.sendPanasonic64(irsend.encodePanasonic(0, 1, 2, 3)); irsend.makeDecodeResult(); // Should fail with strict on. - ASSERT_FALSE(irrecv.decodePanasonic(&irsend.capture, PANASONIC_BITS, true)); + ASSERT_FALSE(irrecv.decodePanasonic(&irsend.capture, kPanasonicBits, true)); // Should pass if strict off. - ASSERT_TRUE(irrecv.decodePanasonic(&irsend.capture, PANASONIC_BITS, false)); + ASSERT_TRUE(irrecv.decodePanasonic(&irsend.capture, kPanasonicBits, false)); EXPECT_EQ(PANASONIC, irsend.capture.decode_type); - EXPECT_EQ(PANASONIC_BITS, irsend.capture.bits); + EXPECT_EQ(kPanasonicBits, irsend.capture.bits); EXPECT_EQ(0x1020300, irsend.capture.value); EXPECT_EQ(0x0, irsend.capture.address); EXPECT_EQ(0x1020300, irsend.capture.command); @@ -308,7 +319,7 @@ TEST(TestDecodePanasonic, DecodeWithNonStrictSize) { irsend.sendPanasonic64(0x12345678, 32); // Illegal size Panasonic message. irsend.makeDecodeResult(); - ASSERT_FALSE(irrecv.decodePanasonic(&irsend.capture, PANASONIC_BITS, true)); + ASSERT_FALSE(irrecv.decodePanasonic(&irsend.capture, kPanasonicBits, true)); irsend.makeDecodeResult(); // Should fail with strict when we ask for the wrong bit size. @@ -326,9 +337,9 @@ TEST(TestDecodePanasonic, DecodeWithNonStrictSize) { irsend.sendPanasonic64(irsend.encodePanasonic(0x4004, 1, 2, 3), 56); irsend.makeDecodeResult(); - ASSERT_FALSE(irrecv.decodePanasonic(&irsend.capture, PANASONIC_BITS, true)); + ASSERT_FALSE(irrecv.decodePanasonic(&irsend.capture, kPanasonicBits, true)); // Shouldn't pass if strict off and wrong bit size. - ASSERT_FALSE(irrecv.decodePanasonic(&irsend.capture, PANASONIC_BITS, false)); + ASSERT_FALSE(irrecv.decodePanasonic(&irsend.capture, kPanasonicBits, false)); // Re-decode with correct bit size. ASSERT_FALSE(irrecv.decodePanasonic(&irsend.capture, 56, true)); ASSERT_TRUE(irrecv.decodePanasonic(&irsend.capture, 56, false)); @@ -367,20 +378,20 @@ TEST(TestDecodePanasonic, DecodeGlobalCacheExample) { irsend.reset(); // Panasonic code from Global Cache. - uint16_t gc_test[103] = {37000, 1, 1, 126, 64, 16, 17, 16, 49, 15, 16, 16, 16, - 16, 16, 16, 17, 15, 17, 15, 17, 15, 17, 15, 16, 16, - 16, 16, 16, 16, 17, 15, 49, 16, 16, 16, 16, 16, 17, - 15, 17, 15, 17, 15, 17, 15, 16, 16, 16, 16, 16, 16, - 49, 15, 49, 16, 17, 15, 17, 15, 49, 16, 16, 16, 17, - 16, 17, 15, 17, 15, 49, 16, 49, 15, 49, 16, 17, 16, - 49, 15, 49, 16, 17, 15, 48, 16, 16, 16, 49, 15, 48, - 16, 49, 15, 49, 16, 49, 15, 17, 15, 16, 16, 2721}; + uint16_t gc_test[103] = { + 37000, 1, 1, 126, 64, 16, 17, 16, 49, 15, 16, 16, 16, 16, 16, + 16, 17, 15, 17, 15, 17, 15, 17, 15, 16, 16, 16, 16, 16, 16, + 17, 15, 49, 16, 16, 16, 16, 16, 17, 15, 17, 15, 17, 15, 17, + 15, 16, 16, 16, 16, 16, 16, 49, 15, 49, 16, 17, 15, 17, 15, + 49, 16, 16, 16, 17, 16, 17, 15, 17, 15, 49, 16, 49, 15, 49, + 16, 17, 16, 49, 15, 49, 16, 17, 15, 48, 16, 16, 16, 49, 15, + 48, 16, 49, 15, 49, 16, 49, 15, 17, 15, 16, 16, 2721}; irsend.sendGC(gc_test, 103); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodePanasonic(&irsend.capture, PANASONIC_BITS, true)); + ASSERT_TRUE(irrecv.decodePanasonic(&irsend.capture, kPanasonicBits, true)); EXPECT_EQ(PANASONIC, irsend.capture.decode_type); - EXPECT_EQ(PANASONIC_BITS, irsend.capture.bits); + EXPECT_EQ(kPanasonicBits, irsend.capture.bits); EXPECT_EQ(0x40040190ED7C, irsend.capture.value); EXPECT_EQ(0x4004, irsend.capture.address); EXPECT_EQ(0x0190ED7C, irsend.capture.command); @@ -388,7 +399,7 @@ TEST(TestDecodePanasonic, DecodeGlobalCacheExample) { ASSERT_TRUE(irrecv.decodePanasonic(&irsend.capture)); EXPECT_EQ(PANASONIC, irsend.capture.decode_type); - EXPECT_EQ(PANASONIC_BITS, irsend.capture.bits); + EXPECT_EQ(kPanasonicBits, irsend.capture.bits); EXPECT_EQ(0x40040190ED7C, irsend.capture.value); EXPECT_EQ(0x4004, irsend.capture.address); EXPECT_EQ(0x0190ED7C, irsend.capture.command); @@ -403,14 +414,15 @@ TEST(TestDecodePanasonic, FailToDecodeNonPanasonicExample) { irsend.reset(); // Modified a few entries to unexpected values, based on previous test case. - uint16_t gc_test[39] = {38000, 1, 1, 322, 162, 20, 61, 20, 61, 20, 20, 20, 20, - 20, 20, 20, 127, 20, 61, 9, 20, 20, 61, 20, 20, 20, - 61, 20, 61, 20, 61, 20, 20, 20, 20, 20, 20, 20, 884}; + uint16_t gc_test[39] = {38000, 1, 1, 322, 162, 20, 61, 20, 61, 20, + 20, 20, 20, 20, 20, 20, 127, 20, 61, 9, + 20, 20, 61, 20, 20, 20, 61, 20, 61, 20, + 61, 20, 20, 20, 20, 20, 20, 20, 884}; irsend.sendGC(gc_test, 39); irsend.makeDecodeResult(); ASSERT_FALSE(irrecv.decodePanasonic(&irsend.capture)); - ASSERT_FALSE(irrecv.decodePanasonic(&irsend.capture, PANASONIC_BITS, false)); + ASSERT_FALSE(irrecv.decodePanasonic(&irsend.capture, kPanasonicBits, false)); } // Failing to decode Panasonic in Issue #245 @@ -421,23 +433,23 @@ TEST(TestDecodePanasonic, DecodeIssue245) { irsend.reset(); - uint16_t rawData[100] = {3550, 1750, 500, 450, 500, 1300, 500, 450, 500, 450, - 500, 450, 500, 450, 500, 450, 500, 450, 500, 450, - 500, 450, 500, 450, 500, 450, 500, 450, 500, 1300, - 500, 450, 500, 450, 500, 450, 500, 450, 500, 450, - 500, 450, 500, 450, 500, 450, 500, 450, 500, 1300, - 500, 450, 500, 450, 500, 450, 500, 450, 500, 450, - 500, 450, 500, 450, 500, 450, 500, 1300, 500, 450, - 500, 1300, 500, 1300, 500, 1300, 500, 1300, 500, 450, - 500, 450, 500, 1300, 500, 450, 500, 1300, 500, 1300, - 500, 1300, 500, 1300, 500, 450, 500, 1300, 500, 5000}; + uint16_t rawData[100] = { + 3550, 1750, 500, 450, 500, 1300, 500, 450, 500, 450, 500, 450, + 500, 450, 500, 450, 500, 450, 500, 450, 500, 450, 500, 450, + 500, 450, 500, 450, 500, 1300, 500, 450, 500, 450, 500, 450, + 500, 450, 500, 450, 500, 450, 500, 450, 500, 450, 500, 450, + 500, 1300, 500, 450, 500, 450, 500, 450, 500, 450, 500, 450, + 500, 450, 500, 450, 500, 450, 500, 1300, 500, 450, 500, 1300, + 500, 1300, 500, 1300, 500, 1300, 500, 450, 500, 450, 500, 1300, + 500, 450, 500, 1300, 500, 1300, 500, 1300, 500, 1300, 500, 450, + 500, 1300, 500, 5000}; irsend.sendRaw(rawData, 100, 37); irsend.makeDecodeResult(); ASSERT_TRUE(irrecv.decodePanasonic(&irsend.capture)); EXPECT_EQ(PANASONIC, irsend.capture.decode_type); - EXPECT_EQ(PANASONIC_BITS, irsend.capture.bits); + EXPECT_EQ(kPanasonicBits, irsend.capture.bits); EXPECT_EQ(0x40040100BCBD, irsend.capture.value); EXPECT_EQ(0x4004, irsend.capture.address); EXPECT_EQ(0x100BCBD, irsend.capture.command); @@ -449,9 +461,675 @@ TEST(TestDecodePanasonic, DecodeIssue245) { ASSERT_TRUE(irrecv.decode(&irsend.capture)); EXPECT_EQ(PANASONIC, irsend.capture.decode_type); - EXPECT_EQ(PANASONIC_BITS, irsend.capture.bits); + EXPECT_EQ(kPanasonicBits, irsend.capture.bits); EXPECT_EQ(0x40040100BCBD, irsend.capture.value); EXPECT_EQ(0x4004, irsend.capture.address); EXPECT_EQ(0x100BCBD, irsend.capture.command); EXPECT_FALSE(irsend.capture.repeat); } + +// Tests for sendPanasonicAC(). + +// Test sending typical data only. +TEST(TestSendPanasonicAC, SendDataOnly) { + IRsendTest irsend(0); + irsend.begin(); + + irsend.reset(); + + uint8_t state[kPanasonicAcStateLength] = { + 0x02, 0x20, 0xE0, 0x04, 0x00, 0x00, 0x00, 0x06, 0x02, + 0x20, 0xE0, 0x04, 0x00, 0x30, 0x32, 0x80, 0xAF, 0x00, + 0x00, 0x06, 0x60, 0x00, 0x00, 0x80, 0x00, 0x06, 0x83}; + irsend.sendPanasonicAC(state); + EXPECT_EQ( + "m3456s1728" + "m432s432m432s1296m432s432m432s432m432s432m432s432m432s432m432s432" + "m432s432m432s432m432s432m432s432m432s432m432s1296m432s432m432s432" + "m432s432m432s432m432s432m432s432m432s432m432s1296m432s1296m432s1296" + "m432s432m432s432m432s1296m432s432m432s432m432s432m432s432m432s432" + "m432s432m432s432m432s432m432s432m432s432m432s432m432s432m432s432" + "m432s432m432s432m432s432m432s432m432s432m432s432m432s432m432s432" + "m432s432m432s432m432s432m432s432m432s432m432s432m432s432m432s432" + "m432s432m432s1296m432s1296m432s432m432s432m432s432m432s432m432s432" + "m432s10000" + "m3456s1728" + "m432s432m432s1296m432s432m432s432m432s432m432s432m432s432m432s432" + "m432s432m432s432m432s432m432s432m432s432m432s1296m432s432m432s432" + "m432s432m432s432m432s432m432s432m432s432m432s1296m432s1296m432s1296" + "m432s432m432s432m432s1296m432s432m432s432m432s432m432s432m432s432" + "m432s432m432s432m432s432m432s432m432s432m432s432m432s432m432s432" + "m432s432m432s432m432s432m432s432m432s1296m432s1296m432s432m432s432" + "m432s432m432s1296m432s432m432s432m432s1296m432s1296m432s432m432s432" + "m432s432m432s432m432s432m432s432m432s432m432s432m432s432m432s1296" + "m432s1296m432s1296m432s1296m432s1296m432s432m432s1296m432s432m432s1296" + "m432s432m432s432m432s432m432s432m432s432m432s432m432s432m432s432" + "m432s432m432s432m432s432m432s432m432s432m432s432m432s432m432s432" + "m432s432m432s1296m432s1296m432s432m432s432m432s432m432s432m432s432" + "m432s432m432s432m432s432m432s432m432s432m432s1296m432s1296m432s432" + "m432s432m432s432m432s432m432s432m432s432m432s432m432s432m432s432" + "m432s432m432s432m432s432m432s432m432s432m432s432m432s432m432s432" + "m432s432m432s432m432s432m432s432m432s432m432s432m432s432m432s1296" + "m432s432m432s432m432s432m432s432m432s432m432s432m432s432m432s432" + "m432s432m432s1296m432s1296m432s432m432s432m432s432m432s432m432s432" + "m432s1296m432s1296m432s432m432s432m432s432m432s432m432s432m432s1296" + "m432s100000", + irsend.outputStr()); +} + +// Tests for the IRPanasonicAc class. + +TEST(TestIRPanasonicAcClass, ChecksumCalculation) { + IRPanasonicAc pana(0); + + const uint8_t originalstate[kPanasonicAcStateLength] = { + 0x02, 0x20, 0xE0, 0x04, 0x00, 0x00, 0x00, 0x06, 0x02, + 0x20, 0xE0, 0x04, 0x00, 0x30, 0x32, 0x80, 0xAF, 0x00, + 0x00, 0x06, 0x60, 0x00, 0x00, 0x80, 0x00, 0x06, 0x83}; + uint8_t examplestate[kPanasonicAcStateLength] = { + 0x02, 0x20, 0xE0, 0x04, 0x00, 0x00, 0x00, 0x06, 0x02, + 0x20, 0xE0, 0x04, 0x00, 0x30, 0x32, 0x80, 0xAF, 0x00, + 0x00, 0x06, 0x60, 0x00, 0x00, 0x80, 0x00, 0x06, 0x83}; + + EXPECT_TRUE(IRPanasonicAc::validChecksum(examplestate)); + EXPECT_EQ(0x83, IRPanasonicAc::calcChecksum(examplestate)); + + examplestate[kPanasonicAcStateLength - 1] = 0x0; // Set incoorect checksum. + EXPECT_FALSE(IRPanasonicAc::validChecksum(examplestate)); + EXPECT_EQ(0x83, IRPanasonicAc::calcChecksum(examplestate)); + pana.setRaw(examplestate); + // Extracting the state from the object should have a correct checksum. + EXPECT_TRUE(IRPanasonicAc::validChecksum(pana.getRaw())); + EXPECT_STATE_EQ(originalstate, pana.getRaw(), kPanasonicAcBits); + examplestate[kPanasonicAcStateLength - 1] = 0x83; // Restore old checksum. + + // Change the state to force a different checksum. + examplestate[6] = 0x01; // Should increase checksum by 1. + EXPECT_FALSE(IRPanasonicAc::validChecksum(examplestate)); + EXPECT_EQ(0x84, IRPanasonicAc::calcChecksum(examplestate)); +} + +TEST(TestIRPanasonicAcClass, SetAndGetPower) { + IRPanasonicAc pana(0); + pana.on(); + EXPECT_TRUE(pana.getPower()); + pana.off(); + EXPECT_FALSE(pana.getPower()); + pana.setPower(true); + EXPECT_TRUE(pana.getPower()); + pana.setPower(false); + EXPECT_FALSE(pana.getPower()); +} + +TEST(TestIRPanasonicAcClass, SetAndGetModel) { + IRPanasonicAc pana(0); + EXPECT_EQ(kPanasonicJke, pana.getModel()); + pana.setModel(kPanasonicDke); + EXPECT_EQ(kPanasonicDke, pana.getModel()); + pana.setModel(kPanasonicLke); + EXPECT_EQ(kPanasonicLke, pana.getModel()); + pana.setModel(kPanasonicNke); + EXPECT_EQ(kPanasonicNke, pana.getModel()); + pana.setModel(kPanasonicUnknown); // shouldn't change. + EXPECT_EQ(kPanasonicNke, pana.getModel()); + pana.setModel((panasonic_ac_remote_model_t)255); // shouldn't change. + EXPECT_EQ(kPanasonicNke, pana.getModel()); + pana.setModel(kPanasonicJke); + EXPECT_EQ(kPanasonicJke, pana.getModel()); + + // This state tickled a bug in getModel(). Should read as a JKE. + uint8_t jkeState[27] = {0x02, 0x20, 0xE0, 0x04, 0x00, 0x00, 0x00, 0x06, 0x02, + 0x20, 0xE0, 0x04, 0x00, 0x32, 0x2E, 0x80, 0xA2, 0x00, + 0x00, 0x06, 0x60, 0x00, 0x00, 0x80, 0x00, 0x06, 0x74}; + pana.setModel(kPanasonicDke); // Make sure it isn't somehow set to JKE + pana.setRaw(jkeState); + EXPECT_EQ(kPanasonicJke, pana.getModel()); + EXPECT_STATE_EQ(jkeState, pana.getRaw(), kPanasonicAcBits); + + // This state tickled a bug in getModel(). Should read as CKP. + uint8_t ckpState[27] = {0x02, 0x20, 0xE0, 0x04, 0x00, 0x00, 0x00, 0x06, 0x02, + 0x20, 0xE0, 0x04, 0x00, 0x67, 0x2E, 0x80, 0xAF, 0x00, + 0xC0, 0x6B, 0x98, 0x10, 0x00, 0x81, 0x64, 0x05, 0x87}; + pana.setModel(kPanasonicDke); // Make sure it isn't somehow set to CKP + pana.setRaw(ckpState); + EXPECT_EQ(kPanasonicCkp, pana.getModel()); + EXPECT_STATE_EQ(ckpState, pana.getRaw(), kPanasonicAcBits); +} + +TEST(TestIRPanasonicAcClass, SetAndGetMode) { + IRPanasonicAc pana(0); + pana.setMode(kPanasonicAcCool); + pana.setTemp(21); + EXPECT_EQ(kPanasonicAcCool, pana.getMode()); + pana.setMode(kPanasonicAcHeat); + EXPECT_EQ(kPanasonicAcHeat, pana.getMode()); + pana.setMode(kPanasonicAcAuto); + EXPECT_EQ(kPanasonicAcAuto, pana.getMode()); + pana.setMode(kPanasonicAcDry); + EXPECT_EQ(kPanasonicAcDry, pana.getMode()); + EXPECT_EQ(21, pana.getTemp()); // Temp should be unchanged. + pana.setMode(kPanasonicAcFan); + EXPECT_EQ(kPanasonicAcFan, pana.getMode()); + EXPECT_EQ(kPanasonicAcFanModeTemp, pana.getTemp()); // Temp should change. + pana.setMode(kPanasonicAcCool); + EXPECT_EQ(kPanasonicAcCool, pana.getMode()); + // Temp should be unchanged from the last manual change. + EXPECT_EQ(21, pana.getTemp()); +} + +TEST(TestIRPanasonicAcClass, SetAndGetTemp) { + IRPanasonicAc pana(0); + pana.setTemp(25); + EXPECT_EQ(25, pana.getTemp()); + pana.setTemp(kPanasonicAcMinTemp); + EXPECT_EQ(kPanasonicAcMinTemp, pana.getTemp()); + pana.setTemp(kPanasonicAcMinTemp - 1); + EXPECT_EQ(kPanasonicAcMinTemp, pana.getTemp()); + pana.setTemp(kPanasonicAcMaxTemp); + EXPECT_EQ(kPanasonicAcMaxTemp, pana.getTemp()); + pana.setTemp(kPanasonicAcMaxTemp + 1); + EXPECT_EQ(kPanasonicAcMaxTemp, pana.getTemp()); +} + +TEST(TestIRPanasonicAcClass, SetAndGetFan) { + IRPanasonicAc pana(0); + pana.setFan(kPanasonicAcFanAuto); + EXPECT_EQ(kPanasonicAcFanAuto, pana.getFan()); + pana.setFan(kPanasonicAcFanMin); + EXPECT_EQ(kPanasonicAcFanMin, pana.getFan()); + pana.setFan(kPanasonicAcFanMin - 1); + EXPECT_EQ(kPanasonicAcFanMin, pana.getFan()); + pana.setFan(kPanasonicAcFanMin + 1); + EXPECT_EQ(kPanasonicAcFanMin + 1, pana.getFan()); + pana.setFan(kPanasonicAcFanMax); + EXPECT_EQ(kPanasonicAcFanMax, pana.getFan()); + pana.setFan(kPanasonicAcFanMax + 1); + EXPECT_EQ(kPanasonicAcFanMax, pana.getFan()); + pana.setFan(kPanasonicAcFanMax - 1); + EXPECT_EQ(kPanasonicAcFanMax - 1, pana.getFan()); +} + +TEST(TestIRPanasonicAcClass, SetAndGetSwings) { + IRPanasonicAc pana(0); + + // Vertical + pana.setSwingVertical(kPanasonicAcSwingVAuto); + EXPECT_EQ(kPanasonicAcSwingVAuto, pana.getSwingVertical()); + + pana.setSwingVertical(kPanasonicAcSwingVUp); + EXPECT_EQ(kPanasonicAcSwingVUp, pana.getSwingVertical()); + pana.setSwingVertical(kPanasonicAcSwingVUp - 1); + EXPECT_EQ(kPanasonicAcSwingVUp, pana.getSwingVertical()); + pana.setSwingVertical(kPanasonicAcSwingVUp + 1); + EXPECT_EQ(kPanasonicAcSwingVUp + 1, pana.getSwingVertical()); + + pana.setSwingVertical(kPanasonicAcSwingVDown); + EXPECT_EQ(kPanasonicAcSwingVDown, pana.getSwingVertical()); + pana.setSwingVertical(kPanasonicAcSwingVDown + 1); + EXPECT_EQ(kPanasonicAcSwingVDown, pana.getSwingVertical()); + pana.setSwingVertical(kPanasonicAcSwingVDown - 1); + EXPECT_EQ(kPanasonicAcSwingVDown - 1, pana.getSwingVertical()); + + pana.setSwingVertical(kPanasonicAcSwingVAuto); + EXPECT_EQ(kPanasonicAcSwingVAuto, pana.getSwingVertical()); + + // Horizontal is model dependant. + pana.setModel(kPanasonicNke); // NKE is always fixed in the middle. + EXPECT_EQ(kPanasonicAcSwingHMiddle, pana.getSwingHorizontal()); + pana.setSwingHorizontal(kPanasonicAcSwingHAuto); + EXPECT_EQ(kPanasonicAcSwingHMiddle, pana.getSwingHorizontal()); + + pana.setModel(kPanasonicJke); // JKE has no H swing. + EXPECT_EQ(0, pana.getSwingHorizontal()); + pana.setSwingHorizontal(kPanasonicAcSwingHMiddle); + EXPECT_EQ(0, pana.getSwingHorizontal()); + + pana.setModel(kPanasonicLke); // LKE is always fixed in the middle. + EXPECT_EQ(kPanasonicAcSwingHMiddle, pana.getSwingHorizontal()); + pana.setSwingHorizontal(kPanasonicAcSwingHAuto); + EXPECT_EQ(kPanasonicAcSwingHMiddle, pana.getSwingHorizontal()); + + pana.setModel(kPanasonicDke); // DKE has full control. + ASSERT_EQ(kPanasonicDke, pana.getModel()); + // Auto was last requested. + EXPECT_EQ(kPanasonicAcSwingHAuto, pana.getSwingHorizontal()); + pana.setSwingHorizontal(kPanasonicAcSwingHLeft); + EXPECT_EQ(kPanasonicAcSwingHLeft, pana.getSwingHorizontal()); + // Changing models from DKE to something else, then back should not change + // the intended swing. + pana.setModel(kPanasonicLke); + EXPECT_EQ(kPanasonicAcSwingHMiddle, pana.getSwingHorizontal()); + pana.setModel(kPanasonicDke); + EXPECT_EQ(kPanasonicAcSwingHLeft, pana.getSwingHorizontal()); +} + +TEST(TestIRPanasonicAcClass, QuietAndPowerful) { + IRPanasonicAc pana(0); + pana.setQuiet(false); + EXPECT_FALSE(pana.getQuiet()); + pana.setQuiet(true); + EXPECT_TRUE(pana.getQuiet()); + EXPECT_FALSE(pana.getPowerful()); + pana.setPowerful(false); + EXPECT_FALSE(pana.getPowerful()); + EXPECT_TRUE(pana.getQuiet()); + pana.setPowerful(true); + EXPECT_TRUE(pana.getPowerful()); + EXPECT_FALSE(pana.getQuiet()); + pana.setPowerful(false); + EXPECT_FALSE(pana.getPowerful()); + EXPECT_FALSE(pana.getQuiet()); + pana.setPowerful(true); + pana.setQuiet(true); + EXPECT_TRUE(pana.getQuiet()); + EXPECT_FALSE(pana.getPowerful()); +} + +TEST(TestIRPanasonicAcClass, HumanReadable) { + IRPanasonicAc pana(0); + EXPECT_EQ( + "Model: 4 (JKE), Power: Off, Mode: 0 (AUTO), Temp: 0C, " + "Fan: 253 (UNKNOWN), Swing (Vertical): 0 (UNKNOWN), Quiet: Off, " + "Powerful: Off, Clock: 0:00, On Timer: Off, Off Timer: Off", + pana.toString()); + pana.setPower(true); + pana.setTemp(kPanasonicAcMaxTemp); + pana.setMode(kPanasonicAcHeat); + pana.setFan(kPanasonicAcFanMax); + pana.setSwingVertical(kPanasonicAcSwingVAuto); + pana.setPowerful(true); + EXPECT_EQ( + "Model: 4 (JKE), Power: On, Mode: 4 (HEAT), Temp: 30C, " + "Fan: 4 (MAX), Swing (Vertical): 15 (AUTO), Quiet: Off, " + "Powerful: On, Clock: 0:00, On Timer: Off, Off Timer: Off", + pana.toString()); + pana.setQuiet(true); + pana.setModel(kPanasonicLke); + EXPECT_EQ( + "Model: 1 (LKE), Power: Off, Mode: 4 (HEAT), Temp: 30C, " + "Fan: 4 (MAX), Swing (Vertical): 15 (AUTO), " + "Swing (Horizontal): 6 (Middle), Quiet: On, Powerful: Off, " + "Clock: 0:00, On Timer: 0:00, Off Timer: Off", + pana.toString()); + pana.setModel(kPanasonicDke); + pana.setSwingHorizontal(kPanasonicAcSwingHRight); + EXPECT_EQ( + "Model: 3 (DKE), Power: Off, Mode: 4 (HEAT), Temp: 30C, " + "Fan: 4 (MAX), Swing (Vertical): 15 (AUTO), " + "Swing (Horizontal): 11 (Right), Quiet: On, Powerful: Off, " + "Clock: 0:00, On Timer: Off, Off Timer: Off", + pana.toString()); +} + +// Tests for decodePanasonicAC(). + +// Decode normal Panasonic AC messages. +TEST(TestDecodePanasonicAC, RealExample) { + IRsendTest irsend(4); + IRrecv irrecv(4); + irsend.begin(); + + // Data from Issue #525 + uint16_t rawData[439] = { + 3582, 1686, 488, 378, 488, 1238, 488, 378, 488, 378, 488, 378, + 488, 378, 488, 378, 488, 384, 488, 378, 488, 378, 488, 378, + 488, 378, 488, 378, 488, 1242, 486, 378, 488, 384, 488, 378, + 488, 378, 488, 380, 486, 382, 484, 382, 484, 1264, 464, 1266, + 460, 1272, 462, 378, 488, 406, 460, 1266, 462, 380, 488, 382, + 484, 388, 478, 406, 462, 410, 462, 404, 462, 406, 462, 396, + 470, 406, 462, 404, 462, 406, 460, 404, 462, 410, 462, 404, + 462, 404, 462, 406, 464, 406, 462, 404, 462, 406, 462, 404, + 462, 410, 462, 404, 462, 406, 462, 404, 462, 404, 462, 404, + 462, 406, 460, 406, 462, 410, 462, 404, 462, 1264, 484, 1244, + 486, 382, 482, 382, 486, 382, 486, 378, 486, 382, 488, 9924, + 3554, 1686, 488, 378, 490, 1240, 486, 378, 488, 378, 488, 378, + 488, 378, 488, 382, 484, 386, 486, 378, 488, 382, 486, 378, + 488, 382, 486, 382, 484, 1242, 486, 380, 488, 386, 484, 382, + 486, 380, 486, 382, 486, 380, 486, 380, 486, 1242, 486, 1242, + 484, 1248, 484, 380, 488, 382, 484, 1242, 486, 382, 484, 382, + 484, 382, 484, 382, 486, 386, 484, 382, 486, 382, 484, 382, + 486, 382, 486, 380, 484, 382, 486, 382, 488, 380, 486, 382, + 484, 380, 462, 406, 488, 376, 484, 1246, 482, 1246, 460, 404, + 480, 392, 484, 386, 482, 1244, 484, 382, 484, 382, 484, 1242, + 482, 1244, 484, 382, 464, 410, 460, 404, 462, 406, 462, 404, + 462, 404, 470, 396, 462, 406, 462, 404, 462, 1286, 460, 1268, + 458, 1268, 460, 1266, 460, 1266, 460, 406, 460, 1266, 462, 406, + 460, 1272, 462, 406, 460, 406, 460, 406, 460, 406, 462, 404, + 462, 406, 460, 406, 462, 410, 462, 404, 462, 406, 460, 406, + 460, 406, 462, 404, 462, 406, 460, 406, 460, 410, 462, 406, + 460, 1268, 460, 1266, 460, 404, 460, 406, 462, 406, 460, 406, + 460, 412, 456, 410, 460, 410, 438, 428, 460, 410, 456, 410, + 456, 1272, 436, 1288, 438, 434, 438, 428, 438, 428, 438, 428, + 438, 428, 438, 428, 438, 428, 438, 428, 438, 434, 438, 428, + 438, 428, 438, 428, 438, 428, 438, 428, 440, 428, 438, 428, + 438, 432, 438, 428, 438, 428, 438, 428, 438, 428, 438, 428, + 438, 428, 438, 430, 438, 1294, 438, 428, 438, 428, 438, 428, + 438, 428, 438, 428, 438, 428, 438, 428, 438, 434, 438, 428, + 438, 1288, 438, 1290, 438, 428, 438, 428, 438, 428, 438, 428, + 438, 432, 438, 1288, 438, 1290, 438, 430, 438, 428, 438, 428, + 438, 428, 438, 428, 438, 1292, 438}; + uint8_t expectedState[kPanasonicAcStateLength] = { + 0x02, 0x20, 0xE0, 0x04, 0x00, 0x00, 0x00, 0x06, 0x02, + 0x20, 0xE0, 0x04, 0x00, 0x30, 0x32, 0x80, 0xAF, 0x00, + 0x00, 0x06, 0x60, 0x00, 0x00, 0x80, 0x00, 0x06, 0x83}; + + irsend.sendRaw(rawData, 439, kPanasonicFreq); + irsend.makeDecodeResult(); + + ASSERT_TRUE(irrecv.decode(&irsend.capture)); + ASSERT_EQ(PANASONIC_AC, irsend.capture.decode_type); + EXPECT_EQ(kPanasonicAcBits, irsend.capture.bits); + EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); + EXPECT_FALSE(irsend.capture.repeat); +} + +// Decode synthetic Panasonic AC message. +TEST(TestDecodePanasonicAC, SyntheticExample) { + IRsendTest irsend(0); + IRrecv irrecv(0); + irsend.begin(); + + // Data from Issue #525 + uint8_t expectedState[kPanasonicAcStateLength] = { + 0x02, 0x20, 0xE0, 0x04, 0x00, 0x00, 0x00, 0x06, 0x02, + 0x20, 0xE0, 0x04, 0x00, 0x30, 0x32, 0x80, 0xAF, 0x00, + 0x00, 0x06, 0x60, 0x00, 0x00, 0x80, 0x00, 0x06, 0x83}; + + irsend.sendPanasonicAC(expectedState); + irsend.makeDecodeResult(); + + ASSERT_TRUE(irrecv.decode(&irsend.capture)); + ASSERT_EQ(PANASONIC_AC, irsend.capture.decode_type); + EXPECT_EQ(kPanasonicAcBits, irsend.capture.bits); + EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); + EXPECT_FALSE(irsend.capture.repeat); + + IRPanasonicAc pana(0); + pana.setRaw(irsend.capture.state); + EXPECT_EQ( + "Model: 4 (JKE), Power: Off, Mode: 3 (COOL), Temp: 25C, " + "Fan: 7 (AUTO), Swing (Vertical): 15 (AUTO), Quiet: Off, " + "Powerful: Off, Clock: 0:00, On Timer: Off, Off Timer: Off", + pana.toString()); +} + +// Tests for general utility functions. +TEST(TestGeneralPanasonic, hasACState) { + EXPECT_TRUE(hasACState(PANASONIC_AC)); + ASSERT_FALSE(hasACState(PANASONIC)); +} + +TEST(TestGeneralPanasonic, typeToString) { + EXPECT_EQ("PANASONIC_AC", typeToString(PANASONIC_AC)); + EXPECT_EQ("PANASONIC", typeToString(PANASONIC)); +} + +// Decode a problematic Panasonic AC message +TEST(TestDecodePanasonicAC, Issue540) { + IRsendTest irsend(0); + IRrecv irrecv(0); + irsend.begin(); + + // Data from Issue #540 + uint16_t rawData[439] = { + 3512, 1714, 466, 408, 466, 1280, 470, 408, 466, 412, 466, 408, + 466, 412, 462, 412, 466, 414, 466, 408, 466, 412, 462, 412, + 466, 412, 466, 408, 466, 1280, 466, 412, 462, 416, 462, 412, + 466, 408, 466, 412, 462, 416, 462, 412, 462, 1282, 462, 1284, + 462, 1288, 466, 412, 462, 412, 462, 1284, 462, 416, 440, 438, + 462, 412, 462, 412, 462, 416, 466, 412, 462, 412, 462, 412, + 440, 442, 462, 412, 462, 412, 460, 418, 462, 416, 462, 412, + 462, 418, 462, 412, 462, 416, 462, 412, 436, 442, 462, 412, + 460, 418, 462, 416, 462, 412, 460, 412, 462, 420, 436, 438, + 462, 412, 462, 416, 432, 448, 436, 438, 436, 1310, 436, 1310, + 462, 420, 432, 442, 436, 438, 462, 416, 432, 444, 432, 10008, + 3480, 1744, 492, 382, 492, 1254, 492, 386, 488, 390, 492, 382, + 492, 386, 488, 386, 492, 386, 492, 386, 488, 386, 488, 386, + 492, 386, 492, 382, 492, 1258, 488, 386, 488, 390, 492, 386, + 488, 386, 488, 386, 492, 390, 488, 386, 488, 1256, 488, 1258, + 488, 1262, 488, 390, 488, 386, 488, 1258, 488, 390, 488, 392, + 488, 386, 488, 386, 488, 394, 488, 386, 488, 386, 488, 390, + 488, 390, 488, 386, 488, 390, 462, 412, 488, 390, 462, 1282, + 488, 390, 456, 416, 458, 1292, 456, 1288, 488, 1258, 488, 392, + 456, 422, 488, 390, 484, 392, 484, 1262, 458, 420, 484, 1262, + 482, 1262, 488, 392, 484, 394, 484, 416, 436, 442, 458, 416, + 458, 422, 430, 448, 432, 442, 458, 416, 458, 1296, 432, 1314, + 458, 1288, 432, 1312, 432, 1322, 428, 446, 428, 1318, 432, 442, + 432, 1318, 432, 1318, 428, 446, 428, 1318, 428, 1322, 430, 448, + 426, 448, 428, 452, 426, 452, 426, 448, 428, 472, 400, 478, + 402, 478, 402, 472, 402, 476, 402, 472, 402, 478, 402, 472, + 402, 1348, 398, 1348, 398, 1352, 398, 508, 370, 478, 398, 476, + 398, 512, 366, 508, 370, 502, 372, 508, 340, 538, 372, 504, + 344, 1400, 344, 1400, 346, 1434, 314, 560, 316, 588, 290, 560, + 314, 564, 396, 400, 474, 400, 480, 394, 480, 404, 474, 400, + 454, 446, 454, 426, 448, 430, 424, 450, 428, 452, 448, 426, + 426, 452, 424, 1322, 454, 426, 450, 424, 426, 452, 428, 452, + 450, 424, 428, 446, 426, 1322, 454, 426, 422, 450, 454, 426, + 448, 430, 454, 426, 448, 426, 428, 446, 454, 430, 454, 422, + 452, 424, 424, 452, 452, 430, 424, 452, 452, 426, 448, 426, + 426, 456, 448, 426, 448, 1296, 424, 1322, 426, 1326, 450, 1270, + 478, 422, 454, 424, 424, 450, 454}; + uint8_t expectedState[kPanasonicAcStateLength] = { + 0x02, 0x20, 0xE0, 0x04, 0x00, 0x00, 0x00, 0x06, 0x02, + 0x20, 0xE0, 0x04, 0x00, 0x39, 0x34, 0x80, 0xAF, 0x0D, + 0x00, 0x0E, 0xE0, 0x00, 0x00, 0x81, 0x00, 0x00, 0x1E}; + + irsend.sendRaw(rawData, 439, kPanasonicFreq); + irsend.makeDecodeResult(); + + ASSERT_TRUE(irrecv.decode(&irsend.capture)); + ASSERT_EQ(PANASONIC_AC, irsend.capture.decode_type); + EXPECT_EQ(kPanasonicAcBits, irsend.capture.bits); + EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); + EXPECT_FALSE(irsend.capture.repeat); + IRPanasonicAc pana(0); + pana.setRaw(irsend.capture.state); + // TODO(crankyoldgit): Try to figure out what model this should be. + EXPECT_EQ( + "Model: 0 (UNKNOWN), Power: On, Mode: 3 (COOL), Temp: 26C, " + "Fan: 7 (AUTO), Swing (Vertical): 15 (AUTO), " + "Swing (Horizontal): 13 (AUTO), Quiet: Off, Powerful: Off, " + "Clock: 0:00, On Timer: Off, Off Timer: Off", + pana.toString()); +} + +TEST(TestIRPanasonicAcClass, TimeBasics) { + EXPECT_EQ(0x186, IRPanasonicAc::encodeTime(6, 30)); + EXPECT_EQ(0x3CA, IRPanasonicAc::encodeTime(16, 10)); + EXPECT_EQ(0x448, IRPanasonicAc::encodeTime(18, 16)); + EXPECT_EQ(0, IRPanasonicAc::encodeTime(0, 0)); + EXPECT_EQ(kPanasonicAcTimeMax, IRPanasonicAc::encodeTime(23, 59)); + EXPECT_EQ("16:10", + IRPanasonicAc::timeToString(IRPanasonicAc::encodeTime(16, 10))); + EXPECT_EQ("6:30", + IRPanasonicAc::timeToString(IRPanasonicAc::encodeTime(6, 30))); + EXPECT_EQ("18:16", + IRPanasonicAc::timeToString(IRPanasonicAc::encodeTime(18, 16))); + EXPECT_EQ("1:01", + IRPanasonicAc::timeToString(IRPanasonicAc::encodeTime(1, 1))); + EXPECT_EQ(kPanasonicAcTimeMax, IRPanasonicAc::encodeTime(23, 59)); + EXPECT_EQ(kPanasonicAcTimeMax, IRPanasonicAc::encodeTime(25, 72)); + EXPECT_EQ(59, IRPanasonicAc::encodeTime(0, 72)); + EXPECT_EQ(23 * 60, IRPanasonicAc::encodeTime(27, 0)); + EXPECT_EQ("0:00", IRPanasonicAc::timeToString(0)); + EXPECT_EQ("23:59", IRPanasonicAc::timeToString(kPanasonicAcTimeMax)); +} + +TEST(TestIRPanasonicAcClass, TimersAndClock) { + IRPanasonicAc pana(0); + // Data from Issue #544 + uint8_t state[27] = {0x02, 0x20, 0xE0, 0x04, 0x00, 0x00, 0x00, 0x06, 0x02, + 0x20, 0xE0, 0x04, 0x00, 0x4E, 0x2E, 0x80, 0xAF, 0x00, + 0xCA, 0x6B, 0x98, 0x10, 0x00, 0x01, 0x48, 0x04, 0xDB}; + pana.setRaw(state); + EXPECT_TRUE(pana.isOnTimerEnabled()); + EXPECT_EQ(0x3CA, pana.getOnTimer()); + EXPECT_TRUE(pana.isOffTimerEnabled()); + EXPECT_EQ(0x186, pana.getOffTimer()); + EXPECT_EQ(0x448, pana.getClock()); + + pana.cancelOnTimer(); + EXPECT_FALSE(pana.isOnTimerEnabled()); + EXPECT_EQ(0, pana.getOnTimer()); + EXPECT_TRUE(pana.isOffTimerEnabled()); + EXPECT_EQ(0x186, pana.getOffTimer()); + EXPECT_EQ(0x448, pana.getClock()); + + pana.cancelOffTimer(); + EXPECT_FALSE(pana.isOnTimerEnabled()); + EXPECT_EQ(0, pana.getOnTimer()); + EXPECT_FALSE(pana.isOffTimerEnabled()); + EXPECT_EQ(0, pana.getOffTimer()); + EXPECT_EQ(0x448, pana.getClock()); + + pana.setOnTimer(7 * 60 + 50); + EXPECT_TRUE(pana.isOnTimerEnabled()); + EXPECT_EQ(7 * 60 + 50, pana.getOnTimer()); + EXPECT_FALSE(pana.isOffTimerEnabled()); + EXPECT_EQ(0, pana.getOffTimer()); + EXPECT_EQ(0x448, pana.getClock()); + + pana.setOnTimer(7 * 60 + 57); // It should round down. + EXPECT_EQ(7 * 60 + 50, pana.getOnTimer()); + pana.setOnTimer(28 * 60); // It should round down. + EXPECT_EQ(kPanasonicAcTimeMax - 9, pana.getOnTimer()); + pana.setOnTimer(kPanasonicAcTimeSpecial); + EXPECT_EQ(0, pana.getOnTimer()); + + pana.setOnTimer(7 * 60 + 50); + pana.setOffTimer(19 * 60 + 30); + + EXPECT_TRUE(pana.isOnTimerEnabled()); + EXPECT_EQ(7 * 60 + 50, pana.getOnTimer()); + EXPECT_TRUE(pana.isOffTimerEnabled()); + EXPECT_EQ(19 * 60 + 30, pana.getOffTimer()); + EXPECT_EQ(0x448, pana.getClock()); + + pana.setOffTimer(19 * 60 + 57); // It should round down. + EXPECT_EQ(19 * 60 + 50, pana.getOffTimer()); + pana.setOffTimer(28 * 60); // It should round down. + EXPECT_EQ(kPanasonicAcTimeMax - 9, pana.getOffTimer()); + pana.setOffTimer(kPanasonicAcTimeSpecial); + EXPECT_EQ(0, pana.getOffTimer()); + + pana.setClock(0); + EXPECT_EQ(0, pana.getClock()); + pana.setClock(kPanasonicAcTimeMax); + EXPECT_EQ(kPanasonicAcTimeMax, pana.getClock()); + pana.setClock(kPanasonicAcTimeMax - 1); + EXPECT_EQ(kPanasonicAcTimeMax - 1, pana.getClock()); + pana.setClock(kPanasonicAcTimeMax + 1); + EXPECT_EQ(kPanasonicAcTimeMax, pana.getClock()); + pana.setClock(kPanasonicAcTimeSpecial); + EXPECT_EQ(0, pana.getClock()); +} + +// Decode a real short Panasonic AC message +TEST(TestDecodePanasonicAC, RealExampleOfShortMessage) { + IRsendTest irsend(0); + IRrecv irrecv(0); + irsend.begin(); + + // Data from Issue #544 (Odour Wash) + uint16_t rawData[263] = { + 3496, 1734, 506, 366, 448, 1294, 504, 368, 498, 374, 452, 418, + 448, 424, 444, 428, 450, 422, 446, 426, 450, 420, 448, 424, + 452, 418, 448, 422, 444, 1300, 498, 374, 504, 368, 448, 424, + 452, 418, 448, 424, 444, 428, 450, 422, 446, 1296, 500, 1242, + 502, 1242, 504, 368, 498, 374, 452, 1292, 504, 366, 450, 422, + 444, 426, 450, 420, 446, 424, 452, 418, 448, 424, 444, 428, + 450, 422, 444, 426, 450, 420, 446, 424, 452, 418, 448, 422, + 444, 428, 450, 422, 446, 426, 452, 420, 446, 426, 452, 418, + 448, 424, 442, 428, 448, 422, 444, 426, 450, 420, 446, 426, + 452, 418, 448, 424, 444, 428, 450, 422, 444, 1298, 500, 1244, + 500, 372, 444, 428, 450, 422, 446, 426, 452, 418, 448, 10020, + 3500, 1732, 498, 372, 452, 1290, 506, 366, 450, 422, 446, 426, + 452, 420, 448, 424, 452, 418, 448, 422, 444, 426, 450, 420, + 446, 426, 452, 420, 446, 1296, 500, 370, 444, 428, 450, 422, + 446, 426, 452, 420, 446, 424, 442, 428, 448, 1294, 502, 1240, + 504, 1238, 506, 366, 448, 422, 444, 1298, 498, 374, 452, 418, + 448, 424, 444, 428, 450, 422, 446, 426, 450, 420, 446, 424, + 452, 418, 448, 422, 444, 428, 450, 420, 446, 1298, 498, 1244, + 500, 1242, 502, 368, 446, 1298, 500, 1244, 500, 372, 444, 428, + 450, 1292, 504, 368, 446, 1296, 502, 370, 444, 426, 452, 1290, + 504, 1238, 506, 366, 450, 422, 446, 1298, 498, 1246, 500, 372, + 444, 428, 450, 1294, 452, 420, 446, 1296, 448, 422, 444}; // UNKNOWN + // 1FB51F79 + + uint8_t expectedState[kPanasonicAcStateShortLength] = { + 0x02, 0x20, 0xE0, 0x04, 0x00, 0x00, 0x00, 0x06, + 0x02, 0x20, 0xE0, 0x04, 0x80, 0x9B, 0x32, 0x53}; + + irsend.sendRaw(rawData, 263, kPanasonicFreq); + irsend.makeDecodeResult(); + + ASSERT_TRUE(irrecv.decode(&irsend.capture)); + ASSERT_EQ(PANASONIC_AC, irsend.capture.decode_type); + EXPECT_EQ(kPanasonicAcShortBits, irsend.capture.bits); + EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); +} + +// Create and decode a short Panasonic AC message +TEST(TestDecodePanasonicAC, SyntheticShortMessage) { + IRsendTest irsend(0); + IRrecv irrecv(0); + irsend.begin(); + + uint8_t odourWash[kPanasonicAcStateShortLength] = { + 0x02, 0x20, 0xE0, 0x04, 0x00, 0x00, 0x00, 0x06, + 0x02, 0x20, 0xE0, 0x04, 0x80, 0x9B, 0x32, 0x53}; + + irsend.sendPanasonicAC(odourWash, kPanasonicAcStateShortLength); + irsend.makeDecodeResult(); + + ASSERT_TRUE(irrecv.decode(&irsend.capture)); + ASSERT_EQ(PANASONIC_AC, irsend.capture.decode_type); + EXPECT_EQ(kPanasonicAcShortBits, irsend.capture.bits); + EXPECT_STATE_EQ(odourWash, irsend.capture.state, irsend.capture.bits); +} +// +// Test for CKP model / see issue #544 +TEST(TestDecodePanasonicAC, CkpModelSpecifics) { + IRsendTest irsend(0); + IRrecv irrecv(0); + irsend.begin(); + + // Data from Issue #544 + uint8_t ckpPowerfulOn[kPanasonicAcStateLength] = { + 0x02, 0x20, 0xE0, 0x04, 0x00, 0x00, 0x00, 0x06, 0x02, + 0x20, 0xE0, 0x04, 0x00, 0x4E, 0x2E, 0x80, 0xAF, 0x00, + 0x00, 0x0E, 0xE0, 0x11, 0x00, 0x01, 0x00, 0x06, 0xB7}; + uint8_t ckpQuietOn[kPanasonicAcStateLength] = { + 0x02, 0x20, 0xE0, 0x04, 0x00, 0x00, 0x00, 0x06, 0x02, + 0x20, 0xE0, 0x04, 0x00, 0x4E, 0x2E, 0x80, 0xAF, 0x00, + 0x00, 0x0E, 0xE0, 0x30, 0x00, 0x01, 0x00, 0x06, 0xD6}; + + irsend.sendPanasonicAC(ckpPowerfulOn); + irsend.makeDecodeResult(); + + ASSERT_TRUE(irrecv.decode(&irsend.capture)); + ASSERT_EQ(PANASONIC_AC, irsend.capture.decode_type); + EXPECT_EQ(kPanasonicAcBits, irsend.capture.bits); + EXPECT_STATE_EQ(ckpPowerfulOn, irsend.capture.state, irsend.capture.bits); + EXPECT_FALSE(irsend.capture.repeat); + + IRPanasonicAc pana(0); + pana.setRaw(irsend.capture.state); + EXPECT_EQ( + "Model: 5 (CKP), Power: Off, Mode: 4 (HEAT), Temp: 23C, " + "Fan: 7 (AUTO), Swing (Vertical): 15 (AUTO), Quiet: Off, " + "Powerful: On, Clock: 0:00, On Timer: 0:00, Off Timer: 0:00", + pana.toString()); + + pana.setQuiet(true); + EXPECT_FALSE(pana.getPowerful()); + EXPECT_TRUE(pana.getQuiet()); + EXPECT_EQ(kPanasonicCkp, pana.getModel()); + EXPECT_STATE_EQ(ckpQuietOn, pana.getRaw(), kPanasonicAcBits); + + pana.setPowerful(true); + EXPECT_TRUE(pana.getPowerful()); + EXPECT_FALSE(pana.getQuiet()); + EXPECT_EQ(kPanasonicCkp, pana.getModel()); + EXPECT_STATE_EQ(ckpPowerfulOn, pana.getRaw(), kPanasonicAcBits); +} diff --git a/lib/IRremoteESP8266/test/ir_Pioneer_test.cpp b/lib/IRremoteESP8266/test/ir_Pioneer_test.cpp new file mode 100644 index 0000000..b78469a --- /dev/null +++ b/lib/IRremoteESP8266/test/ir_Pioneer_test.cpp @@ -0,0 +1,152 @@ +// Copyright 2018 David Conran + +#include "IRsend.h" +#include "IRsend_test.h" +#include "IRutils.h" +#include "gtest/gtest.h" + +// Tests for sendPioneer(). + +// Test sending typical data only. +TEST(TestSendPioneer, SendDataOnly) { + IRsendTest irsend(0); + irsend.begin(); + irsend.sendPioneer(0); + EXPECT_EQ( + "m8960s4480" + "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560" + "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560" + "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560" + "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560" + "m560s58240" + "m8960s4480" + "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560" + "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560" + "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560" + "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560" + "m560s58240", + irsend.outputStr()); + irsend.sendPioneer(0x55FF00AAAA00FF55); + EXPECT_EQ( + "m8960s4480" + "m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680" + "m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680" + "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560" + "m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560" + "m560s40320" + "m8960s4480" + "m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560" + "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560" + "m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680" + "m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680" + "m560s40320", + irsend.outputStr()); +} + +// Tests for IRutils. + +TEST(TestIRUtils, TypeToString) { EXPECT_EQ("PIONEER", typeToString(PIONEER)); } + +// Tests for encodePioneer(). + +TEST(TestEncodePioneer, SimpleEncoding) { + IRsendTest irsend(0); + IRrecv irrecv(0); + + // Spotify button (A556+AF20) + // via + // https://www.pioneerelectronics.com/StaticFiles/PUSA/Files/Home%20Custom%20Install/2015%20Pioneer%20&%20Elite%20AVR%20IR%20with%20Hex_1.xls + EXPECT_EQ(0xA55A6A95F50A04FB, irsend.encodePioneer(0xA556, 0xAF20)); + + // "Source" from + // https://github.com/markszabo/IRremoteESP8266/pull/547#issuecomment-429616582 + EXPECT_EQ(0x659A05FAF50AC53A, irsend.encodePioneer(0xA6A0, 0xAFA3)); +} + +// Tests for decodePioneer(). + +// Synthesised Normal Pioneer message. +TEST(TestDecodePioneer, SyntheticPioneerDecode) { + IRsendTest irsend(0); + IRrecv irrecv(0); + irsend.begin(); + + irsend.reset(); + irsend.sendPioneer(0x659A05FAF50AC53A); + irsend.makeDecodeResult(); + EXPECT_TRUE(irrecv.decode(&irsend.capture)); + EXPECT_EQ(PIONEER, irsend.capture.decode_type); + EXPECT_EQ(kPioneerBits, irsend.capture.bits); + EXPECT_EQ(0x659A05FAF50AC53A, irsend.capture.value); + EXPECT_EQ(0xA6A0, irsend.capture.address); + EXPECT_EQ(0xAFA3, irsend.capture.command); +} + +// Real long Pioneer message. +TEST(TestDecodePioneer, RealExampleLongDecodeSourceButton) { + IRsendTest irsend(0); + IRrecv irrecv(0); + irsend.begin(); + + irsend.reset(); + // "Source" button. + // https://github.com/markszabo/IRremoteESP8266/pull/547#issuecomment-429616582 + uint16_t rawData[135] = { + 8552, 4184, 596, 472, 592, 1524, 594, 1524, 594, 472, 592, 472, + 598, 1520, 596, 472, 594, 1524, 592, 1524, 592, 472, 592, 472, + 596, 1520, 598, 1520, 596, 472, 592, 1524, 592, 472, 592, 476, + 592, 472, 592, 472, 592, 476, 592, 472, 592, 1524, 592, 472, + 598, 1518, 598, 1520, 596, 1520, 596, 1520, 596, 1520, 596, 1520, + 596, 472, 592, 1524, 592, 472, 598, 25282, 8552, 4182, 596, 1520, + 598, 1518, 598, 1520, 596, 1520, 596, 472, 592, 1524, 592, 472, + 598, 1520, 596, 472, 594, 472, 592, 472, 596, 472, 592, 1524, + 592, 472, 592, 1524, 596, 472, 594, 1520, 596, 1520, 598, 472, + 592, 472, 598, 472, 594, 1522, 594, 472, 592, 1524, 594, 472, + 596, 472, 594, 1524, 592, 1524, 592, 1524, 592, 472, 594, 1524, + 598, 472, 592}; + + irsend.sendRaw(rawData, 135, 38000); + irsend.makeDecodeResult(); + EXPECT_TRUE(irrecv.decode(&irsend.capture)); + EXPECT_EQ(PIONEER, irsend.capture.decode_type); + EXPECT_EQ(kPioneerBits, irsend.capture.bits); + EXPECT_EQ(0x659A05FAF50AC53A, irsend.capture.value); + EXPECT_EQ(0xA6A0, irsend.capture.address); + EXPECT_EQ(0xAFA3, irsend.capture.command); +} + +// Synthetic Pioneer message. +// For: +// https://github.com/markszabo/IRremoteESP8266/pull/547#issuecomment-430800734 +TEST(TestDecodePioneer, SyntheticPioneerMessage) { + IRsendTest irsend(0); + IRrecv irrecv(0); + irsend.begin(); + + irsend.reset(); + irsend.sendPioneer(0x659A857AF50A3DC2, 64, 0); + irsend.makeDecodeResult(); + EXPECT_TRUE(irrecv.decode(&irsend.capture)); + EXPECT_EQ(PIONEER, irsend.capture.decode_type); + EXPECT_EQ(kPioneerBits, irsend.capture.bits); + EXPECT_EQ(0x659A857AF50A3DC2, irsend.capture.value); + EXPECT_EQ(0xA6A1, irsend.capture.address); + EXPECT_EQ(0xAFBC, irsend.capture.command); + + irsend.reset(); + irsend.sendPioneer(0x659A857AF50A3DC2, 64, 0); + EXPECT_EQ( + "m8960s4480" + "m560s560m560s1680m560s1680m560s560m560s560m560s1680m560s560m560s1680" + "m560s1680m560s560m560s560m560s1680m560s1680m560s560m560s1680m560s560" + "m560s1680m560s560m560s560m560s560m560s560m560s1680m560s560m560s1680" + "m560s560m560s1680m560s1680m560s1680m560s1680m560s560m560s1680m560s560" + "m560s40320" + "m8960s4480" + "m560s1680m560s1680m560s1680m560s1680m560s560m560s1680m560s560m560s1680" + "m560s560m560s560m560s560m560s560m560s1680m560s560m560s1680m560s560" + "m560s560m560s560m560s1680m560s1680m560s1680m560s1680m560s560m560s1680" + "m560s1680m560s1680m560s560m560s560m560s560m560s560m560s1680m560s560" + "m560s40320", + irsend.outputStr()); +} diff --git a/lib/IRremoteESP8266/test/ir_Pronto_test.cpp b/lib/IRremoteESP8266/test/ir_Pronto_test.cpp index c8cac92..e52c6dd 100644 --- a/lib/IRremoteESP8266/test/ir_Pronto_test.cpp +++ b/lib/IRremoteESP8266/test/ir_Pronto_test.cpp @@ -79,8 +79,8 @@ TEST(TestSendPronto, MoreDataThanNeededInBoth) { irsend.reset(); // We should handle when we are given more data than needed. (repeat seq.) - uint16_t pronto_test[10] = {0x0000, 0x0067, 0x0001, 0x0001, - 0x0001, 0x0002, 0x0003, 0x0004, 0x5, 0x6}; + uint16_t pronto_test[10] = {0x0000, 0x0067, 0x0001, 0x0001, 0x0001, + 0x0002, 0x0003, 0x0004, 0x5, 0x6}; irsend.sendPronto(pronto_test, 10); EXPECT_EQ("m25s50", irsend.outputStr()); // Only send the data required. irsend.sendPronto(pronto_test, 10, 1); @@ -110,20 +110,18 @@ TEST(TestSendPronto, NonRepeatingCode) { // It was an example of a poor Pronto code. // It turned out to be a 4 copies of a Sony 12-bit code. Who knew!?! uint16_t pronto_test[108] = { - 0x0000, 0x0067, 0x0034, 0x0000, - 0x0060, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, - 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, - 0x0030, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, - 0x0018, 0x0452, 0x0060, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, - 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, - 0x0018, 0x0018, 0x0030, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, - 0x0018, 0x0018, 0x0018, 0x0452, 0x0060, 0x0018, 0x0018, 0x0018, - 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, - 0x0018, 0x0018, 0x0018, 0x0018, 0x0030, 0x0018, 0x0018, 0x0018, - 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0452, 0x0060, 0x0018, - 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, - 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0030, 0x0018, - 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018}; + 0x0000, 0x0067, 0x0034, 0x0000, 0x0060, 0x0018, 0x0018, 0x0018, 0x0018, + 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, + 0x0018, 0x0018, 0x0030, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, + 0x0018, 0x0018, 0x0452, 0x0060, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, + 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, + 0x0018, 0x0030, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, + 0x0018, 0x0452, 0x0060, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, + 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, + 0x0030, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, + 0x0452, 0x0060, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, + 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0030, + 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018}; // Send the Pronto code without any repeats set. irsend.reset(); @@ -131,7 +129,7 @@ TEST(TestSendPronto, NonRepeatingCode) { irsend.makeDecodeResult(); EXPECT_TRUE(irrecv.decode(&irsend.capture)); EXPECT_EQ(SONY, irsend.capture.decode_type); - EXPECT_EQ(SONY_12_BITS, irsend.capture.bits); + EXPECT_EQ(kSony12Bits, irsend.capture.bits); EXPECT_EQ(0x10, irsend.capture.value); EXPECT_EQ(0x1, irsend.capture.address); EXPECT_EQ(0x0, irsend.capture.command); @@ -147,7 +145,8 @@ TEST(TestSendPronto, NonRepeatingCode) { "m600s600m600s600m600s600m600s27650" "m2400s600" "m600s600m600s600m600s600m600s600m600s600m600s600m600s600m1200s600" - "m600s600m600s600m600s600m600s600", irsend.outputStr()); + "m600s600m600s600m600s600m600s600", + irsend.outputStr()); // Now try repeating it. // As it has no repeat sequence, we shouldn't repeat it. (I think) @@ -156,7 +155,7 @@ TEST(TestSendPronto, NonRepeatingCode) { irsend.makeDecodeResult(); EXPECT_TRUE(irrecv.decode(&irsend.capture)); EXPECT_EQ(SONY, irsend.capture.decode_type); - EXPECT_EQ(SONY_12_BITS, irsend.capture.bits); + EXPECT_EQ(kSony12Bits, irsend.capture.bits); EXPECT_EQ(0x10, irsend.capture.value); EXPECT_EQ(0x1, irsend.capture.address); EXPECT_EQ(0x0, irsend.capture.command); @@ -172,7 +171,8 @@ TEST(TestSendPronto, NonRepeatingCode) { "m600s600m600s600m600s600m600s27650" "m2400s600" "m600s600m600s600m600s600m600s600m600s600m600s600m600s600m1200s600" - "m600s600m600s600m600s600m600s600", irsend.outputStr()); + "m600s600m600s600m600s600m600s600", + irsend.outputStr()); } // Test sending a Pronto code that only has a repeat sequence (Sony). @@ -183,13 +183,12 @@ TEST(TestSendPronto, RepeatSequenceOnlyForSony) { // Sony 20-bit command. uint16_t pronto_test[46] = { - 0x0000, 0x0067, 0x0000, 0x0015, - 0x0060, 0x0018, 0x0018, 0x0018, 0x0030, 0x0018, 0x0030, 0x0018, - 0x0030, 0x0018, 0x0018, 0x0018, 0x0030, 0x0018, 0x0018, 0x0018, - 0x0018, 0x0018, 0x0030, 0x0018, 0x0018, 0x0018, 0x0030, 0x0018, - 0x0030, 0x0018, 0x0030, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, + 0x0000, 0x0067, 0x0000, 0x0015, 0x0060, 0x0018, 0x0018, 0x0018, + 0x0030, 0x0018, 0x0030, 0x0018, 0x0030, 0x0018, 0x0018, 0x0018, 0x0030, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0030, 0x0018, - 0x0018, 0x03f6}; + 0x0018, 0x0018, 0x0030, 0x0018, 0x0030, 0x0018, 0x0030, 0x0018, + 0x0018, 0x0018, 0x0018, 0x0018, 0x0030, 0x0018, 0x0018, 0x0018, + 0x0018, 0x0018, 0x0030, 0x0018, 0x0018, 0x03f6}; // Send the Pronto code without any repeats set. irsend.reset(); @@ -197,7 +196,7 @@ TEST(TestSendPronto, RepeatSequenceOnlyForSony) { irsend.makeDecodeResult(); EXPECT_TRUE(irrecv.decode(&irsend.capture)); EXPECT_EQ(SONY, irsend.capture.decode_type); - EXPECT_EQ(SONY_20_BITS, irsend.capture.bits); + EXPECT_EQ(kSony20Bits, irsend.capture.bits); EXPECT_EQ(0x74B92, irsend.capture.value); EXPECT_EQ(0x1A, irsend.capture.address); EXPECT_EQ(0x24AE, irsend.capture.command); @@ -205,15 +204,16 @@ TEST(TestSendPronto, RepeatSequenceOnlyForSony) { "m2400s600" "m600s600m1200s600m1200s600m1200s600m600s600m1200s600m600s600m600s600" "m1200s600m600s600m1200s600m1200s600m1200s600m600s600m600s600m1200s600" - "m600s600m600s600m1200s600m600s25350", irsend.outputStr()); + "m600s600m600s600m1200s600m600s25350", + irsend.outputStr()); // Send the Pronto code with 2 repeats. irsend.reset(); - irsend.sendPronto(pronto_test, 46, SONY_MIN_REPEAT); + irsend.sendPronto(pronto_test, 46, kSonyMinRepeat); irsend.makeDecodeResult(); EXPECT_TRUE(irrecv.decode(&irsend.capture)); EXPECT_EQ(SONY, irsend.capture.decode_type); - EXPECT_EQ(SONY_20_BITS, irsend.capture.bits); + EXPECT_EQ(kSony20Bits, irsend.capture.bits); EXPECT_EQ(0x74B92, irsend.capture.value); EXPECT_EQ(0x1A, irsend.capture.address); EXPECT_EQ(0x24AE, irsend.capture.command); @@ -229,7 +229,8 @@ TEST(TestSendPronto, RepeatSequenceOnlyForSony) { "m2400s600" "m600s600m1200s600m1200s600m1200s600m600s600m1200s600m600s600m600s600" "m1200s600m600s600m1200s600m1200s600m1200s600m600s600m600s600m1200s600" - "m600s600m600s600m1200s600m600s25350", irsend.outputStr()); + "m600s600m600s600m1200s600m600s25350", + irsend.outputStr()); } // Test sending a Pronto code that only has a repeat sequence (Panasonic). @@ -240,20 +241,18 @@ TEST(TestSendPronto, RepeatSequenceOnlyForPanasonic) { // Panasonic Plasma TV Descrete code (Power On). uint16_t pronto_test[104] = { - 0x0000, 0x0071, 0x0000, 0x0032, - 0x0080, 0x003F, 0x0010, 0x0010, 0x0010, 0x0030, 0x0010, 0x0010, - 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, - 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, - 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0030, 0x0010, 0x0010, - 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, - 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, - 0x0010, 0x0030, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, - 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, - 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0030, 0x0010, 0x0030, - 0x0010, 0x0030, 0x0010, 0x0030, 0x0010, 0x0030, 0x0010, 0x0010, - 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0030, 0x0010, 0x0030, - 0x0010, 0x0030, 0x0010, 0x0030, 0x0010, 0x0030, 0x0010, 0x0010, - 0x0010, 0x0030, 0x0010, 0x0A98}; + 0x0000, 0x0071, 0x0000, 0x0032, 0x0080, 0x003F, 0x0010, 0x0010, 0x0010, + 0x0030, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, + 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, + 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0030, 0x0010, 0x0010, + 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, + 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0030, + 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, + 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, + 0x0010, 0x0030, 0x0010, 0x0030, 0x0010, 0x0030, 0x0010, 0x0030, 0x0010, + 0x0030, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0030, + 0x0010, 0x0030, 0x0010, 0x0030, 0x0010, 0x0030, 0x0010, 0x0030, 0x0010, + 0x0010, 0x0010, 0x0030, 0x0010, 0x0A98}; // Send the Pronto code without any repeats set. irsend.reset(); @@ -261,7 +260,7 @@ TEST(TestSendPronto, RepeatSequenceOnlyForPanasonic) { irsend.makeDecodeResult(); EXPECT_TRUE(irrecv.decode(&irsend.capture)); EXPECT_EQ(PANASONIC, irsend.capture.decode_type); - EXPECT_EQ(PANASONIC_BITS, irsend.capture.bits); + EXPECT_EQ(kPanasonicBits, irsend.capture.bits); EXPECT_EQ(0x400401007C7D, irsend.capture.value); EXPECT_EQ(0x4004, irsend.capture.address); EXPECT_EQ(0x1007C7D, irsend.capture.command); @@ -273,10 +272,10 @@ TEST(TestSendPronto, RepeatSequenceOnlyForPanasonic) { "m432s432m432s432m432s432m432s432m432s432m432s432m432s432m432s432" "m432s432m432s1296m432s1296m432s1296m432s1296m432s1296m432s432m432s432" "m432s432m432s1296m432s1296m432s1296m432s1296m432s1296m432s432m432s1296" - "m432s73224", irsend.outputStr()); + "m432s73224", + irsend.outputStr()); } - // Test sending a Pronto code that has a normal & arepeat sequence (NEC). TEST(TestSendPronto, NormalPlusRepeatSequence) { IRsendTest irsend(4); @@ -285,16 +284,14 @@ TEST(TestSendPronto, NormalPlusRepeatSequence) { // NEC 32 bit power on command. uint16_t pronto_test[76] = { - 0x0000, 0x006D, 0x0022, 0x0002, - 0x0156, 0x00AB, 0x0015, 0x0015, 0x0015, 0x0015, 0x0015, 0x0015, - 0x0015, 0x0040, 0x0015, 0x0040, 0x0015, 0x0015, 0x0015, 0x0015, - 0x0015, 0x0015, 0x0015, 0x0040, 0x0015, 0x0040, 0x0015, 0x0040, - 0x0015, 0x0015, 0x0015, 0x0015, 0x0015, 0x0040, 0x0015, 0x0040, - 0x0015, 0x0040, 0x0015, 0x0015, 0x0015, 0x0015, 0x0015, 0x0015, - 0x0015, 0x0040, 0x0015, 0x0015, 0x0015, 0x0015, 0x0015, 0x0015, - 0x0015, 0x0015, 0x0015, 0x0040, 0x0015, 0x0040, 0x0015, 0x0040, - 0x0015, 0x0015, 0x0015, 0x0040, 0x0015, 0x0040, 0x0015, 0x0040, - 0x0015, 0x0040, 0x0015, 0x05FD, + 0x0000, 0x006D, 0x0022, 0x0002, 0x0156, 0x00AB, 0x0015, 0x0015, 0x0015, + 0x0015, 0x0015, 0x0015, 0x0015, 0x0040, 0x0015, 0x0040, 0x0015, 0x0015, + 0x0015, 0x0015, 0x0015, 0x0015, 0x0015, 0x0040, 0x0015, 0x0040, 0x0015, + 0x0040, 0x0015, 0x0015, 0x0015, 0x0015, 0x0015, 0x0040, 0x0015, 0x0040, + 0x0015, 0x0040, 0x0015, 0x0015, 0x0015, 0x0015, 0x0015, 0x0015, 0x0015, + 0x0040, 0x0015, 0x0015, 0x0015, 0x0015, 0x0015, 0x0015, 0x0015, 0x0015, + 0x0015, 0x0040, 0x0015, 0x0040, 0x0015, 0x0040, 0x0015, 0x0015, 0x0015, + 0x0040, 0x0015, 0x0040, 0x0015, 0x0040, 0x0015, 0x0040, 0x0015, 0x05FD, 0x0156, 0x0055, 0x0015, 0x0E4E}; // Send the Pronto code without any repeats set. @@ -303,7 +300,7 @@ TEST(TestSendPronto, NormalPlusRepeatSequence) { irsend.makeDecodeResult(); EXPECT_TRUE(irrecv.decode(&irsend.capture)); EXPECT_EQ(NEC, irsend.capture.decode_type); - EXPECT_EQ(NEC_BITS, irsend.capture.bits); + EXPECT_EQ(kNECBits, irsend.capture.bits); EXPECT_EQ(0x18E710EF, irsend.capture.value); EXPECT_EQ(0x18, irsend.capture.address); EXPECT_EQ(0x8, irsend.capture.command); @@ -313,7 +310,8 @@ TEST(TestSendPronto, NormalPlusRepeatSequence) { "m546s1664m546s1664m546s1664m546s546m546s546m546s1664m546s1664m546s1664" "m546s546m546s546m546s546m546s1664m546s546m546s546m546s546m546s546" "m546s1664m546s1664m546s1664m546s546m546s1664m546s1664m546s1664m546s1664" - "m546s39858", irsend.outputStr()); + "m546s39858", + irsend.outputStr()); // Send it again with a single repeat. irsend.reset(); @@ -321,7 +319,7 @@ TEST(TestSendPronto, NormalPlusRepeatSequence) { irsend.makeDecodeResult(); EXPECT_TRUE(irrecv.decode(&irsend.capture)); EXPECT_EQ(NEC, irsend.capture.decode_type); - EXPECT_EQ(NEC_BITS, irsend.capture.bits); + EXPECT_EQ(kNECBits, irsend.capture.bits); EXPECT_EQ(0x18E710EF, irsend.capture.value); EXPECT_EQ(0x18, irsend.capture.address); EXPECT_EQ(0x8, irsend.capture.command); @@ -332,7 +330,8 @@ TEST(TestSendPronto, NormalPlusRepeatSequence) { "m546s546m546s546m546s546m546s1664m546s546m546s546m546s546m546s546" "m546s1664m546s1664m546s1664m546s546m546s1664m546s1664m546s1664m546s1664" "m546s39858" - "m8892s2210m546s95212", irsend.outputStr()); + "m8892s2210m546s95212", + irsend.outputStr()); // Send it again with a two repeats. irsend.reset(); @@ -340,7 +339,7 @@ TEST(TestSendPronto, NormalPlusRepeatSequence) { irsend.makeDecodeResult(); EXPECT_TRUE(irrecv.decode(&irsend.capture)); EXPECT_EQ(NEC, irsend.capture.decode_type); - EXPECT_EQ(NEC_BITS, irsend.capture.bits); + EXPECT_EQ(kNECBits, irsend.capture.bits); EXPECT_EQ(0x18E710EF, irsend.capture.value); EXPECT_EQ(0x18, irsend.capture.address); EXPECT_EQ(0x8, irsend.capture.command); @@ -352,5 +351,6 @@ TEST(TestSendPronto, NormalPlusRepeatSequence) { "m546s1664m546s1664m546s1664m546s546m546s1664m546s1664m546s1664m546s1664" "m546s39858" "m8892s2210m546s95212" - "m8892s2210m546s95212", irsend.outputStr()); + "m8892s2210m546s95212", + irsend.outputStr()); } diff --git a/lib/IRremoteESP8266/test/ir_RC5_RC6_test.cpp b/lib/IRremoteESP8266/test/ir_RC5_RC6_test.cpp index 2699d33..e8aa9bf 100644 --- a/lib/IRremoteESP8266/test/ir_RC5_RC6_test.cpp +++ b/lib/IRremoteESP8266/test/ir_RC5_RC6_test.cpp @@ -77,52 +77,56 @@ TEST(TestSendRC5, SendDataOnly) { irsend.begin(); irsend.reset(); - irsend.sendRC5(0x0, RC5_BITS); + irsend.sendRC5(0x0, kRC5Bits); EXPECT_EQ( "m889s889m1778s889m889s889m889s889m889s889m889s889m889" "s889m889s889m889s889m889s889m889s889m889s889m889s90664", irsend.outputStr()); irsend.reset(); - irsend.sendRC5(0x1AAA, RC5_BITS); + irsend.sendRC5(0x1AAA, kRC5Bits); EXPECT_EQ( "m889s889m889s889m1778s1778m1778s1778m1778s1778" - "m1778s1778m1778s1778m1778s90664", irsend.outputStr()); + "m1778s1778m1778s1778m1778s90664", + irsend.outputStr()); irsend.reset(); - irsend.sendRC5(0x175, RC5_BITS); + irsend.sendRC5(0x175, kRC5Bits); EXPECT_EQ( "m889s889m1778s889m889s889m889s1778m1778s1778" - "m889s889m889s889m1778s1778m1778s1778m889s89775", irsend.outputStr()); + "m889s889m889s889m1778s1778m1778s1778m889s89775", + irsend.outputStr()); irsend.reset(); - irsend.sendRC5(0x3FFF, RC5_BITS); + irsend.sendRC5(0x3FFF, kRC5Bits); EXPECT_EQ( "m889s889m889s889m889s889m889s889m889s889m889s889m889s889" "m889s889m889s889m889s889m889s889m889s889m889s889m889s89775", irsend.outputStr()); irsend.reset(); - irsend.sendRC5(0x0, RC5X_BITS); + irsend.sendRC5(0x0, kRC5XBits); EXPECT_EQ( "m889s889m1778s889m889s889m889s889m889s889m889s889m889" "s889m889s889m889s889m889s889m889s889m889s889m889s90664", irsend.outputStr()); irsend.reset(); - irsend.sendRC5(0x1AAA, RC5X_BITS); + irsend.sendRC5(0x1AAA, kRC5XBits); EXPECT_EQ( "m1778s1778m1778s1778m1778s1778m1778" - "s1778m1778s1778m1778s1778m1778s90664", irsend.outputStr()); + "s1778m1778s1778m1778s1778m1778s90664", + irsend.outputStr()); irsend.reset(); - irsend.sendRC5(0x175, RC5X_BITS); + irsend.sendRC5(0x175, kRC5XBits); EXPECT_EQ( "m889s889m1778s889m889s889m889s1778m1778s1778" - "m889s889m889s889m1778s1778m1778s1778m889s89775", irsend.outputStr()); + "m889s889m889s889m1778s1778m1778s1778m889s89775", + irsend.outputStr()); irsend.reset(); - irsend.sendRC5(0x3FFF, RC5X_BITS); + irsend.sendRC5(0x3FFF, kRC5XBits); EXPECT_EQ( "m1778s1778m889s889m889s889m889s889m889s889m889s889m889" "s889m889s889m889s889m889s889m889s889m889s889m889s89775", @@ -135,40 +139,44 @@ TEST(TestSendRC5, SendWithRepeats) { irsend.begin(); irsend.reset(); - irsend.sendRC5(0x175, RC5_BITS, 1); + irsend.sendRC5(0x175, kRC5Bits, 1); EXPECT_EQ( "m889s889m1778s889m889s889m889s1778m1778s1778" "m889s889m889s889m1778s1778m1778s1778m889s90664" "m889s889m1778s889m889s889m889s1778m1778s1778" - "m889s889m889s889m1778s1778m1778s1778m889s88886", irsend.outputStr()); + "m889s889m889s889m1778s1778m1778s1778m889s88886", + irsend.outputStr()); irsend.reset(); - irsend.sendRC5(0x175, RC5_BITS, 2); + irsend.sendRC5(0x175, kRC5Bits, 2); EXPECT_EQ( "m889s889m1778s889m889s889m889s1778m1778s1778" "m889s889m889s889m1778s1778m1778s1778m889s90664" "m889s889m1778s889m889s889m889s1778m1778s1778" "m889s889m889s889m1778s1778m1778s1778m889s89775" "m889s889m1778s889m889s889m889s1778m1778s1778" - "m889s889m889s889m1778s1778m1778s1778m889s88886", irsend.outputStr()); + "m889s889m889s889m1778s1778m1778s1778m889s88886", + irsend.outputStr()); irsend.reset(); - irsend.sendRC5(0x175, RC5X_BITS, 1); + irsend.sendRC5(0x175, kRC5XBits, 1); EXPECT_EQ( "m889s889m1778s889m889s889m889s1778m1778s1778" "m889s889m889s889m1778s1778m1778s1778m889s90664" "m889s889m1778s889m889s889m889s1778m1778s1778" - "m889s889m889s889m1778s1778m1778s1778m889s88886", irsend.outputStr()); + "m889s889m889s889m1778s1778m1778s1778m889s88886", + irsend.outputStr()); irsend.reset(); - irsend.sendRC5(0x1175, RC5X_BITS, 2); + irsend.sendRC5(0x1175, kRC5XBits, 2); EXPECT_EQ( "m1778s889m889s889m889s889m889s1778m1778s1778" "m889s889m889s889m1778s1778m1778s1778m889s90664" "m1778s889m889s889m889s889m889s1778m1778s1778" "m889s889m889s889m1778s1778m1778s1778m889s89775" "m1778s889m889s889m889s889m889s1778m1778s1778" - "m889s889m889s889m1778s1778m1778s1778m889s88886", irsend.outputStr()); + "m889s889m889s889m1778s1778m1778s1778m889s88886", + irsend.outputStr()); } // Tests for decodeRC5(). @@ -182,9 +190,9 @@ TEST(TestDecodeRC5, NormalDecodeWithStrict) { irsend.reset(); irsend.sendRC5(0x175); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodeRC5(&irsend.capture, RC5_BITS, true)); + ASSERT_TRUE(irrecv.decodeRC5(&irsend.capture, kRC5Bits, true)); EXPECT_EQ(RC5, irsend.capture.decode_type); - EXPECT_EQ(RC5_BITS, irsend.capture.bits); + EXPECT_EQ(kRC5Bits, irsend.capture.bits); EXPECT_EQ(0x175, irsend.capture.value); EXPECT_EQ(0x05, irsend.capture.address); EXPECT_EQ(0x35, irsend.capture.command); @@ -194,9 +202,9 @@ TEST(TestDecodeRC5, NormalDecodeWithStrict) { irsend.reset(); irsend.sendRC5(0x175); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodeRC5(&irsend.capture, RC5X_BITS, true)); + ASSERT_TRUE(irrecv.decodeRC5(&irsend.capture, kRC5XBits, true)); EXPECT_EQ(RC5, irsend.capture.decode_type); - EXPECT_EQ(RC5_BITS, irsend.capture.bits); + EXPECT_EQ(kRC5Bits, irsend.capture.bits); EXPECT_EQ(0x175, irsend.capture.value); EXPECT_EQ(0x05, irsend.capture.address); EXPECT_EQ(0x35, irsend.capture.command); @@ -205,11 +213,11 @@ TEST(TestDecodeRC5, NormalDecodeWithStrict) { // A RC-5X 13-bit message but with a value that is valid for RC-5 decoded // as RC5-X. irsend.reset(); - irsend.sendRC5(0x175, RC5X_BITS); + irsend.sendRC5(0x175, kRC5XBits); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodeRC5(&irsend.capture, RC5X_BITS, true)); + ASSERT_TRUE(irrecv.decodeRC5(&irsend.capture, kRC5XBits, true)); EXPECT_EQ(RC5, irsend.capture.decode_type); - EXPECT_EQ(RC5_BITS, irsend.capture.bits); + EXPECT_EQ(kRC5Bits, irsend.capture.bits); EXPECT_EQ(0x175, irsend.capture.value); EXPECT_EQ(0x05, irsend.capture.address); EXPECT_EQ(0x35, irsend.capture.command); @@ -219,9 +227,9 @@ TEST(TestDecodeRC5, NormalDecodeWithStrict) { irsend.reset(); irsend.sendRC5(irsend.encodeRC5(0x00, 0x0B, true)); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodeRC5(&irsend.capture, RC5_BITS, true)); + ASSERT_TRUE(irrecv.decodeRC5(&irsend.capture, kRC5Bits, true)); EXPECT_EQ(RC5, irsend.capture.decode_type); - EXPECT_EQ(RC5_BITS, irsend.capture.bits); + EXPECT_EQ(kRC5Bits, irsend.capture.bits); EXPECT_EQ(0x80B, irsend.capture.value); EXPECT_EQ(0x00, irsend.capture.address); EXPECT_EQ(0x0B, irsend.capture.command); @@ -229,11 +237,11 @@ TEST(TestDecodeRC5, NormalDecodeWithStrict) { // Synthesised Normal RC-5X 13-bit message. irsend.reset(); - irsend.sendRC5(irsend.encodeRC5X(0x02, 0x41, true), RC5X_BITS); + irsend.sendRC5(irsend.encodeRC5X(0x02, 0x41, true), kRC5XBits); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodeRC5(&irsend.capture, RC5X_BITS, true)); + ASSERT_TRUE(irrecv.decodeRC5(&irsend.capture, kRC5XBits, true)); EXPECT_EQ(RC5X, irsend.capture.decode_type); - EXPECT_EQ(RC5X_BITS, irsend.capture.bits); + EXPECT_EQ(kRC5XBits, irsend.capture.bits); EXPECT_EQ(0x1881, irsend.capture.value); EXPECT_EQ(0x02, irsend.capture.address); EXPECT_EQ(0x41, irsend.capture.command); @@ -242,9 +250,9 @@ TEST(TestDecodeRC5, NormalDecodeWithStrict) { // Synthesised Normal RC-5X 13-bit message should fail at being decoded // as a normal RC-5 (12 bit) message. irsend.reset(); - irsend.sendRC5(irsend.encodeRC5X(0x02, 0x41, true), RC5X_BITS); + irsend.sendRC5(irsend.encodeRC5X(0x02, 0x41, true), kRC5XBits); irsend.makeDecodeResult(); - ASSERT_FALSE(irrecv.decodeRC5(&irsend.capture, RC5_BITS, true)); + ASSERT_FALSE(irrecv.decodeRC5(&irsend.capture, kRC5Bits, true)); } // Decode normal repeated RC5 messages. @@ -255,33 +263,33 @@ TEST(TestDecodeRC5, NormalDecodeWithRepeatAndStrict) { // Normal RC-5 12-bit (even) message with one repeat. irsend.reset(); - irsend.sendRC5(0x174, RC5_BITS, 1); + irsend.sendRC5(0x174, kRC5Bits, 1); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodeRC5(&irsend.capture, RC5_BITS, true)); + ASSERT_TRUE(irrecv.decodeRC5(&irsend.capture, kRC5Bits, true)); EXPECT_EQ(RC5, irsend.capture.decode_type); - EXPECT_EQ(RC5_BITS, irsend.capture.bits); + EXPECT_EQ(kRC5Bits, irsend.capture.bits); EXPECT_EQ(0x174, irsend.capture.value); EXPECT_EQ(0x05, irsend.capture.address); EXPECT_EQ(0x34, irsend.capture.command); // Normal RC-5 12-bit (odd) message with one repeat. irsend.reset(); - irsend.sendRC5(0x175, RC5_BITS, 1); + irsend.sendRC5(0x175, kRC5Bits, 1); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodeRC5(&irsend.capture, RC5_BITS, true)); + ASSERT_TRUE(irrecv.decodeRC5(&irsend.capture, kRC5Bits, true)); EXPECT_EQ(RC5, irsend.capture.decode_type); - EXPECT_EQ(RC5_BITS, irsend.capture.bits); + EXPECT_EQ(kRC5Bits, irsend.capture.bits); EXPECT_EQ(0x175, irsend.capture.value); EXPECT_EQ(0x05, irsend.capture.address); EXPECT_EQ(0x35, irsend.capture.command); // Synthesised Normal RC-5X 13-bit message with 2 repeats. irsend.reset(); - irsend.sendRC5(irsend.encodeRC5X(0x02, 0x41, true), RC5X_BITS, 2); + irsend.sendRC5(irsend.encodeRC5X(0x02, 0x41, true), kRC5XBits, 2); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodeRC5(&irsend.capture, RC5X_BITS, true)); + ASSERT_TRUE(irrecv.decodeRC5(&irsend.capture, kRC5XBits, true)); EXPECT_EQ(RC5X, irsend.capture.decode_type); - EXPECT_EQ(RC5X_BITS, irsend.capture.bits); + EXPECT_EQ(kRC5XBits, irsend.capture.bits); EXPECT_EQ(0x1881, irsend.capture.value); EXPECT_EQ(0x02, irsend.capture.address); EXPECT_EQ(0x41, irsend.capture.command); @@ -297,8 +305,8 @@ TEST(TestDecodeRC5, DecodeWithNonStrictValues) { irsend.sendRC5(0xFA, 8); // Illegal value RC5 8-bit message. irsend.makeDecodeResult(); // Should fail with strict on. - ASSERT_FALSE(irrecv.decodeRC5(&irsend.capture, RC5_BITS, true)); - ASSERT_FALSE(irrecv.decodeRC5(&irsend.capture, RC5X_BITS, true)); + ASSERT_FALSE(irrecv.decodeRC5(&irsend.capture, kRC5Bits, true)); + ASSERT_FALSE(irrecv.decodeRC5(&irsend.capture, kRC5XBits, true)); // Should pass if strict off. ASSERT_TRUE(irrecv.decodeRC5(&irsend.capture, 8, false)); EXPECT_EQ(RC5, irsend.capture.decode_type); @@ -311,8 +319,8 @@ TEST(TestDecodeRC5, DecodeWithNonStrictValues) { irsend.sendRC5(0x12345678, 32); // Illegal size RC5 32-bit message. irsend.makeDecodeResult(); // Should fail with strict on. - ASSERT_FALSE(irrecv.decodeRC5(&irsend.capture, RC5_BITS, true)); - ASSERT_FALSE(irrecv.decodeRC5(&irsend.capture, RC5X_BITS, true)); + ASSERT_FALSE(irrecv.decodeRC5(&irsend.capture, kRC5Bits, true)); + ASSERT_FALSE(irrecv.decodeRC5(&irsend.capture, kRC5XBits, true)); irsend.makeDecodeResult(); // Should fail with strict when we ask for the wrong bit size. @@ -327,8 +335,8 @@ TEST(TestDecodeRC5, DecodeWithNonStrictValues) { irsend.sendRC5(0x87654321, 32); // Illegal size RC5 32-bit message. irsend.makeDecodeResult(); // Should fail with strict on. - ASSERT_FALSE(irrecv.decodeRC5(&irsend.capture, RC5_BITS, true)); - ASSERT_FALSE(irrecv.decodeRC5(&irsend.capture, RC5X_BITS, true)); + ASSERT_FALSE(irrecv.decodeRC5(&irsend.capture, kRC5Bits, true)); + ASSERT_FALSE(irrecv.decodeRC5(&irsend.capture, kRC5XBits, true)); irsend.makeDecodeResult(); // Should fail with strict when we ask for the wrong bit size. @@ -364,14 +372,15 @@ TEST(TestDecodeRC5, FailToDecodeNonRC5Example) { irsend.begin(); irsend.reset(); - uint16_t gc_test[39] = {38000, 1, 1, 322, 162, 20, 61, 20, 61, 20, 20, 20, 20, - 20, 20, 20, 127, 20, 61, 9, 20, 20, 61, 20, 20, 20, - 61, 20, 61, 20, 61, 20, 20, 20, 20, 20, 20, 20, 884}; + uint16_t gc_test[39] = {38000, 1, 1, 322, 162, 20, 61, 20, 61, 20, + 20, 20, 20, 20, 20, 20, 127, 20, 61, 9, + 20, 20, 61, 20, 20, 20, 61, 20, 61, 20, + 61, 20, 20, 20, 20, 20, 20, 20, 884}; irsend.sendGC(gc_test, 39); irsend.makeDecodeResult(); ASSERT_FALSE(irrecv.decodeRC5(&irsend.capture)); - ASSERT_FALSE(irrecv.decodeRC5(&irsend.capture, RC5_BITS, false)); + ASSERT_FALSE(irrecv.decodeRC5(&irsend.capture, kRC5Bits, false)); } // RRRRRR CCCCC 666 @@ -383,24 +392,24 @@ TEST(TestDecodeRC5, FailToDecodeNonRC5Example) { // Tests for encodeRC6(). TEST(TestEncodeRC6, Mode0Encoding) { IRsendTest irsend(4); - EXPECT_EQ(0x0, irsend.encodeRC6(0, 0, RC6_MODE0_BITS)); - EXPECT_EQ(0x1234, irsend.encodeRC6(0x12, 0x34, RC6_MODE0_BITS)); - EXPECT_EQ(0x12345, irsend.encodeRC6(0x123, 0x45, RC6_MODE0_BITS)); - EXPECT_EQ(0xFFFFF, irsend.encodeRC6(0xFFF, 0xFF, RC6_MODE0_BITS)); - EXPECT_EQ(0xFFF00, irsend.encodeRC6(0xFFFF, 0x00, RC6_MODE0_BITS)); - EXPECT_EQ(0xFF, irsend.encodeRC6(0x00, 0xFF, RC6_MODE0_BITS)); + EXPECT_EQ(0x0, irsend.encodeRC6(0, 0, kRC6Mode0Bits)); + EXPECT_EQ(0x1234, irsend.encodeRC6(0x12, 0x34, kRC6Mode0Bits)); + EXPECT_EQ(0x12345, irsend.encodeRC6(0x123, 0x45, kRC6Mode0Bits)); + EXPECT_EQ(0xFFFFF, irsend.encodeRC6(0xFFF, 0xFF, kRC6Mode0Bits)); + EXPECT_EQ(0xFFF00, irsend.encodeRC6(0xFFFF, 0x00, kRC6Mode0Bits)); + EXPECT_EQ(0xFF, irsend.encodeRC6(0x00, 0xFF, kRC6Mode0Bits)); } TEST(TestEncodeRC6, 36BitEncoding) { IRsendTest irsend(4); - EXPECT_EQ(0x0, irsend.encodeRC6(0, 0, RC6_36_BITS)); - EXPECT_EQ(0x1234, irsend.encodeRC6(0x12, 0x34, RC6_36_BITS)); - EXPECT_EQ(0x123456789, irsend.encodeRC6(0x1234567, 0x89, RC6_36_BITS)); - EXPECT_EQ(0xFFFFFFFFF, irsend.encodeRC6(0xFFFFFFF, 0xFF, RC6_36_BITS)); - EXPECT_EQ(0xFFFFFFFFF, irsend.encodeRC6(0xFFFFFFFF, 0xFF, RC6_36_BITS)); - EXPECT_EQ(0xFFFFFFF00, irsend.encodeRC6(0xFFFFFFF, 0x00, RC6_36_BITS)); - EXPECT_EQ(0xFF, irsend.encodeRC6(0x0, 0xFF, RC6_36_BITS)); - EXPECT_EQ(0xFFFFFFFFF, irsend.encodeRC6(0xFFFFFFFF, 0xFF, RC6_36_BITS)); + EXPECT_EQ(0x0, irsend.encodeRC6(0, 0, kRC6_36Bits)); + EXPECT_EQ(0x1234, irsend.encodeRC6(0x12, 0x34, kRC6_36Bits)); + EXPECT_EQ(0x123456789, irsend.encodeRC6(0x1234567, 0x89, kRC6_36Bits)); + EXPECT_EQ(0xFFFFFFFFF, irsend.encodeRC6(0xFFFFFFF, 0xFF, kRC6_36Bits)); + EXPECT_EQ(0xFFFFFFFFF, irsend.encodeRC6(0xFFFFFFFF, 0xFF, kRC6_36Bits)); + EXPECT_EQ(0xFFFFFFF00, irsend.encodeRC6(0xFFFFFFF, 0x00, kRC6_36Bits)); + EXPECT_EQ(0xFF, irsend.encodeRC6(0x0, 0xFF, kRC6_36Bits)); + EXPECT_EQ(0xFFFFFFFFF, irsend.encodeRC6(0xFFFFFFFF, 0xFF, kRC6_36Bits)); } // Tests for toggleRC6(). @@ -410,7 +419,7 @@ TEST(TestToggleRC6, Mode0) { IRsendTest irsend(4); EXPECT_EQ(0x10000, irsend.toggleRC6(0x0)); - EXPECT_EQ(irsend.toggleRC6(0x0), irsend.toggleRC6(0x0, RC6_MODE0_BITS)); + EXPECT_EQ(irsend.toggleRC6(0x0), irsend.toggleRC6(0x0, kRC6Mode0Bits)); EXPECT_EQ(0x0, irsend.toggleRC6(0x10000)); EXPECT_EQ(0x0, irsend.toggleRC6(irsend.toggleRC6(0x0))); } @@ -419,10 +428,10 @@ TEST(TestToggleRC6, Mode0) { TEST(TestToggleRC6, 36BitUse) { IRsendTest irsend(4); - EXPECT_EQ(0x8000, irsend.toggleRC6(0x0, RC6_36_BITS)); - EXPECT_EQ(0x0, irsend.toggleRC6(0x8000, RC6_36_BITS)); - EXPECT_EQ(0x0, irsend.toggleRC6(irsend.toggleRC6(0x0, RC6_36_BITS), - RC6_36_BITS)); + EXPECT_EQ(0x8000, irsend.toggleRC6(0x0, kRC6_36Bits)); + EXPECT_EQ(0x0, irsend.toggleRC6(0x8000, kRC6_36Bits)); + EXPECT_EQ(0x0, + irsend.toggleRC6(irsend.toggleRC6(0x0, kRC6_36Bits), kRC6_36Bits)); } // Tests for sendRC6(). @@ -439,7 +448,8 @@ TEST(TestSendRC6, SendMode0DataOnly) { "m444s888m444s444m444s444m444s888m888s444m444s444m444s444" "m444s444m444s444m444s444m444s444m444s444m444s444m444s444" "m444s444m444s444m444s444m444s444m444s444m444s444m444" - "s83028", irsend.outputStr()); + "s83028", + irsend.outputStr()); irsend.reset(); irsend.sendRC6(0x1FFFF); @@ -448,7 +458,8 @@ TEST(TestSendRC6, SendMode0DataOnly) { "m444s888m444s444m444s444m1332s888m444s444m444s444m444s444" "m444s444m444s444m444s444m444s444m444s444m444s444m444s444" "m444s444m444s444m444s444m444s444m444s444m444" - "s83472", irsend.outputStr()); + "s83472", + irsend.outputStr()); irsend.reset(); irsend.sendRC6(0x15555); @@ -456,7 +467,8 @@ TEST(TestSendRC6, SendMode0DataOnly) { "m2664s888" "m444s888m444s444m444s444m1332s1332m888s888m888s888" "m888s888m888s888m888s888m888s888m888s888m888" - "s83472", irsend.outputStr()); + "s83472", + irsend.outputStr()); } // Test sending typical RC-6 36-bit data only. @@ -465,7 +477,7 @@ TEST(TestSendRC6, Send36BitDataOnly) { irsend.begin(); irsend.reset(); - irsend.sendRC6(0x0, RC6_36_BITS); + irsend.sendRC6(0x0, kRC6_36Bits); EXPECT_EQ( "m2664s888" "m444s888m444s444m444s444m444" @@ -474,10 +486,11 @@ TEST(TestSendRC6, Send36BitDataOnly) { "s444m444s444m444s444m444s444m444s444m444s444m444s444m444s444m444" "s444m444s444m444s444m444s444m444s444m444s444m444s444m444s444m444" "s444m444s444m444s444m444s444m444s444m444s444m444s444m444s444m444" - "s83028", irsend.outputStr()); + "s83028", + irsend.outputStr()); irsend.reset(); - irsend.sendRC6(0xFFFFFFFFF, RC6_36_BITS); + irsend.sendRC6(0xFFFFFFFFF, kRC6_36Bits); EXPECT_EQ( "m2664s888" "m444s444m444s444m444s444m444s444" @@ -486,10 +499,11 @@ TEST(TestSendRC6, Send36BitDataOnly) { "m444s444m444s444m444s444m444s444m444s444m444s444m444s444m444s444" "m444s444m444s444m444s444m444s444m444s444m444s444m444s444m444s444" "m444s444m444s444m444s444m444s444m444s444m444s444m444s444m444" - "s83472", irsend.outputStr()); + "s83472", + irsend.outputStr()); irsend.reset(); - irsend.sendRC6(0xAAAAAAAAAA, RC6_36_BITS); + irsend.sendRC6(0xAAAAAAAAAA, kRC6_36Bits); EXPECT_EQ( "m2664s888m444s444m444s888m888" "s1332m1332" @@ -498,7 +512,7 @@ TEST(TestSendRC6, Send36BitDataOnly) { irsend.outputStr()); irsend.reset(); - irsend.sendRC6(0xC800F740C, RC6_36_BITS); // Xbox 360 OnOff code + irsend.sendRC6(0xC800F740C, kRC6_36Bits); // Xbox 360 OnOff code EXPECT_EQ( "m2664s888" "m444s444m444s444m444s888m444" @@ -506,10 +520,11 @@ TEST(TestSendRC6, Send36BitDataOnly) { "s888m444s444m444s444m444s444m444s444m444s444m444s444m444s444m444" "s444m444s444m444s444m888s444m444s444m444s444m444s888m888s444m444" "s444m444s888m888s888m444s444m444s444m444s444m444s444m444s444m888" - "s444m444s888m444s444m444s83028", irsend.outputStr()); + "s444m444s888m444s444m444s83028", + irsend.outputStr()); irsend.reset(); - irsend.sendRC6(irsend.toggleRC6(0xC800F740C, RC6_36_BITS), - RC6_36_BITS); // Xbox 360 OnOff code (toggled) + irsend.sendRC6(irsend.toggleRC6(0xC800F740C, kRC6_36Bits), + kRC6_36Bits); // Xbox 360 OnOff code (toggled) EXPECT_EQ( "m2664s888" "m444s444m444s444m444s888m444" @@ -517,7 +532,8 @@ TEST(TestSendRC6, Send36BitDataOnly) { "s888m444s444m444s444m444s444m444s444m444s444m444s444m444s444m444" "s444m444s444m444s444m888s444m444s444m444s444m444s444m444s444m444" "s444m444s444m444s888m888s888m444s444m444s444m444s444m444s444m444" - "s444m888s444m444s888m444s444m444s83028", irsend.outputStr()); + "s444m888s444m444s888m444s444m444s83028", + irsend.outputStr()); } // Test sending RC-6 Mode 0 with different repeats. @@ -526,16 +542,17 @@ TEST(TestSendRC6, SendMode0WithRepeats) { irsend.begin(); irsend.reset(); - irsend.sendRC6(0x175, RC6_MODE0_BITS, 0); + irsend.sendRC6(0x175, kRC6Mode0Bits, 0); EXPECT_EQ( "m2664s888" "m444s888m444s444m444s444m444" "s888m888" "s444m444s444m444s444m444s444m444s444m444s444m444s444m888s888m888" - "s444m444s444m444s888m888s888m888s83472", irsend.outputStr()); + "s444m444s444m444s888m888s888m888s83472", + irsend.outputStr()); irsend.reset(); - irsend.sendRC6(0x175, RC6_MODE0_BITS, 1); + irsend.sendRC6(0x175, kRC6Mode0Bits, 1); EXPECT_EQ( "m2664s888" "m444s888m444s444m444s444m444" @@ -546,10 +563,11 @@ TEST(TestSendRC6, SendMode0WithRepeats) { "m444s888m444s444m444s444m444" "s888m888" "s444m444s444m444s444m444s444m444s444m444s444m444s444m888s888m888" - "s444m444s444m444s888m888s888m888s83472", irsend.outputStr()); + "s444m444s444m444s888m888s888m888s83472", + irsend.outputStr()); irsend.reset(); - irsend.sendRC6(0x175, RC6_MODE0_BITS, 2); + irsend.sendRC6(0x175, kRC6Mode0Bits, 2); EXPECT_EQ( "m2664s888" "m444s888m444s444m444s444m444" @@ -565,7 +583,8 @@ TEST(TestSendRC6, SendMode0WithRepeats) { "m444s888m444s444m444s444m444" "s888m888" "s444m444s444m444s444m444s444m444s444m444s444m444s444m888s888m888" - "s444m444s444m444s888m888s888m888s83472", irsend.outputStr()); + "s444m444s444m444s888m888s888m888s83472", + irsend.outputStr()); } // Test sending RC-6 36-bit with different repeats. @@ -574,7 +593,7 @@ TEST(TestSendRC6, Send36BitWithRepeats) { irsend.begin(); irsend.reset(); - irsend.sendRC6(0x175, RC6_36_BITS, 0); + irsend.sendRC6(0x175, kRC6_36Bits, 0); EXPECT_EQ( "m2664s888" "m444s888m444s444m444s444m444" @@ -582,10 +601,11 @@ TEST(TestSendRC6, Send36BitWithRepeats) { "s444m444s444m444s444m444s444m444s444m444s444m444s444m444s444m444" "s444m444s444m444s444m444s444m444s444m444s444m444s444m444s444m444" "s444m444s444m444s444m444s444m444s444m444s444m444s444m888s888m888" - "s444m444s444m444s888m888s888m888s83472", irsend.outputStr()); + "s444m444s444m444s888m888s888m888s83472", + irsend.outputStr()); irsend.reset(); - irsend.sendRC6(0x175, RC6_36_BITS, 1); + irsend.sendRC6(0x175, kRC6_36Bits, 1); EXPECT_EQ( "m2664s888" "m444s888m444s444m444s444m444" @@ -600,10 +620,11 @@ TEST(TestSendRC6, Send36BitWithRepeats) { "s444m444s444m444s444m444s444m444s444m444s444m444s444m444s444m444" "s444m444s444m444s444m444s444m444s444m444s444m444s444m444s444m444" "s444m444s444m444s444m444s444m444s444m444s444m444s444m888s888m888" - "s444m444s444m444s888m888s888m888s83472", irsend.outputStr()); + "s444m444s444m444s888m888s888m888s83472", + irsend.outputStr()); irsend.reset(); - irsend.sendRC6(0x175, RC6_36_BITS, 2); + irsend.sendRC6(0x175, kRC6_36Bits, 2); EXPECT_EQ( "m2664s888" "m444s888m444s444m444s444m444" @@ -625,7 +646,8 @@ TEST(TestSendRC6, Send36BitWithRepeats) { "s444m444s444m444s444m444s444m444s444m444s444m444s444m444s444m444" "s444m444s444m444s444m444s444m444s444m444s444m444s444m444s444m444" "s444m444s444m444s444m444s444m444s444m444s444m444s444m888s888m888" - "s444m444s444m444s888m888s888m888s83472", irsend.outputStr()); + "s444m444s444m444s888m888s888m888s83472", + irsend.outputStr()); } // Tests for decodeRC6(). @@ -640,9 +662,9 @@ TEST(TestDecodeRC6, NormalMode0DecodeWithStrict) { irsend.reset(); irsend.sendRC6(0x175); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodeRC6(&irsend.capture, RC6_MODE0_BITS, true)); + ASSERT_TRUE(irrecv.decodeRC6(&irsend.capture, kRC6Mode0Bits, true)); EXPECT_EQ(RC6, irsend.capture.decode_type); - EXPECT_EQ(RC6_MODE0_BITS, irsend.capture.bits); + EXPECT_EQ(kRC6Mode0Bits, irsend.capture.bits); EXPECT_EQ(0x175, irsend.capture.value); EXPECT_EQ(0x01, irsend.capture.address); EXPECT_EQ(0x75, irsend.capture.command); @@ -650,11 +672,11 @@ TEST(TestDecodeRC6, NormalMode0DecodeWithStrict) { // Normal Synthesised RC-6 Mode 0 (20-bit) message. irsend.reset(); - irsend.sendRC6(irsend.encodeRC6(0x1234567, 0x89, RC6_MODE0_BITS)); + irsend.sendRC6(irsend.encodeRC6(0x1234567, 0x89, kRC6Mode0Bits)); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodeRC6(&irsend.capture, RC6_MODE0_BITS, true)); + ASSERT_TRUE(irrecv.decodeRC6(&irsend.capture, kRC6Mode0Bits, true)); EXPECT_EQ(RC6, irsend.capture.decode_type); - EXPECT_EQ(RC6_MODE0_BITS, irsend.capture.bits); + EXPECT_EQ(kRC6Mode0Bits, irsend.capture.bits); EXPECT_EQ(0x56789, irsend.capture.value); EXPECT_EQ(0x567, irsend.capture.address); EXPECT_EQ(0x89, irsend.capture.command); @@ -662,11 +684,11 @@ TEST(TestDecodeRC6, NormalMode0DecodeWithStrict) { // Same again, but encoded manually. irsend.reset(); - irsend.sendRC6(0x123456789, RC6_MODE0_BITS); + irsend.sendRC6(0x123456789, kRC6Mode0Bits); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodeRC6(&irsend.capture, RC6_MODE0_BITS, true)); + ASSERT_TRUE(irrecv.decodeRC6(&irsend.capture, kRC6Mode0Bits, true)); EXPECT_EQ(RC6, irsend.capture.decode_type); - EXPECT_EQ(RC6_MODE0_BITS, irsend.capture.bits); + EXPECT_EQ(kRC6Mode0Bits, irsend.capture.bits); EXPECT_EQ(0x56789, irsend.capture.value); EXPECT_EQ(0x567, irsend.capture.address); EXPECT_EQ(0x89, irsend.capture.command); @@ -681,11 +703,11 @@ TEST(TestDecodeRC6, Normal36BitDecodeWithStrict) { // Normal RC-6 36-bit message. irsend.reset(); - irsend.sendRC6(0x175, RC6_36_BITS); + irsend.sendRC6(0x175, kRC6_36Bits); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodeRC6(&irsend.capture, RC6_36_BITS, true)); + ASSERT_TRUE(irrecv.decodeRC6(&irsend.capture, kRC6_36Bits, true)); EXPECT_EQ(RC6, irsend.capture.decode_type); - EXPECT_EQ(RC6_36_BITS, irsend.capture.bits); + EXPECT_EQ(kRC6_36Bits, irsend.capture.bits); EXPECT_EQ(0x175, irsend.capture.value); EXPECT_EQ(0x01, irsend.capture.address); EXPECT_EQ(0x75, irsend.capture.command); @@ -693,11 +715,11 @@ TEST(TestDecodeRC6, Normal36BitDecodeWithStrict) { // Normal Synthesised RC-6 36-bit message. irsend.reset(); - irsend.sendRC6(irsend.encodeRC6(0x1234567, 0x89, RC6_36_BITS), RC6_36_BITS); + irsend.sendRC6(irsend.encodeRC6(0x1234567, 0x89, kRC6_36Bits), kRC6_36Bits); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodeRC6(&irsend.capture, RC6_36_BITS, true)); + ASSERT_TRUE(irrecv.decodeRC6(&irsend.capture, kRC6_36Bits, true)); EXPECT_EQ(RC6, irsend.capture.decode_type); - EXPECT_EQ(RC6_36_BITS, irsend.capture.bits); + EXPECT_EQ(kRC6_36Bits, irsend.capture.bits); EXPECT_EQ(0x123456789, irsend.capture.value); EXPECT_EQ(0x1234567, irsend.capture.address); EXPECT_EQ(0x89, irsend.capture.command); @@ -712,22 +734,22 @@ TEST(TestDecodeRC6, NormalMode0DecodeWithRepeatAndStrict) { // Normal RC-6 Mode 0 (20-bit) even message with one repeat. irsend.reset(); - irsend.sendRC6(0x174, RC6_MODE0_BITS, 1); + irsend.sendRC6(0x174, kRC6Mode0Bits, 1); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodeRC6(&irsend.capture, RC6_MODE0_BITS, true)); + ASSERT_TRUE(irrecv.decodeRC6(&irsend.capture, kRC6Mode0Bits, true)); EXPECT_EQ(RC6, irsend.capture.decode_type); - EXPECT_EQ(RC6_MODE0_BITS, irsend.capture.bits); + EXPECT_EQ(kRC6Mode0Bits, irsend.capture.bits); EXPECT_EQ(0x174, irsend.capture.value); EXPECT_EQ(0x1, irsend.capture.address); EXPECT_EQ(0x74, irsend.capture.command); // Normal RC-6 Mode 0 (20-bit) odd message with one repeat. irsend.reset(); - irsend.sendRC6(0x175, RC6_MODE0_BITS, 1); + irsend.sendRC6(0x175, kRC6Mode0Bits, 1); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodeRC6(&irsend.capture, RC6_MODE0_BITS, true)); + ASSERT_TRUE(irrecv.decodeRC6(&irsend.capture, kRC6Mode0Bits, true)); EXPECT_EQ(RC6, irsend.capture.decode_type); - EXPECT_EQ(RC6_MODE0_BITS, irsend.capture.bits); + EXPECT_EQ(kRC6Mode0Bits, irsend.capture.bits); EXPECT_EQ(0x175, irsend.capture.value); EXPECT_EQ(0x1, irsend.capture.address); EXPECT_EQ(0x75, irsend.capture.command); @@ -741,22 +763,22 @@ TEST(TestDecodeRC6, Normal36BitDecodeWithRepeatAndStrict) { // Normal RC-6 36-bit odd message with one repeat. irsend.reset(); - irsend.sendRC6(0x175, RC6_36_BITS, 1); + irsend.sendRC6(0x175, kRC6_36Bits, 1); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodeRC6(&irsend.capture, RC6_36_BITS, true)); + ASSERT_TRUE(irrecv.decodeRC6(&irsend.capture, kRC6_36Bits, true)); EXPECT_EQ(RC6, irsend.capture.decode_type); - EXPECT_EQ(RC6_36_BITS, irsend.capture.bits); + EXPECT_EQ(kRC6_36Bits, irsend.capture.bits); EXPECT_EQ(0x175, irsend.capture.value); EXPECT_EQ(0x1, irsend.capture.address); EXPECT_EQ(0x75, irsend.capture.command); // Normal RC-6 36-bit even message with one repeat. irsend.reset(); - irsend.sendRC6(0x174, RC6_36_BITS, 1); + irsend.sendRC6(0x174, kRC6_36Bits, 1); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodeRC6(&irsend.capture, RC6_36_BITS, true)); + ASSERT_TRUE(irrecv.decodeRC6(&irsend.capture, kRC6_36Bits, true)); EXPECT_EQ(RC6, irsend.capture.decode_type); - EXPECT_EQ(RC6_36_BITS, irsend.capture.bits); + EXPECT_EQ(kRC6_36Bits, irsend.capture.bits); EXPECT_EQ(0x174, irsend.capture.value); EXPECT_EQ(0x1, irsend.capture.address); EXPECT_EQ(0x74, irsend.capture.command); @@ -770,11 +792,11 @@ TEST(TestDecodeRC6, NormalDecodeWithoutStrict) { // Normal RC-6 Mode 0 (20-bit) message. irsend.reset(); - irsend.sendRC6(0x175, RC6_MODE0_BITS); + irsend.sendRC6(0x175, kRC6Mode0Bits); irsend.makeDecodeResult(); ASSERT_TRUE(irrecv.decodeRC6(&irsend.capture)); EXPECT_EQ(RC6, irsend.capture.decode_type); - EXPECT_EQ(RC6_MODE0_BITS, irsend.capture.bits); + EXPECT_EQ(kRC6Mode0Bits, irsend.capture.bits); EXPECT_EQ(0x175, irsend.capture.value); EXPECT_EQ(0x01, irsend.capture.address); EXPECT_EQ(0x75, irsend.capture.command); @@ -782,11 +804,11 @@ TEST(TestDecodeRC6, NormalDecodeWithoutStrict) { // Normal RC-6 Mode 0 (20-bit) message. irsend.reset(); - irsend.sendRC6(0x174, RC6_MODE0_BITS); + irsend.sendRC6(0x174, kRC6Mode0Bits); irsend.makeDecodeResult(); ASSERT_TRUE(irrecv.decodeRC6(&irsend.capture)); EXPECT_EQ(RC6, irsend.capture.decode_type); - EXPECT_EQ(RC6_MODE0_BITS, irsend.capture.bits); + EXPECT_EQ(kRC6Mode0Bits, irsend.capture.bits); EXPECT_EQ(0x174, irsend.capture.value); EXPECT_EQ(0x01, irsend.capture.address); EXPECT_EQ(0x74, irsend.capture.command); @@ -794,11 +816,11 @@ TEST(TestDecodeRC6, NormalDecodeWithoutStrict) { // Normal RC-6 36-bit message. irsend.reset(); - irsend.sendRC6(0x174, RC6_36_BITS); + irsend.sendRC6(0x174, kRC6_36Bits); irsend.makeDecodeResult(); ASSERT_TRUE(irrecv.decodeRC6(&irsend.capture)); EXPECT_EQ(RC6, irsend.capture.decode_type); - EXPECT_EQ(RC6_36_BITS, irsend.capture.bits); + EXPECT_EQ(kRC6_36Bits, irsend.capture.bits); EXPECT_EQ(0x174, irsend.capture.value); EXPECT_EQ(0x01, irsend.capture.address); EXPECT_EQ(0x74, irsend.capture.command); @@ -806,11 +828,11 @@ TEST(TestDecodeRC6, NormalDecodeWithoutStrict) { // Normal Synthesised RC-6 36-bit message. irsend.reset(); - irsend.sendRC6(irsend.encodeRC6(0x1234567, 0x89, RC6_36_BITS), RC6_36_BITS); + irsend.sendRC6(irsend.encodeRC6(0x1234567, 0x89, kRC6_36Bits), kRC6_36Bits); irsend.makeDecodeResult(); ASSERT_TRUE(irrecv.decodeRC6(&irsend.capture)); EXPECT_EQ(RC6, irsend.capture.decode_type); - EXPECT_EQ(RC6_36_BITS, irsend.capture.bits); + EXPECT_EQ(kRC6_36Bits, irsend.capture.bits); EXPECT_EQ(0x123456789, irsend.capture.value); EXPECT_EQ(0x1234567, irsend.capture.address); EXPECT_EQ(0x89, irsend.capture.command); @@ -825,17 +847,17 @@ TEST(TestDecodeRC6, Decode36BitGlobalCacheExample) { irsend.reset(); // Xbox-360 Power On from Global Cache. - uint16_t gc_test[65] = {36000, 1, 1, 96, 32, 16, 16, 16, 16, 16, 32, 16, 32, - 48, 32, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 32, 16, 16, 16, - 16, 16, 16, 32, 32, 16, 16, 16, 16, 32, 32, 32, 16, - 16, 16, 16, 16, 16, 32, 32, 32, 32, 32, 32, 16, 2476}; + uint16_t gc_test[65] = { + 36000, 1, 1, 96, 32, 16, 16, 16, 16, 16, 32, 16, 32, 48, 32, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 32, 16, 16, 16, 16, 16, 16, 32, 32, 16, 16, 16, 16, 32, 32, 32, + 16, 16, 16, 16, 16, 16, 32, 32, 32, 32, 32, 32, 16, 2476}; irsend.sendGC(gc_test, 65); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodeRC6(&irsend.capture, RC6_36_BITS)); + ASSERT_TRUE(irrecv.decodeRC6(&irsend.capture, kRC6_36Bits)); EXPECT_EQ(RC6, irsend.capture.decode_type); - EXPECT_EQ(RC6_36_BITS, irsend.capture.bits); + EXPECT_EQ(kRC6_36Bits, irsend.capture.bits); EXPECT_EQ(0xC800F742A, irsend.capture.value); EXPECT_EQ(0xC800F74, irsend.capture.address); EXPECT_EQ(0x2A, irsend.capture.command); @@ -849,25 +871,26 @@ TEST(TestDecodeRC5, FailToDecodeNonRC6Example) { irsend.begin(); irsend.reset(); - uint16_t gc_test[39] = {38000, 1, 1, 322, 162, 20, 61, 20, 61, 20, 20, 20, 20, - 20, 20, 20, 127, 20, 61, 9, 20, 20, 61, 20, 20, 20, - 61, 20, 61, 20, 61, 20, 20, 20, 20, 20, 20, 20, 884}; + uint16_t gc_test[39] = {38000, 1, 1, 322, 162, 20, 61, 20, 61, 20, + 20, 20, 20, 20, 20, 20, 127, 20, 61, 9, + 20, 20, 61, 20, 20, 20, 61, 20, 61, 20, + 61, 20, 20, 20, 20, 20, 20, 20, 884}; irsend.sendGC(gc_test, 39); irsend.makeDecodeResult(); ASSERT_FALSE(irrecv.decodeRC6(&irsend.capture)); - ASSERT_FALSE(irrecv.decodeRC6(&irsend.capture, RC6_MODE0_BITS, true)); - ASSERT_FALSE(irrecv.decodeRC6(&irsend.capture, RC6_MODE0_BITS, false)); - ASSERT_FALSE(irrecv.decodeRC6(&irsend.capture, RC6_36_BITS, true)); - ASSERT_FALSE(irrecv.decodeRC6(&irsend.capture, RC6_36_BITS, false)); + ASSERT_FALSE(irrecv.decodeRC6(&irsend.capture, kRC6Mode0Bits, true)); + ASSERT_FALSE(irrecv.decodeRC6(&irsend.capture, kRC6Mode0Bits, false)); + ASSERT_FALSE(irrecv.decodeRC6(&irsend.capture, kRC6_36Bits, true)); + ASSERT_FALSE(irrecv.decodeRC6(&irsend.capture, kRC6_36Bits, false)); irsend.reset(); irsend.sendRC5(0x0); irsend.makeDecodeResult(); ASSERT_FALSE(irrecv.decodeRC6(&irsend.capture)); - ASSERT_FALSE(irrecv.decodeRC6(&irsend.capture, RC6_MODE0_BITS, true)); - ASSERT_FALSE(irrecv.decodeRC6(&irsend.capture, RC6_MODE0_BITS, false)); - ASSERT_FALSE(irrecv.decodeRC6(&irsend.capture, RC6_36_BITS, true)); - ASSERT_FALSE(irrecv.decodeRC6(&irsend.capture, RC6_36_BITS, false)); + ASSERT_FALSE(irrecv.decodeRC6(&irsend.capture, kRC6Mode0Bits, true)); + ASSERT_FALSE(irrecv.decodeRC6(&irsend.capture, kRC6Mode0Bits, false)); + ASSERT_FALSE(irrecv.decodeRC6(&irsend.capture, kRC6_36Bits, true)); + ASSERT_FALSE(irrecv.decodeRC6(&irsend.capture, kRC6_36Bits, false)); } diff --git a/lib/IRremoteESP8266/test/ir_RCMM_test.cpp b/lib/IRremoteESP8266/test/ir_RCMM_test.cpp index ad11dd7..028dbd8 100644 --- a/lib/IRremoteESP8266/test/ir_RCMM_test.cpp +++ b/lib/IRremoteESP8266/test/ir_RCMM_test.cpp @@ -13,16 +13,20 @@ TEST(TestSendRCMM, SendDataOnly) { irsend.reset(); irsend.sendRCMM(0xe0a600); - EXPECT_EQ("m416s277" - "m166s777m166s611m166s277m166s277" - "m166s611m166s611m166s444m166s611m166s277m166s277m166s277m166s277" - "m166s19600", irsend.outputStr()); + EXPECT_EQ( + "m416s277" + "m166s777m166s611m166s277m166s277" + "m166s611m166s611m166s444m166s611m166s277m166s277m166s277m166s277" + "m166s19600", + irsend.outputStr()); irsend.reset(); irsend.sendRCMM(0x28e0a600UL, 32); - EXPECT_EQ("m416s277" - "m166s277m166s611m166s611m166s277m166s777m166s611m166s277m166s277" - "m166s611m166s611m166s444m166s611m166s277m166s277m166s277m166s277" - "m166s17160", irsend.outputStr()); + EXPECT_EQ( + "m416s277" + "m166s277m166s611m166s611m166s277m166s777m166s611m166s277m166s277" + "m166s611m166s611m166s444m166s611m166s277m166s277m166s277m166s277" + "m166s17160", + irsend.outputStr()); } // Test sending with different repeats. @@ -32,18 +36,20 @@ TEST(TestSendRCMM, SendWithRepeats) { irsend.reset(); irsend.sendRCMM(0x28e0a600, 32, 2); // 2 repeats. - EXPECT_EQ("m416s277" - "m166s277m166s611m166s611m166s277m166s777m166s611m166s277m166s277" - "m166s611m166s611m166s444m166s611m166s277m166s277m166s277m166s277" - "m166s17160" - "m416s277" - "m166s277m166s611m166s611m166s277m166s777m166s611m166s277m166s277" - "m166s611m166s611m166s444m166s611m166s277m166s277m166s277m166s277" - "m166s17160" - "m416s277" - "m166s277m166s611m166s611m166s277m166s777m166s611m166s277m166s277" - "m166s611m166s611m166s444m166s611m166s277m166s277m166s277m166s277" - "m166s17160", irsend.outputStr()); + EXPECT_EQ( + "m416s277" + "m166s277m166s611m166s611m166s277m166s777m166s611m166s277m166s277" + "m166s611m166s611m166s444m166s611m166s277m166s277m166s277m166s277" + "m166s17160" + "m416s277" + "m166s277m166s611m166s611m166s277m166s777m166s611m166s277m166s277" + "m166s611m166s611m166s444m166s611m166s277m166s277m166s277m166s277" + "m166s17160" + "m416s277" + "m166s277m166s611m166s611m166s277m166s777m166s611m166s277m166s277" + "m166s611m166s611m166s444m166s611m166s277m166s277m166s277m166s277" + "m166s17160", + irsend.outputStr()); } // Test sending an atypical data size. @@ -53,15 +59,19 @@ TEST(TestSendRCMM, SendUnusualSize) { irsend.reset(); irsend.sendRCMM(0xE0, 8); - EXPECT_EQ("m416s277" - "m166s777m166s611m166s277m166s277" - "m166s24313", irsend.outputStr()); + EXPECT_EQ( + "m416s277" + "m166s777m166s611m166s277m166s277" + "m166s24313", + irsend.outputStr()); irsend.reset(); irsend.sendRCMM(0x28e0a60000UL, 40); - EXPECT_EQ("m416s277" - "m166s277m166s611m166s611m166s277m166s777m166s611m166s277m166s277" - "m166s611m166s611m166s444m166s611m166s277m166s277m166s277m166s277" - "m166s277m166s277m166s277m166s277m166s15388", irsend.outputStr()); + EXPECT_EQ( + "m416s277" + "m166s277m166s611m166s611m166s277m166s777m166s611m166s277m166s277" + "m166s611m166s611m166s444m166s611m166s277m166s277m166s277m166s277" + "m166s277m166s277m166s277m166s277m166s15388", + irsend.outputStr()); } // Tests for decodeRCMM(). @@ -76,9 +86,9 @@ TEST(TestDecodeRCMM, NormalDecodeWithStrict) { irsend.reset(); irsend.sendRCMM(0xe0a600); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodeRCMM(&irsend.capture, RCMM_BITS, true)); + ASSERT_TRUE(irrecv.decodeRCMM(&irsend.capture, kRCMMBits, true)); EXPECT_EQ(RCMM, irsend.capture.decode_type); - EXPECT_EQ(RCMM_BITS, irsend.capture.bits); + EXPECT_EQ(kRCMMBits, irsend.capture.bits); EXPECT_EQ(0xe0a600, irsend.capture.value); EXPECT_EQ(0x0, irsend.capture.address); EXPECT_EQ(0x0, irsend.capture.command); @@ -203,14 +213,15 @@ TEST(TestDecodeRCMM, FailToDecodeNonRCMMExample) { irsend.reset(); // Modified a few entries to unexpected values, based on previous test case. - uint16_t gc_test[39] = {38000, 1, 1, 322, 162, 20, 61, 20, 61, 20, 20, 20, 20, - 20, 20, 20, 127, 20, 61, 9, 20, 20, 61, 20, 20, 20, - 61, 20, 61, 20, 61, 20, 20, 20, 20, 20, 20, 20, 884}; + uint16_t gc_test[39] = {38000, 1, 1, 322, 162, 20, 61, 20, 61, 20, + 20, 20, 20, 20, 20, 20, 127, 20, 61, 9, + 20, 20, 61, 20, 20, 20, 61, 20, 61, 20, + 61, 20, 20, 20, 20, 20, 20, 20, 884}; irsend.sendGC(gc_test, 39); irsend.makeDecodeResult(); ASSERT_FALSE(irrecv.decodeRCMM(&irsend.capture)); - ASSERT_FALSE(irrecv.decodeRCMM(&irsend.capture, RCMM_BITS, false)); + ASSERT_FALSE(irrecv.decodeRCMM(&irsend.capture, kRCMMBits, false)); } // Issue 281 Debugging @@ -220,11 +231,12 @@ TEST(TestDecodeRCMM, DebugIssue281) { irsend.begin(); // Data from Issue #281 (shortened version) - uint16_t rawData[36] = {448, 276, 150, 285, 164, 613, 163, 447, 162, 613, - 164, 445, 164, 776, 167, 278, 163, 280, 163, 280, - 162, 611, 168, 444, 163, 612, 164, 277, 168, 447, - 157, 282, 165, 276, - 165, 65535}; // Last value modified from 89729 + uint16_t + rawData[36] = {448, 276, 150, 285, 164, 613, 163, 447, 162, 613, + 164, 445, 164, 776, 167, 278, 163, 280, 163, 280, + 162, 611, 168, 444, 163, 612, 164, 277, 168, 447, + 157, 282, 165, 276, 165, 65535}; // Last value modified + // from 89729 irsend.reset(); irsend.sendRaw(rawData, 36, 36); diff --git a/lib/IRremoteESP8266/test/ir_Samsung_test.cpp b/lib/IRremoteESP8266/test/ir_Samsung_test.cpp index 5361776..4c79803 100644 --- a/lib/IRremoteESP8266/test/ir_Samsung_test.cpp +++ b/lib/IRremoteESP8266/test/ir_Samsung_test.cpp @@ -1,5 +1,8 @@ // Copyright 2017 David Conran +#include "ir_Samsung.h" +#include "IRrecv.h" +#include "IRrecv_test.h" #include "IRsend.h" #include "IRsend_test.h" #include "gtest/gtest.h" @@ -13,13 +16,14 @@ TEST(TestSendSamsung, SendDataOnly) { irsend.reset(); irsend.sendSAMSUNG(0xE0E09966); // Samsung TV Power On. - EXPECT_EQ("m4480s4480" - "m560s1680m560s1680m560s1680m560s560m560s560m560s560m560s560" - "m560s560m560s1680m560s1680m560s1680m560s560m560s560m560s560" - "m560s560m560s560m560s1680m560s560m560s560m560s1680m560s1680" - "m560s560m560s560m560s1680m560s560m560s1680m560s1680m560s560" - "m560s560m560s1680m560s1680m560s560m560s47040", - irsend.outputStr()); + EXPECT_EQ( + "m4480s4480" + "m560s1680m560s1680m560s1680m560s560m560s560m560s560m560s560" + "m560s560m560s1680m560s1680m560s1680m560s560m560s560m560s560" + "m560s560m560s560m560s1680m560s560m560s560m560s1680m560s1680" + "m560s560m560s560m560s1680m560s560m560s1680m560s1680m560s560" + "m560s560m560s1680m560s1680m560s560m560s47040", + irsend.outputStr()); irsend.reset(); } @@ -30,40 +34,42 @@ TEST(TestSendSamsung, SendWithRepeats) { irsend.begin(); irsend.reset(); - irsend.sendSAMSUNG(0xE0E09966, SAMSUNG_BITS, 1); // 1 repeat. - EXPECT_EQ("m4480s4480" - "m560s1680m560s1680m560s1680m560s560m560s560m560s560m560s560" - "m560s560m560s1680m560s1680m560s1680m560s560m560s560m560s560" - "m560s560m560s560m560s1680m560s560m560s560m560s1680m560s1680" - "m560s560m560s560m560s1680m560s560m560s1680m560s1680m560s560" - "m560s560m560s1680m560s1680m560s560m560s47040" - "m4480s4480" - "m560s1680m560s1680m560s1680m560s560m560s560m560s560m560s560" - "m560s560m560s1680m560s1680m560s1680m560s560m560s560m560s560" - "m560s560m560s560m560s1680m560s560m560s560m560s1680m560s1680" - "m560s560m560s560m560s1680m560s560m560s1680m560s1680m560s560" - "m560s560m560s1680m560s1680m560s560m560s47040" - , irsend.outputStr()); - irsend.sendSAMSUNG(0xE0E09966, SAMSUNG_BITS, 2); // 2 repeats. - EXPECT_EQ("m4480s4480" - "m560s1680m560s1680m560s1680m560s560m560s560m560s560m560s560" - "m560s560m560s1680m560s1680m560s1680m560s560m560s560m560s560" - "m560s560m560s560m560s1680m560s560m560s560m560s1680m560s1680" - "m560s560m560s560m560s1680m560s560m560s1680m560s1680m560s560" - "m560s560m560s1680m560s1680m560s560m560s47040" - "m4480s4480" - "m560s1680m560s1680m560s1680m560s560m560s560m560s560m560s560" - "m560s560m560s1680m560s1680m560s1680m560s560m560s560m560s560" - "m560s560m560s560m560s1680m560s560m560s560m560s1680m560s1680" - "m560s560m560s560m560s1680m560s560m560s1680m560s1680m560s560" - "m560s560m560s1680m560s1680m560s560m560s47040" - "m4480s4480" - "m560s1680m560s1680m560s1680m560s560m560s560m560s560m560s560" - "m560s560m560s1680m560s1680m560s1680m560s560m560s560m560s560" - "m560s560m560s560m560s1680m560s560m560s560m560s1680m560s1680" - "m560s560m560s560m560s1680m560s560m560s1680m560s1680m560s560" - "m560s560m560s1680m560s1680m560s560m560s47040" - , irsend.outputStr()); + irsend.sendSAMSUNG(0xE0E09966, kSamsungBits, 1); // 1 repeat. + EXPECT_EQ( + "m4480s4480" + "m560s1680m560s1680m560s1680m560s560m560s560m560s560m560s560" + "m560s560m560s1680m560s1680m560s1680m560s560m560s560m560s560" + "m560s560m560s560m560s1680m560s560m560s560m560s1680m560s1680" + "m560s560m560s560m560s1680m560s560m560s1680m560s1680m560s560" + "m560s560m560s1680m560s1680m560s560m560s47040" + "m4480s4480" + "m560s1680m560s1680m560s1680m560s560m560s560m560s560m560s560" + "m560s560m560s1680m560s1680m560s1680m560s560m560s560m560s560" + "m560s560m560s560m560s1680m560s560m560s560m560s1680m560s1680" + "m560s560m560s560m560s1680m560s560m560s1680m560s1680m560s560" + "m560s560m560s1680m560s1680m560s560m560s47040", + irsend.outputStr()); + irsend.sendSAMSUNG(0xE0E09966, kSamsungBits, 2); // 2 repeats. + EXPECT_EQ( + "m4480s4480" + "m560s1680m560s1680m560s1680m560s560m560s560m560s560m560s560" + "m560s560m560s1680m560s1680m560s1680m560s560m560s560m560s560" + "m560s560m560s560m560s1680m560s560m560s560m560s1680m560s1680" + "m560s560m560s560m560s1680m560s560m560s1680m560s1680m560s560" + "m560s560m560s1680m560s1680m560s560m560s47040" + "m4480s4480" + "m560s1680m560s1680m560s1680m560s560m560s560m560s560m560s560" + "m560s560m560s1680m560s1680m560s1680m560s560m560s560m560s560" + "m560s560m560s560m560s1680m560s560m560s560m560s1680m560s1680" + "m560s560m560s560m560s1680m560s560m560s1680m560s1680m560s560" + "m560s560m560s1680m560s1680m560s560m560s47040" + "m4480s4480" + "m560s1680m560s1680m560s1680m560s560m560s560m560s560m560s560" + "m560s560m560s1680m560s1680m560s1680m560s560m560s560m560s560" + "m560s560m560s560m560s1680m560s560m560s560m560s1680m560s1680" + "m560s560m560s560m560s1680m560s560m560s1680m560s1680m560s560" + "m560s560m560s1680m560s1680m560s560m560s47040", + irsend.outputStr()); } // Tests for encodeSAMSUNG(). @@ -90,9 +96,9 @@ TEST(TestDecodeSamsung, NormalDecodeWithStrict) { irsend.reset(); irsend.sendSAMSUNG(0xE0E09966); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodeSAMSUNG(&irsend.capture, SAMSUNG_BITS, true)); + ASSERT_TRUE(irrecv.decodeSAMSUNG(&irsend.capture, kSamsungBits, true)); EXPECT_EQ(SAMSUNG, irsend.capture.decode_type); - EXPECT_EQ(SAMSUNG_BITS, irsend.capture.bits); + EXPECT_EQ(kSamsungBits, irsend.capture.bits); EXPECT_EQ(0xE0E09966, irsend.capture.value); EXPECT_EQ(0x07, irsend.capture.address); EXPECT_EQ(0x99, irsend.capture.command); @@ -101,9 +107,9 @@ TEST(TestDecodeSamsung, NormalDecodeWithStrict) { irsend.reset(); irsend.sendSAMSUNG(irsend.encodeSAMSUNG(0x07, 0x99)); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodeSAMSUNG(&irsend.capture, SAMSUNG_BITS, true)); + ASSERT_TRUE(irrecv.decodeSAMSUNG(&irsend.capture, kSamsungBits, true)); EXPECT_EQ(SAMSUNG, irsend.capture.decode_type); - EXPECT_EQ(SAMSUNG_BITS, irsend.capture.bits); + EXPECT_EQ(kSamsungBits, irsend.capture.bits); EXPECT_EQ(0xE0E09966, irsend.capture.value); EXPECT_EQ(0x07, irsend.capture.address); EXPECT_EQ(0x99, irsend.capture.command); @@ -112,9 +118,9 @@ TEST(TestDecodeSamsung, NormalDecodeWithStrict) { irsend.reset(); irsend.sendSAMSUNG(irsend.encodeSAMSUNG(0x1, 0x1)); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodeSAMSUNG(&irsend.capture, SAMSUNG_BITS, true)); + ASSERT_TRUE(irrecv.decodeSAMSUNG(&irsend.capture, kSamsungBits, true)); EXPECT_EQ(SAMSUNG, irsend.capture.decode_type); - EXPECT_EQ(SAMSUNG_BITS, irsend.capture.bits); + EXPECT_EQ(kSamsungBits, irsend.capture.bits); EXPECT_EQ(0x8080807F, irsend.capture.value); EXPECT_EQ(0x1, irsend.capture.address); EXPECT_EQ(0x1, irsend.capture.command); @@ -128,11 +134,11 @@ TEST(TestDecodeSamsung, NormalDecodeWithRepeatAndStrict) { // Normal Samsung 32-bit message. irsend.reset(); - irsend.sendSAMSUNG(0xE0E09966, SAMSUNG_BITS, 2); + irsend.sendSAMSUNG(0xE0E09966, kSamsungBits, 2); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodeSAMSUNG(&irsend.capture, SAMSUNG_BITS, true)); + ASSERT_TRUE(irrecv.decodeSAMSUNG(&irsend.capture, kSamsungBits, true)); EXPECT_EQ(SAMSUNG, irsend.capture.decode_type); - EXPECT_EQ(SAMSUNG_BITS, irsend.capture.bits); + EXPECT_EQ(kSamsungBits, irsend.capture.bits); EXPECT_EQ(0xE0E09966, irsend.capture.value); EXPECT_EQ(0x07, irsend.capture.address); EXPECT_EQ(0x99, irsend.capture.command); @@ -148,11 +154,11 @@ TEST(TestDecodeSamsung, DecodeWithNonStrictValues) { irsend.sendSAMSUNG(0x0); // Illegal value Samsung 32-bit message. irsend.makeDecodeResult(); // Should fail with strict on. - ASSERT_FALSE(irrecv.decodeSAMSUNG(&irsend.capture, SAMSUNG_BITS, true)); + ASSERT_FALSE(irrecv.decodeSAMSUNG(&irsend.capture, kSamsungBits, true)); // Should pass if strict off. - ASSERT_TRUE(irrecv.decodeSAMSUNG(&irsend.capture, SAMSUNG_BITS, false)); + ASSERT_TRUE(irrecv.decodeSAMSUNG(&irsend.capture, kSamsungBits, false)); EXPECT_EQ(SAMSUNG, irsend.capture.decode_type); - EXPECT_EQ(SAMSUNG_BITS, irsend.capture.bits); + EXPECT_EQ(kSamsungBits, irsend.capture.bits); EXPECT_EQ(0x0, irsend.capture.value); EXPECT_EQ(0x0, irsend.capture.address); EXPECT_EQ(0x0, irsend.capture.command); @@ -161,11 +167,11 @@ TEST(TestDecodeSamsung, DecodeWithNonStrictValues) { irsend.sendSAMSUNG(0x12345678); // Illegal value Samsung 32-bit message. irsend.makeDecodeResult(); // Should fail with strict on. - ASSERT_FALSE(irrecv.decodeSAMSUNG(&irsend.capture, SAMSUNG_BITS, true)); + ASSERT_FALSE(irrecv.decodeSAMSUNG(&irsend.capture, kSamsungBits, true)); // Should pass if strict off. - ASSERT_TRUE(irrecv.decodeSAMSUNG(&irsend.capture, SAMSUNG_BITS, false)); + ASSERT_TRUE(irrecv.decodeSAMSUNG(&irsend.capture, kSamsungBits, false)); EXPECT_EQ(SAMSUNG, irsend.capture.decode_type); - EXPECT_EQ(SAMSUNG_BITS, irsend.capture.bits); + EXPECT_EQ(kSamsungBits, irsend.capture.bits); EXPECT_EQ(0x12345678, irsend.capture.value); EXPECT_EQ(0x48, irsend.capture.address); EXPECT_EQ(0x6A, irsend.capture.command); @@ -175,9 +181,9 @@ TEST(TestDecodeSamsung, DecodeWithNonStrictValues) { irsend.sendSAMSUNG(irsend.encodeSAMSUNG(0, 0), 36); irsend.makeDecodeResult(); // Should fail with strict on. - ASSERT_FALSE(irrecv.decodeSAMSUNG(&irsend.capture, SAMSUNG_BITS, true)); + ASSERT_FALSE(irrecv.decodeSAMSUNG(&irsend.capture, kSamsungBits, true)); // Shouldn't pass if strict off and wrong expected bit size. - ASSERT_FALSE(irrecv.decodeSAMSUNG(&irsend.capture, SAMSUNG_BITS, false)); + ASSERT_FALSE(irrecv.decodeSAMSUNG(&irsend.capture, kSamsungBits, false)); // Re-decode with correct bit size. ASSERT_FALSE(irrecv.decodeSAMSUNG(&irsend.capture, 36, true)); ASSERT_TRUE(irrecv.decodeSAMSUNG(&irsend.capture, 36, false)); @@ -192,9 +198,9 @@ TEST(TestDecodeSamsung, DecodeWithNonStrictValues) { irsend.sendSAMSUNG(irsend.encodeSAMSUNG(0x0, 0x0), 16); irsend.makeDecodeResult(); // Should fail with strict on. - ASSERT_FALSE(irrecv.decodeSAMSUNG(&irsend.capture, SAMSUNG_BITS, true)); + ASSERT_FALSE(irrecv.decodeSAMSUNG(&irsend.capture, kSamsungBits, true)); // And it should fail when we expect more bits. - ASSERT_FALSE(irrecv.decodeSAMSUNG(&irsend.capture, SAMSUNG_BITS, false)); + ASSERT_FALSE(irrecv.decodeSAMSUNG(&irsend.capture, kSamsungBits, false)); // Should pass if strict off if we ask for correct nr. of bits sent. ASSERT_TRUE(irrecv.decodeSAMSUNG(&irsend.capture, 16, false)); @@ -219,7 +225,7 @@ TEST(TestDecodeSamsung, Decode64BitMessages) { // Illegal value & size Samsung 64-bit message. irsend.sendSAMSUNG(0xFFFFFFFFFFFFFFFF, 64); irsend.makeDecodeResult(); - ASSERT_FALSE(irrecv.decodeSAMSUNG(&irsend.capture, SAMSUNG_BITS, true)); + ASSERT_FALSE(irrecv.decodeSAMSUNG(&irsend.capture, kSamsungBits, true)); // Should work with a 'normal' match (not strict) ASSERT_TRUE(irrecv.decodeSAMSUNG(&irsend.capture, 64, false)); EXPECT_EQ(SAMSUNG, irsend.capture.decode_type); @@ -237,18 +243,18 @@ TEST(TestDecodeSamsung, DecodeGlobalCacheExample) { irsend.reset(); // Samsung TV Power On from Global Cache. - uint16_t gc_test[71] = {38000, 1, 1, 172, 172, 22, 64, 22, 64, 22, 64, 22, 21, - 22, 21, 22, 21, 22, 21, 22, 21, 22, 64, 22, 64, 22, - 64, 22, 21, 22, 21, 22, 21, 22, 21, 22, 21, 22, 64, - 22, 21, 22, 21, 22, 64, 22, 64, 22, 21, 22, 21, 22, - 64, 22, 21, 22, 64, 22, 64, 22, 21, 22, 21, 22, 64, - 22, 64, 22, 21, 22, 1820}; + uint16_t gc_test[71] = {38000, 1, 1, 172, 172, 22, 64, 22, 64, 22, 64, 22, + 21, 22, 21, 22, 21, 22, 21, 22, 21, 22, 64, 22, + 64, 22, 64, 22, 21, 22, 21, 22, 21, 22, 21, 22, + 21, 22, 64, 22, 21, 22, 21, 22, 64, 22, 64, 22, + 21, 22, 21, 22, 64, 22, 21, 22, 64, 22, 64, 22, + 21, 22, 21, 22, 64, 22, 64, 22, 21, 22, 1820}; irsend.sendGC(gc_test, 71); irsend.makeDecodeResult(); ASSERT_TRUE(irrecv.decodeSAMSUNG(&irsend.capture)); EXPECT_EQ(SAMSUNG, irsend.capture.decode_type); - EXPECT_EQ(SAMSUNG_BITS, irsend.capture.bits); + EXPECT_EQ(kSamsungBits, irsend.capture.bits); EXPECT_EQ(0xE0E09966, irsend.capture.value); EXPECT_EQ(0x07, irsend.capture.address); EXPECT_EQ(0x99, irsend.capture.command); @@ -262,15 +268,711 @@ TEST(TestDecodeSamsung, FailToDecodeNonSamsungExample) { irsend.reset(); // Modified a few entries to unexpected values, based on previous test case. - uint16_t gc_test[71] = {38000, 1, 1, 172, 172, 22, 64, 22, 64, 22, 64, 22, 21, - 22, 21, 22, 21, 22, 11, 22, 21, 22, 128, 22, 64, 22, - 64, 22, 21, 22, 21, 22, 21, 22, 21, 22, 21, 22, 64, - 22, 21, 22, 21, 22, 64, 22, 64, 22, 21, 22, 21, 22, - 64, 22, 21, 22, 64, 22, 64, 22, 21, 22, 21, 22, 64, - 22, 64, 22, 21, 22, 1820}; + uint16_t gc_test[71] = {38000, 1, 1, 172, 172, 22, 64, 22, 64, 22, 64, 22, + 21, 22, 21, 22, 21, 22, 11, 22, 21, 22, 128, 22, + 64, 22, 64, 22, 21, 22, 21, 22, 21, 22, 21, 22, + 21, 22, 64, 22, 21, 22, 21, 22, 64, 22, 64, 22, + 21, 22, 21, 22, 64, 22, 21, 22, 64, 22, 64, 22, + 21, 22, 21, 22, 64, 22, 64, 22, 21, 22, 1820}; irsend.sendGC(gc_test, 71); irsend.makeDecodeResult(); ASSERT_FALSE(irrecv.decodeSAMSUNG(&irsend.capture)); - ASSERT_FALSE(irrecv.decodeSAMSUNG(&irsend.capture, SAMSUNG_BITS, false)); + ASSERT_FALSE(irrecv.decodeSAMSUNG(&irsend.capture, kSamsungBits, false)); +} + +// Tests for sendSamsungAC(). + +// Test sending typical data only. +TEST(TestSendSamsungAC, SendDataOnly) { + IRsendTest irsend(0); + irsend.begin(); + uint8_t data[kSamsungAcStateLength] = { + 0x02, 0x92, 0x0F, 0x00, 0x00, 0x00, 0xF0, + 0x01, 0x02, 0xAF, 0x71, 0x00, 0x15, 0xF0}; + irsend.sendSamsungAC(data); + EXPECT_EQ( + "m690s17844" + "m3086s8864" + "m586s436m586s1432m586s436m586s436m586s436m586s436m586s436m586s436" + "m586s436m586s1432m586s436m586s436m586s1432m586s436m586s436m586s1432" + "m586s1432m586s1432m586s1432m586s1432m586s436m586s436m586s436m586s436" + "m586s436m586s436m586s436m586s436m586s436m586s436m586s436m586s436" + "m586s436m586s436m586s436m586s436m586s436m586s436m586s436m586s436" + "m586s436m586s436m586s436m586s436m586s436m586s436m586s436m586s436" + "m586s436m586s436m586s436m586s436m586s1432m586s1432m586s1432m586s1432" + "m586s2886" + "m3086s8864" + "m586s1432m586s436m586s436m586s436m586s436m586s436m586s436m586s436" + "m586s436m586s1432m586s436m586s436m586s436m586s436m586s436m586s436" + "m586s1432m586s1432m586s1432m586s1432m586s436m586s1432m586s436m586s1432" + "m586s1432m586s436m586s436m586s436m586s1432m586s1432m586s1432m586s436" + "m586s436m586s436m586s436m586s436m586s436m586s436m586s436m586s436" + "m586s1432m586s436m586s1432m586s436m586s1432m586s436m586s436m586s436" + "m586s436m586s436m586s436m586s436m586s1432m586s1432m586s1432m586s1432" + "m586s100000", + irsend.outputStr()); +} + +// Test sending extended data. +TEST(TestSendSamsungAC, SendExtendedData) { + IRsendTest irsend(0); + irsend.begin(); + // "Off" message. + uint8_t data[kSamsungAcExtendedStateLength] = { + 0x02, 0xB2, 0x0F, 0x00, 0x00, 0x00, 0xC0, + 0x01, 0xD2, 0x0F, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x02, 0xFF, 0x71, 0x80, 0x11, 0xC0}; + irsend.sendSamsungAC(data, kSamsungAcExtendedStateLength); + EXPECT_EQ( + "m690s17844" + "m3086s8864" + "m586s436m586s1432m586s436m586s436m586s436m586s436m586s436m586s436" + "m586s436m586s1432m586s436m586s436m586s1432m586s1432m586s436m586s1432" + "m586s1432m586s1432m586s1432m586s1432m586s436m586s436m586s436m586s436" + "m586s436m586s436m586s436m586s436m586s436m586s436m586s436m586s436" + "m586s436m586s436m586s436m586s436m586s436m586s436m586s436m586s436" + "m586s436m586s436m586s436m586s436m586s436m586s436m586s436m586s436" + "m586s436m586s436m586s436m586s436m586s436m586s436m586s1432m586s1432" + "m586s2886" + "m3086s8864" + "m586s1432m586s436m586s436m586s436m586s436m586s436m586s436m586s436" + "m586s436m586s1432m586s436m586s436m586s1432m586s436m586s1432m586s1432" + "m586s1432m586s1432m586s1432m586s1432m586s436m586s436m586s436m586s436" + "m586s436m586s436m586s436m586s436m586s436m586s436m586s436m586s436" + "m586s436m586s436m586s436m586s436m586s436m586s436m586s436m586s436" + "m586s436m586s436m586s436m586s436m586s436m586s436m586s436m586s436" + "m586s436m586s436m586s436m586s436m586s436m586s436m586s436m586s436" + "m586s2886" + "m3086s8864" + "m586s1432m586s436m586s436m586s436m586s436m586s436m586s436m586s436" + "m586s436m586s1432m586s436m586s436m586s436m586s436m586s436m586s436" + "m586s1432m586s1432m586s1432m586s1432m586s1432m586s1432m586s1432m586s1432" + "m586s1432m586s436m586s436m586s436m586s1432m586s1432m586s1432m586s436" + "m586s436m586s436m586s436m586s436m586s436m586s436m586s436m586s1432" + "m586s1432m586s436m586s436m586s436m586s1432m586s436m586s436m586s436" + "m586s436m586s436m586s436m586s436m586s436m586s436m586s1432m586s1432" + "m586s100000", + irsend.outputStr()); +} + +// Tests for IRSamsungAc class. + +TEST(TestIRSamsungAcClass, SetAndGetRaw) { + uint8_t expectedState[kSamsungAcStateLength] = { + 0x02, 0x92, 0x0F, 0x00, 0x00, 0x00, 0xF0, + 0x01, 0xE2, 0xFE, 0x71, 0x40, 0x11, 0xF0}; + IRSamsungAc samsung(0); + samsung.setRaw(expectedState); + EXPECT_STATE_EQ(expectedState, samsung.getRaw(), kSamsungAcBits); + uint8_t extendedState[kSamsungAcExtendedStateLength] = { + 0x02, 0x92, 0x0F, 0x00, 0x00, 0x00, 0xF0, + 0x01, 0xD2, 0x0F, 0x00, 0x00, 0x00, 0x00, + 0x01, 0xE2, 0xFE, 0x71, 0x40, 0x11, 0xF0}; + samsung.setRaw(extendedState, kSamsungAcExtendedStateLength); + // We should NOT get the extended state back. + EXPECT_STATE_EQ(expectedState, samsung.getRaw(), kSamsungAcBits); +} + +TEST(TestIRSamsungAcClass, SetAndGetPower) { + IRSamsungAc samsung(0); + samsung.on(); + EXPECT_TRUE(samsung.getPower()); + samsung.off(); + EXPECT_FALSE(samsung.getPower()); + samsung.setPower(true); + EXPECT_TRUE(samsung.getPower()); + samsung.setPower(false); + EXPECT_FALSE(samsung.getPower()); +} + +TEST(TestIRSamsungAcClass, SetAndGetSwing) { + IRSamsungAc samsung(0); + samsung.setSwing(true); + EXPECT_TRUE(samsung.getSwing()); + samsung.setSwing(false); + EXPECT_FALSE(samsung.getSwing()); + samsung.setSwing(true); + EXPECT_TRUE(samsung.getSwing()); + + // Real examples from: + // https://github.com/markszabo/IRremoteESP8266/issues/505#issuecomment-424036602 + // TODO(Hollako): Explain why state[9] lowest bit changes between on and off. + const uint8_t expected_off[kSamsungAcStateLength] = { + 0x02, 0x92, 0x0F, 0x00, 0x00, 0x00, 0xF0, + 0x01, 0xE2, 0xFE, 0x71, 0x80, 0x11, 0xF0}; + samsung.setRaw(expected_off); + EXPECT_FALSE(samsung.getSwing()); + const uint8_t expected_on[kSamsungAcStateLength] = { + 0x02, 0x92, 0x0F, 0x00, 0x00, 0x00, 0xF0, + 0x01, 0x02, 0xAF, 0x71, 0x80, 0x11, 0xF0}; + samsung.setRaw(expected_on); + EXPECT_TRUE(samsung.getSwing()); +} + +TEST(TestIRSamsungAcClass, SetAndGetClean) { + IRSamsungAc samsung(0); + samsung.setClean(true); + EXPECT_TRUE(samsung.getClean()); + samsung.setClean(false); + EXPECT_FALSE(samsung.getClean()); + samsung.setClean(true); + EXPECT_TRUE(samsung.getClean()); +} + +TEST(TestIRSamsungAcClass, SetAndGetBeep) { + IRSamsungAc samsung(0); + samsung.setBeep(false); + EXPECT_FALSE(samsung.getBeep()); + samsung.setBeep(true); + EXPECT_TRUE(samsung.getBeep()); + samsung.setBeep(false); + EXPECT_FALSE(samsung.getBeep()); + samsung.setBeep(true); + EXPECT_TRUE(samsung.getBeep()); +} + +TEST(TestIRSamsungAcClass, SetAndGetTemp) { + IRSamsungAc samsung(0); + samsung.setTemp(25); + EXPECT_EQ(25, samsung.getTemp()); + samsung.setTemp(kSamsungAcMinTemp); + EXPECT_EQ(kSamsungAcMinTemp, samsung.getTemp()); + samsung.setTemp(kSamsungAcMinTemp - 1); + EXPECT_EQ(kSamsungAcMinTemp, samsung.getTemp()); + samsung.setTemp(kSamsungAcMaxTemp); + EXPECT_EQ(kSamsungAcMaxTemp, samsung.getTemp()); + samsung.setTemp(kSamsungAcMaxTemp + 1); + EXPECT_EQ(kSamsungAcMaxTemp, samsung.getTemp()); +} + +TEST(TestIRSamsungAcClass, SetAndGetMode) { + IRSamsungAc samsung(0); + samsung.setMode(kSamsungAcCool); + EXPECT_EQ(kSamsungAcCool, samsung.getMode()); + EXPECT_NE(kSamsungAcFanAuto2, samsung.getFan()); + samsung.setMode(kSamsungAcHeat); + EXPECT_EQ(kSamsungAcHeat, samsung.getMode()); + EXPECT_NE(kSamsungAcFanAuto2, samsung.getFan()); + samsung.setMode(kSamsungAcAuto); + EXPECT_EQ(kSamsungAcAuto, samsung.getMode()); + EXPECT_EQ(kSamsungAcFanAuto2, samsung.getFan()); + samsung.setMode(kSamsungAcDry); + EXPECT_EQ(kSamsungAcDry, samsung.getMode()); + EXPECT_NE(kSamsungAcFanAuto2, samsung.getFan()); +} + +TEST(TestIRSamsungAcClass, SetAndGetFan) { + IRSamsungAc samsung(0); + samsung.setMode(kSamsungAcCool); // Most fan modes avail in this setting. + samsung.setFan(kSamsungAcFanAuto); + EXPECT_EQ(kSamsungAcFanAuto, samsung.getFan()); + samsung.setFan(kSamsungAcFanLow); + EXPECT_EQ(kSamsungAcFanLow, samsung.getFan()); + samsung.setFan(kSamsungAcFanAuto2); // Not available in Cool mode. + EXPECT_EQ(kSamsungAcFanLow, samsung.getFan()); // Shouldn't change. + samsung.setMode(kSamsungAcAuto); // Has special fan setting. + EXPECT_EQ(kSamsungAcFanAuto2, samsung.getFan()); + samsung.setFan(kSamsungAcFanLow); // Shouldn't be available in Auto mode. + EXPECT_EQ(kSamsungAcFanAuto2, samsung.getFan()); + samsung.setMode(kSamsungAcHeat); // Most fan modes avail in this setting. + samsung.setFan(kSamsungAcFanHigh); + EXPECT_EQ(kSamsungAcFanHigh, samsung.getFan()); +} + +TEST(TestIRSamsungAcClass, SetAndGetQuiet) { + IRSamsungAc samsung(0); + samsung.setQuiet(false); + EXPECT_FALSE(samsung.getQuiet()); + samsung.setFan(kSamsungAcFanHigh); + samsung.setQuiet(true); + EXPECT_TRUE(samsung.getQuiet()); + EXPECT_EQ(kSamsungAcFanAuto, samsung.getFan()); + samsung.setQuiet(false); + EXPECT_FALSE(samsung.getQuiet()); +} + +TEST(TestIRSamsungAcClass, ChecksumCalculation) { + IRSamsungAc samsung(0); + + const uint8_t originalstate[kSamsungAcStateLength] = { + 0x02, 0x92, 0x0F, 0x00, 0x00, 0x00, 0xF0, + 0x01, 0x02, 0xAF, 0x71, 0x00, 0x15, 0xF0}; + uint8_t examplestate[kSamsungAcStateLength] = { + 0x02, 0x92, 0x0F, 0x00, 0x00, 0x00, 0xF0, + 0x01, 0x02, 0xAF, 0x71, 0x00, 0x15, 0xF0}; + + const uint8_t extendedstate[kSamsungAcExtendedStateLength] = { + 0x02, 0xA9, 0x0F, 0x00, 0x00, 0x00, 0xC0, + 0x01, 0xC9, 0x0F, 0x00, 0x00, 0x00, 0x00, + 0x01, 0xF9, 0xCE, 0x71, 0xE0, 0x41, 0xC0}; + + + EXPECT_TRUE(IRSamsungAc::validChecksum(examplestate)); + EXPECT_EQ(0, IRSamsungAc::calcChecksum(examplestate)); + + examplestate[8] = 0x12; // Set an incoorect checksum. + EXPECT_FALSE(IRSamsungAc::validChecksum(examplestate)); + EXPECT_EQ(0, IRSamsungAc::calcChecksum(examplestate)); + samsung.setRaw(examplestate); + // Extracting the state from the object should have a correct checksum. + EXPECT_TRUE(IRSamsungAc::validChecksum(samsung.getRaw())); + EXPECT_STATE_EQ(originalstate, samsung.getRaw(), kSamsungAcBits); + examplestate[8] = 0x02; // Restore old checksum value. + + // Change the state to force a different checksum. + examplestate[11] = 0x01; + EXPECT_FALSE(IRSamsungAc::validChecksum(examplestate)); + EXPECT_EQ(0xF, IRSamsungAc::calcChecksum(examplestate)); + + // Check an extended state is valid. + EXPECT_TRUE(IRSamsungAc::validChecksum(extendedstate, 21)); +} + +TEST(TestIRSamsungAcClass, HumanReadable) { + IRSamsungAc samsung(0); + EXPECT_EQ( + "Power: On, Mode: 1 (COOL), Temp: 16C, Fan: 2 (LOW), Swing: On, " + "Beep: Off, Clean: Off, Quiet: Off", + samsung.toString()); + samsung.setTemp(kSamsungAcMaxTemp); + samsung.setMode(kSamsungAcHeat); + samsung.off(); + samsung.setFan(kSamsungAcFanHigh); + samsung.setSwing(false); + samsung.setBeep(true); + samsung.setClean(true); + EXPECT_EQ( + "Power: Off, Mode: 4 (HEAT), Temp: 30C, Fan: 5 (HIGH), Swing: Off, " + "Beep: On, Clean: On, Quiet: Off", + samsung.toString()); + samsung.setQuiet(true); + EXPECT_EQ( + "Power: Off, Mode: 4 (HEAT), Temp: 30C, Fan: 0 (AUTO), Swing: Off, " + "Beep: On, Clean: On, Quiet: On", + samsung.toString()); +} + +TEST(TestIRSamsungAcClass, GeneralConstruction) { + IRSamsungAc samsung(0); + + uint8_t OnCoolFAutoBOffCOffQOffT20Soff[kSamsungAcStateLength] = { + 0x02, 0x92, 0x0F, 0x00, 0x00, 0x00, 0xF0, + 0x01, 0xE2, 0xFE, 0x71, 0x40, 0x11, 0xF0}; + + samsung.setPower(true); + samsung.setMode(kSamsungAcCool); + samsung.setFan(kSamsungAcFanAuto); + samsung.setSwing(false); + samsung.setBeep(false); + samsung.setClean(false); + samsung.setQuiet(false); + samsung.setTemp(20); + EXPECT_STATE_EQ(OnCoolFAutoBOffCOffQOffT20Soff, samsung.getRaw(), + kSamsungAcBits); + /* Disabled until we understand why LSB bit of the swing byte changes. + // TODO(Hollako): Explain why sometimes the LSB of state[9] is a 1. + // e.g. 0xAE or 0XAF for swing move. + uint8_t OnHeatFAutoBOffCOffQOffT17Son[kSamsungAcStateLength] = { + 0x02, 0x92, 0x0F, 0x00, 0x00, 0x00, 0xF0, + 0x01, 0x02, 0xAF, 0x71, 0x10, 0x41, 0xF0}; + samsung.setPower(true); + samsung.setMode(kSamsungAcHeat); + samsung.setFan(kSamsungAcFanAuto); + samsung.setSwing(true); + samsung.setBeep(false); + samsung.setClean(false); + samsung.setQuiet(false); + samsung.setTemp(17); + EXPECT_STATE_EQ(OnHeatFAutoBOffCOffQOffT17Son, samsung.getRaw(), + kSamsungAcBits); + */ +} +// Tests for decodeSamsungAC(). + +// Decode normal SamsungAC messages. +TEST(TestDecodeSamsungAC, SyntheticDecode) { + IRsendTest irsend(0); + IRrecv irrecv(0); + irsend.begin(); + irsend.reset(); + uint8_t expectedState[kSamsungAcStateLength] = { + 0x02, 0x92, 0x0F, 0x00, 0x00, 0x00, 0xF0, + 0x01, 0x02, 0xAF, 0x71, 0x00, 0x15, 0xF0}; + // Synthesised Normal Samsung A/C message. + irsend.sendSamsungAC(expectedState); + irsend.makeDecodeResult(); + EXPECT_TRUE(irrecv.decode(&irsend.capture)); + EXPECT_EQ(SAMSUNG_AC, irsend.capture.decode_type); + EXPECT_EQ(kSamsungAcBits, irsend.capture.bits); + EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); +} + +// Decode a real Samsung A/C example from Issue #505 +TEST(TestDecodeSamsungAC, DecodeRealExample) { + IRsendTest irsend(4); + IRrecv irrecv(4); + irsend.begin(); + + irsend.reset(); + // Samsung A/C example from Issue #505 + uint16_t rawData[233] = { + 690, 17844, 3084, 8864, 606, 406, 586, 1410, 580, 436, 570, 424, + 570, 426, 570, 404, 596, 418, 580, 416, 584, 410, 586, 1402, + 588, 408, 586, 410, 584, 1380, 610, 408, 586, 408, 586, 1404, + 586, 1404, 586, 1408, 594, 1396, 596, 1394, 602, 418, 582, 410, + 586, 408, 584, 408, 586, 408, 586, 410, 586, 408, 586, 410, + 586, 408, 586, 408, 586, 408, 586, 408, 586, 410, 584, 436, + 558, 436, 570, 424, 570, 424, 574, 420, 578, 416, 582, 412, + 586, 410, 586, 408, 584, 410, 586, 408, 586, 410, 584, 410, + 584, 408, 586, 408, 586, 410, 586, 408, 586, 412, 584, 436, + 556, 1410, 592, 1396, 602, 1390, 608, 1384, 608, 2886, 3086, 8858, + 610, 1380, 610, 410, 586, 408, 586, 410, 586, 408, 586, 410, + 586, 408, 586, 436, 558, 436, 554, 1410, 594, 426, 572, 422, + 578, 418, 582, 412, 586, 410, 584, 410, 586, 1380, 610, 1382, + 608, 1404, 586, 1404, 586, 408, 586, 1432, 558, 436, 554, 1414, + 590, 1398, 602, 418, 580, 414, 586, 410, 584, 1382, 606, 1382, + 608, 1382, 608, 408, 586, 408, 586, 408, 586, 408, 586, 410, + 584, 436, 560, 434, 570, 426, 566, 430, 568, 1400, 600, 416, + 584, 1406, 586, 410, 584, 1384, 606, 410, 586, 410, 584, 408, + 586, 408, 586, 408, 586, 408, 588, 410, 584, 1408, 590, 1400, + 592, 1398, 602, 1388, 612}; + uint8_t expectedState[kSamsungAcStateLength] = { + 0x02, 0x92, 0x0F, 0x00, 0x00, 0x00, 0xF0, + 0x01, 0x02, 0xAF, 0x71, 0x00, 0x15, 0xF0}; + + irsend.sendRaw(rawData, 233, 38000); + irsend.makeDecodeResult(); + + ASSERT_TRUE(irrecv.decode(&irsend.capture)); + ASSERT_EQ(SAMSUNG_AC, irsend.capture.decode_type); + EXPECT_EQ(kSamsungAcBits, irsend.capture.bits); + EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); + + IRSamsungAc samsung(0); + samsung.setRaw(irsend.capture.state); + EXPECT_EQ( + "Power: On, Mode: 1 (COOL), Temp: 16C, Fan: 2 (LOW), Swing: On, " + "Beep: Off, Clean: Off, Quiet: Off", + samsung.toString()); +} + +// Decode a real Samsung A/C example from Issue #505 +TEST(TestDecodeSamsungAC, DecodeRealExample2) { + IRsendTest irsend(4); + IRrecv irrecv(4); + irsend.begin(); + + irsend.reset(); + // Samsung A/C example from Issue #505 + uint16_t rawData[233] = { + 668, 17834, 3092, 8862, 608, 410, 586, 1378, 612, 410, 584, 410, + 586, 410, 584, 410, 586, 408, 586, 408, 586, 410, 586, 1404, + 588, 436, 558, 436, 570, 1398, 592, 424, 576, 420, 578, 1388, + 608, 1382, 610, 1382, 608, 1380, 610, 1384, 606, 408, 586, 408, + 588, 408, 588, 408, 586, 436, 558, 436, 570, 424, 570, 426, + 572, 422, 578, 418, 582, 412, 586, 408, 586, 410, 584, 410, + 584, 410, 584, 410, 586, 410, 586, 408, 586, 408, 586, 408, + 586, 408, 586, 408, 586, 438, 558, 436, 568, 426, 570, 424, + 574, 422, 576, 418, 582, 414, 584, 410, 586, 410, 584, 410, + 586, 1380, 610, 1382, 608, 1404, 586, 1404, 602, 2872, 3096, 8878, + 582, 1432, 570, 426, 568, 426, 574, 420, 578, 416, 582, 412, + 586, 410, 584, 410, 586, 410, 586, 1382, 608, 410, 586, 410, + 586, 408, 586, 1404, 586, 1408, 582, 1410, 590, 428, 568, 1400, + 598, 1394, 606, 1382, 610, 1382, 608, 1378, 612, 1382, 608, 1384, + 606, 1404, 586, 408, 586, 414, 582, 436, 558, 1410, 590, 1422, + 576, 1390, 608, 410, 586, 410, 586, 410, 584, 410, 584, 410, + 586, 410, 586, 410, 584, 410, 586, 1404, 586, 1404, 588, 436, + 560, 436, 486, 510, 566, 1400, 598, 420, 576, 418, 582, 414, + 586, 410, 584, 410, 584, 410, 586, 410, 584, 1382, 608, 1384, + 606, 1384, 606, 1408, 600}; + uint8_t expectedState[kSamsungAcStateLength] = { + 0x02, 0x92, 0x0F, 0x00, 0x00, 0x00, 0xF0, + 0x01, 0xE2, 0xFE, 0x71, 0x80, 0x11, 0xF0}; + + irsend.sendRaw(rawData, 233, 38000); + irsend.makeDecodeResult(); + + ASSERT_TRUE(irrecv.decode(&irsend.capture)); + ASSERT_EQ(SAMSUNG_AC, irsend.capture.decode_type); + EXPECT_EQ(kSamsungAcBits, irsend.capture.bits); + EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); + + IRSamsungAc samsung(0); + samsung.setRaw(irsend.capture.state); + EXPECT_EQ( + "Power: On, Mode: 1 (COOL), Temp: 24C, Fan: 0 (AUTO), Swing: Off, " + "Beep: Off, Clean: Off, Quiet: Off", + samsung.toString()); +} + +// Decode a real Samsung A/C example from: +// https://github.com/markszabo/IRremoteESP8266/issues/505#issuecomment-424036602 +TEST(TestDecodeSamsungAC, DecodePowerOnSample) { + IRsendTest irsend(0); + IRrecv irrecv(0); + irsend.begin(); + + irsend.reset(); + uint16_t rawData[349] = { + 662, 17870, 3026, 8966, 540, 484, 514, 1482, 518, 482, 514, 482, + 518, 482, 516, 510, 490, 508, 490, 508, 572, 428, 576, 1398, + 542, 482, 514, 484, 514, 1460, 540, 482, 518, 482, 516, 1456, + 544, 1480, 518, 1480, 518, 1480, 518, 1484, 514, 510, 566, 432, + 576, 424, 574, 426, 540, 458, 516, 482, 516, 482, 516, 482, + 518, 480, 518, 482, 518, 482, 518, 482, 516, 482, 518, 482, + 516, 482, 518, 480, 516, 508, 492, 508, 490, 508, 572, 428, + 576, 422, 572, 428, 542, 456, 514, 484, 518, 480, 518, 480, + 518, 480, 516, 482, 516, 482, 520, 478, 518, 482, 518, 480, + 518, 1480, 518, 1480, 516, 1484, 594, 1428, 518, 2964, 3032, 8964, + 540, 1458, 542, 480, 518, 480, 520, 480, 518, 482, 520, 480, + 520, 478, 518, 480, 520, 478, 520, 1478, 522, 478, 518, 506, + 494, 1484, 594, 426, 574, 1400, 564, 1434, 540, 1454, 544, 1478, + 520, 1454, 544, 1458, 540, 480, 520, 480, 518, 480, 520, 480, + 518, 508, 490, 506, 568, 432, 572, 426, 576, 424, 544, 454, + 518, 480, 516, 482, 520, 478, 520, 478, 522, 478, 518, 480, + 520, 478, 520, 478, 520, 478, 520, 478, 520, 478, 518, 478, + 522, 506, 494, 504, 566, 432, 576, 424, 576, 424, 570, 428, + 518, 482, 518, 480, 518, 482, 520, 478, 520, 478, 520, 480, + 520, 478, 520, 478, 520, 2964, 3032, 8986, 520, 1478, 520, 506, + 492, 506, 492, 506, 568, 430, 574, 424, 546, 454, 516, 482, + 518, 482, 518, 1456, 544, 478, 546, 452, 520, 478, 544, 1432, + 542, 1478, 520, 1478, 520, 478, 520, 1482, 586, 1412, 598, 1400, + 564, 1432, 540, 1458, 544, 1454, 544, 1454, 544, 1456, 542, 480, + 518, 480, 520, 480, 520, 1462, 536, 1482, 588, 1410, 598, 424, + 572, 426, 542, 456, 518, 482, 520, 478, 520, 478, 522, 478, + 520, 478, 520, 1456, 542, 1458, 540, 478, 520, 478, 520, 478, + 520, 1482, 540, 482, 568, 430, 576, 424, 570, 428, 542, 458, + 518, 480, 520, 480, 520, 1454, 568, 1430, 566, 1432, 566, 1454, + 594}; + uint8_t expectedState[kSamsungAcExtendedStateLength] = { + 0x02, 0x92, 0x0F, 0x00, 0x00, 0x00, 0xF0, + 0x01, 0xD2, 0x0F, 0x00, 0x00, 0x00, 0x00, + 0x01, 0xE2, 0xFE, 0x71, 0x80, 0x11, 0xF0}; + + irsend.sendRaw(rawData, 349, 38000); + irsend.makeDecodeResult(); + ASSERT_TRUE(irrecv.decode(&irsend.capture)); + ASSERT_EQ(SAMSUNG_AC, irsend.capture.decode_type); + EXPECT_EQ(kSamsungAcExtendedBits, irsend.capture.bits); + EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); + + IRSamsungAc samsung(0); + samsung.setRaw(irsend.capture.state, kSamsungAcExtendedStateLength); + EXPECT_EQ( + "Power: On, Mode: 1 (COOL), Temp: 24C, Fan: 0 (AUTO), Swing: Off, " + "Beep: Off, Clean: Off, Quiet: Off", + samsung.toString()); +} + +// Decode a real Samsung A/C example from: +// https://github.com/markszabo/IRremoteESP8266/issues/505#issuecomment-424036602 +TEST(TestDecodeSamsungAC, DecodePowerOffSample) { + IRsendTest irsend(0); + IRrecv irrecv(0); + irsend.begin(); + + irsend.reset(); + uint16_t rawData[349] = { + 670, 17802, 3096, 8898, 602, 420, 580, 1418, 582, 418, 582, 416, + 582, 416, 584, 442, 550, 448, 568, 430, 570, 430, 576, 1396, + 600, 424, 546, 452, 578, 1394, 604, 1396, 600, 420, 580, 1398, + 602, 1416, 586, 1412, 582, 1420, 576, 1422, 592, 428, 574, 424, + 576, 422, 578, 420, 548, 452, 578, 420, 578, 420, 584, 416, + 580, 418, 580, 418, 582, 418, 580, 418, 582, 414, 584, 414, + 584, 416, 582, 418, 584, 442, 558, 442, 568, 430, 576, 424, + 578, 420, 576, 424, 576, 422, 580, 420, 584, 414, 584, 416, + 584, 414, 582, 418, 580, 418, 582, 416, 582, 416, 584, 414, + 584, 414, 586, 442, 554, 1420, 570, 1452, 578, 2884, 3120, 8898, + 596, 1400, 602, 422, 582, 418, 584, 414, 582, 416, 584, 414, + 584, 416, 582, 416, 584, 416, 584, 1410, 586, 414, 582, 444, + 556, 1420, 590, 432, 572, 1402, 602, 1396, 600, 1398, 606, 1414, + 582, 1394, 604, 1394, 604, 414, 584, 414, 586, 412, 586, 410, + 586, 442, 556, 440, 544, 456, 568, 430, 576, 424, 578, 420, + 578, 420, 576, 424, 584, 412, 586, 412, 586, 412, 584, 414, + 586, 412, 584, 414, 586, 412, 586, 412, 586, 414, 586, 412, + 584, 442, 558, 442, 558, 440, 566, 432, 574, 424, 578, 422, + 576, 422, 578, 420, 586, 414, 586, 414, 586, 412, 584, 414, + 586, 414, 586, 414, 586, 2902, 3096, 8900, 600, 1416, 586, 442, + 556, 442, 558, 440, 564, 434, 572, 428, 578, 420, 580, 420, + 578, 420, 584, 1392, 608, 414, 586, 414, 582, 414, 586, 412, + 586, 412, 586, 414, 584, 1394, 606, 1416, 580, 1418, 568, 1432, + 594, 1402, 602, 1398, 606, 1392, 606, 1390, 608, 1390, 608, 414, + 584, 414, 586, 414, 584, 1412, 586, 1398, 600, 1418, 590, 430, + 566, 432, 576, 422, 578, 420, 578, 422, 582, 416, 586, 414, + 586, 412, 584, 1390, 606, 1392, 608, 414, 586, 412, 584, 412, + 588, 1410, 586, 442, 558, 440, 568, 430, 566, 434, 574, 426, + 578, 420, 578, 420, 582, 416, 586, 412, 586, 1390, 608, 1390, + 608}; + + uint8_t expectedState[kSamsungAcExtendedStateLength] = { + 0x02, 0xB2, 0x0F, 0x00, 0x00, 0x00, 0xC0, + 0x01, 0xD2, 0x0F, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x02, 0xFF, 0x71, 0x80, 0x11, 0xC0}; + + irsend.sendRaw(rawData, 349, 38000); + irsend.makeDecodeResult(); + ASSERT_TRUE(irrecv.decode(&irsend.capture)); + ASSERT_EQ(SAMSUNG_AC, irsend.capture.decode_type); + EXPECT_EQ(kSamsungAcExtendedBits, irsend.capture.bits); + EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); + + IRSamsungAc samsung(0); + samsung.setRaw(irsend.capture.state, kSamsungAcExtendedStateLength); + EXPECT_EQ( + "Power: Off, Mode: 1 (COOL), Temp: 24C, Fan: 0 (AUTO), Swing: Off, " + "Beep: Off, Clean: Off, Quiet: Off", + samsung.toString()); +} + +TEST(TestDecodeSamsungAC, DecodeHeatSample) { + IRsendTest irsend(0); + IRrecv irrecv(0); + irsend.begin(); + + irsend.reset(); + uint16_t rawData[233] = { + 650, 16260, 3014, 8934, 534, 486, 508, 1478, 514, 484, 510, 486, + 508, 512, 484, 510, 562, 432, 572, 422, 540, 454, 514, 1452, + 534, 486, 510, 484, 510, 1456, 536, 484, 510, 484, 510, 1454, + 536, 1478, 512, 1476, 514, 1482, 508, 1482, 592, 428, 570, 424, + 538, 456, 508, 486, 510, 484, 512, 484, 510, 486, 510, 484, + 510, 484, 510, 486, 510, 484, 510, 484, 510, 484, 510, 484, + 510, 484, 510, 486, 508, 510, 484, 510, 568, 428, 570, 424, + 538, 458, 512, 482, 510, 486, 510, 484, 510, 484, 510, 484, + 510, 484, 510, 484, 510, 484, 510, 484, 510, 484, 510, 484, + 510, 1474, 516, 1502, 534, 1432, 594, 1398, 536, 2954, 3018, 8932, + 536, 1458, 532, 484, 510, 484, 512, 484, 510, 484, 510, 484, + 510, 484, 512, 484, 510, 484, 510, 1480, 508, 510, 530, 464, + 568, 426, 568, 426, 514, 480, 508, 486, 508, 1456, 534, 1478, + 514, 1452, 538, 1478, 512, 484, 510, 1456, 534, 486, 510, 1478, + 512, 1480, 570, 450, 570, 424, 540, 454, 512, 1452, 534, 1458, + 534, 1454, 536, 484, 512, 482, 512, 484, 512, 484, 512, 482, + 512, 1474, 514, 484, 512, 510, 486, 508, 534, 1430, 594, 426, + 512, 482, 512, 482, 510, 484, 512, 482, 512, 1452, 538, 482, + 512, 482, 512, 482, 510, 484, 510, 484, 510, 1478, 512, 1504, + 488, 1480, 560, 1454, 514}; + + uint8_t expectedState[kSamsungAcStateLength] = { + 0x02, 0x92, 0x0F, 0x00, 0x00, 0x00, 0xF0, + 0x01, 0x02, 0xAF, 0x71, 0x10, 0x41, 0xF0}; + + irsend.sendRaw(rawData, 233, 38000); + irsend.makeDecodeResult(); + ASSERT_TRUE(irrecv.decode(&irsend.capture)); + ASSERT_EQ(SAMSUNG_AC, irsend.capture.decode_type); + EXPECT_EQ(kSamsungAcBits, irsend.capture.bits); + EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); + + IRSamsungAc samsung(0); + samsung.setRaw(irsend.capture.state); + EXPECT_EQ( + "Power: On, Mode: 4 (HEAT), Temp: 17C, Fan: 0 (AUTO), Swing: On, " + "Beep: Off, Clean: Off, Quiet: Off", + samsung.toString()); +} + +TEST(TestDecodeSamsungAC, DecodeCoolSample) { + IRsendTest irsend(0); + IRrecv irrecv(0); + irsend.begin(); + + irsend.reset(); + uint16_t rawData[233] = { + 690, 17854, 3086, 8862, 610, 410, 584, 1382, 610, 410, 586, 408, + 586, 408, 586, 408, 588, 410, 584, 436, 558, 436, 570, 1396, + 598, 422, 576, 418, 580, 1384, 612, 410, 586, 410, 584, 1380, + 612, 1382, 608, 1384, 606, 1404, 586, 1404, 586, 436, 558, 438, + 566, 428, 568, 426, 570, 424, 576, 418, 578, 416, 584, 410, + 586, 408, 584, 410, 586, 408, 586, 408, 586, 410, 586, 408, + 586, 408, 588, 408, 586, 408, 588, 408, 586, 438, 558, 436, + 568, 426, 568, 428, 568, 426, 576, 418, 578, 416, 584, 412, + 584, 410, 586, 408, 586, 410, 586, 410, 584, 410, 586, 408, + 586, 1384, 606, 1402, 588, 1410, 580, 1410, 608, 2864, 3108, 8864, + 594, 1394, 604, 416, 584, 410, 586, 410, 586, 410, 586, 410, + 584, 410, 586, 410, 586, 408, 586, 1404, 588, 408, 586, 408, + 586, 436, 560, 1408, 592, 1400, 596, 1396, 600, 416, 584, 1382, + 608, 1380, 610, 1404, 586, 1384, 608, 1384, 606, 1402, 588, 1408, + 582, 1410, 564, 452, 568, 428, 572, 424, 576, 1414, 582, 1386, + 608, 1382, 608, 410, 584, 410, 584, 410, 586, 408, 586, 408, + 586, 408, 586, 408, 588, 1408, 582, 436, 540, 1426, 590, 428, + 574, 420, 578, 418, 580, 1384, 610, 410, 584, 410, 584, 410, + 584, 412, 584, 408, 586, 410, 586, 408, 586, 1404, 586, 1408, + 582, 1410, 562, 1426, 610}; + + uint8_t expectedState[kSamsungAcStateLength] = { + 0x02, 0x92, 0x0F, 0x00, 0x00, 0x00, 0xF0, + 0x01, 0xE2, 0xFE, 0x71, 0x40, 0x11, 0xF0}; + + irsend.sendRaw(rawData, 233, 38000); + irsend.makeDecodeResult(); + ASSERT_TRUE(irrecv.decode(&irsend.capture)); + ASSERT_EQ(SAMSUNG_AC, irsend.capture.decode_type); + EXPECT_EQ(kSamsungAcBits, irsend.capture.bits); + EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); + + IRSamsungAc samsung(0); + samsung.setRaw(irsend.capture.state); + EXPECT_EQ( + "Power: On, Mode: 1 (COOL), Temp: 20C, Fan: 0 (AUTO), Swing: Off, " + "Beep: Off, Clean: Off, Quiet: Off", + samsung.toString()); +} + +TEST(TestDecodeSamsungAC, Issue604DecodeExtended) { + IRsendTest irsend(0); + IRrecv irrecv(0); + irsend.begin(); + + irsend.reset(); + uint16_t sendOff[349] = { + 642, 17730, 3056, 8916, 542, 448, 552, 1440, 552, 444, 552, 444, + 552, 444, 552, 440, 556, 440, 556, 440, 556, 1436, 552, 444, + 552, 444, 552, 1440, 548, 470, 526, 1464, 470, 526, 516, 1470, + 552, 1440, 552, 1440, 550, 1436, 556, 1434, 552, 444, 552, 444, + 552, 444, 552, 442, 552, 444, 546, 470, 526, 470, 526, 470, + 470, 524, 518, 474, 548, 448, 552, 444, 552, 442, 552, 444, + 550, 444, 552, 440, 556, 440, 556, 438, 556, 440, 552, 442, + 552, 444, 552, 442, 552, 444, 550, 470, 526, 466, 524, 470, + 470, 524, 470, 524, 518, 476, 548, 444, 552, 444, 556, 440, + 552, 442, 552, 444, 550, 1436, 556, 1436, 552, 2946, 3026, 8918, + 550, 1440, 552, 444, 548, 468, 526, 468, 470, 526, 470, 526, + 542, 452, 548, 444, 552, 1440, 550, 444, 552, 444, 552, 1436, + 556, 438, 552, 442, 552, 1440, 552, 1440, 552, 1460, 526, 1464, + 470, 1516, 548, 1444, 552, 444, 552, 442, 552, 444, 552, 438, + 556, 440, 556, 440, 552, 444, 552, 444, 552, 444, 552, 444, + 552, 444, 548, 448, 546, 470, 526, 468, 526, 470, 470, 524, + 520, 470, 548, 448, 552, 444, 552, 444, 552, 444, 552, 444, + 552, 438, 556, 440, 556, 438, 552, 444, 552, 442, 552, 444, + 552, 444, 552, 444, 552, 470, 526, 466, 526, 470, 470, 524, + 518, 478, 546, 448, 552, 2920, 3052, 8916, 552, 1434, 556, 440, + 556, 438, 552, 444, 552, 442, 552, 442, 552, 442, 552, 444, + 548, 1444, 548, 470, 526, 470, 522, 1466, 470, 1520, 548, 1438, + 556, 1436, 552, 1440, 552, 442, 552, 1436, 552, 1440, 552, 1440, + 552, 442, 552, 470, 522, 1466, 526, 1466, 470, 1516, 552, 444, + 552, 442, 552, 444, 552, 1436, 556, 1436, 552, 1440, 550, 444, + 552, 444, 552, 444, 548, 448, 546, 448, 548, 470, 526, 1462, + 474, 1518, 548, 1440, 552, 1438, 556, 440, 550, 444, 552, 444, + 552, 444, 552, 440, 556, 1436, 552, 444, 552, 444, 552, 444, + 550, 470, 522, 470, 524, 470, 470, 524, 518, 1474, 548, 1440, + 556}; + + uint8_t expectedState[kSamsungAcExtendedStateLength] = { + 0x02, 0xA9, 0x0F, 0x00, 0x00, 0x00, 0xC0, + 0x01, 0xC9, 0x0F, 0x00, 0x00, 0x00, 0x00, + 0x01, 0xF9, 0xCE, 0x71, 0xE0, 0x41, 0xC0}; + + irsend.sendRaw(sendOff, 349, 38000); + irsend.makeDecodeResult(); + ASSERT_TRUE(irrecv.decode(&irsend.capture)); + ASSERT_EQ(SAMSUNG_AC, irsend.capture.decode_type); + EXPECT_EQ(kSamsungAcExtendedBits, irsend.capture.bits); + EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); + + IRSamsungAc samsung(0); + samsung.setRaw(irsend.capture.state, irsend.capture.bits / 8); + EXPECT_EQ( + "Power: Off, Mode: 4 (HEAT), Temp: 30C, Fan: 0 (AUTO), Swing: Off, " + "Beep: Off, Clean: Off, Quiet: Off", + samsung.toString()); } diff --git a/lib/IRremoteESP8266/test/ir_Sanyo_test.cpp b/lib/IRremoteESP8266/test/ir_Sanyo_test.cpp index c04dc1e..14c1c7d 100644 --- a/lib/IRremoteESP8266/test/ir_Sanyo_test.cpp +++ b/lib/IRremoteESP8266/test/ir_Sanyo_test.cpp @@ -4,7 +4,6 @@ #include "IRsend_test.h" #include "gtest/gtest.h" - // Tests for encodeSanyoLC7461(). TEST(TestEncodeSanyoLC7461, NormalEncoding) { @@ -34,7 +33,8 @@ TEST(TestEncodeSanyoLC7461, SendDataOnly) { "m560s560m560s1680m560s560m560s560m560s1680m560s1680m560s1680m560s1680" "m560s1680m560s1680m560s560m560s560m560s560m560s560m560s560m560s560" "m560s560m560s560m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680" - "m560s1680m560s1680m560s23520", irsend.outputStr()); + "m560s1680m560s1680m560s23520", + irsend.outputStr()); } // Test sending with different repeats. @@ -43,7 +43,7 @@ TEST(TestEncodeSanyoLC7461, SendWithRepeats) { irsend.begin(); irsend.reset(); - irsend.sendSanyoLC7461(0x1D8113F00FF, SANYO_LC7461_BITS, 1); // 1 repeat. + irsend.sendSanyoLC7461(0x1D8113F00FF, kSanyoLC7461Bits, 1); // 1 repeat. EXPECT_EQ( "m8960s4480" "m560s560m560s1680m560s1680m560s1680m560s560m560s1680m560s1680m560s560" @@ -52,7 +52,8 @@ TEST(TestEncodeSanyoLC7461, SendWithRepeats) { "m560s1680m560s1680m560s560m560s560m560s560m560s560m560s560m560s560" "m560s560m560s560m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680" "m560s1680m560s1680m560s23520" - "m8960s2240m560s96320", irsend.outputStr()); + "m8960s2240m560s96320", + irsend.outputStr()); } // Tests for decodeSanyoLC7461(). @@ -67,10 +68,10 @@ TEST(TestDecodeSanyoLC7461, NormalDecodeWithStrict) { irsend.reset(); irsend.sendSanyoLC7461(0x1D8113F00FF); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodeSanyoLC7461(&irsend.capture, SANYO_LC7461_BITS, - true)); + ASSERT_TRUE( + irrecv.decodeSanyoLC7461(&irsend.capture, kSanyoLC7461Bits, true)); EXPECT_EQ(SANYO_LC7461, irsend.capture.decode_type); - EXPECT_EQ(SANYO_LC7461_BITS, irsend.capture.bits); + EXPECT_EQ(kSanyoLC7461Bits, irsend.capture.bits); EXPECT_EQ(0x1D8113F00FF, irsend.capture.value); EXPECT_EQ(0xEC0, irsend.capture.address); EXPECT_EQ(0x0, irsend.capture.command); @@ -80,10 +81,10 @@ TEST(TestDecodeSanyoLC7461, NormalDecodeWithStrict) { irsend.reset(); irsend.sendSanyoLC7461(irsend.encodeSanyoLC7461(0x1234, 0x56)); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodeSanyoLC7461(&irsend.capture, SANYO_LC7461_BITS, - true)); + ASSERT_TRUE( + irrecv.decodeSanyoLC7461(&irsend.capture, kSanyoLC7461Bits, true)); EXPECT_EQ(SANYO_LC7461, irsend.capture.decode_type); - EXPECT_EQ(SANYO_LC7461_BITS, irsend.capture.bits); + EXPECT_EQ(kSanyoLC7461Bits, irsend.capture.bits); EXPECT_EQ(0x2468DCB56A9, irsend.capture.value); EXPECT_EQ(0x1234, irsend.capture.address); EXPECT_EQ(0x56, irsend.capture.command); @@ -93,10 +94,10 @@ TEST(TestDecodeSanyoLC7461, NormalDecodeWithStrict) { irsend.reset(); irsend.sendSanyoLC7461(irsend.encodeSanyoLC7461(0x1, 0x1)); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodeSanyoLC7461(&irsend.capture, SANYO_LC7461_BITS, - true)); + ASSERT_TRUE( + irrecv.decodeSanyoLC7461(&irsend.capture, kSanyoLC7461Bits, true)); EXPECT_EQ(SANYO_LC7461, irsend.capture.decode_type); - EXPECT_EQ(SANYO_LC7461_BITS, irsend.capture.bits); + EXPECT_EQ(kSanyoLC7461Bits, irsend.capture.bits); EXPECT_EQ(0x3FFE01FE, irsend.capture.value); EXPECT_EQ(0x1, irsend.capture.address); EXPECT_EQ(0x1, irsend.capture.command); @@ -111,12 +112,12 @@ TEST(TestDecodeSanyoLC7461, NormalDecodeWithRepeatAndStrict) { // Normal Sanyo LC7461 16-bit message with 1 repeat. irsend.reset(); - irsend.sendSanyoLC7461(0x3FFE01FE, SANYO_LC7461_BITS, 1); + irsend.sendSanyoLC7461(0x3FFE01FE, kSanyoLC7461Bits, 1); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodeSanyoLC7461(&irsend.capture, SANYO_LC7461_BITS, - true)); + ASSERT_TRUE( + irrecv.decodeSanyoLC7461(&irsend.capture, kSanyoLC7461Bits, true)); EXPECT_EQ(SANYO_LC7461, irsend.capture.decode_type); - EXPECT_EQ(SANYO_LC7461_BITS, irsend.capture.bits); + EXPECT_EQ(kSanyoLC7461Bits, irsend.capture.bits); EXPECT_EQ(0x3FFE01FE, irsend.capture.value); EXPECT_EQ(0x1, irsend.capture.address); EXPECT_EQ(0x1, irsend.capture.command); @@ -133,13 +134,13 @@ TEST(TestDecodeSanyoLC7461, DecodeWithNonStrictValues) { irsend.sendSanyoLC7461(0x0); // Illegal value Sanyo LC7461 message. irsend.makeDecodeResult(); // Should fail with strict on. - ASSERT_FALSE(irrecv.decodeSanyoLC7461(&irsend.capture, SANYO_LC7461_BITS, - true)); + ASSERT_FALSE( + irrecv.decodeSanyoLC7461(&irsend.capture, kSanyoLC7461Bits, true)); // Should pass if strict off. - ASSERT_TRUE(irrecv.decodeSanyoLC7461(&irsend.capture, SANYO_LC7461_BITS, - false)); + ASSERT_TRUE( + irrecv.decodeSanyoLC7461(&irsend.capture, kSanyoLC7461Bits, false)); EXPECT_EQ(SANYO_LC7461, irsend.capture.decode_type); - EXPECT_EQ(SANYO_LC7461_BITS, irsend.capture.bits); + EXPECT_EQ(kSanyoLC7461Bits, irsend.capture.bits); EXPECT_EQ(0x0, irsend.capture.value); EXPECT_EQ(0x0, irsend.capture.address); EXPECT_EQ(0x0, irsend.capture.command); @@ -148,22 +149,20 @@ TEST(TestDecodeSanyoLC7461, DecodeWithNonStrictValues) { // Illegal value Sanyo LC7461 42-bit message. irsend.sendSanyoLC7461(0x1234567890A); irsend.makeDecodeResult(); - ASSERT_FALSE(irrecv.decodeSanyoLC7461(&irsend.capture, SANYO_LC7461_BITS, - true)); + ASSERT_FALSE( + irrecv.decodeSanyoLC7461(&irsend.capture, kSanyoLC7461Bits, true)); // Should fail with strict when we ask for the wrong bit size. - ASSERT_FALSE(irrecv.decodeSanyoLC7461(&irsend.capture, 32, - true)); - ASSERT_FALSE(irrecv.decodeSanyoLC7461(&irsend.capture, 64, - true)); + ASSERT_FALSE(irrecv.decodeSanyoLC7461(&irsend.capture, 32, true)); + ASSERT_FALSE(irrecv.decodeSanyoLC7461(&irsend.capture, 64, true)); // And should fail for a bad value. - ASSERT_FALSE(irrecv.decodeSanyoLC7461(&irsend.capture, SANYO_LC7461_BITS, - true)); + ASSERT_FALSE( + irrecv.decodeSanyoLC7461(&irsend.capture, kSanyoLC7461Bits, true)); // Should pass if strict off. - ASSERT_TRUE(irrecv.decodeSanyoLC7461(&irsend.capture, SANYO_LC7461_BITS, - false)); + ASSERT_TRUE( + irrecv.decodeSanyoLC7461(&irsend.capture, kSanyoLC7461Bits, false)); EXPECT_EQ(SANYO_LC7461, irsend.capture.decode_type); - EXPECT_EQ(SANYO_LC7461_BITS, irsend.capture.bits); + EXPECT_EQ(kSanyoLC7461Bits, irsend.capture.bits); EXPECT_EQ(0x1234567890A, irsend.capture.value); EXPECT_EQ(0x91A, irsend.capture.address); EXPECT_EQ(0x89, irsend.capture.command); @@ -193,33 +192,33 @@ TEST(TestDecodeSanyoLC7461, Decode64BitMessages) { // Decode a 'real' example via GlobalCache TEST(TestDecodeSanyoLC7461, DecodeGlobalCacheExample) { -IRsendTest irsend(4); -IRrecv irrecv(4); -irsend.begin(); + IRsendTest irsend(4); + IRrecv irrecv(4); + irsend.begin(); -irsend.reset(); -uint16_t gc_test[95] = {38000, 1, 89, 342, 171, 21, 21, 21, 64, 21, 64, - 21, 64, 21, 21, 21, 64, 21, 64, 21, 21, 21, 21, - 21, 21, 21, 21, 21, 21, 21, 21, 21, 64, 21, 21, - 21, 21, 21, 21, 21, 64, 21, 21, 21, 21, 21, 64, - 21, 64, 21, 64, 21, 64, 21, 64, 21, 64, 21, 21, - 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, - 21, 21, 21, 64, 21, 64, 21, 64, 21, 64, 21, 64, - 21, 64, 21, 64, 21, 64, 21, 875, 342, 171, 21, 3565}; -irsend.sendGC(gc_test, 95); -irsend.makeDecodeResult(); + irsend.reset(); + uint16_t gc_test[95] = { + 38000, 1, 89, 342, 171, 21, 21, 21, 64, 21, 64, 21, 64, 21, 21, 21, + 64, 21, 64, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 64, 21, 21, 21, 21, 21, 21, 21, 64, 21, 21, 21, 21, 21, 64, 21, + 64, 21, 64, 21, 64, 21, 64, 21, 64, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 64, 21, 64, 21, 64, 21, + 64, 21, 64, 21, 64, 21, 64, 21, 64, 21, 875, 342, 171, 21, 3565}; + irsend.sendGC(gc_test, 95); + irsend.makeDecodeResult(); -ASSERT_TRUE(irrecv.decodeSanyoLC7461(&irsend.capture, SANYO_LC7461_BITS, true)); -EXPECT_EQ(SANYO_LC7461, irsend.capture.decode_type); -EXPECT_EQ(SANYO_LC7461_BITS, irsend.capture.bits); -EXPECT_EQ(0x1D8113F00FF, irsend.capture.value); -EXPECT_EQ(0xEC0, irsend.capture.address); -EXPECT_EQ(0x0, irsend.capture.command); -EXPECT_FALSE(irsend.capture.repeat); + ASSERT_TRUE( + irrecv.decodeSanyoLC7461(&irsend.capture, kSanyoLC7461Bits, true)); + EXPECT_EQ(SANYO_LC7461, irsend.capture.decode_type); + EXPECT_EQ(kSanyoLC7461Bits, irsend.capture.bits); + EXPECT_EQ(0x1D8113F00FF, irsend.capture.value); + EXPECT_EQ(0xEC0, irsend.capture.address); + EXPECT_EQ(0x0, irsend.capture.command); + EXPECT_FALSE(irsend.capture.repeat); -// Confirm what the 42-bit NEC decode is. -ASSERT_TRUE(irrecv.decodeNEC(&irsend.capture, 42, false)); -EXPECT_EQ(0x1D8113F00FF, irsend.capture.value); + // Confirm what the 42-bit NEC decode is. + ASSERT_TRUE(irrecv.decodeNEC(&irsend.capture, 42, false)); + EXPECT_EQ(0x1D8113F00FF, irsend.capture.value); } // Fail to decode a non-Sanyo LC7461 example via GlobalCache @@ -230,13 +229,14 @@ TEST(TestDecodeSanyoLC7461, FailToDecodeNonSanyoLC7461Example) { irsend.reset(); // Modified a few entries to unexpected values, based on previous test case. - uint16_t gc_test[39] = {38000, 1, 1, 322, 162, 20, 61, 20, 61, 20, 20, 20, 20, - 20, 20, 20, 127, 20, 61, 9, 20, 20, 61, 20, 20, 20, - 61, 20, 61, 20, 61, 20, 20, 20, 20, 20, 20, 20, 884}; + uint16_t gc_test[39] = {38000, 1, 1, 322, 162, 20, 61, 20, 61, 20, + 20, 20, 20, 20, 20, 20, 127, 20, 61, 9, + 20, 20, 61, 20, 20, 20, 61, 20, 61, 20, + 61, 20, 20, 20, 20, 20, 20, 20, 884}; irsend.sendGC(gc_test, 39); irsend.makeDecodeResult(); ASSERT_FALSE(irrecv.decodeSanyoLC7461(&irsend.capture)); - ASSERT_FALSE(irrecv.decodeSanyoLC7461(&irsend.capture, SANYO_LC7461_BITS, - false)); + ASSERT_FALSE( + irrecv.decodeSanyoLC7461(&irsend.capture, kSanyoLC7461Bits, false)); } diff --git a/lib/IRremoteESP8266/test/ir_Sharp_test.cpp b/lib/IRremoteESP8266/test/ir_Sharp_test.cpp index 0329b4e..8481a46 100644 --- a/lib/IRremoteESP8266/test/ir_Sharp_test.cpp +++ b/lib/IRremoteESP8266/test/ir_Sharp_test.cpp @@ -37,7 +37,6 @@ TEST(TestEncodeSharp, AdvancedEncoding) { EXPECT_EQ(0x454A, irsend.encodeSharp(0x11, 0x52, 1, 0, true)); } - // Tests for sendSharp(). // Test sending typical data only. @@ -53,7 +52,8 @@ TEST(TestSendSharp, SendDataOnly) { "m260s43602" "m260s1820m260s780m260s780m260s780m260s1820m260s1820m260s780m260s1820" "m260s780m260s1820m260s1820m260s780m260s1820m260s780m260s1820" - "m260s43602", irsend.outputStr()); + "m260s43602", + irsend.outputStr()); } // Test sending with different repeats. @@ -62,7 +62,7 @@ TEST(TestSendSharp, SendWithRepeats) { irsend.begin(); irsend.reset(); - irsend.sendSharp(0x11, 0x52, SHARP_BITS, 1); // 1 repeat. + irsend.sendSharp(0x11, 0x52, kSharpBits, 1); // 1 repeat. EXPECT_EQ( "m260s1820m260s780m260s780m260s780m260s1820m260s780m260s1820m260s780" "m260s1820m260s780m260s780m260s1820m260s780m260s1820m260s780" @@ -75,7 +75,8 @@ TEST(TestSendSharp, SendWithRepeats) { "m260s43602" "m260s1820m260s780m260s780m260s780m260s1820m260s1820m260s780m260s1820" "m260s780m260s1820m260s1820m260s780m260s1820m260s780m260s1820" - "m260s43602", irsend.outputStr()); + "m260s43602", + irsend.outputStr()); } // Test sending an atypical data size. @@ -89,7 +90,8 @@ TEST(TestSendSharp, SendUnusualSize) { "m260s780m260s780m260s780m260s780m260s780m260s780m260s1820m260s780" "m260s43602" "m260s1820m260s1820m260s1820m260s1820m260s1820m260s1820m260s780m260s1820" - "m260s43602", irsend.outputStr()); + "m260s43602", + irsend.outputStr()); irsend.reset(); irsend.sendSharp(0x0, 0x0, 16); @@ -99,7 +101,8 @@ TEST(TestSendSharp, SendUnusualSize) { "m260s43602" "m260s780m260s780m260s780m260s780m260s780m260s780m260s1820m260s1820" "m260s1820m260s1820m260s1820m260s1820m260s1820m260s1820m260s780m260s1820" - "m260s43602", irsend.outputStr()); + "m260s43602", + irsend.outputStr()); } // Tests for sendSharpRaw(). @@ -117,7 +120,8 @@ TEST(TestSendSharpRaw, SendDataOnly) { "m260s43602" "m260s1820m260s780m260s780m260s780m260s1820m260s1820m260s780m260s1820" "m260s780m260s1820m260s1820m260s780m260s1820m260s780m260s1820" - "m260s43602", irsend.outputStr()); + "m260s43602", + irsend.outputStr()); } // Test sending with different repeats. @@ -126,7 +130,7 @@ TEST(TestSendSharpRaw, SendWithRepeats) { irsend.begin(); irsend.reset(); - irsend.sendSharpRaw(0x454A, SHARP_BITS, 1); // 1 repeat. + irsend.sendSharpRaw(0x454A, kSharpBits, 1); // 1 repeat. EXPECT_EQ( "m260s1820m260s780m260s780m260s780m260s1820m260s780m260s1820m260s780" "m260s1820m260s780m260s780m260s1820m260s780m260s1820m260s780" @@ -139,7 +143,8 @@ TEST(TestSendSharpRaw, SendWithRepeats) { "m260s43602" "m260s1820m260s780m260s780m260s780m260s1820m260s1820m260s780m260s1820" "m260s780m260s1820m260s1820m260s780m260s1820m260s780m260s1820" - "m260s43602", irsend.outputStr()); + "m260s43602", + irsend.outputStr()); } // Test sending an atypical data size. @@ -153,7 +158,8 @@ TEST(TestSendSharpRaw, SendUnusualSize) { "m260s780m260s780m260s780m260s780m260s780m260s780m260s1820m260s780" "m260s43602" "m260s1820m260s1820m260s1820m260s1820m260s1820m260s1820m260s780m260s1820" - "m260s43602", irsend.outputStr()); + "m260s43602", + irsend.outputStr()); irsend.reset(); irsend.sendSharpRaw(0x2, 16); @@ -163,7 +169,8 @@ TEST(TestSendSharpRaw, SendUnusualSize) { "m260s43602" "m260s780m260s780m260s780m260s780m260s780m260s780m260s1820m260s1820" "m260s1820m260s1820m260s1820m260s1820m260s1820m260s1820m260s780m260s1820" - "m260s43602", irsend.outputStr()); + "m260s43602", + irsend.outputStr()); } // Tests for decodeSharp(). @@ -178,9 +185,9 @@ TEST(TestDecodeSharp, NormalDecodeWithStrict) { irsend.reset(); irsend.sendSharpRaw(0x454A); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodeSharp(&irsend.capture, SHARP_BITS, true)); + ASSERT_TRUE(irrecv.decodeSharp(&irsend.capture, kSharpBits, true)); EXPECT_EQ(SHARP, irsend.capture.decode_type); - EXPECT_EQ(SHARP_BITS, irsend.capture.bits); + EXPECT_EQ(kSharpBits, irsend.capture.bits); EXPECT_EQ(0x454A, irsend.capture.value); EXPECT_EQ(0x11, irsend.capture.address); EXPECT_EQ(0x4A, irsend.capture.command); @@ -190,9 +197,9 @@ TEST(TestDecodeSharp, NormalDecodeWithStrict) { irsend.reset(); irsend.sendSharpRaw(irsend.encodeSharp(0x07, 0x99)); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodeSharp(&irsend.capture, SHARP_BITS, true)); + ASSERT_TRUE(irrecv.decodeSharp(&irsend.capture, kSharpBits, true)); EXPECT_EQ(SHARP, irsend.capture.decode_type); - EXPECT_EQ(SHARP_BITS, irsend.capture.bits); + EXPECT_EQ(kSharpBits, irsend.capture.bits); EXPECT_EQ(0x7266, irsend.capture.value); EXPECT_EQ(0x07, irsend.capture.address); EXPECT_EQ(0x99, irsend.capture.command); @@ -202,9 +209,9 @@ TEST(TestDecodeSharp, NormalDecodeWithStrict) { irsend.reset(); irsend.sendSharpRaw(irsend.encodeSharp(0x1, 0x1)); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodeSharp(&irsend.capture, SHARP_BITS, true)); + ASSERT_TRUE(irrecv.decodeSharp(&irsend.capture, kSharpBits, true)); EXPECT_EQ(SHARP, irsend.capture.decode_type); - EXPECT_EQ(SHARP_BITS, irsend.capture.bits); + EXPECT_EQ(kSharpBits, irsend.capture.bits); EXPECT_EQ(0x4202, irsend.capture.value); EXPECT_EQ(0x1, irsend.capture.address); EXPECT_EQ(0x1, irsend.capture.command); @@ -219,19 +226,19 @@ TEST(TestDecodeSharp, NormalDecodeWithRepeatAndStrict) { // Normal Sharp 15-bit message with 1 repeat. irsend.reset(); - irsend.sendSharpRaw(0x7266, SHARP_BITS, 1); + irsend.sendSharpRaw(0x7266, kSharpBits, 1); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodeSharp(&irsend.capture, SHARP_BITS, true)); + ASSERT_TRUE(irrecv.decodeSharp(&irsend.capture, kSharpBits, true)); EXPECT_EQ(SHARP, irsend.capture.decode_type); - EXPECT_EQ(SHARP_BITS, irsend.capture.bits); + EXPECT_EQ(kSharpBits, irsend.capture.bits); EXPECT_EQ(0x7266, irsend.capture.value); EXPECT_EQ(0x07, irsend.capture.address); EXPECT_EQ(0x99, irsend.capture.command); - irsend.makeDecodeResult(2 * (2 * SHARP_BITS + FOOTER)); - ASSERT_TRUE(irrecv.decodeSharp(&irsend.capture, SHARP_BITS, true)); + irsend.makeDecodeResult(2 * (2 * kSharpBits + kFooter)); + ASSERT_TRUE(irrecv.decodeSharp(&irsend.capture, kSharpBits, true)); EXPECT_EQ(SHARP, irsend.capture.decode_type); - EXPECT_EQ(SHARP_BITS, irsend.capture.bits); + EXPECT_EQ(kSharpBits, irsend.capture.bits); EXPECT_EQ(0x7266, irsend.capture.value); } @@ -245,7 +252,7 @@ TEST(TestDecodeSharp, DecodeWithNonStrict) { irsend.sendSharpRaw(0x0, 8); // Illegal length Sharp 8-bit message. irsend.makeDecodeResult(); // Should fail with strict on. - ASSERT_FALSE(irrecv.decodeSharp(&irsend.capture, SHARP_BITS, true)); + ASSERT_FALSE(irrecv.decodeSharp(&irsend.capture, kSharpBits, true)); // Should pass if strict off. ASSERT_TRUE(irrecv.decodeSharp(&irsend.capture, 8, false)); EXPECT_EQ(SHARP, irsend.capture.decode_type); @@ -258,7 +265,7 @@ TEST(TestDecodeSharp, DecodeWithNonStrict) { irsend.sendSharpRaw(0x12345678, 32); // Illegal length Sharp 32-bit message. irsend.makeDecodeResult(); // Should fail with strict on. - ASSERT_FALSE(irrecv.decodeSharp(&irsend.capture, SHARP_BITS, true)); + ASSERT_FALSE(irrecv.decodeSharp(&irsend.capture, kSharpBits, true)); // Should fail with strict when we ask for the wrong bit size. ASSERT_FALSE(irrecv.decodeSharp(&irsend.capture, 32, true)); @@ -298,21 +305,17 @@ TEST(TestDecodeSharp, DecodeGlobalCacheExample) { irsend.reset(); // Sharp Power On from Global Cache. - uint16_t gc_test[67] = {38000, 1, 1, - 10, 70, 10, 30, 10, 30, 10, 30, 10, 70, 10, 30, - 10, 70, 10, 30, 10, 70, 10, 30, 10, 30, 10, 70, - 10, 30, 10, 70, 10, 30, - 10, 1657, - 10, 70, 10, 30, 10, 30, 10, 30, 10, 70, 10, 70, - 10, 30, 10, 70, 10, 30, 10, 70, 10, 70, 10, 30, - 10, 70, 10, 30, 10, 70, - 10, 1657}; + uint16_t gc_test[67] = { + 38000, 1, 1, 10, 70, 10, 30, 10, 30, 10, 30, 10, 70, 10, 30, 10, 70, + 10, 30, 10, 70, 10, 30, 10, 30, 10, 70, 10, 30, 10, 70, 10, 30, 10, + 1657, 10, 70, 10, 30, 10, 30, 10, 30, 10, 70, 10, 70, 10, 30, 10, 70, + 10, 30, 10, 70, 10, 70, 10, 30, 10, 70, 10, 30, 10, 70, 10, 1657}; irsend.sendGC(gc_test, 67); irsend.makeDecodeResult(); ASSERT_TRUE(irrecv.decodeSharp(&irsend.capture)); EXPECT_EQ(SHARP, irsend.capture.decode_type); - EXPECT_EQ(SHARP_BITS, irsend.capture.bits); + EXPECT_EQ(kSharpBits, irsend.capture.bits); EXPECT_EQ(0x454A, irsend.capture.value); EXPECT_EQ(0x11, irsend.capture.address); EXPECT_EQ(0x4A, irsend.capture.command); @@ -327,31 +330,25 @@ TEST(TestDecodeSharp, FailToDecodeNonSharpExample) { irsend.reset(); // Modified a few entries to unexpected values, based on previous test case. - uint16_t gc_test[67] = {38000, 1, 1, - 10, 70, 30, 30, 10, 30, 10, 30, 10, 70, 10, 30, - 10, 70, 10, 30, 10, 70, 10, 30, 10, 30, 10, 70, - 10, 30, 10, 70, 10, 30, - 10, 1657, - 10, 70, 10, 30, 10, 30, 10, 30, 10, 70, 10, 70, - 10, 30, 10, 60, 10, 30, 10, 70, 10, 70, 10, 30, - 10, 10, 70, 30, 10, 70, - 10, 1657}; + uint16_t gc_test[67] = { + 38000, 1, 1, 10, 70, 30, 30, 10, 30, 10, 30, 10, 70, 10, 30, 10, 70, + 10, 30, 10, 70, 10, 30, 10, 30, 10, 70, 10, 30, 10, 70, 10, 30, 10, + 1657, 10, 70, 10, 30, 10, 30, 10, 30, 10, 70, 10, 70, 10, 30, 10, 60, + 10, 30, 10, 70, 10, 70, 10, 30, 10, 10, 70, 30, 10, 70, 10, 1657}; irsend.sendGC(gc_test, 67); irsend.makeDecodeResult(); ASSERT_FALSE(irrecv.decodeSharp(&irsend.capture)); - ASSERT_FALSE(irrecv.decodeSharp(&irsend.capture, SHARP_BITS, false)); + ASSERT_FALSE(irrecv.decodeSharp(&irsend.capture, kSharpBits, false)); // Test only half of a good message, as it is sent (sort of) twice. - uint16_t gc_half[35] = {38000, 1, 1, - 10, 70, 10, 30, 10, 30, 10, 30, 10, 70, 10, 30, - 10, 70, 10, 30, 10, 70, 10, 30, 10, 30, 10, 70, - 10, 30, 10, 70, 10, 30, - 10, 1657}; + uint16_t gc_half[35] = {38000, 1, 1, 10, 70, 10, 30, 10, 30, 10, 30, 10, + 70, 10, 30, 10, 70, 10, 30, 10, 70, 10, 30, 10, + 30, 10, 70, 10, 30, 10, 70, 10, 30, 10, 1657}; irsend.sendGC(gc_half, 35); irsend.makeDecodeResult(); ASSERT_FALSE(irrecv.decodeSharp(&irsend.capture)); - ASSERT_FALSE(irrecv.decodeSharp(&irsend.capture, SHARP_BITS, false)); + ASSERT_FALSE(irrecv.decodeSharp(&irsend.capture, kSharpBits, false)); } diff --git a/lib/IRremoteESP8266/test/ir_Sherwood_test.cpp b/lib/IRremoteESP8266/test/ir_Sherwood_test.cpp index a1c622a..22d9ead 100644 --- a/lib/IRremoteESP8266/test/ir_Sherwood_test.cpp +++ b/lib/IRremoteESP8266/test/ir_Sherwood_test.cpp @@ -13,12 +13,14 @@ TEST(TestSendSherwood, SendDataOnly) { irsend.reset(); irsend.sendSherwood(0xC1A28877); - EXPECT_EQ("m8960s4480m560s1680m560s1680m560s560m560s560m560s560m560s560" - "m560s560m560s1680m560s1680m560s560m560s1680m560s560m560s560" - "m560s560m560s1680m560s560m560s1680m560s560m560s560m560s560" - "m560s1680m560s560m560s560m560s560m560s560m560s1680m560s1680" - "m560s1680m560s560m560s1680m560s1680m560s1680m560s42560" - "m8960s2240m560s96320", irsend.outputStr()); + EXPECT_EQ( + "m8960s4480m560s1680m560s1680m560s560m560s560m560s560m560s560" + "m560s560m560s1680m560s1680m560s560m560s1680m560s560m560s560" + "m560s560m560s1680m560s560m560s1680m560s560m560s560m560s560" + "m560s1680m560s560m560s560m560s560m560s560m560s1680m560s1680" + "m560s1680m560s560m560s1680m560s1680m560s1680m560s42560" + "m8960s2240m560s96320", + irsend.outputStr()); } // Test sending typical data with extra repeats. @@ -28,13 +30,15 @@ TEST(TestSendSherwood, SendDataWithRepeats) { irsend.reset(); irsend.sendSherwood(0xC1A28877, 32, 2); - EXPECT_EQ("m8960s4480m560s1680m560s1680m560s560m560s560m560s560m560s560" - "m560s560m560s1680m560s1680m560s560m560s1680m560s560m560s560" - "m560s560m560s1680m560s560m560s1680m560s560m560s560m560s560" - "m560s1680m560s560m560s560m560s560m560s560m560s1680m560s1680" - "m560s1680m560s560m560s1680m560s1680m560s1680m560s42560" - "m8960s2240m560s96320" - "m8960s2240m560s96320", irsend.outputStr()); + EXPECT_EQ( + "m8960s4480m560s1680m560s1680m560s560m560s560m560s560m560s560" + "m560s560m560s1680m560s1680m560s560m560s1680m560s560m560s560" + "m560s560m560s1680m560s560m560s1680m560s560m560s560m560s560" + "m560s1680m560s560m560s560m560s560m560s560m560s1680m560s1680" + "m560s1680m560s560m560s1680m560s1680m560s1680m560s42560" + "m8960s2240m560s96320" + "m8960s2240m560s96320", + irsend.outputStr()); } // Test sending typical data with explicit no repeats. @@ -45,12 +49,14 @@ TEST(TestSendSherwood, SendDataWithZeroRepeats) { irsend.reset(); irsend.sendSherwood(0xC1A28877, 32, 0); // Should have a single NEC repeat, as we always send one. - EXPECT_EQ("m8960s4480m560s1680m560s1680m560s560m560s560m560s560m560s560" - "m560s560m560s1680m560s1680m560s560m560s1680m560s560m560s560" - "m560s560m560s1680m560s560m560s1680m560s560m560s560m560s560" - "m560s1680m560s560m560s560m560s560m560s560m560s1680m560s1680" - "m560s1680m560s560m560s1680m560s1680m560s1680m560s42560" - "m8960s2240m560s96320", irsend.outputStr()); + EXPECT_EQ( + "m8960s4480m560s1680m560s1680m560s560m560s560m560s560m560s560" + "m560s560m560s1680m560s1680m560s560m560s1680m560s560m560s560" + "m560s560m560s1680m560s560m560s1680m560s560m560s560m560s560" + "m560s1680m560s560m560s560m560s560m560s560m560s1680m560s1680" + "m560s1680m560s560m560s1680m560s1680m560s1680m560s42560" + "m8960s2240m560s96320", + irsend.outputStr()); } // Test that a typical Sherwood send decodes as the appropriate NEC value. @@ -65,7 +71,7 @@ TEST(TestSendSherwood, DecodesAsNEC) { EXPECT_TRUE(irrecv.decodeNEC(&irsend.capture)); EXPECT_EQ(NEC, irsend.capture.decode_type); - EXPECT_EQ(NEC_BITS, irsend.capture.bits); + EXPECT_EQ(kNECBits, irsend.capture.bits); EXPECT_EQ(0xC1A28877, irsend.capture.value); EXPECT_EQ(0x4583, irsend.capture.address); EXPECT_EQ(0x11, irsend.capture.command); diff --git a/lib/IRremoteESP8266/test/ir_Sony_test.cpp b/lib/IRremoteESP8266/test/ir_Sony_test.cpp index 4025eec..c79ff61 100644 --- a/lib/IRremoteESP8266/test/ir_Sony_test.cpp +++ b/lib/IRremoteESP8266/test/ir_Sony_test.cpp @@ -14,52 +14,59 @@ TEST(TestSendSony, SendDataOnly) { irsend.reset(); irsend.sendSony(0); // We expect three 20-bit commands to be sent. - EXPECT_EQ("m2400s600m600s600m600s600m600s600m600s600m600s600m600s600m600s600" - "m600s600m600s600m600s600m600s600m600s600m600s600m600s600m600s600" - "m600s600m600s600m600s600m600s600m600s18600" - "m2400s600m600s600m600s600m600s600m600s600m600s600m600s600m600s600" - "m600s600m600s600m600s600m600s600m600s600m600s600m600s600m600s600" - "m600s600m600s600m600s600m600s600m600s18600" - "m2400s600m600s600m600s600m600s600m600s600m600s600m600s600m600s600" - "m600s600m600s600m600s600m600s600m600s600m600s600m600s600m600s600" - "m600s600m600s600m600s600m600s600m600s18600", irsend.outputStr()); + EXPECT_EQ( + "m2400s600m600s600m600s600m600s600m600s600m600s600m600s600m600s600" + "m600s600m600s600m600s600m600s600m600s600m600s600m600s600m600s600" + "m600s600m600s600m600s600m600s600m600s18600" + "m2400s600m600s600m600s600m600s600m600s600m600s600m600s600m600s600" + "m600s600m600s600m600s600m600s600m600s600m600s600m600s600m600s600" + "m600s600m600s600m600s600m600s600m600s18600" + "m2400s600m600s600m600s600m600s600m600s600m600s600m600s600m600s600" + "m600s600m600s600m600s600m600s600m600s600m600s600m600s600m600s600" + "m600s600m600s600m600s600m600s600m600s18600", + irsend.outputStr()); irsend.reset(); - irsend.sendSony(0x240C, SONY_20_BITS); + irsend.sendSony(0x240C, kSony20Bits); // We expect three 20-bit commands to be sent. - EXPECT_EQ("m2400s600m600s600m600s600m600s600m600s600m600s600m600s600m1200s600" - "m600s600m600s600m1200s600m600s600m600s600m600s600m600s600m600s600" - "m600s600m1200s600m1200s600m600s600m600s16200" - "m2400s600m600s600m600s600m600s600m600s600m600s600m600s600m1200s600" - "m600s600m600s600m1200s600m600s600m600s600m600s600m600s600m600s600" - "m600s600m1200s600m1200s600m600s600m600s16200" - "m2400s600m600s600m600s600m600s600m600s600m600s600m600s600m1200s600" - "m600s600m600s600m1200s600m600s600m600s600m600s600m600s600m600s600" - "m600s600m1200s600m1200s600m600s600m600s16200", irsend.outputStr()); + EXPECT_EQ( + "m2400s600m600s600m600s600m600s600m600s600m600s600m600s600m1200s600" + "m600s600m600s600m1200s600m600s600m600s600m600s600m600s600m600s600" + "m600s600m1200s600m1200s600m600s600m600s16200" + "m2400s600m600s600m600s600m600s600m600s600m600s600m600s600m1200s600" + "m600s600m600s600m1200s600m600s600m600s600m600s600m600s600m600s600" + "m600s600m1200s600m1200s600m600s600m600s16200" + "m2400s600m600s600m600s600m600s600m600s600m600s600m600s600m1200s600" + "m600s600m600s600m1200s600m600s600m600s600m600s600m600s600m600s600" + "m600s600m1200s600m1200s600m600s600m600s16200", + irsend.outputStr()); irsend.reset(); - irsend.sendSony(0x240C, SONY_15_BITS); + irsend.sendSony(0x240C, kSony15Bits); // We expect three 15-bit commands to be sent. - EXPECT_EQ("m2400s600m600s600m1200s600m600s600m600s600m1200s600m600s600" - "m600s600m600s600m600s600m600s600m600s600m1200s600m1200s600m600s600" - "m600s22200" - "m2400s600m600s600m1200s600m600s600m600s600m1200s600m600s600" - "m600s600m600s600m600s600m600s600m600s600m1200s600m1200s600m600s600" - "m600s22200" - "m2400s600m600s600m1200s600m600s600m600s600m1200s600m600s600" - "m600s600m600s600m600s600m600s600m600s600m1200s600m1200s600m600s600" - "m600s22200", irsend.outputStr()); + EXPECT_EQ( + "m2400s600m600s600m1200s600m600s600m600s600m1200s600m600s600" + "m600s600m600s600m600s600m600s600m600s600m1200s600m1200s600m600s600" + "m600s22200" + "m2400s600m600s600m1200s600m600s600m600s600m1200s600m600s600" + "m600s600m600s600m600s600m600s600m600s600m1200s600m1200s600m600s600" + "m600s22200" + "m2400s600m600s600m1200s600m600s600m600s600m1200s600m600s600" + "m600s600m600s600m600s600m600s600m600s600m1200s600m1200s600m600s600" + "m600s22200", + irsend.outputStr()); irsend.reset(); - irsend.sendSony(0xA90, SONY_12_BITS); + irsend.sendSony(0xA90, kSony12Bits); // We expect three 15-bit commands to be sent. - EXPECT_EQ("m2400s600m1200s600m600s600m1200s600m600s600m1200s600m600s600" - "m600s600m1200s600m600s600m600s600m600s600m600s25800" - "m2400s600m1200s600m600s600m1200s600m600s600m1200s600m600s600" - "m600s600m1200s600m600s600m600s600m600s600m600s25800" - "m2400s600m1200s600m600s600m1200s600m600s600m1200s600m600s600" - "m600s600m1200s600m600s600m600s600m600s600m600s25800", - irsend.outputStr()); + EXPECT_EQ( + "m2400s600m1200s600m600s600m1200s600m600s600m1200s600m600s600" + "m600s600m1200s600m600s600m600s600m600s600m600s25800" + "m2400s600m1200s600m600s600m1200s600m600s600m1200s600m600s600" + "m600s600m1200s600m600s600m600s600m600s600m600s25800" + "m2400s600m1200s600m600s600m1200s600m600s600m1200s600m600s600" + "m600s600m1200s600m600s600m600s600m600s600m600s25800", + irsend.outputStr()); } // Test sending with different repeats. @@ -68,57 +75,63 @@ TEST(TestSendSony, SendWithDiffRepeats) { irsend.begin(); irsend.reset(); - irsend.sendSony(0x240C, SONY_20_BITS, 0); // Send a command with 0 repeats. - EXPECT_EQ("m2400s600m600s600m600s600m600s600m600s600m600s600m600s600m1200s600" - "m600s600m600s600m1200s600m600s600m600s600m600s600m600s600m600s600" - "m600s600m1200s600m1200s600m600s600m600s16200", irsend.outputStr()); - irsend.sendSony(0x240C, SONY_20_BITS, 1); // Send a command with 1 repeat. - EXPECT_EQ("m2400s600m600s600m600s600m600s600m600s600m600s600m600s600m1200s600" - "m600s600m600s600m1200s600m600s600m600s600m600s600m600s600m600s600" - "m600s600m1200s600m1200s600m600s600m600s16200" - "m2400s600m600s600m600s600m600s600m600s600m600s600m600s600m1200s600" - "m600s600m600s600m1200s600m600s600m600s600m600s600m600s600m600s600" - "m600s600m1200s600m1200s600m600s600m600s16200", irsend.outputStr()); - irsend.sendSony(0x240C, SONY_20_BITS, 3); // Send a command with 3 repeats. - EXPECT_EQ("m2400s600m600s600m600s600m600s600m600s600m600s600m600s600m1200s600" - "m600s600m600s600m1200s600m600s600m600s600m600s600m600s600m600s600" - "m600s600m1200s600m1200s600m600s600m600s16200" - "m2400s600m600s600m600s600m600s600m600s600m600s600m600s600m1200s600" - "m600s600m600s600m1200s600m600s600m600s600m600s600m600s600m600s600" - "m600s600m1200s600m1200s600m600s600m600s16200" - "m2400s600m600s600m600s600m600s600m600s600m600s600m600s600m1200s600" - "m600s600m600s600m1200s600m600s600m600s600m600s600m600s600m600s600" - "m600s600m1200s600m1200s600m600s600m600s16200" - "m2400s600m600s600m600s600m600s600m600s600m600s600m600s600m1200s600" - "m600s600m600s600m1200s600m600s600m600s600m600s600m600s600m600s600" - "m600s600m1200s600m1200s600m600s600m600s16200", irsend.outputStr()); + irsend.sendSony(0x240C, kSony20Bits, 0); // Send a command with 0 repeats. + EXPECT_EQ( + "m2400s600m600s600m600s600m600s600m600s600m600s600m600s600m1200s600" + "m600s600m600s600m1200s600m600s600m600s600m600s600m600s600m600s600" + "m600s600m1200s600m1200s600m600s600m600s16200", + irsend.outputStr()); + irsend.sendSony(0x240C, kSony20Bits, 1); // Send a command with 1 repeat. + EXPECT_EQ( + "m2400s600m600s600m600s600m600s600m600s600m600s600m600s600m1200s600" + "m600s600m600s600m1200s600m600s600m600s600m600s600m600s600m600s600" + "m600s600m1200s600m1200s600m600s600m600s16200" + "m2400s600m600s600m600s600m600s600m600s600m600s600m600s600m1200s600" + "m600s600m600s600m1200s600m600s600m600s600m600s600m600s600m600s600" + "m600s600m1200s600m1200s600m600s600m600s16200", + irsend.outputStr()); + irsend.sendSony(0x240C, kSony20Bits, 3); // Send a command with 3 repeats. + EXPECT_EQ( + "m2400s600m600s600m600s600m600s600m600s600m600s600m600s600m1200s600" + "m600s600m600s600m1200s600m600s600m600s600m600s600m600s600m600s600" + "m600s600m1200s600m1200s600m600s600m600s16200" + "m2400s600m600s600m600s600m600s600m600s600m600s600m600s600m1200s600" + "m600s600m600s600m1200s600m600s600m600s600m600s600m600s600m600s600" + "m600s600m1200s600m1200s600m600s600m600s16200" + "m2400s600m600s600m600s600m600s600m600s600m600s600m600s600m1200s600" + "m600s600m600s600m1200s600m600s600m600s600m600s600m600s600m600s600" + "m600s600m1200s600m1200s600m600s600m600s16200" + "m2400s600m600s600m600s600m600s600m600s600m600s600m600s600m1200s600" + "m600s600m600s600m1200s600m600s600m600s600m600s600m600s600m600s600" + "m600s600m1200s600m1200s600m600s600m600s16200", + irsend.outputStr()); } // Tests for encodeSony(). TEST(TestEncodeSony, NormalSonyEncoding) { IRsendTest irsend(4); - EXPECT_EQ(0x0, irsend.encodeSony(SONY_12_BITS, 0, 0)); - EXPECT_EQ(0xA90, irsend.encodeSony(SONY_12_BITS, 21, 1)); - EXPECT_EQ(0xFFF, irsend.encodeSony(SONY_12_BITS, 0x7F, 0x1F)); + EXPECT_EQ(0x0, irsend.encodeSony(kSony12Bits, 0, 0)); + EXPECT_EQ(0xA90, irsend.encodeSony(kSony12Bits, 21, 1)); + EXPECT_EQ(0xFFF, irsend.encodeSony(kSony12Bits, 0x7F, 0x1F)); - EXPECT_EQ(0x0, irsend.encodeSony(SONY_15_BITS, 0, 0)); - EXPECT_EQ(0x5480, irsend.encodeSony(SONY_15_BITS, 21, 1)); - EXPECT_EQ(0x5455, irsend.encodeSony(SONY_15_BITS, 21, 0xAA)); - EXPECT_EQ(0x7FFF, irsend.encodeSony(SONY_15_BITS, 0x7F, 0xFF)); + EXPECT_EQ(0x0, irsend.encodeSony(kSony15Bits, 0, 0)); + EXPECT_EQ(0x5480, irsend.encodeSony(kSony15Bits, 21, 1)); + EXPECT_EQ(0x5455, irsend.encodeSony(kSony15Bits, 21, 0xAA)); + EXPECT_EQ(0x7FFF, irsend.encodeSony(kSony15Bits, 0x7F, 0xFF)); - EXPECT_EQ(0x0, irsend.encodeSony(SONY_20_BITS, 0, 0, 0)); - EXPECT_EQ(0x81080, irsend.encodeSony(SONY_20_BITS, 1, 1, 1)); - EXPECT_EQ(0xFFFFF, irsend.encodeSony(SONY_20_BITS, 0x7F, 0x1F, 0xFF)); + EXPECT_EQ(0x0, irsend.encodeSony(kSony20Bits, 0, 0, 0)); + EXPECT_EQ(0x81080, irsend.encodeSony(kSony20Bits, 1, 1, 1)); + EXPECT_EQ(0xFFFFF, irsend.encodeSony(kSony20Bits, 0x7F, 0x1F, 0xFF)); } TEST(TestEncodeSony, SonyEncodingWithOversizedValues) { IRsendTest irsend(4); - EXPECT_EQ(0xFFF, irsend.encodeSony(SONY_12_BITS, 0xFFFF, 0xFFFF)); + EXPECT_EQ(0xFFF, irsend.encodeSony(kSony12Bits, 0xFFFF, 0xFFFF)); - EXPECT_EQ(0x7FFF, irsend.encodeSony(SONY_15_BITS, 0xFFFF, 0xFFFF)); + EXPECT_EQ(0x7FFF, irsend.encodeSony(kSony15Bits, 0xFFFF, 0xFFFF)); - EXPECT_EQ(0xFFFFF, irsend.encodeSony(SONY_20_BITS, 0xFFFF, 0xFFFF, 0xFFFF)); + EXPECT_EQ(0xFFFFF, irsend.encodeSony(kSony20Bits, 0xFFFF, 0xFFFF, 0xFFFF)); } // Tests for decodeSony(). @@ -131,33 +144,33 @@ TEST(TestDecodeSony, NormalSonyDecodeWithStrict) { // Synthesised Normal Sony 20-bit message. irsend.reset(); - irsend.sendSony(irsend.encodeSony(SONY_20_BITS, 0x1, 0x1, 0x1)); + irsend.sendSony(irsend.encodeSony(kSony20Bits, 0x1, 0x1, 0x1)); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodeSony(&irsend.capture, SONY_20_BITS, true)); + ASSERT_TRUE(irrecv.decodeSony(&irsend.capture, kSony20Bits, true)); EXPECT_EQ(SONY, irsend.capture.decode_type); - EXPECT_EQ(SONY_20_BITS, irsend.capture.bits); + EXPECT_EQ(kSony20Bits, irsend.capture.bits); EXPECT_EQ(0x81080, irsend.capture.value); EXPECT_EQ(0x1, irsend.capture.address); EXPECT_EQ(0x81, irsend.capture.command); // Synthesised Normal Sony 15-bit message. irsend.reset(); - irsend.sendSony(irsend.encodeSony(SONY_15_BITS, 21, 1), SONY_15_BITS); + irsend.sendSony(irsend.encodeSony(kSony15Bits, 21, 1), kSony15Bits); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodeSony(&irsend.capture, SONY_15_BITS, true)); + ASSERT_TRUE(irrecv.decodeSony(&irsend.capture, kSony15Bits, true)); EXPECT_EQ(SONY, irsend.capture.decode_type); - EXPECT_EQ(SONY_15_BITS, irsend.capture.bits); + EXPECT_EQ(kSony15Bits, irsend.capture.bits); EXPECT_EQ(0x5480, irsend.capture.value); EXPECT_EQ(1, irsend.capture.address); EXPECT_EQ(21, irsend.capture.command); // Synthesised Normal Sony 12-bit message. irsend.reset(); - irsend.sendSony(irsend.encodeSony(SONY_12_BITS, 21, 1), SONY_12_BITS); + irsend.sendSony(irsend.encodeSony(kSony12Bits, 21, 1), kSony12Bits); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodeSony(&irsend.capture, SONY_12_BITS, true)); + ASSERT_TRUE(irrecv.decodeSony(&irsend.capture, kSony12Bits, true)); EXPECT_EQ(SONY, irsend.capture.decode_type); - EXPECT_EQ(SONY_12_BITS, irsend.capture.bits); + EXPECT_EQ(kSony12Bits, irsend.capture.bits); EXPECT_EQ(0xA90, irsend.capture.value); EXPECT_EQ(1, irsend.capture.address); EXPECT_EQ(21, irsend.capture.command); @@ -171,46 +184,46 @@ TEST(TestDecodeSony, SonyDecodeWithUnexpectedLegalSize) { // Synthesised Normal Sony 20-bit message decoded when looking for 12-bits irsend.reset(); - irsend.sendSony(irsend.encodeSony(SONY_20_BITS, 0x1, 0x1, 0x1)); + irsend.sendSony(irsend.encodeSony(kSony20Bits, 0x1, 0x1, 0x1)); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodeSony(&irsend.capture, SONY_MIN_BITS)); + ASSERT_TRUE(irrecv.decodeSony(&irsend.capture, kSonyMinBits)); EXPECT_EQ(SONY, irsend.capture.decode_type); - EXPECT_EQ(SONY_20_BITS, irsend.capture.bits); + EXPECT_EQ(kSony20Bits, irsend.capture.bits); EXPECT_EQ(0x81080, irsend.capture.value); EXPECT_EQ(0x1, irsend.capture.address); EXPECT_EQ(0x81, irsend.capture.command); // Synthesised Normal Sony 12-bit message when expecting 20-bits. irsend.reset(); - irsend.sendSony(irsend.encodeSony(SONY_12_BITS, 21, 1), SONY_12_BITS); + irsend.sendSony(irsend.encodeSony(kSony12Bits, 21, 1), kSony12Bits); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodeSony(&irsend.capture, SONY_20_BITS)); + ASSERT_TRUE(irrecv.decodeSony(&irsend.capture, kSony20Bits)); EXPECT_EQ(SONY, irsend.capture.decode_type); - EXPECT_EQ(SONY_12_BITS, irsend.capture.bits); + EXPECT_EQ(kSony12Bits, irsend.capture.bits); EXPECT_EQ(0xA90, irsend.capture.value); EXPECT_EQ(1, irsend.capture.address); EXPECT_EQ(21, irsend.capture.command); // 12-bit message should be regected when using strict and a different size. irsend.reset(); - irsend.sendSony(irsend.encodeSony(SONY_12_BITS, 21, 1), SONY_12_BITS); + irsend.sendSony(irsend.encodeSony(kSony12Bits, 21, 1), kSony12Bits); irsend.makeDecodeResult(); - ASSERT_FALSE(irrecv.decodeSony(&irsend.capture, SONY_20_BITS, true)); - ASSERT_FALSE(irrecv.decodeSony(&irsend.capture, SONY_15_BITS, true)); + ASSERT_FALSE(irrecv.decodeSony(&irsend.capture, kSony20Bits, true)); + ASSERT_FALSE(irrecv.decodeSony(&irsend.capture, kSony15Bits, true)); // 15-bit message should be regected when using strict and a different size. irsend.reset(); - irsend.sendSony(irsend.encodeSony(SONY_15_BITS, 21, 1), SONY_15_BITS); + irsend.sendSony(irsend.encodeSony(kSony15Bits, 21, 1), kSony15Bits); irsend.makeDecodeResult(); - ASSERT_FALSE(irrecv.decodeSony(&irsend.capture, SONY_12_BITS, true)); - ASSERT_FALSE(irrecv.decodeSony(&irsend.capture, SONY_20_BITS, true)); + ASSERT_FALSE(irrecv.decodeSony(&irsend.capture, kSony12Bits, true)); + ASSERT_FALSE(irrecv.decodeSony(&irsend.capture, kSony20Bits, true)); // 20-bit message should be regected when using strict and a different size. irsend.reset(); - irsend.sendSony(irsend.encodeSony(SONY_20_BITS, 1, 1, 1), SONY_20_BITS); + irsend.sendSony(irsend.encodeSony(kSony20Bits, 1, 1, 1), kSony20Bits); irsend.makeDecodeResult(); - ASSERT_FALSE(irrecv.decodeSony(&irsend.capture, SONY_12_BITS, true)); - ASSERT_FALSE(irrecv.decodeSony(&irsend.capture, SONY_15_BITS, true)); + ASSERT_FALSE(irrecv.decodeSony(&irsend.capture, kSony12Bits, true)); + ASSERT_FALSE(irrecv.decodeSony(&irsend.capture, kSony15Bits, true)); } // Decode unsupported Sony messages. i.e non-standard sizes. @@ -223,10 +236,10 @@ TEST(TestDecodeSony, SonyDecodeWithIllegalSize) { irsend.sendSony(0xFF, 8); // Illegal 8-bit Sony-like message. irsend.makeDecodeResult(); // Should fail with strict on. - EXPECT_FALSE(irrecv.decodeSony(&irsend.capture, SONY_MIN_BITS, true)); - EXPECT_FALSE(irrecv.decodeSony(&irsend.capture, SONY_12_BITS, true)); - EXPECT_FALSE(irrecv.decodeSony(&irsend.capture, SONY_15_BITS, true)); - EXPECT_FALSE(irrecv.decodeSony(&irsend.capture, SONY_20_BITS, true)); + EXPECT_FALSE(irrecv.decodeSony(&irsend.capture, kSonyMinBits, true)); + EXPECT_FALSE(irrecv.decodeSony(&irsend.capture, kSony12Bits, true)); + EXPECT_FALSE(irrecv.decodeSony(&irsend.capture, kSony15Bits, true)); + EXPECT_FALSE(irrecv.decodeSony(&irsend.capture, kSony20Bits, true)); // Should work with a 'normal' match (not strict) ASSERT_TRUE(irrecv.decodeSony(&irsend.capture)); EXPECT_EQ(SONY, irsend.capture.decode_type); @@ -239,10 +252,10 @@ TEST(TestDecodeSony, SonyDecodeWithIllegalSize) { irsend.sendSony(0x1FFF, 13); // Illegal 13-bit Sony-like message. irsend.makeDecodeResult(); // Should fail with strict on. - EXPECT_FALSE(irrecv.decodeSony(&irsend.capture, SONY_MIN_BITS, true)); - EXPECT_FALSE(irrecv.decodeSony(&irsend.capture, SONY_12_BITS, true)); - EXPECT_FALSE(irrecv.decodeSony(&irsend.capture, SONY_15_BITS, true)); - EXPECT_FALSE(irrecv.decodeSony(&irsend.capture, SONY_20_BITS, true)); + EXPECT_FALSE(irrecv.decodeSony(&irsend.capture, kSonyMinBits, true)); + EXPECT_FALSE(irrecv.decodeSony(&irsend.capture, kSony12Bits, true)); + EXPECT_FALSE(irrecv.decodeSony(&irsend.capture, kSony15Bits, true)); + EXPECT_FALSE(irrecv.decodeSony(&irsend.capture, kSony20Bits, true)); // Should work with a 'normal' match (not strict) ASSERT_TRUE(irrecv.decodeSony(&irsend.capture)); EXPECT_EQ(SONY, irsend.capture.decode_type); @@ -255,10 +268,10 @@ TEST(TestDecodeSony, SonyDecodeWithIllegalSize) { irsend.sendSony(0x1FFFF, 17); // Illegal 17-bit Sony-like message. irsend.makeDecodeResult(); // Should fail with strict on. - EXPECT_FALSE(irrecv.decodeSony(&irsend.capture, SONY_MIN_BITS, true)); - EXPECT_FALSE(irrecv.decodeSony(&irsend.capture, SONY_12_BITS, true)); - EXPECT_FALSE(irrecv.decodeSony(&irsend.capture, SONY_15_BITS, true)); - EXPECT_FALSE(irrecv.decodeSony(&irsend.capture, SONY_20_BITS, true)); + EXPECT_FALSE(irrecv.decodeSony(&irsend.capture, kSonyMinBits, true)); + EXPECT_FALSE(irrecv.decodeSony(&irsend.capture, kSony12Bits, true)); + EXPECT_FALSE(irrecv.decodeSony(&irsend.capture, kSony15Bits, true)); + EXPECT_FALSE(irrecv.decodeSony(&irsend.capture, kSony20Bits, true)); // Should work with a 'normal' match (not strict) ASSERT_TRUE(irrecv.decodeSony(&irsend.capture)); EXPECT_EQ(SONY, irsend.capture.decode_type); @@ -271,10 +284,10 @@ TEST(TestDecodeSony, SonyDecodeWithIllegalSize) { irsend.sendSony(0x1FFFFF, 21); // Illegal 21-bit Sony-like message. irsend.makeDecodeResult(); // Should fail with strict on. - EXPECT_FALSE(irrecv.decodeSony(&irsend.capture, SONY_MIN_BITS, true)); - EXPECT_FALSE(irrecv.decodeSony(&irsend.capture, SONY_12_BITS, true)); - EXPECT_FALSE(irrecv.decodeSony(&irsend.capture, SONY_15_BITS, true)); - EXPECT_FALSE(irrecv.decodeSony(&irsend.capture, SONY_20_BITS, true)); + EXPECT_FALSE(irrecv.decodeSony(&irsend.capture, kSonyMinBits, true)); + EXPECT_FALSE(irrecv.decodeSony(&irsend.capture, kSony12Bits, true)); + EXPECT_FALSE(irrecv.decodeSony(&irsend.capture, kSony15Bits, true)); + EXPECT_FALSE(irrecv.decodeSony(&irsend.capture, kSony20Bits, true)); // Should work with a 'normal' match (not strict) ASSERT_TRUE(irrecv.decodeSony(&irsend.capture)); EXPECT_EQ(SONY, irsend.capture.decode_type); @@ -296,7 +309,6 @@ TEST(TestDecodeSony, SonyDecodeWithIllegalSize) { EXPECT_EQ(0x0, irsend.capture.command); } - // Decode unsupported Sony messages. i.e non-standard sizes. TEST(TestDecodeSony, DecodeGlobalCacheExample) { IRsendTest irsend(4); @@ -305,9 +317,9 @@ TEST(TestDecodeSony, DecodeGlobalCacheExample) { irsend.reset(); // Sony "Power On" from Global Cache. - uint16_t gc_test[29] = {40000, 1, 1, 96, 24, 24, 24, 48, 24, 48, 24, 48, 24, - 24, 24, 48, 24, 24, 24, 48, 24, 24, 24, 24, 24, 24, - 24, 24, 1013}; + uint16_t gc_test[29] = {40000, 1, 1, 96, 24, 24, 24, 48, 24, 48, + 24, 48, 24, 24, 24, 48, 24, 24, 24, 48, + 24, 24, 24, 24, 24, 24, 24, 24, 1013}; irsend.sendGC(gc_test, 29); irsend.makeDecodeResult(); @@ -319,5 +331,27 @@ TEST(TestDecodeSony, DecodeGlobalCacheExample) { EXPECT_EQ(0x1, irsend.capture.address); EXPECT_EQ(0x2E, irsend.capture.command); // With strict and correct size. - ASSERT_TRUE(irrecv.decodeSony(&irsend.capture, SONY_12_BITS, true)); + ASSERT_TRUE(irrecv.decodeSony(&irsend.capture, kSony12Bits, true)); +} + +// Encoding & Decode 20 bit Sony messages. Issue #476 +TEST(TestEncodeSony, Issue476) { + IRsendTest irsend(0); + IRrecv irrecv(0); + irsend.begin(); + + irsend.reset(); + irsend.sendSony(0x6AB47, 20); + irsend.makeDecodeResult(); + + // Without strict. + ASSERT_TRUE(irrecv.decode(&irsend.capture)); + EXPECT_EQ(SONY, irsend.capture.decode_type); + EXPECT_EQ(20, irsend.capture.bits); + EXPECT_EQ(0x6AB47, irsend.capture.value); // 20 bits + EXPECT_EQ(0x1A, irsend.capture.address); // 5 bits + EXPECT_EQ(0x7156, irsend.capture.command); // 15 bits + EXPECT_EQ(0x56, 0x7156 & 0x7F); // command (lower 7 bits) + EXPECT_EQ(0xE2, (0x7156 >> 7) & 0xFF); // extended (top 8 of 15 bits) + EXPECT_EQ(0x6AB47, irsend.encodeSony(20, 0x56, 0x1A, 0xE2)); } diff --git a/lib/IRremoteESP8266/test/ir_Toshiba_test.cpp b/lib/IRremoteESP8266/test/ir_Toshiba_test.cpp index 7411198..b5e1e07 100644 --- a/lib/IRremoteESP8266/test/ir_Toshiba_test.cpp +++ b/lib/IRremoteESP8266/test/ir_Toshiba_test.cpp @@ -1,9 +1,9 @@ // Copyright 2017 David Conran +#include "ir_Toshiba.h" #include "IRrecv.h" #include "IRrecv_test.h" #include "IRsend.h" #include "IRsend_test.h" -#include "ir_Toshiba.h" #include "gtest/gtest.h" // Tests for Toshiba A/C methods. @@ -13,8 +13,8 @@ TEST(TestSendToshibaAC, SendDataOnly) { IRsendTest irsend(4); irsend.begin(); - uint8_t toshiba_code[TOSHIBA_AC_STATE_LENGTH] = { - 0xF2, 0x0D, 0x03, 0xFC, 0x01, 0x00, 0x00, 0x00, 0x00}; + uint8_t toshiba_code[kToshibaACStateLength] = {0xF2, 0x0D, 0x03, 0xFC, 0x01, + 0x00, 0x00, 0x00, 0x00}; irsend.reset(); irsend.sendToshibaAC(toshiba_code); EXPECT_EQ( @@ -39,7 +39,8 @@ TEST(TestSendToshibaAC, SendDataOnly) { "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s472" "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s472" "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s472" - "m543s7048", irsend.outputStr()); + "m543s7048", + irsend.outputStr()); } // Test sending with repeats. @@ -48,59 +49,61 @@ TEST(TestSendToshibaAC, SendWithRepeats) { irsend.begin(); irsend.reset(); - uint8_t toshiba_code[TOSHIBA_AC_STATE_LENGTH] = { - 0xF2, 0x0D, 0x03, 0xFC, 0x01, 0x00, 0x00, 0x00, 0x00}; + uint8_t toshiba_code[kToshibaACStateLength] = {0xF2, 0x0D, 0x03, 0xFC, 0x01, + 0x00, 0x00, 0x00, 0x00}; - irsend.sendToshibaAC(toshiba_code, TOSHIBA_AC_STATE_LENGTH, 0); + irsend.sendToshibaAC(toshiba_code, kToshibaACStateLength, 0); EXPECT_EQ( - "m4400s4300" - "m543s1623m543s1623m543s1623m543s1623m543s472m543s472m543s1623m543s472" - "m543s472m543s472m543s472m543s472m543s1623m543s1623m543s472m543s1623" - "m543s472m543s472m543s472m543s472m543s472m543s472m543s1623m543s1623" - "m543s1623m543s1623m543s1623m543s1623m543s1623m543s1623m543s472m543s472" - "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s1623" - "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s472" - "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s472" - "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s472" - "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s472" - "m543s7048", irsend.outputStr()); + "m4400s4300" + "m543s1623m543s1623m543s1623m543s1623m543s472m543s472m543s1623m543s472" + "m543s472m543s472m543s472m543s472m543s1623m543s1623m543s472m543s1623" + "m543s472m543s472m543s472m543s472m543s472m543s472m543s1623m543s1623" + "m543s1623m543s1623m543s1623m543s1623m543s1623m543s1623m543s472m543s472" + "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s1623" + "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s472" + "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s472" + "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s472" + "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s472" + "m543s7048", + irsend.outputStr()); irsend.reset(); - irsend.sendToshibaAC(toshiba_code, TOSHIBA_AC_STATE_LENGTH, 2); + irsend.sendToshibaAC(toshiba_code, kToshibaACStateLength, 2); EXPECT_EQ( - "m4400s4300" - "m543s1623m543s1623m543s1623m543s1623m543s472m543s472m543s1623m543s472" - "m543s472m543s472m543s472m543s472m543s1623m543s1623m543s472m543s1623" - "m543s472m543s472m543s472m543s472m543s472m543s472m543s1623m543s1623" - "m543s1623m543s1623m543s1623m543s1623m543s1623m543s1623m543s472m543s472" - "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s1623" - "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s472" - "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s472" - "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s472" - "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s472" - "m543s7048" - "m4400s4300" - "m543s1623m543s1623m543s1623m543s1623m543s472m543s472m543s1623m543s472" - "m543s472m543s472m543s472m543s472m543s1623m543s1623m543s472m543s1623" - "m543s472m543s472m543s472m543s472m543s472m543s472m543s1623m543s1623" - "m543s1623m543s1623m543s1623m543s1623m543s1623m543s1623m543s472m543s472" - "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s1623" - "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s472" - "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s472" - "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s472" - "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s472" - "m543s7048" - "m4400s4300" - "m543s1623m543s1623m543s1623m543s1623m543s472m543s472m543s1623m543s472" - "m543s472m543s472m543s472m543s472m543s1623m543s1623m543s472m543s1623" - "m543s472m543s472m543s472m543s472m543s472m543s472m543s1623m543s1623" - "m543s1623m543s1623m543s1623m543s1623m543s1623m543s1623m543s472m543s472" - "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s1623" - "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s472" - "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s472" - "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s472" - "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s472" - "m543s7048", irsend.outputStr()); + "m4400s4300" + "m543s1623m543s1623m543s1623m543s1623m543s472m543s472m543s1623m543s472" + "m543s472m543s472m543s472m543s472m543s1623m543s1623m543s472m543s1623" + "m543s472m543s472m543s472m543s472m543s472m543s472m543s1623m543s1623" + "m543s1623m543s1623m543s1623m543s1623m543s1623m543s1623m543s472m543s472" + "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s1623" + "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s472" + "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s472" + "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s472" + "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s472" + "m543s7048" + "m4400s4300" + "m543s1623m543s1623m543s1623m543s1623m543s472m543s472m543s1623m543s472" + "m543s472m543s472m543s472m543s472m543s1623m543s1623m543s472m543s1623" + "m543s472m543s472m543s472m543s472m543s472m543s472m543s1623m543s1623" + "m543s1623m543s1623m543s1623m543s1623m543s1623m543s1623m543s472m543s472" + "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s1623" + "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s472" + "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s472" + "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s472" + "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s472" + "m543s7048" + "m4400s4300" + "m543s1623m543s1623m543s1623m543s1623m543s472m543s472m543s1623m543s472" + "m543s472m543s472m543s472m543s472m543s1623m543s1623m543s472m543s1623" + "m543s472m543s472m543s472m543s472m543s472m543s472m543s1623m543s1623" + "m543s1623m543s1623m543s1623m543s1623m543s1623m543s1623m543s472m543s472" + "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s1623" + "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s472" + "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s472" + "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s472" + "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s472" + "m543s7048", + irsend.outputStr()); } // Test sending atypical sizes. @@ -113,11 +116,11 @@ TEST(TestSendToshibaAC, SendUnexpectedSizes) { uint8_t toshiba_long_code[10] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A}; irsend.reset(); - irsend.sendToshibaAC(toshiba_short_code, TOSHIBA_AC_STATE_LENGTH - 1); + irsend.sendToshibaAC(toshiba_short_code, kToshibaACStateLength - 1); ASSERT_EQ("", irsend.outputStr()); irsend.reset(); - irsend.sendToshibaAC(toshiba_long_code, TOSHIBA_AC_STATE_LENGTH + 1); + irsend.sendToshibaAC(toshiba_long_code, kToshibaACStateLength + 1); ASSERT_EQ( "m4400s4300" "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s1623" @@ -142,7 +145,8 @@ TEST(TestSendToshibaAC, SendUnexpectedSizes) { "m543s472m543s472m543s472m543s472m543s1623m543s472m543s472m543s472" "m543s472m543s472m543s472m543s472m543s1623m543s472m543s472m543s1623" "m543s472m543s472m543s472m543s472m543s1623m543s472m543s1623m543s472" - "m543s7048", irsend.outputStr()); + "m543s7048", + irsend.outputStr()); } // Tests for IRToshibaAC class. @@ -169,22 +173,22 @@ TEST(TestToshibaACClass, Temperature) { toshiba.begin(); toshiba.setTemp(0); - EXPECT_EQ(TOSHIBA_AC_MIN_TEMP, toshiba.getTemp()); + EXPECT_EQ(kToshibaAcMinTemp, toshiba.getTemp()); toshiba.setTemp(255); - EXPECT_EQ(TOSHIBA_AC_MAX_TEMP, toshiba.getTemp()); + EXPECT_EQ(kToshibaAcMaxTemp, toshiba.getTemp()); - toshiba.setTemp(TOSHIBA_AC_MIN_TEMP); - EXPECT_EQ(TOSHIBA_AC_MIN_TEMP, toshiba.getTemp()); + toshiba.setTemp(kToshibaAcMinTemp); + EXPECT_EQ(kToshibaAcMinTemp, toshiba.getTemp()); - toshiba.setTemp(TOSHIBA_AC_MAX_TEMP); - EXPECT_EQ(TOSHIBA_AC_MAX_TEMP, toshiba.getTemp()); + toshiba.setTemp(kToshibaAcMaxTemp); + EXPECT_EQ(kToshibaAcMaxTemp, toshiba.getTemp()); - toshiba.setTemp(TOSHIBA_AC_MIN_TEMP - 1); - EXPECT_EQ(TOSHIBA_AC_MIN_TEMP, toshiba.getTemp()); + toshiba.setTemp(kToshibaAcMinTemp - 1); + EXPECT_EQ(kToshibaAcMinTemp, toshiba.getTemp()); - toshiba.setTemp(TOSHIBA_AC_MAX_TEMP + 1); - EXPECT_EQ(TOSHIBA_AC_MAX_TEMP, toshiba.getTemp()); + toshiba.setTemp(kToshibaAcMaxTemp + 1); + EXPECT_EQ(kToshibaAcMaxTemp, toshiba.getTemp()); toshiba.setTemp(17); EXPECT_EQ(17, toshiba.getTemp()); @@ -203,49 +207,49 @@ TEST(TestToshibaACClass, OperatingMode) { IRToshibaAC toshiba(0); toshiba.begin(); - toshiba.setMode(TOSHIBA_AC_AUTO); - EXPECT_EQ(TOSHIBA_AC_AUTO, toshiba.getMode()); + toshiba.setMode(kToshibaAcAuto); + EXPECT_EQ(kToshibaAcAuto, toshiba.getMode()); - toshiba.setMode(TOSHIBA_AC_COOL); - EXPECT_EQ(TOSHIBA_AC_COOL, toshiba.getMode()); + toshiba.setMode(kToshibaAcCool); + EXPECT_EQ(kToshibaAcCool, toshiba.getMode()); - toshiba.setMode(TOSHIBA_AC_HEAT); - EXPECT_EQ(TOSHIBA_AC_HEAT, toshiba.getMode()); + toshiba.setMode(kToshibaAcHeat); + EXPECT_EQ(kToshibaAcHeat, toshiba.getMode()); - toshiba.setMode(TOSHIBA_AC_DRY); - EXPECT_EQ(TOSHIBA_AC_DRY, toshiba.getMode()); + toshiba.setMode(kToshibaAcDry); + EXPECT_EQ(kToshibaAcDry, toshiba.getMode()); - toshiba.setMode(TOSHIBA_AC_HEAT + 1); - EXPECT_EQ(TOSHIBA_AC_AUTO, toshiba.getMode()); + toshiba.setMode(kToshibaAcHeat + 1); + EXPECT_EQ(kToshibaAcAuto, toshiba.getMode()); toshiba.setMode(255); - EXPECT_EQ(TOSHIBA_AC_AUTO, toshiba.getMode()); + EXPECT_EQ(kToshibaAcAuto, toshiba.getMode()); // Setting the power off changes the underlying mode in the state to heat. toshiba.setPower(true); - toshiba.setMode(TOSHIBA_AC_COOL); - EXPECT_EQ(TOSHIBA_AC_COOL, toshiba.getMode()); - EXPECT_EQ(TOSHIBA_AC_COOL, toshiba.getMode(true)); + toshiba.setMode(kToshibaAcCool); + EXPECT_EQ(kToshibaAcCool, toshiba.getMode()); + EXPECT_EQ(kToshibaAcCool, toshiba.getMode(true)); toshiba.setPower(false); - EXPECT_EQ(TOSHIBA_AC_COOL, toshiba.getMode()); - EXPECT_EQ(TOSHIBA_AC_HEAT, toshiba.getMode(true)); + EXPECT_EQ(kToshibaAcCool, toshiba.getMode()); + EXPECT_EQ(kToshibaAcHeat, toshiba.getMode(true)); } TEST(TestToshibaACClass, FanSpeed) { IRToshibaAC toshiba(0); toshiba.begin(); - toshiba.setFan(TOSHIBA_AC_FAN_AUTO); - EXPECT_EQ(TOSHIBA_AC_FAN_AUTO, toshiba.getFan()); + toshiba.setFan(kToshibaAcFanAuto); + EXPECT_EQ(kToshibaAcFanAuto, toshiba.getFan()); toshiba.setFan(255); - EXPECT_EQ(TOSHIBA_AC_FAN_MAX, toshiba.getFan()); + EXPECT_EQ(kToshibaAcFanMax, toshiba.getFan()); - toshiba.setFan(TOSHIBA_AC_FAN_MAX); - EXPECT_EQ(TOSHIBA_AC_FAN_MAX, toshiba.getFan()); + toshiba.setFan(kToshibaAcFanMax); + EXPECT_EQ(kToshibaAcFanMax, toshiba.getFan()); - toshiba.setFan(TOSHIBA_AC_FAN_MAX - 1); - EXPECT_EQ(TOSHIBA_AC_FAN_MAX - 1, toshiba.getFan()); + toshiba.setFan(kToshibaAcFanMax - 1); + EXPECT_EQ(kToshibaAcFanMax - 1, toshiba.getFan()); toshiba.setFan(1); EXPECT_EQ(1, toshiba.getFan()); @@ -259,56 +263,56 @@ TEST(TestToshibaACClass, FanSpeed) { toshiba.setFan(4); EXPECT_EQ(4, toshiba.getFan()); - toshiba.setFan(TOSHIBA_AC_FAN_MAX + 1); - EXPECT_EQ(TOSHIBA_AC_FAN_MAX, toshiba.getFan()); + toshiba.setFan(kToshibaAcFanMax + 1); + EXPECT_EQ(kToshibaAcFanMax, toshiba.getFan()); } TEST(TestToshibaACClass, RawState) { IRToshibaAC toshiba(0); toshiba.begin(); - uint8_t initial_state[TOSHIBA_AC_STATE_LENGTH] = { - 0xF2, 0x0D, 0x03, 0xFC, 0x01, 0x00, 0x00, 0x00, 0x01}; - uint8_t modified_state[TOSHIBA_AC_STATE_LENGTH] = { - 0xF2, 0x0D, 0x03, 0xFC, 0x01, 0x00, 0xC1, 0x00, 0xC0}; + uint8_t initial_state[kToshibaACStateLength] = {0xF2, 0x0D, 0x03, 0xFC, 0x01, + 0x00, 0x00, 0x00, 0x01}; + uint8_t modified_state[kToshibaACStateLength] = {0xF2, 0x0D, 0x03, 0xFC, 0x01, + 0x00, 0xC1, 0x00, 0xC0}; // Verify the starting state. - EXPECT_STATE_EQ(initial_state, toshiba.getRaw(), TOSHIBA_AC_BITS); + EXPECT_STATE_EQ(initial_state, toshiba.getRaw(), kToshibaACBits); EXPECT_TRUE(toshiba.getPower()); - EXPECT_EQ(TOSHIBA_AC_AUTO, toshiba.getMode()); - EXPECT_EQ(TOSHIBA_AC_FAN_AUTO, toshiba.getFan()); + EXPECT_EQ(kToshibaAcAuto, toshiba.getMode()); + EXPECT_EQ(kToshibaAcFanAuto, toshiba.getFan()); // Change some settings. - toshiba.setMode(TOSHIBA_AC_COOL); - toshiba.setFan(TOSHIBA_AC_FAN_MAX); - toshiba.setTemp(TOSHIBA_AC_MIN_TEMP); + toshiba.setMode(kToshibaAcCool); + toshiba.setFan(kToshibaAcFanMax); + toshiba.setTemp(kToshibaAcMinTemp); // Verify those were set. - EXPECT_EQ(TOSHIBA_AC_COOL, toshiba.getMode()); - EXPECT_EQ(TOSHIBA_AC_FAN_MAX, toshiba.getFan()); - EXPECT_EQ(TOSHIBA_AC_MIN_TEMP, toshiba.getTemp()); + EXPECT_EQ(kToshibaAcCool, toshiba.getMode()); + EXPECT_EQ(kToshibaAcFanMax, toshiba.getFan()); + EXPECT_EQ(kToshibaAcMinTemp, toshiba.getTemp()); // Retrieve the modified state. - EXPECT_STATE_EQ(modified_state, toshiba.getRaw(), TOSHIBA_AC_BITS); + EXPECT_STATE_EQ(modified_state, toshiba.getRaw(), kToshibaACBits); // Set it back to the initial state. toshiba.setRaw(initial_state); // Check the new state was set correctly. EXPECT_TRUE(toshiba.getPower()); - EXPECT_EQ(TOSHIBA_AC_AUTO, toshiba.getMode()); - EXPECT_EQ(TOSHIBA_AC_FAN_AUTO, toshiba.getFan()); - EXPECT_STATE_EQ(initial_state, toshiba.getRaw(), TOSHIBA_AC_BITS); + EXPECT_EQ(kToshibaAcAuto, toshiba.getMode()); + EXPECT_EQ(kToshibaAcFanAuto, toshiba.getFan()); + EXPECT_STATE_EQ(initial_state, toshiba.getRaw(), kToshibaACBits); } TEST(TestToshibaACClass, Checksums) { IRToshibaAC toshiba(0); toshiba.begin(); - uint8_t initial_state[TOSHIBA_AC_STATE_LENGTH] = { - 0xF2, 0x0D, 0x03, 0xFC, 0x01, 0x00, 0x00, 0x00, 0x01}; - uint8_t modified_state[TOSHIBA_AC_STATE_LENGTH] = { - 0xF2, 0x0D, 0x03, 0xFC, 0x01, 0x00, 0xC1, 0x00, 0xC0}; - uint8_t invalid_state[TOSHIBA_AC_STATE_LENGTH] = { - 0xF2, 0x0D, 0x03, 0xFC, 0x01, 0x00, 0x00, 0x00, 0x00}; + uint8_t initial_state[kToshibaACStateLength] = {0xF2, 0x0D, 0x03, 0xFC, 0x01, + 0x00, 0x00, 0x00, 0x01}; + uint8_t modified_state[kToshibaACStateLength] = {0xF2, 0x0D, 0x03, 0xFC, 0x01, + 0x00, 0xC1, 0x00, 0xC0}; + uint8_t invalid_state[kToshibaACStateLength] = {0xF2, 0x0D, 0x03, 0xFC, 0x01, + 0x00, 0x00, 0x00, 0x00}; EXPECT_EQ(0x01, toshiba.calcChecksum(initial_state)); EXPECT_EQ(0xC0, toshiba.calcChecksum(modified_state)); @@ -316,7 +320,7 @@ TEST(TestToshibaACClass, Checksums) { EXPECT_EQ(0x01, IRToshibaAC::calcChecksum(initial_state)); // Use different lengths. EXPECT_EQ(0x01, IRToshibaAC::calcChecksum(initial_state, - TOSHIBA_AC_STATE_LENGTH - 1)); + kToshibaACStateLength - 1)); EXPECT_EQ(0xFF, IRToshibaAC::calcChecksum(initial_state, 3)); // Minimum length that actually means anything. EXPECT_EQ(0xF2, IRToshibaAC::calcChecksum(initial_state, 2)); @@ -338,10 +342,10 @@ TEST(TestToshibaACClass, HumanReadableOutput) { IRToshibaAC toshiba(0); toshiba.begin(); - uint8_t initial_state[TOSHIBA_AC_STATE_LENGTH] = { - 0xF2, 0x0D, 0x03, 0xFC, 0x01, 0x00, 0x00, 0x00, 0x01}; - uint8_t modified_state[TOSHIBA_AC_STATE_LENGTH] = { - 0xF2, 0x0D, 0x03, 0xFC, 0x01, 0x00, 0xC1, 0x00, 0xC0}; + uint8_t initial_state[kToshibaACStateLength] = {0xF2, 0x0D, 0x03, 0xFC, 0x01, + 0x00, 0x00, 0x00, 0x01}; + uint8_t modified_state[kToshibaACStateLength] = {0xF2, 0x0D, 0x03, 0xFC, 0x01, + 0x00, 0xC1, 0x00, 0xC0}; toshiba.setRaw(initial_state); EXPECT_EQ("Power: On, Mode: 0 (AUTO), Temp: 17C, Fan: 0 (AUTO)", @@ -352,9 +356,8 @@ TEST(TestToshibaACClass, HumanReadableOutput) { toshiba.off(); toshiba.setTemp(25); toshiba.setFan(3); - toshiba.setMode(TOSHIBA_AC_DRY); - EXPECT_EQ("Power: Off, Mode: 2 (DRY), Temp: 25C, Fan: 3", - toshiba.toString()); + toshiba.setMode(kToshibaAcDry); + EXPECT_EQ("Power: Off, Mode: 2 (DRY), Temp: 25C, Fan: 3", toshiba.toString()); } TEST(TestToshibaACClass, MessageConstuction) { @@ -364,13 +367,13 @@ TEST(TestToshibaACClass, MessageConstuction) { irsend.begin(); toshiba.setFan(1); - toshiba.setMode(TOSHIBA_AC_COOL); + toshiba.setMode(kToshibaAcCool); toshiba.setTemp(27); toshiba.on(); // Check everything for kicks. EXPECT_EQ(1, toshiba.getFan()); - EXPECT_EQ(TOSHIBA_AC_COOL, toshiba.getMode()); + EXPECT_EQ(kToshibaAcCool, toshiba.getMode()); EXPECT_EQ(27, toshiba.getTemp()); EXPECT_TRUE(toshiba.getPower()); @@ -398,13 +401,14 @@ TEST(TestToshibaACClass, MessageConstuction) { "m543s472m543s1623m543s472m543s472m543s472m543s472m543s472m543s1623" "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s472" "m543s1623m543s1623m543s1623m543s472m543s472m543s472m543s472m543s472" - "m543s7048", irsend.outputStr()); + "m543s7048", + irsend.outputStr()); // Turn off the power and re-check. toshiba.setPower(false); // Check everything for kicks. EXPECT_EQ(1, toshiba.getFan()); - EXPECT_EQ(TOSHIBA_AC_COOL, toshiba.getMode()); + EXPECT_EQ(kToshibaAcCool, toshiba.getMode()); EXPECT_EQ(27, toshiba.getTemp()); EXPECT_FALSE(toshiba.getPower()); @@ -432,13 +436,14 @@ TEST(TestToshibaACClass, MessageConstuction) { "m543s472m543s1623m543s472m543s472m543s472m543s1623m543s1623m543s1623" "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s472" "m543s1623m543s1623m543s1623m543s472m543s472m543s1623m543s1623m543s472" - "m543s7048", irsend.outputStr()); + "m543s7048", + irsend.outputStr()); // Turn the power back on, and check nothing changed. toshiba.on(); EXPECT_EQ(1, toshiba.getFan()); - EXPECT_EQ(TOSHIBA_AC_COOL, toshiba.getMode()); + EXPECT_EQ(kToshibaAcCool, toshiba.getMode()); EXPECT_EQ(27, toshiba.getTemp()); EXPECT_TRUE(toshiba.getPower()); @@ -466,7 +471,8 @@ TEST(TestToshibaACClass, MessageConstuction) { "m543s472m543s1623m543s472m543s472m543s472m543s472m543s472m543s1623" "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s472" "m543s1623m543s1623m543s1623m543s472m543s472m543s472m543s472m543s472" - "m543s7048", irsend.outputStr()); + "m543s7048", + irsend.outputStr()); } // Decoding a message we entirely constructed based solely on a given state. @@ -475,15 +481,15 @@ TEST(TestDecodeToshibaAC, SyntheticExample) { IRrecv irrecv(4); irsend.begin(); - uint8_t expectedState[TOSHIBA_AC_STATE_LENGTH] = { - 0xF2, 0x0D, 0x03, 0xFC, 0x01, 0x00, 0x00, 0x00, 0x01}; + uint8_t expectedState[kToshibaACStateLength] = {0xF2, 0x0D, 0x03, 0xFC, 0x01, + 0x00, 0x00, 0x00, 0x01}; irsend.reset(); irsend.sendToshibaAC(expectedState); irsend.makeDecodeResult(); EXPECT_TRUE(irrecv.decode(&irsend.capture)); ASSERT_EQ(TOSHIBA_AC, irsend.capture.decode_type); - ASSERT_EQ(TOSHIBA_AC_BITS, irsend.capture.bits); + ASSERT_EQ(kToshibaACBits, irsend.capture.bits); EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); } @@ -496,163 +502,163 @@ TEST(TestDecodeToshibaAC, RealExamples) { irsend.begin(); uint16_t rawData1[295] = { - 4442, 4292, 612, 1544, 616, 1544, 616, 1544, 612, 1548, 610, 468, - 612, 468, 662, 1494, 640, 438, 616, 464, 614, 464, 616, 464, - 612, 468, 610, 1544, 616, 1544, 616, 468, 612, 1544, 616, 464, - 694, 386, 616, 464, 612, 468, 612, 468, 636, 444, 610, 1546, - 616, 1544, 612, 1546, 614, 1546, 616, 1546, 740, 1420, 612, 1544, - 616, 1546, 616, 464, 610, 468, 610, 470, 612, 468, 610, 468, 610, - 470, 636, 438, 616, 464, 616, 464, 616, 1546, 636, 442, 612, 1546, - 614, 1544, 616, 464, 614, 464, 610, 468, 612, 468, 612, 468, - 612, 468, 636, 440, 614, 464, 616, 464, 616, 464, 612, 468, - 636, 442, 638, 442, 662, 418, 610, 464, 616, 464, 616, 464, - 610, 468, 612, 468, 636, 444, 610, 468, 638, 438, 614, 1546, - 612, 1548, 612, 470, 610, 468, 636, 442, 612, 468, 612, 1544, - 612, 7396, 4442, 4292, 610, 1546, 616, 1544, 612, 1548, 612, 1546, - 616, 464, 616, 464, 616, 1544, 612, 468, 662, 418, 610, 468, - 638, 442, 638, 438, 616, 1546, 616, 1544, 612, 468, 610, 1546, - 616, 464, 616, 464, 642, 438, 616, 464, 612, 468, 610, 470, - 610, 1546, 616, 1544, 612, 1546, 616, 1546, 614, 1546, 612, 1550, - 610, 1544, 616, 1546, 614, 464, 642, 438, 610, 468, 612, 468, - 612, 468, 612, 468, 610, 468, 638, 438, 614, 464, 616, 1544, - 636, 444, 636, 1520, 616, 1544, 616, 464, 616, 464, 612, 468, - 612, 468, 612, 468, 612, 468, 612, 464, 612, 470, 636, 442, - 638, 442, 612, 470, 692, 384, 614, 464, 616, 464, 612, 468, - 610, 468, 612, 468, 610, 470, 610, 464, 616, 464, 616, 464, - 616, 464, 610, 1550, 610, 1546, 640, 444, 688, 386, 616, 464, - 612, 468, 612, 1544, 642}; + 4442, 4292, 612, 1544, 616, 1544, 616, 1544, 612, 1548, 610, 468, + 612, 468, 662, 1494, 640, 438, 616, 464, 614, 464, 616, 464, + 612, 468, 610, 1544, 616, 1544, 616, 468, 612, 1544, 616, 464, + 694, 386, 616, 464, 612, 468, 612, 468, 636, 444, 610, 1546, + 616, 1544, 612, 1546, 614, 1546, 616, 1546, 740, 1420, 612, 1544, + 616, 1546, 616, 464, 610, 468, 610, 470, 612, 468, 610, 468, + 610, 470, 636, 438, 616, 464, 616, 464, 616, 1546, 636, 442, + 612, 1546, 614, 1544, 616, 464, 614, 464, 610, 468, 612, 468, + 612, 468, 612, 468, 636, 440, 614, 464, 616, 464, 616, 464, + 612, 468, 636, 442, 638, 442, 662, 418, 610, 464, 616, 464, + 616, 464, 610, 468, 612, 468, 636, 444, 610, 468, 638, 438, + 614, 1546, 612, 1548, 612, 470, 610, 468, 636, 442, 612, 468, + 612, 1544, 612, 7396, 4442, 4292, 610, 1546, 616, 1544, 612, 1548, + 612, 1546, 616, 464, 616, 464, 616, 1544, 612, 468, 662, 418, + 610, 468, 638, 442, 638, 438, 616, 1546, 616, 1544, 612, 468, + 610, 1546, 616, 464, 616, 464, 642, 438, 616, 464, 612, 468, + 610, 470, 610, 1546, 616, 1544, 612, 1546, 616, 1546, 614, 1546, + 612, 1550, 610, 1544, 616, 1546, 614, 464, 642, 438, 610, 468, + 612, 468, 612, 468, 612, 468, 610, 468, 638, 438, 614, 464, + 616, 1544, 636, 444, 636, 1520, 616, 1544, 616, 464, 616, 464, + 612, 468, 612, 468, 612, 468, 612, 468, 612, 464, 612, 470, + 636, 442, 638, 442, 612, 470, 692, 384, 614, 464, 616, 464, + 612, 468, 610, 468, 612, 468, 610, 470, 610, 464, 616, 464, + 616, 464, 616, 464, 610, 1550, 610, 1546, 640, 444, 688, 386, + 616, 464, 612, 468, 612, 1544, 642}; irsend.reset(); irsend.sendRaw(rawData1, 295, 38000); irsend.makeDecodeResult(); EXPECT_TRUE(irrecv.decode(&irsend.capture)); ASSERT_EQ(TOSHIBA_AC, irsend.capture.decode_type); - ASSERT_EQ(TOSHIBA_AC_BITS, irsend.capture.bits); + ASSERT_EQ(kToshibaACBits, irsend.capture.bits); toshiba.setRaw(irsend.capture.state); EXPECT_TRUE(toshiba.getPower()); EXPECT_EQ(23, toshiba.getTemp()); - EXPECT_EQ(TOSHIBA_AC_FAN_AUTO, toshiba.getFan()); - EXPECT_EQ(TOSHIBA_AC_AUTO, toshiba.getMode()); + EXPECT_EQ(kToshibaAcFanAuto, toshiba.getFan()); + EXPECT_EQ(kToshibaAcAuto, toshiba.getMode()); uint16_t rawData2[295] = { - 4500, 4236, 636, 1520, 642, 1520, 640, 1520, 664, 1492, 642, 440, - 668, 412, 642, 1518, 638, 438, 666, 414, 640, 438, 642, 438, - 638, 442, 642, 1516, 640, 1520, 642, 438, 642, 1520, 636, 438, - 668, 412, 640, 440, 666, 412, 642, 438, 668, 412, 640, 1516, - 668, 1492, 642, 1520, 666, 1494, 638, 1520, 642, 1520, 668, 1490, - 666, 1494, 642, 438, 638, 438, 668, 412, 668, 412, 642, 438, - 642, 438, 664, 412, 642, 438, 642, 438, 642, 1518, 642, 434, - 668, 412, 642, 438, 668, 412, 692, 388, 666, 412, 642, 434, - 642, 438, 642, 1518, 668, 412, 668, 412, 640, 438, 638, 438, - 642, 438, 640, 438, 668, 1492, 642, 440, 666, 412, 640, 438, - 642, 438, 642, 434, 668, 412, 668, 412, 666, 414, 666, 1494, - 640, 438, 642, 434, 668, 412, 642, 438, 642, 438, 668, 412, - 668, 414, 640, 7362, 4474, 4262, 642, 1518, 638, 1520, 640, 1520, - 668, 1494, 640, 434, 642, 438, 640, 1520, 642, 438, 642, 438, - 642, 438, 642, 438, 642, 434, 668, 1494, 642, 1518, 638, 442, - 638, 1520, 642, 438, 642, 438, 668, 414, 664, 408, 642, 438, - 668, 412, 642, 1520, 666, 1494, 642, 1514, 642, 1518, 642, 1520, - 636, 1520, 668, 1494, 666, 1494, 638, 438, 666, 414, 640, 440, - 666, 412, 668, 412, 668, 412, 642, 434, 668, 412, 668, 412, - 668, 1494, 642, 438, 642, 434, 642, 438, 642, 438, 642, 438, - 642, 438, 642, 434, 646, 434, 642, 1518, 668, 412, 642, 438, - 642, 434, 666, 414, 640, 438, 642, 438, 642, 1518, 642, 438, - 642, 434, 668, 412, 642, 438, 642, 438, 642, 438, 642, 438, - 642, 438, 640, 1520, 636, 438, 642, 438, 642, 438, 666, 414, - 668, 412, 642, 440, 640, 438, 640}; + 4500, 4236, 636, 1520, 642, 1520, 640, 1520, 664, 1492, 642, 440, + 668, 412, 642, 1518, 638, 438, 666, 414, 640, 438, 642, 438, + 638, 442, 642, 1516, 640, 1520, 642, 438, 642, 1520, 636, 438, + 668, 412, 640, 440, 666, 412, 642, 438, 668, 412, 640, 1516, + 668, 1492, 642, 1520, 666, 1494, 638, 1520, 642, 1520, 668, 1490, + 666, 1494, 642, 438, 638, 438, 668, 412, 668, 412, 642, 438, + 642, 438, 664, 412, 642, 438, 642, 438, 642, 1518, 642, 434, + 668, 412, 642, 438, 668, 412, 692, 388, 666, 412, 642, 434, + 642, 438, 642, 1518, 668, 412, 668, 412, 640, 438, 638, 438, + 642, 438, 640, 438, 668, 1492, 642, 440, 666, 412, 640, 438, + 642, 438, 642, 434, 668, 412, 668, 412, 666, 414, 666, 1494, + 640, 438, 642, 434, 668, 412, 642, 438, 642, 438, 668, 412, + 668, 414, 640, 7362, 4474, 4262, 642, 1518, 638, 1520, 640, 1520, + 668, 1494, 640, 434, 642, 438, 640, 1520, 642, 438, 642, 438, + 642, 438, 642, 438, 642, 434, 668, 1494, 642, 1518, 638, 442, + 638, 1520, 642, 438, 642, 438, 668, 414, 664, 408, 642, 438, + 668, 412, 642, 1520, 666, 1494, 642, 1514, 642, 1518, 642, 1520, + 636, 1520, 668, 1494, 666, 1494, 638, 438, 666, 414, 640, 440, + 666, 412, 668, 412, 668, 412, 642, 434, 668, 412, 668, 412, + 668, 1494, 642, 438, 642, 434, 642, 438, 642, 438, 642, 438, + 642, 438, 642, 434, 646, 434, 642, 1518, 668, 412, 642, 438, + 642, 434, 666, 414, 640, 438, 642, 438, 642, 1518, 642, 438, + 642, 434, 668, 412, 642, 438, 642, 438, 642, 438, 642, 438, + 642, 438, 640, 1520, 636, 438, 642, 438, 642, 438, 666, 414, + 668, 412, 642, 440, 640, 438, 640}; irsend.reset(); irsend.sendRaw(rawData2, 295, 38000); irsend.makeDecodeResult(); EXPECT_TRUE(irrecv.decode(&irsend.capture)); ASSERT_EQ(TOSHIBA_AC, irsend.capture.decode_type); - ASSERT_EQ(TOSHIBA_AC_BITS, irsend.capture.bits); + ASSERT_EQ(kToshibaACBits, irsend.capture.bits); toshiba.setRaw(irsend.capture.state); EXPECT_TRUE(toshiba.getPower()); EXPECT_EQ(17, toshiba.getTemp()); EXPECT_EQ(3, toshiba.getFan()); - EXPECT_EQ(TOSHIBA_AC_COOL, toshiba.getMode()); + EXPECT_EQ(kToshibaAcCool, toshiba.getMode()); uint16_t rawData3[295] = { - 4474, 4262, 642, 1514, 642, 1520, 642, 1520, 642, 1514, - 642, 438, 642, 438, 642, 1520, 636, 438, 642, 438, 642, 438, - 642, 438, 642, 438, 640, 1520, 638, 1520, 642, 438, 640, 1520, - 642, 438, 642, 434, 642, 438, 642, 438, 642, 438, 668, 414, - 636, 1520, 642, 1520, 642, 1514, 642, 1520, 642, 1520, 640, 1518, - 638, 1520, 666, 1494, 642, 438, 642, 434, 642, 438, 640, 438, - 642, 438, 642, 440, 640, 434, 642, 438, 642, 438, 642, 1520, - 642, 438, 642, 1514, 642, 1520, 640, 1520, 636, 438, 642, 438, - 642, 438, 666, 414, 642, 1520, 636, 1520, 642, 438, 642, 438, - 640, 438, 642, 434, 642, 1518, 642, 1520, 642, 438, 642, 434, - 640, 438, 642, 438, 642, 438, 642, 440, 642, 438, 668, 408, - 642, 1520, 642, 438, 642, 1520, 638, 1518, 642, 438, 642, 438, - 640, 1520, 640, 438, 642, 7362, 4474, 4262, 642, 1518, 638, 1520, - 640, 1520, 642, 1520, 638, 438, 642, 438, 642, 1518, 642, 438, - 638, 438, 642, 438, 642, 438, 642, 438, 642, 1514, 642, 1520, - 642, 438, 666, 1490, 642, 438, 642, 438, 642, 440, 640, 438, - 642, 434, 640, 438, 642, 1520, 642, 1520, 636, 1520, 642, 1520, - 642, 1514, 642, 1518, 642, 1518, 640, 1516, 642, 438, 642, 438, - 642, 438, 640, 438, 638, 442, 642, 434, 642, 440, 640, 438, - 642, 438, 642, 1518, 642, 438, 642, 1514, 642, 1520, 642, 1518, - 642, 438, 642, 432, 642, 438, 642, 438, 642, 1520, 642, 1514, - 642, 438, 642, 438, 642, 438, 642, 438, 642, 1514, 642, 1520, - 642, 438, 642, 438, 638, 438, 642, 438, 642, 438, 640, 440, - 642, 438, 640, 434, 642, 1520, 642, 438, 640, 1520, 668, 1490, - 666, 414, 640, 438, 642, 1520, 642, 438, 636}; + 4474, 4262, 642, 1514, 642, 1520, 642, 1520, 642, 1514, 642, 438, + 642, 438, 642, 1520, 636, 438, 642, 438, 642, 438, 642, 438, + 642, 438, 640, 1520, 638, 1520, 642, 438, 640, 1520, 642, 438, + 642, 434, 642, 438, 642, 438, 642, 438, 668, 414, 636, 1520, + 642, 1520, 642, 1514, 642, 1520, 642, 1520, 640, 1518, 638, 1520, + 666, 1494, 642, 438, 642, 434, 642, 438, 640, 438, 642, 438, + 642, 440, 640, 434, 642, 438, 642, 438, 642, 1520, 642, 438, + 642, 1514, 642, 1520, 640, 1520, 636, 438, 642, 438, 642, 438, + 666, 414, 642, 1520, 636, 1520, 642, 438, 642, 438, 640, 438, + 642, 434, 642, 1518, 642, 1520, 642, 438, 642, 434, 640, 438, + 642, 438, 642, 438, 642, 440, 642, 438, 668, 408, 642, 1520, + 642, 438, 642, 1520, 638, 1518, 642, 438, 642, 438, 640, 1520, + 640, 438, 642, 7362, 4474, 4262, 642, 1518, 638, 1520, 640, 1520, + 642, 1520, 638, 438, 642, 438, 642, 1518, 642, 438, 638, 438, + 642, 438, 642, 438, 642, 438, 642, 1514, 642, 1520, 642, 438, + 666, 1490, 642, 438, 642, 438, 642, 440, 640, 438, 642, 434, + 640, 438, 642, 1520, 642, 1520, 636, 1520, 642, 1520, 642, 1514, + 642, 1518, 642, 1518, 640, 1516, 642, 438, 642, 438, 642, 438, + 640, 438, 638, 442, 642, 434, 642, 440, 640, 438, 642, 438, + 642, 1518, 642, 438, 642, 1514, 642, 1520, 642, 1518, 642, 438, + 642, 432, 642, 438, 642, 438, 642, 1520, 642, 1514, 642, 438, + 642, 438, 642, 438, 642, 438, 642, 1514, 642, 1520, 642, 438, + 642, 438, 638, 438, 642, 438, 642, 438, 640, 440, 642, 438, + 640, 434, 642, 1520, 642, 438, 640, 1520, 668, 1490, 666, 414, + 640, 438, 642, 1520, 642, 438, 636}; irsend.reset(); irsend.sendRaw(rawData3, 295, 38000); irsend.makeDecodeResult(); EXPECT_TRUE(irrecv.decode(&irsend.capture)); ASSERT_EQ(TOSHIBA_AC, irsend.capture.decode_type); - ASSERT_EQ(TOSHIBA_AC_BITS, irsend.capture.bits); + ASSERT_EQ(kToshibaACBits, irsend.capture.bits); toshiba.setRaw(irsend.capture.state); EXPECT_TRUE(toshiba.getPower()); EXPECT_EQ(24, toshiba.getTemp()); - EXPECT_EQ(TOSHIBA_AC_FAN_MAX, toshiba.getFan()); - EXPECT_EQ(TOSHIBA_AC_HEAT, toshiba.getMode()); + EXPECT_EQ(kToshibaAcFanMax, toshiba.getFan()); + EXPECT_EQ(kToshibaAcHeat, toshiba.getMode()); uint16_t rawData4[295] = { - 4474, 4262, 636, 1520, 640, 1520, 640, 1520, 638, 1518, 642, 438, - 642, 438, 642, 1520, 636, 438, 642, 438, 642, 438, 642, 438, - 636, 444, 636, 1520, 640, 1520, 642, 438, 638, 1524, 638, 438, - 640, 438, 642, 438, 640, 438, 642, 438, 638, 438, 642, 1518, - 642, 1520, 666, 1494, 636, 1520, 640, 1520, 640, 1520, 636, 1524, - 638, 1520, 640, 440, 640, 438, 642, 438, 636, 444, 636, 438, - 642, 438, 640, 440, 640, 438, 642, 438, 642, 1518, 638, 438, - 642, 1518, 642, 438, 640, 1520, 636, 444, 636, 438, 640, 438, - 642, 438, 668, 1494, 640, 438, 642, 1518, 636, 444, 636, 438, - 640, 1520, 642, 1518, 642, 1520, 636, 444, 636, 438, 642, 438, - 642, 438, 640, 440, 640, 438, 640, 440, 640, 438, 640, 1518, - 642, 1520, 636, 1524, 636, 1518, 642, 438, 642, 1518, 642, 1518, - 640, 438, 642, 7364, 4472, 4262, 642, 1518, 642, 1518, 638, 1518, - 642, 1520, 642, 438, 642, 438, 640, 1520, 636, 440, 640, 438, - 642, 438, 640, 438, 642, 438, 642, 1518, 636, 1524, 636, 438, - 640, 1520, 642, 438, 642, 438, 640, 438, 636, 444, 636, 438, - 668, 412, 642, 1518, 642, 1520, 642, 1520, 636, 1518, 642, 1518, - 642, 1520, 636, 1520, 668, 1494, 642, 438, 636, 444, 664, 412, - 642, 438, 668, 412, 642, 438, 636, 442, 638, 442, 638, 438, - 642, 1518, 642, 438, 642, 1518, 638, 438, 642, 1518, 642, 440, - 640, 438, 636, 444, 636, 444, 636, 1520, 642, 438, 642, 1520, - 636, 444, 636, 438, 642, 1520, 640, 1520, 636, 1520, 668, 412, - 642, 438, 642, 438, 642, 438, 638, 442, 636, 438, 642, 438, - 668, 412, 640, 1520, 638, 1524, 636, 1520, 642, 1520, 636, 444, - 638, 1522, 638, 1518, 640, 438, 642}; + 4474, 4262, 636, 1520, 640, 1520, 640, 1520, 638, 1518, 642, 438, + 642, 438, 642, 1520, 636, 438, 642, 438, 642, 438, 642, 438, + 636, 444, 636, 1520, 640, 1520, 642, 438, 638, 1524, 638, 438, + 640, 438, 642, 438, 640, 438, 642, 438, 638, 438, 642, 1518, + 642, 1520, 666, 1494, 636, 1520, 640, 1520, 640, 1520, 636, 1524, + 638, 1520, 640, 440, 640, 438, 642, 438, 636, 444, 636, 438, + 642, 438, 640, 440, 640, 438, 642, 438, 642, 1518, 638, 438, + 642, 1518, 642, 438, 640, 1520, 636, 444, 636, 438, 640, 438, + 642, 438, 668, 1494, 640, 438, 642, 1518, 636, 444, 636, 438, + 640, 1520, 642, 1518, 642, 1520, 636, 444, 636, 438, 642, 438, + 642, 438, 640, 440, 640, 438, 640, 440, 640, 438, 640, 1518, + 642, 1520, 636, 1524, 636, 1518, 642, 438, 642, 1518, 642, 1518, + 640, 438, 642, 7364, 4472, 4262, 642, 1518, 642, 1518, 638, 1518, + 642, 1520, 642, 438, 642, 438, 640, 1520, 636, 440, 640, 438, + 642, 438, 640, 438, 642, 438, 642, 1518, 636, 1524, 636, 438, + 640, 1520, 642, 438, 642, 438, 640, 438, 636, 444, 636, 438, + 668, 412, 642, 1518, 642, 1520, 642, 1520, 636, 1518, 642, 1518, + 642, 1520, 636, 1520, 668, 1494, 642, 438, 636, 444, 664, 412, + 642, 438, 668, 412, 642, 438, 636, 442, 638, 442, 638, 438, + 642, 1518, 642, 438, 642, 1518, 638, 438, 642, 1518, 642, 440, + 640, 438, 636, 444, 636, 444, 636, 1520, 642, 438, 642, 1520, + 636, 444, 636, 438, 642, 1520, 640, 1520, 636, 1520, 668, 412, + 642, 438, 642, 438, 642, 438, 638, 442, 636, 438, 642, 438, + 668, 412, 640, 1520, 638, 1524, 636, 1520, 642, 1520, 636, 444, + 638, 1522, 638, 1518, 640, 438, 642}; - irsend.reset(); - irsend.sendRaw(rawData4, 295, 38000); - irsend.makeDecodeResult(); - EXPECT_TRUE(irrecv.decode(&irsend.capture)); - ASSERT_EQ(TOSHIBA_AC, irsend.capture.decode_type); - ASSERT_EQ(TOSHIBA_AC_BITS, irsend.capture.bits); - toshiba.setRaw(irsend.capture.state); - EXPECT_FALSE(toshiba.getPower()); - EXPECT_EQ(22, toshiba.getTemp()); - EXPECT_EQ(4, toshiba.getFan()); + irsend.reset(); + irsend.sendRaw(rawData4, 295, 38000); + irsend.makeDecodeResult(); + EXPECT_TRUE(irrecv.decode(&irsend.capture)); + ASSERT_EQ(TOSHIBA_AC, irsend.capture.decode_type); + ASSERT_EQ(kToshibaACBits, irsend.capture.bits); + toshiba.setRaw(irsend.capture.state); + EXPECT_FALSE(toshiba.getPower()); + EXPECT_EQ(22, toshiba.getTemp()); + EXPECT_EQ(4, toshiba.getFan()); - // Confirming the quirky behaviour that the 'Power OFF' signal - // sets the mode to heat. - // The previous state the remote was in was 'AUTO' just prior to - // sending the power off message. - EXPECT_EQ(TOSHIBA_AC_HEAT, toshiba.getMode()); + // Confirming the quirky behaviour that the 'Power OFF' signal + // sets the mode to heat. + // The previous state the remote was in was 'AUTO' just prior to + // sending the power off message. + EXPECT_EQ(kToshibaAcHeat, toshiba.getMode()); } diff --git a/lib/IRremoteESP8266/test/ir_Vestel_test.cpp b/lib/IRremoteESP8266/test/ir_Vestel_test.cpp new file mode 100644 index 0000000..b921bf8 --- /dev/null +++ b/lib/IRremoteESP8266/test/ir_Vestel_test.cpp @@ -0,0 +1,511 @@ +// Copyright 2019 David Conran + +#include "ir_Vestel.h" +#include "IRrecv.h" +#include "IRrecv_test.h" +#include "IRsend.h" +#include "IRsend_test.h" +#include "gtest/gtest.h" + +// Tests for sendVestelAC() + +// Test sending typical data only. +TEST(TestSendVestelAC, SendDataOnly) { + IRsendTest irsend(0); + irsend.begin(); + + irsend.reset(); + irsend.sendVestelAC(0x0F00D9001FEF201ULL); + EXPECT_EQ( + "m3110s9066" + "m520s1535m520s480m520s480m520s480m520s480m520s480m520s480m520s480" + "m520s480m520s1535m520s480m520s480m520s1535m520s1535m520s1535m520s1535" + "m520s480m520s1535m520s1535m520s1535m520s1535m520s1535m520s1535m520s1535" + "m520s1535m520s480m520s480m520s480m520s480m520s480m520s480m520s480" + "m520s480m520s480m520s480m520s480m520s1535m520s480m520s480m520s1535" + "m520s1535m520s480m520s1535m520s1535m520s480m520s480m520s480m520s480" + "m520s480m520s480m520s480m520s480m520s1535m520s1535m520s1535m520s1535" + "m520s100000", + irsend.outputStr()); +} + +// Test sending typical data with repeats. +TEST(TestSendVestelAC, SendWithRepeats) { + IRsendTest irsend(0); + irsend.begin(); + + irsend.reset(); + irsend.sendVestelAC(0x0F00D9001FEF201ULL, kVestelACBits, 2); // two repeats. + EXPECT_EQ( + "m3110s9066" + "m520s1535m520s480m520s480m520s480m520s480m520s480m520s480m520s480" + "m520s480m520s1535m520s480m520s480m520s1535m520s1535m520s1535m520s1535" + "m520s480m520s1535m520s1535m520s1535m520s1535m520s1535m520s1535m520s1535" + "m520s1535m520s480m520s480m520s480m520s480m520s480m520s480m520s480" + "m520s480m520s480m520s480m520s480m520s1535m520s480m520s480m520s1535" + "m520s1535m520s480m520s1535m520s1535m520s480m520s480m520s480m520s480" + "m520s480m520s480m520s480m520s480m520s1535m520s1535m520s1535m520s1535" + "m520s100000" + "m3110s9066" + "m520s1535m520s480m520s480m520s480m520s480m520s480m520s480m520s480" + "m520s480m520s1535m520s480m520s480m520s1535m520s1535m520s1535m520s1535" + "m520s480m520s1535m520s1535m520s1535m520s1535m520s1535m520s1535m520s1535" + "m520s1535m520s480m520s480m520s480m520s480m520s480m520s480m520s480" + "m520s480m520s480m520s480m520s480m520s1535m520s480m520s480m520s1535" + "m520s1535m520s480m520s1535m520s1535m520s480m520s480m520s480m520s480" + "m520s480m520s480m520s480m520s480m520s1535m520s1535m520s1535m520s1535" + "m520s100000" + "m3110s9066" + "m520s1535m520s480m520s480m520s480m520s480m520s480m520s480m520s480" + "m520s480m520s1535m520s480m520s480m520s1535m520s1535m520s1535m520s1535" + "m520s480m520s1535m520s1535m520s1535m520s1535m520s1535m520s1535m520s1535" + "m520s1535m520s480m520s480m520s480m520s480m520s480m520s480m520s480" + "m520s480m520s480m520s480m520s480m520s1535m520s480m520s480m520s1535" + "m520s1535m520s480m520s1535m520s1535m520s480m520s480m520s480m520s480" + "m520s480m520s480m520s480m520s480m520s1535m520s1535m520s1535m520s1535" + "m520s100000", + irsend.outputStr()); +} + +// Tests for IRVestelAC class. + +TEST(TestVestelACClass, Power) { + IRVestelAC ac(0); + ac.begin(); + + ac.setPower(true); + EXPECT_TRUE(ac.getPower()); + + ac.setPower(false); + EXPECT_EQ(false, ac.getPower()); + + ac.setPower(true); + EXPECT_TRUE(ac.getPower()); + + ac.off(); + EXPECT_EQ(false, ac.getPower()); + + ac.on(); + EXPECT_TRUE(ac.getPower()); + EXPECT_FALSE(ac.isTimeCommand()); +} + +TEST(TestVestelACClass, OperatingMode) { + IRVestelAC ac(0); + ac.begin(); + + ac.setMode(kVestelACAuto); + EXPECT_EQ(kVestelACAuto, ac.getMode()); + + ac.setMode(kVestelACCool); + EXPECT_EQ(kVestelACCool, ac.getMode()); + + ac.setMode(kVestelACHeat); + EXPECT_EQ(kVestelACHeat, ac.getMode()); + + ac.setMode(kVestelACFan); + EXPECT_EQ(kVestelACFan, ac.getMode()); + + ac.setMode(kVestelACDry); + EXPECT_EQ(kVestelACDry, ac.getMode()); + + ac.setMode(kVestelACAuto - 1); + EXPECT_EQ(kVestelACAuto, ac.getMode()); + + ac.setMode(kVestelACCool); + EXPECT_EQ(kVestelACCool, ac.getMode()); + + ac.setMode(kVestelACHeat + 1); + EXPECT_EQ(kVestelACAuto, ac.getMode()); + + ac.setMode(255); + EXPECT_EQ(kVestelACAuto, ac.getMode()); + EXPECT_FALSE(ac.isTimeCommand()); +} + +TEST(TestVestelACClass, Temperature) { + IRVestelAC ac(0); + ac.begin(); + + ac.setTemp(kVestelACMinTempC); + EXPECT_EQ(kVestelACMinTempC, ac.getTemp()); + + ac.setTemp(kVestelACMinTempC + 1); + EXPECT_EQ(kVestelACMinTempC + 1, ac.getTemp()); + + ac.setTemp(kVestelACMaxTemp); + EXPECT_EQ(kVestelACMaxTemp, ac.getTemp()); + + ac.setTemp(kVestelACMinTempC - 1); + EXPECT_EQ(kVestelACMinTempC, ac.getTemp()); + + ac.setTemp(kVestelACMaxTemp + 1); + EXPECT_EQ(kVestelACMaxTemp, ac.getTemp()); + + ac.setTemp(23); + EXPECT_EQ(23, ac.getTemp()); + + ac.setTemp(0); + EXPECT_EQ(kVestelACMinTempC, ac.getTemp()); + + ac.setTemp(255); + EXPECT_EQ(kVestelACMaxTemp, ac.getTemp()); + EXPECT_FALSE(ac.isTimeCommand()); +} + +TEST(TestVestelACClass, FanSpeed) { + IRVestelAC ac(0); + ac.begin(); + ac.setFan(kVestelACFanLow); + + ac.setFan(kVestelACFanAuto); + EXPECT_EQ(kVestelACFanAuto, ac.getFan()); + + ac.setFan(kVestelACFanLow); + EXPECT_EQ(kVestelACFanLow, ac.getFan()); + ac.setFan(kVestelACFanMed); + EXPECT_EQ(kVestelACFanMed, ac.getFan()); + ac.setFan(kVestelACFanHigh); + EXPECT_EQ(kVestelACFanHigh, ac.getFan()); + + ac.setFan(kVestelACFanHigh); + EXPECT_EQ(kVestelACFanHigh, ac.getFan()); + EXPECT_FALSE(ac.isTimeCommand()); +} + +TEST(TestVestelACClass, Swing) { + IRVestelAC ac(0); + ac.begin(); + + ac.setSwing(true); + EXPECT_TRUE(ac.getSwing()); + + ac.setSwing(false); + EXPECT_EQ(false, ac.getSwing()); + + ac.setSwing(true); + EXPECT_TRUE(ac.getSwing()); + EXPECT_FALSE(ac.isTimeCommand()); +} + +TEST(TestVestelACClass, Ion) { + IRVestelAC ac(0); + ac.begin(); + + ac.setIon(true); + EXPECT_TRUE(ac.getIon()); + + ac.setIon(false); + EXPECT_EQ(false, ac.getIon()); + + ac.setIon(true); + EXPECT_TRUE(ac.getIon()); + EXPECT_FALSE(ac.isTimeCommand()); +} + +TEST(TestVestelACClass, Turbo) { + IRVestelAC ac(0); + ac.begin(); + + ac.setTurbo(true); + EXPECT_TRUE(ac.getTurbo()); + + ac.setTurbo(false); + EXPECT_EQ(false, ac.getTurbo()); + + ac.setTurbo(true); + EXPECT_TRUE(ac.getTurbo()); + EXPECT_FALSE(ac.isTimeCommand()); +} + +TEST(TestVestelACClass, Sleep) { + IRVestelAC ac(0); + ac.begin(); + + ac.setSleep(true); + EXPECT_TRUE(ac.getSleep()); + + ac.setSleep(false); + EXPECT_EQ(false, ac.getSleep()); + + ac.setSleep(true); + EXPECT_TRUE(ac.getSleep()); + EXPECT_FALSE(ac.isTimeCommand()); +} + +TEST(TestVestelACClass, Time) { + IRVestelAC ac(0); + ac.begin(); + + ac.setTime(0); + EXPECT_EQ(0, ac.getTime()); + EXPECT_TRUE(ac.isTimeCommand()); + + ac.setTime(1); + EXPECT_EQ(1, ac.getTime()); + + ac.setTime(1234); + EXPECT_EQ(1234, ac.getTime()); + + ac.setTime(23 * 60 + 59); + EXPECT_EQ(23 * 60 + 59, ac.getTime()); +} + +TEST(TestVestelACClass, OnTimer) { + IRVestelAC ac(0); + ac.begin(); + + ac.setOnTimer(0); + EXPECT_EQ(0, ac.getOnTimer()); + EXPECT_TRUE(ac.isTimeCommand()); + + ac.setOnTimer(1); + EXPECT_EQ(0, ac.getOnTimer()); + + ac.setOnTimer(10); + EXPECT_EQ(10, ac.getOnTimer()); + + ac.setOnTimer(12 * 60 + 15); // we will round down to 10 min increments. + EXPECT_EQ(12 * 60 + 10, ac.getOnTimer()); + + ac.setOnTimer(23 * 60 + 50); + EXPECT_EQ(23 * 60 + 50, ac.getOnTimer()); +} + +TEST(TestVestelACClass, OffTimer) { + IRVestelAC ac(0); + ac.begin(); + + ac.setOffTimer(0); + EXPECT_EQ(0, ac.getOffTimer()); + EXPECT_TRUE(ac.isTimeCommand()); + + ac.setOffTimer(1); + EXPECT_EQ(0, ac.getOffTimer()); + + ac.setOffTimer(10); + EXPECT_EQ(10, ac.getOffTimer()); + + ac.setOffTimer(12 * 60 + 15); // we will round down to 10 min increments. + EXPECT_EQ(12 * 60 + 10, ac.getOffTimer()); + + ac.setOffTimer(23 * 60 + 50); + EXPECT_EQ(23 * 60 + 50, ac.getOffTimer()); +} + +TEST(TestVestelACClass, Timer) { + IRVestelAC ac(0); + ac.begin(); + + ac.setTimer(0); + EXPECT_EQ(0, ac.getTimer()); + EXPECT_EQ(0, ac.getOnTimer()); + EXPECT_TRUE(ac.isTimeCommand()); + + ac.setTimer(10); + EXPECT_EQ(10, ac.getTimer()); + EXPECT_EQ(0, ac.getOnTimer()); + + ac.setTimer(12 * 60 + 15); // we will round down to 10 min increments. + EXPECT_EQ(12 * 60 + 10, ac.getTimer()); + EXPECT_EQ(0, ac.getOnTimer()); + + ac.setTimer(23 * 60 + 50); + EXPECT_EQ(23 * 60 + 50, ac.getTimer()); + EXPECT_EQ(0, ac.getOnTimer()); +} + +TEST(TestVestelACClass, MessageConstuction) { + IRVestelAC ac(0); + + EXPECT_EQ( + "Power: On, Mode: 0 (AUTO), Temp: 25C, Fan: 13 (AUTO HOT), Sleep: Off, " + "Turbo: Off, Ion: Off, Swing: Off", + ac.toString()); + ac.setMode(kVestelACCool); + ac.setTemp(21); + ac.setFan(kVestelACFanHigh); + EXPECT_FALSE(ac.isTimeCommand()); + EXPECT_EQ( + "Power: On, Mode: 1 (COOL), Temp: 21C, Fan: 11 (HIGH), Sleep: Off, " + "Turbo: Off, Ion: Off, Swing: Off", + ac.toString()); + ac.setSwing(true); + ac.setIon(true); + ac.setTurbo(true); + EXPECT_FALSE(ac.isTimeCommand()); + EXPECT_EQ( + "Power: On, Mode: 1 (COOL), Temp: 21C, Fan: 11 (HIGH), Sleep: Off, " + "Turbo: On, Ion: On, Swing: On", + ac.toString()); + + // Now change a few already set things. + ac.setSleep(true); + ac.setMode(kVestelACHeat); + EXPECT_EQ( + "Power: On, Mode: 4 (HEAT), Temp: 21C, Fan: 11 (HIGH), Sleep: On, " + "Turbo: Off, Ion: On, Swing: On", + ac.toString()); + EXPECT_FALSE(ac.isTimeCommand()); + + ac.setTemp(25); + ac.setPower(false); + EXPECT_EQ( + "Power: Off, Mode: 4 (HEAT), Temp: 25C, Fan: 11 (HIGH), Sleep: On, " + "Turbo: Off, Ion: On, Swing: On", + ac.toString()); + EXPECT_FALSE(ac.isTimeCommand()); + + // Check that the checksum is valid. + EXPECT_TRUE(IRVestelAC::validChecksum(ac.getRaw())); + ac.setTime(23 * 60 + 59); + EXPECT_TRUE(ac.isTimeCommand()); + EXPECT_EQ( + "Time: 23:59, Timer: Off, On Timer: Off, Off Timer: Off", + ac.toString()); + ac.setTimer(8 * 60 + 0); + EXPECT_TRUE(ac.isTimeCommand()); + EXPECT_EQ( + "Time: 23:59, Timer: 8:00, On Timer: Off, Off Timer: Off", + ac.toString()); + ac.setOnTimer(7 * 60 + 40); + EXPECT_EQ( + "Time: 23:59, Timer: Off, On Timer: 7:40, Off Timer: Off", + ac.toString()); + ac.setOffTimer(17 * 60 + 10); + EXPECT_EQ( + "Time: 23:59, Timer: Off, On Timer: 7:40, Off Timer: 17:10", + ac.toString()); + ac.setTimer(8 * 60 + 0); + EXPECT_EQ( + "Time: 23:59, Timer: 8:00, On Timer: Off, Off Timer: Off", + ac.toString()); + ac.setTimer(0); + EXPECT_EQ( + "Time: 23:59, Timer: Off, On Timer: Off, Off Timer: Off", + ac.toString()); + ac.on(); + EXPECT_FALSE(ac.isTimeCommand()); + EXPECT_EQ( + "Power: On, Mode: 4 (HEAT), Temp: 25C, Fan: 11 (HIGH), Sleep: On, " + "Turbo: Off, Ion: On, Swing: On", + ac.toString()); +} + +// Tests for decodeVestelAC(). + +// Decode normal "synthetic" messages. +TEST(TestDecodeVestelAC, NormalDecodeWithStrict) { + IRsendTest irsend(0); + IRrecv irrecv(0); + irsend.begin(); + + // With the specific decoder. + uint64_t expectedState = 0x0F00D9001FEF201ULL; + irsend.reset(); + irsend.sendVestelAC(expectedState); + irsend.makeDecodeResult(); + ASSERT_TRUE(irrecv.decodeVestelAC(&irsend.capture, kVestelACBits, true)); + EXPECT_EQ(VESTEL_AC, irsend.capture.decode_type); + EXPECT_EQ(kVestelACBits, irsend.capture.bits); + EXPECT_FALSE(irsend.capture.repeat); + EXPECT_EQ(expectedState, irsend.capture.value); + EXPECT_EQ(0, irsend.capture.address); + EXPECT_EQ(0, irsend.capture.command); + + // With the all the decoders. + irsend.reset(); + irsend.sendVestelAC(expectedState); + irsend.makeDecodeResult(); + ASSERT_TRUE(irrecv.decode(&irsend.capture)); + EXPECT_EQ(VESTEL_AC, irsend.capture.decode_type); + EXPECT_EQ(kVestelACBits, irsend.capture.bits); + EXPECT_FALSE(irsend.capture.repeat); + EXPECT_EQ(expectedState, irsend.capture.value); + EXPECT_EQ(0, irsend.capture.address); + EXPECT_EQ(0, irsend.capture.command); + + IRVestelAC ac(0); + ac.begin(); + ac.setRaw(irsend.capture.value); + EXPECT_EQ( + "Power: On, Mode: 0 (AUTO), Temp: 25C, Fan: 13 (AUTO HOT), Sleep: Off, " + "Turbo: Off, Ion: Off, Swing: Off", + ac.toString()); +} + +// Decode a real message from Raw Data. +TEST(TestDecodeVestelAC, RealNormalExample) { + IRsendTest irsend(0); + IRrecv irrecv(0); + IRVestelAC ac(0); + irsend.begin(); + + uint16_t rawData[115] = { + 3098, 9080, 548, 1538, 526, 492, 526, 468, 524, 468, 526, 468, + 550, 466, 526, 466, 526, 504, 540, 466, 526, 1538, 526, 466, + 526, 466, 552, 1540, 522, 466, 526, 492, 526, 544, 526, 1536, + 526, 1536, 552, 1536, 526, 1536, 552, 1536, 552, 1536, 526, 1536, + 526, 1574, 542, 1536, 526, 492, 526, 466, 526, 494, 524, 468, + 524, 468, 526, 492, 526, 502, 540, 468, 524, 494, 524, 468, + 526, 468, 524, 468, 526, 492, 526, 468, 524, 520, 524, 1538, + 524, 468, 524, 468, 524, 468, 524, 468, 524, 468, 524, 1538, + 524, 506, 538, 468, 524, 468, 524, 1538, 524, 468, 550, 1538, + 550, 1538, 524, 1538, 534, 1528, 544}; // VESTEL_AC + irsend.reset(); + irsend.sendRaw(rawData, 115, 38); + irsend.makeDecodeResult(); + ASSERT_TRUE(irrecv.decode(&irsend.capture)); + EXPECT_EQ(VESTEL_AC, irsend.capture.decode_type); + EXPECT_EQ(kVestelACBits, irsend.capture.bits); + EXPECT_FALSE(irsend.capture.repeat); + EXPECT_EQ(0xF4410001FF1201ULL, irsend.capture.value); + EXPECT_EQ(0, irsend.capture.address); + EXPECT_EQ(0, irsend.capture.command); + ac.begin(); + ac.setRaw(irsend.capture.value); + EXPECT_EQ( + "Power: On, Mode: 4 (HEAT), Temp: 16C, Fan: 1 (AUTO), Sleep: Off, " + "Turbo: Off, Ion: On, Swing: Off", + ac.toString()); +} + +TEST(TestDecodeVestelAC, RealTimerExample) { + IRsendTest irsend(0); + IRrecv irrecv(0); + IRVestelAC ac(0); + irsend.begin(); + + uint16_t rawData[115] = { + 3022, 9080, 546, 1536, 526, 466, 526, 492, 526, 468, 526, 492, + 524, 468, 524, 494, 524, 504, 540, 492, 524, 1538, 526, 468, + 524, 492, 526, 466, 552, 1536, 526, 1536, 526, 1570, 542, 492, + 524, 1538, 550, 1538, 524, 1536, 526, 494, 524, 466, 526, 468, + 524, 1574, 540, 1536, 550, 1536, 526, 468, 550, 1536, 526, 492, + 526, 468, 524, 492, 526, 518, 526, 1536, 552, 1536, 550, 1536, + 526, 494, 550, 1538, 526, 492, 524, 1538, 526, 504, 540, 466, + 526, 1536, 526, 1536, 526, 468, 550, 1538, 524, 468, 524, 1538, + 550, 1574, 540, 468, 550, 1538, 526, 492, 524, 468, 526, 466, + 526, 468, 524, 494, 524, 468, 546}; // VESTEL_AC 2D6570B8EE201 + irsend.reset(); + irsend.sendRaw(rawData, 115, 38); + irsend.makeDecodeResult(); + ASSERT_TRUE(irrecv.decode(&irsend.capture)); + EXPECT_EQ(VESTEL_AC, irsend.capture.decode_type); + EXPECT_EQ(kVestelACBits, irsend.capture.bits); + EXPECT_FALSE(irsend.capture.repeat); + EXPECT_EQ(0x2D6570B8EE201ULL, irsend.capture.value); + EXPECT_EQ(0, irsend.capture.address); + EXPECT_EQ(0, irsend.capture.command); + ac.begin(); + ac.setRaw(irsend.capture.value); + EXPECT_EQ( + "Time: 5:45, Timer: Off, On Timer: 14:00, Off Timer: 23:00", + ac.toString()); +} + +// General housekeeping +TEST(TestDecodeVestelAC, Housekeeping) { + ASSERT_EQ("VESTEL_AC", typeToString(VESTEL_AC)); + ASSERT_FALSE(hasACState(VESTEL_AC)); // Uses uint64_t, not uint8_t*. +} diff --git a/lib/IRremoteESP8266/test/ir_Whirlpool_test.cpp b/lib/IRremoteESP8266/test/ir_Whirlpool_test.cpp new file mode 100644 index 0000000..f0c4ebe --- /dev/null +++ b/lib/IRremoteESP8266/test/ir_Whirlpool_test.cpp @@ -0,0 +1,584 @@ +// Copyright 2018 David Conran + +#include "ir_Whirlpool.h" +#include "IRrecv.h" +#include "IRrecv_test.h" +#include "IRsend.h" +#include "IRsend_test.h" +#include "gtest/gtest.h" + +// Tests for sendWhirlpoolAC(). + +// Test sending typical data only. +TEST(TestSendWhirlpoolAC, SendDataOnly) { + IRsendTest irsend(0); + irsend.begin(); + uint8_t data[kWhirlpoolAcStateLength] = { + 0x83, 0x06, 0x10, 0x71, 0x00, 0x00, 0x91, 0x1F, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xEF, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02}; + + irsend.sendWhirlpoolAC(data); + EXPECT_EQ( + "m8950s4484" + "m597s1649m597s1649m597s533m597s533m597s533m597s533m597s533m597s1649" + "m597s533m597s1649m597s1649m597s533m597s533m597s533m597s533m597s533" + "m597s533m597s533m597s533m597s533m597s1649m597s533m597s533m597s533" + "m597s1649m597s533m597s533m597s533m597s1649m597s1649m597s1649m597s533" + "m597s533m597s533m597s533m597s533m597s533m597s533m597s533m597s533" + "m597s533m597s533m597s533m597s533m597s533m597s533m597s533m597s533" + "m597s7920" + "m597s1649m597s533m597s533m597s533m597s1649m597s533m597s533m597s1649" + "m597s1649m597s1649m597s1649m597s1649m597s1649m597s533m597s533m597s533" + "m597s533m597s533m597s533m597s533m597s533m597s533m597s533m597s533" + "m597s533m597s533m597s533m597s533m597s533m597s533m597s533m597s533" + "m597s533m597s533m597s533m597s533m597s533m597s533m597s533m597s533" + "m597s533m597s533m597s533m597s533m597s533m597s533m597s533m597s533" + "m597s533m597s533m597s533m597s533m597s533m597s533m597s533m597s533" + "m597s1649m597s1649m597s1649m597s1649m597s533m597s1649m597s1649m597s1649" + "m597s7920" + "m597s533m597s533m597s533m597s533m597s533m597s533m597s533m597s533" + "m597s533m597s1649m597s533m597s533m597s533m597s533m597s533m597s533" + "m597s533m597s533m597s533m597s533m597s533m597s533m597s533m597s533" + "m597s533m597s533m597s533m597s533m597s533m597s533m597s533m597s533" + "m597s533m597s533m597s533m597s533m597s533m597s533m597s533m597s533" + "m597s533m597s533m597s533m597s533m597s533m597s533m597s533m597s533" + "m597s533m597s1649m597s533m597s533m597s533m597s533m597s533m597s533" + "m597s100000", + irsend.outputStr()); +} + +// Tests for decodeWhirlpoolAC(). +// Decode normal WhirlpoolAC messages. +TEST(TestDecodeWhirlpoolAC, SyntheticDecode) { + IRsendTest irsend(0); + IRrecv irrecv(0); + irsend.begin(); + + // Synthesised Normal WhirlpoolAC message. + irsend.reset(); + uint8_t expectedState[kWhirlpoolAcStateLength] = { + 0x83, 0x06, 0x10, 0x71, 0x00, 0x00, 0x91, 0x1F, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xEF, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02}; + irsend.sendWhirlpoolAC(expectedState); + irsend.makeDecodeResult(); + EXPECT_TRUE(irrecv.decode(&irsend.capture)); + EXPECT_EQ(WHIRLPOOL_AC, irsend.capture.decode_type); + EXPECT_EQ(kWhirlpoolAcBits, irsend.capture.bits); + EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); + IRWhirlpoolAc ac(0); + ac.setRaw(irsend.capture.state); + EXPECT_EQ( + "Model: 1 (DG11J13A), Power toggle: Off, Mode: 1 (AUTO), Temp: 25C, " + "Fan: 0 (AUTO), Swing: Off, Light: On, Clock: 17:31, On Timer: Off, " + "Off Timer: Off, Sleep: Off, Super: Off, Command: 2 (TEMP)", + ac.toString()); +} + +TEST(TestDecodeWhirlpoolAC, Real26CFanAutoCoolingSwingOnClock1918) { + IRsendTest irsend(0); + IRrecv irrecv(0); + irsend.begin(); + + irsend.reset(); + uint8_t expectedState[kWhirlpoolAcStateLength] = { + 0x83, 0x06, 0x80, 0x82, 0x00, 0x00, 0x93, 0x12, 0x40, 0x00, 0x00, + 0x00, 0x00, 0xC3, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x07}; + irsend.sendWhirlpoolAC(expectedState); + irsend.makeDecodeResult(); + EXPECT_TRUE(irrecv.decode(&irsend.capture)); + EXPECT_EQ(WHIRLPOOL_AC, irsend.capture.decode_type); + EXPECT_EQ(kWhirlpoolAcBits, irsend.capture.bits); + EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); + IRWhirlpoolAc ac(0); + ac.setRaw(irsend.capture.state); + EXPECT_EQ( + "Model: 1 (DG11J13A), Power toggle: Off, Mode: 2 (COOL), Temp: 26C, " + "Fan: 0 (AUTO), Swing: On, Light: On, Clock: 19:18, On Timer: Off, " + "Off Timer: Off, Sleep: Off, Super: Off, Command: 7 (SWING)", + ac.toString()); +} + +TEST(TestDecodeWhirlpoolAC, RealTimerExample) { + IRsendTest irsend(0); + IRrecv irrecv(0); + irsend.begin(); + + irsend.reset(); + // Dehumidify timer on 7:40 off 8:05 + uint16_t rawData[343] = { + 9092, 4556, 604, 1664, 604, 1674, 630, 514, 630, 518, 628, 522, + 604, 550, 628, 530, 602, 1680, 630, 508, 630, 1644, 604, 1674, + 604, 544, 604, 548, 630, 524, 604, 554, 620, 530, 630, 506, + 602, 538, 602, 542, 604, 542, 604, 546, 630, 524, 602, 556, + 628, 518, 604, 1666, 632, 1644, 604, 540, 602, 546, 604, 1680, + 604, 1684, 604, 1686, 630, 520, 602, 534, 606, 538, 602, 540, + 604, 544, 604, 548, 602, 552, 630, 528, 602, 546, 602, 536, + 628, 510, 606, 540, 604, 544, 630, 522, 604, 554, 600, 554, + 602, 528, 602, 8032, 604, 1666, 604, 1668, 602, 1676, 630, 518, + 630, 520, 602, 550, 604, 554, 604, 1678, 630, 1640, 602, 1672, + 602, 542, 602, 544, 628, 522, 630, 1658, 604, 554, 628, 1652, + 630, 508, 602, 538, 630, 514, 630, 1652, 602, 546, 604, 550, + 602, 554, 602, 546, 630, 1638, 604, 536, 630, 1646, 602, 544, + 628, 522, 632, 524, 628, 528, 602, 1686, 594, 1666, 604, 1670, + 602, 1674, 632, 516, 604, 546, 638, 518, 622, 534, 628, 518, + 604, 532, 604, 536, 600, 550, 622, 1652, 630, 520, 602, 1684, + 602, 554, 602, 544, 630, 506, 628, 512, 602, 540, 628, 518, + 602, 550, 602, 552, 604, 554, 602, 544, 628, 1642, 602, 536, + 632, 1646, 630, 516, 602, 1680, 630, 1656, 604, 1688, 602, 1660, + 602, 8030, 604, 532, 604, 536, 604, 540, 602, 544, 628, 522, + 602, 552, 602, 556, 602, 544, 602, 1666, 630, 510, 602, 1674, + 604, 544, 628, 522, 602, 552, 630, 526, 628, 520, 602, 534, + 630, 510, 604, 540, 602, 544, 606, 544, 604, 550, 604, 554, + 602, 544, 604, 534, 602, 538, 602, 542, 604, 542, 604, 546, + 604, 550, 632, 526, 604, 544, 630, 506, 604, 536, 604, 540, + 628, 518, 602, 548, 604, 550, 604, 552, 630, 516, 602, 534, + 604, 536, 630, 512, 604, 544, 602, 548, 630, 524, 602, 554, + 602, 542, 604, 1666, 606, 532, 630, 1644, 602, 544, 630, 520, + 604, 550, 604, 554, 602, 526, 598}; + uint8_t expectedState[kWhirlpoolAcStateLength] = { + 0x83, 0x06, 0x00, 0x73, 0x00, 0x00, 0x87, 0xA3, 0x08, 0x85, 0x07, + 0x28, 0x00, 0xF5, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x05}; + irsend.sendRaw(rawData, 343, 38000); + irsend.makeDecodeResult(); + EXPECT_TRUE(irrecv.decode(&irsend.capture)); + EXPECT_EQ(WHIRLPOOL_AC, irsend.capture.decode_type); + EXPECT_EQ(kWhirlpoolAcBits, irsend.capture.bits); + EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); + IRWhirlpoolAc ac(0); + ac.setRaw(irsend.capture.state); + EXPECT_EQ( + "Model: 1 (DG11J13A), Power toggle: Off, Mode: 3 (DRY), Temp: 25C, " + "Fan: 0 (AUTO), Swing: Off, Light: On, Clock: 07:35, On Timer: 07:40, " + "Off Timer: 08:05, Sleep: Off, Super: Off, Command: 5 (ONTIMER)", + ac.toString()); +} + +// Decode a recorded example +TEST(TestDecodeWhirlpoolAC, RealExampleDecode) { + IRsendTest irsend(0); + IRrecv irrecv(0); + irsend.begin(); + + // Real WhirlpoolAC message. + // Ref: https://github.com/markszabo/IRremoteESP8266/issues/509 + uint16_t rawData[343] = { + 8950, 4484, 598, 1642, 598, 1646, 594, 534, 594, 538, 602, 532, + 598, 540, 600, 542, 598, 1650, 600, 522, 598, 1644, 596, 1650, + 600, 532, 598, 538, 602, 536, 594, 548, 592, 538, 602, 518, + 600, 524, 596, 532, 598, 532, 598, 1654, 596, 544, 596, 544, + 596, 536, 594, 1644, 596, 528, 600, 528, 592, 538, 602, 1648, + 602, 1654, 596, 1664, 598, 534, 594, 526, 594, 530, 598, 528, + 602, 530, 600, 534, 596, 542, 598, 542, 598, 534, 596, 526, + 594, 530, 600, 528, 602, 530, 600, 534, 596, 542, 598, 544, + 596, 518, 602, 7916, 598, 1642, 598, 528, 600, 528, 602, 530, + 600, 1652, 598, 542, 598, 544, 596, 1654, 596, 1644, 596, 1648, + 602, 1644, 596, 1654, 596, 1656, 604, 536, 594, 548, 602, 528, + 600, 520, 600, 524, 596, 532, 598, 532, 596, 538, 602, 536, + 594, 546, 594, 538, 602, 518, 600, 524, 596, 532, 598, 532, + 598, 536, 594, 544, 596, 544, 596, 536, 594, 526, 592, 530, + 600, 528, 600, 530, 602, 532, 596, 542, 598, 542, 598, 534, + 596, 524, 596, 528, 600, 526, 592, 538, 592, 542, 598, 540, + 600, 540, 600, 530, 598, 522, 598, 526, 594, 534, 596, 534, + 594, 540, 602, 536, 592, 548, 592, 538, 600, 1636, 594, 1648, + 602, 1642, 598, 1652, 598, 538, 602, 1680, 570, 1662, 598, 1634, + 596, 7924, 600, 520, 598, 526, 592, 534, 596, 534, 596, 540, + 600, 536, 604, 538, 602, 530, 600, 520, 598, 1640, 600, 528, + 600, 530, 600, 534, 594, 544, 596, 544, 596, 534, 596, 526, + 594, 528, 600, 526, 594, 536, 592, 542, 598, 538, 602, 538, + 602, 528, 600, 520, 600, 524, 596, 530, 600, 532, 598, 534, + 596, 542, 598, 542, 598, 532, 598, 524, 596, 528, 602, 526, + 594, 536, 594, 540, 600, 536, 594, 548, 592, 538, 602, 518, + 602, 522, 596, 530, 600, 530, 600, 534, 596, 542, 598, 544, + 596, 534, 596, 524, 594, 1644, 596, 532, 596, 534, 596, 538, + 602, 536, 594, 546, 594, 520, 600}; + uint8_t expectedState[kWhirlpoolAcStateLength] = { + 0x83, 0x06, 0x10, 0x71, 0x00, 0x00, 0x91, 0x1F, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xEF, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02}; + + irsend.reset(); + irsend.sendRaw(rawData, 343, 38000); + irsend.makeDecodeResult(); + EXPECT_TRUE(irrecv.decode(&irsend.capture)); + EXPECT_EQ(WHIRLPOOL_AC, irsend.capture.decode_type); + EXPECT_EQ(kWhirlpoolAcBits, irsend.capture.bits); + EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); + IRWhirlpoolAc ac(0); + ac.setRaw(irsend.capture.state); + EXPECT_EQ( + "Model: 1 (DG11J13A), Power toggle: Off, Mode: 1 (AUTO), Temp: 25C, " + "Fan: 0 (AUTO), Swing: Off, Light: On, Clock: 17:31, On Timer: Off, " + "Off Timer: Off, Sleep: Off, Super: Off, Command: 2 (TEMP)", + ac.toString()); +} + +// Tests for IRWhirlpoolAc class. + +TEST(TestIRWhirlpoolAcClass, SetAndGetRaw) { + uint8_t expectedState[kWhirlpoolAcStateLength] = { + 0x83, 0x06, 0x10, 0x71, 0x00, 0x00, 0x91, 0x1F, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xEF, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02}; + IRWhirlpoolAc ac(0); + ac.setRaw(expectedState); + EXPECT_STATE_EQ(expectedState, ac.getRaw(), kWhirlpoolAcBits); +} + +TEST(TestIRWhirlpoolAcClass, SetAndGetTemp) { + IRWhirlpoolAc ac(0); + ac.setCommand(0); // Clear the previous command. + + ac.setModel(DG11J13A); + ac.setTemp(25); + EXPECT_EQ(25, ac.getTemp()); + EXPECT_EQ(kWhirlpoolAcCommandTemp, ac.getCommand()); + ac.setTemp(kWhirlpoolAcMinTemp); + EXPECT_EQ(kWhirlpoolAcMinTemp, ac.getTemp()); + ac.setTemp(kWhirlpoolAcMinTemp - 1); + EXPECT_EQ(kWhirlpoolAcMinTemp, ac.getTemp()); + ac.setTemp(kWhirlpoolAcMaxTemp); + EXPECT_EQ(kWhirlpoolAcMaxTemp, ac.getTemp()); + ac.setTemp(kWhirlpoolAcMaxTemp + 1); + EXPECT_EQ(kWhirlpoolAcMaxTemp, ac.getTemp()); + + ac.setModel(DG11J191); // Has a -2 offset on min/max temps. + ac.setTemp(25); + EXPECT_EQ(25, ac.getTemp()); + EXPECT_EQ(kWhirlpoolAcCommandTemp, ac.getCommand()); + ac.setTemp(kWhirlpoolAcMinTemp - 2); + EXPECT_EQ(kWhirlpoolAcMinTemp - 2, ac.getTemp()); + ac.setTemp(kWhirlpoolAcMinTemp - 2 - 1); + EXPECT_EQ(kWhirlpoolAcMinTemp - 2 , ac.getTemp()); + ac.setTemp(kWhirlpoolAcMaxTemp - 2); + EXPECT_EQ(kWhirlpoolAcMaxTemp - 2, ac.getTemp()); + ac.setTemp(kWhirlpoolAcMaxTemp - 2 + 1); + EXPECT_EQ(kWhirlpoolAcMaxTemp - 2, ac.getTemp()); +} + +TEST(TestIRWhirlpoolAcClass, SetAndGetMode) { + IRWhirlpoolAc ac(0); + ac.setCommand(0); // Clear the previous command. + + ac.setMode(kWhirlpoolAcCool); + EXPECT_EQ(kWhirlpoolAcCool, ac.getMode()); + EXPECT_EQ(kWhirlpoolAcCommandMode, ac.getCommand()); + ac.setMode(kWhirlpoolAcHeat); + EXPECT_EQ(kWhirlpoolAcHeat, ac.getMode()); + ac.setMode(kWhirlpoolAcAuto); + EXPECT_EQ(kWhirlpoolAcAuto, ac.getMode()); + EXPECT_EQ(kWhirlpoolAcCommand6thSense, ac.getCommand()); + ac.setMode(kWhirlpoolAcDry); + EXPECT_EQ(kWhirlpoolAcDry, ac.getMode()); + EXPECT_EQ(kWhirlpoolAcCommandMode, ac.getCommand()); +} + +TEST(TestIRWhirlpoolAcClass, SetAndGetFan) { + IRWhirlpoolAc ac(0); + ac.setCommand(0); // Clear the previous command. + + ac.setFan(kWhirlpoolAcFanAuto); + EXPECT_EQ(kWhirlpoolAcFanAuto, ac.getFan()); + EXPECT_EQ(kWhirlpoolAcCommandFanSpeed, ac.getCommand()); + ac.setFan(kWhirlpoolAcFanLow); + EXPECT_EQ(kWhirlpoolAcFanLow, ac.getFan()); + ac.setFan(kWhirlpoolAcFanMedium); + EXPECT_EQ(kWhirlpoolAcFanMedium, ac.getFan()); + ac.setFan(kWhirlpoolAcFanHigh); + EXPECT_EQ(kWhirlpoolAcFanHigh, ac.getFan()); + ac.setFan(kWhirlpoolAcFanAuto); + EXPECT_EQ(kWhirlpoolAcFanAuto, ac.getFan()); + + // Known state with a non-auto fan mode. + const uint8_t state[21] = {0x83, 0x06, 0x0B, 0x82, 0x00, 0x00, 0x93, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, + 0x00, 0x03, 0x00, 0x00, 0x08, 0x00, 0x0B}; + ac.setRaw(state); + EXPECT_EQ(kWhirlpoolAcFanLow, ac.getFan()); +} + +TEST(TestIRWhirlpoolAcClass, SetAndGetSwing) { + IRWhirlpoolAc ac(0); + ac.setCommand(0); // Clear the previous command. + + ac.setSwing(true); + EXPECT_TRUE(ac.getSwing()); + EXPECT_EQ(kWhirlpoolAcCommandSwing, ac.getCommand()); + ac.setSwing(false); + EXPECT_FALSE(ac.getSwing()); + ac.setSwing(true); + EXPECT_TRUE(ac.getSwing()); +} + +TEST(TestIRWhirlpoolAcClass, SetAndGetLight) { + IRWhirlpoolAc ac(0); + ac.setCommand(0); // Clear the previous command. + + ac.setLight(true); + EXPECT_TRUE(ac.getLight()); + ac.setLight(false); + EXPECT_FALSE(ac.getLight()); + ac.setLight(true); + EXPECT_TRUE(ac.getLight()); +} + +TEST(TestIRWhirlpoolAcClass, SetAndGetClock) { + IRWhirlpoolAc ac(0); + ac.setClock(0); + EXPECT_EQ(0, ac.getClock()); + EXPECT_EQ("00:00", ac.timeToString(ac.getClock())); + ac.setClock(1); + EXPECT_EQ(1, ac.getClock()); + EXPECT_EQ("00:01", ac.timeToString(ac.getClock())); + ac.setClock(12 * 60 + 34); + EXPECT_EQ(12 * 60 + 34, ac.getClock()); + EXPECT_EQ("12:34", ac.timeToString(ac.getClock())); + ac.setClock(7 * 60 + 5); + EXPECT_EQ(7 * 60 + 5, ac.getClock()); + EXPECT_EQ("07:05", ac.timeToString(ac.getClock())); + ac.setClock(23 * 60 + 59); + EXPECT_EQ(23 * 60 + 59, ac.getClock()); + EXPECT_EQ("23:59", ac.timeToString(ac.getClock())); + ac.setClock(24 * 60 + 0); + EXPECT_EQ(0, ac.getClock()); + EXPECT_EQ("00:00", ac.timeToString(ac.getClock())); + ac.setClock(25 * 60 + 23); + EXPECT_EQ(1 * 60 + 23, ac.getClock()); + EXPECT_EQ("01:23", ac.timeToString(ac.getClock())); +} + +TEST(TestIRWhirlpoolAcClass, OnOffTimers) { + IRWhirlpoolAc ac(0); + ac.setCommand(0); // Clear the previous command. + + // On Timer + ac.enableOnTimer(false); + ac.setOnTimer(0); + EXPECT_EQ(0, ac.getOnTimer()); + EXPECT_EQ("00:00", ac.timeToString(ac.getOnTimer())); + EXPECT_FALSE(ac.isOnTimerEnabled()); + EXPECT_EQ(kWhirlpoolAcCommandOnTimer, ac.getCommand()); + ac.setOnTimer(1); + EXPECT_EQ(1, ac.getOnTimer()); + EXPECT_EQ("00:01", ac.timeToString(ac.getOnTimer())); + ac.enableOnTimer(true); + ac.setOnTimer(12 * 60 + 34); + EXPECT_EQ(12 * 60 + 34, ac.getOnTimer()); + EXPECT_EQ("12:34", ac.timeToString(ac.getOnTimer())); + EXPECT_TRUE(ac.isOnTimerEnabled()); + ac.setOnTimer(7 * 60 + 5); + EXPECT_EQ(7 * 60 + 5, ac.getOnTimer()); + EXPECT_EQ("07:05", ac.timeToString(ac.getOnTimer())); + ac.setOnTimer(23 * 60 + 59); + EXPECT_EQ(23 * 60 + 59, ac.getOnTimer()); + EXPECT_EQ("23:59", ac.timeToString(ac.getOnTimer())); + ac.setOnTimer(24 * 60 + 0); + EXPECT_EQ(0, ac.getOnTimer()); + EXPECT_EQ("00:00", ac.timeToString(ac.getOnTimer())); + ac.setOnTimer(25 * 60 + 23); + EXPECT_EQ(1 * 60 + 23, ac.getOnTimer()); + EXPECT_EQ("01:23", ac.timeToString(ac.getOnTimer())); + // Off Timer + ac.enableOffTimer(false); + ac.setOffTimer(0); + EXPECT_EQ(0, ac.getOffTimer()); + EXPECT_EQ("00:00", ac.timeToString(ac.getOffTimer())); + EXPECT_FALSE(ac.isOffTimerEnabled()); + EXPECT_EQ(kWhirlpoolAcCommandOffTimer, ac.getCommand()); + ac.setOffTimer(1); + EXPECT_EQ(1, ac.getOffTimer()); + EXPECT_EQ("00:01", ac.timeToString(ac.getOffTimer())); + ac.enableOffTimer(true); + ac.setOffTimer(12 * 60 + 34); + EXPECT_EQ(12 * 60 + 34, ac.getOffTimer()); + EXPECT_EQ("12:34", ac.timeToString(ac.getOffTimer())); + EXPECT_TRUE(ac.isOffTimerEnabled()); + ac.setOffTimer(7 * 60 + 5); + EXPECT_EQ(7 * 60 + 5, ac.getOffTimer()); + EXPECT_EQ("07:05", ac.timeToString(ac.getOffTimer())); + ac.setOffTimer(23 * 60 + 59); + EXPECT_EQ(23 * 60 + 59, ac.getOffTimer()); + EXPECT_EQ("23:59", ac.timeToString(ac.getOffTimer())); + ac.setOffTimer(24 * 60 + 0); + EXPECT_EQ(0, ac.getOffTimer()); + EXPECT_EQ("00:00", ac.timeToString(ac.getOffTimer())); + ac.setOffTimer(25 * 60 + 23); + EXPECT_EQ(1 * 60 + 23, ac.getOffTimer()); + EXPECT_EQ("01:23", ac.timeToString(ac.getOffTimer())); +} + +TEST(TestIRWhirlpoolAcClass, SetAndGetCommand) { + IRWhirlpoolAc ac(0); + ac.setCommand(0); + EXPECT_EQ(0, ac.getCommand()); + ac.setCommand(kWhirlpoolAcCommandFanSpeed); + EXPECT_EQ(kWhirlpoolAcCommandFanSpeed, ac.getCommand()); + ac.setCommand(255); + EXPECT_EQ(255, ac.getCommand()); +} + +TEST(TestIRWhirlpoolAcClass, SetAndGetPowerToggle) { + IRWhirlpoolAc ac(0); + ac.setCommand(0); + + ac.setPowerToggle(false); + EXPECT_FALSE(ac.getPowerToggle()); + ac.setPowerToggle(true); + EXPECT_TRUE(ac.getPowerToggle()); + ac.setPowerToggle(false); + EXPECT_FALSE(ac.getPowerToggle()); + + // Known state with a power toggle in it. + uint8_t state[21] = {0x83, 0x06, 0x07, 0x82, 0x00, 0x00, 0x93, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, + 0x00, 0x01, 0x00, 0x00, 0x08, 0x00, 0x09}; + ac.setRaw(state); + EXPECT_TRUE(ac.getPowerToggle()); +} + +TEST(TestIRWhirlpoolAcClass, SetAndGetModel) { + IRWhirlpoolAc ac(0); + ac.setTemp(19); + ac.setCommand(0); // Set model shouldn't change the command setting. + + ac.setModel(DG11J191); + EXPECT_EQ(DG11J191, ac.getModel()); + EXPECT_EQ(19, ac.getTemp()); + EXPECT_EQ(0, ac.getCommand()); + ac.setModel(DG11J13A); + EXPECT_EQ(DG11J13A, ac.getModel()); + EXPECT_EQ(19, ac.getTemp()); + ac.setModel(DG11J191); + EXPECT_EQ(DG11J191, ac.getModel()); + EXPECT_EQ(19, ac.getTemp()); + EXPECT_EQ(0, ac.getCommand()); + + // One of the models has a lower min temp. Check that desired temp is kept. + ac.setTemp(16); + ac.setCommand(0); // Set model shouldn't change the command setting. + EXPECT_EQ(16, ac.getTemp()); + EXPECT_EQ(0, ac.getCommand()); + ac.setModel(DG11J13A); + EXPECT_EQ(DG11J13A, ac.getModel()); + EXPECT_EQ(18, ac.getTemp()); + ac.setModel(DG11J191); + EXPECT_EQ(DG11J191, ac.getModel()); + EXPECT_EQ(16, ac.getTemp()); + EXPECT_EQ(0, ac.getCommand()); + + // Known states with different models. + uint8_t state_1[21] = {0x83, 0x06, 0x01, 0x30, 0x00, 0x00, 0x92, + 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x95, + 0x00, 0x02, 0x00, 0x00, 0x08, 0x00, 0x0A}; + uint8_t state_2[21] = {0x83, 0x06, 0x00, 0x30, 0x00, 0x00, 0x8B, + 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8E, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02}; + + ac.setRaw(state_1); + EXPECT_EQ(DG11J191, ac.getModel()); + ac.setRaw(state_2); + EXPECT_EQ(DG11J13A, ac.getModel()); +} + +TEST(TestIRWhirlpoolAcClass, SetAndGetSleep) { + IRWhirlpoolAc ac(0); + ac.setFan(kWhirlpoolAcFanAuto); + ac.setCommand(0); + + ac.setSleep(false); + EXPECT_FALSE(ac.getSleep()); + EXPECT_EQ(kWhirlpoolAcCommandSleep, ac.getCommand()); + ac.setSleep(true); + EXPECT_TRUE(ac.getSleep()); + EXPECT_EQ(kWhirlpoolAcCommandSleep, ac.getCommand()); + EXPECT_EQ(kWhirlpoolAcFanLow, ac.getFan()); + ac.setSleep(false); + EXPECT_FALSE(ac.getSleep()); + + // Known state with sleep mode in it. + uint8_t state[21] = {0x83, 0x06, 0x0B, 0x73, 0x00, 0x00, 0x90, + 0x9E, 0x00, 0xA0, 0x17, 0x3A, 0x00, 0xFB, + 0x00, 0x03, 0x00, 0x00, 0x08, 0x00, 0x0B}; + ac.setRaw(state); + EXPECT_TRUE(ac.getSleep()); +} + +TEST(TestIRWhirlpoolAcClass, SetAndGetSuper) { + IRWhirlpoolAc ac(0); + ac.setFan(kWhirlpoolAcFanAuto); + ac.setMode(kWhirlpoolAcDry); + ac.setCommand(0); + + ac.setSuper(false); + EXPECT_FALSE(ac.getSuper()); + EXPECT_EQ(kWhirlpoolAcCommandSuper, ac.getCommand()); + ac.setSuper(true); + EXPECT_TRUE(ac.getSuper()); + EXPECT_EQ(kWhirlpoolAcCommandSuper, ac.getCommand()); + EXPECT_EQ(kWhirlpoolAcFanHigh, ac.getFan()); + EXPECT_EQ(kWhirlpoolAcCool, ac.getMode()); + EXPECT_EQ(kWhirlpoolAcMinTemp, ac.getTemp()); + + ac.setSuper(false); + EXPECT_FALSE(ac.getSuper()); + EXPECT_EQ(kWhirlpoolAcFanHigh, ac.getFan()); + EXPECT_EQ(kWhirlpoolAcCool, ac.getMode()); + EXPECT_EQ(kWhirlpoolAcMinTemp, ac.getTemp()); + + // When in heat mode, it should stay in heat mode. + ac.setFan(kWhirlpoolAcFanAuto); + ac.setMode(kWhirlpoolAcHeat); + ac.setSuper(true); + EXPECT_TRUE(ac.getSuper()); + EXPECT_EQ(kWhirlpoolAcCommandSuper, ac.getCommand()); + EXPECT_EQ(kWhirlpoolAcFanHigh, ac.getFan()); + EXPECT_EQ(kWhirlpoolAcHeat, ac.getMode()); + EXPECT_EQ(kWhirlpoolAcMaxTemp, ac.getTemp()); + + // Changing mode/temp/fan/power should cancel super, + ac.setMode(kWhirlpoolAcCool); + EXPECT_FALSE(ac.getSuper()); + ac.setSuper(true); + ac.setTemp(25); + EXPECT_FALSE(ac.getSuper()); + ac.setSuper(true); + ac.setFan(kWhirlpoolAcFanMedium); + EXPECT_FALSE(ac.getSuper()); + ac.setSuper(true); + ac.setPowerToggle(true); + EXPECT_FALSE(ac.getSuper()); + + // Known state with Super mode in it. + uint8_t state[21] = {0x83, 0x06, 0x01, 0x02, 0x00, 0x90, 0x90, + 0x9F, 0x00, 0xA0, 0x17, 0x3A, 0x00, 0x11, + 0x00, 0x04, 0x00, 0x00, 0x08, 0x00, 0x0C}; + ac.setRaw(state); + EXPECT_TRUE(ac.getSuper()); +} + +// Build a known good message from scratch. +TEST(TestIRWhirlpoolAcClass, MessageConstruction) { + // Real example captured from a remote. (ref: RealTimerExample) + uint8_t expectedState[kWhirlpoolAcStateLength] = { + 0x83, 0x06, 0x00, 0x73, 0x00, 0x00, 0x87, 0xA3, 0x08, 0x85, 0x07, + 0x28, 0x00, 0xF5, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x05}; + IRWhirlpoolAc ac(0); + ac.setModel(DG11J13A); + ac.setTemp(25); + ac.setPowerToggle(false); + ac.setMode(kWhirlpoolAcDry); + ac.setFan(kWhirlpoolAcFanAuto); + ac.setSwing(false); + ac.setLight(true); + ac.setClock(7 * 60 + 35); + ac.setOnTimer(7 * 60 + 40); + ac.setOffTimer(8 * 60 + 5); + ac.enableOffTimer(true); + ac.setSleep(false); + ac.setSuper(false); + ac.enableOnTimer(true); + + EXPECT_EQ( + "Model: 1 (DG11J13A), Power toggle: Off, Mode: 3 (DRY), Temp: 25C, " + "Fan: 0 (AUTO), Swing: Off, Light: On, Clock: 07:35, On Timer: 07:40, " + "Off Timer: 08:05, Sleep: Off, Super: Off, Command: 5 (ONTIMER)", + ac.toString()); + EXPECT_STATE_EQ(expectedState, ac.getRaw(), kWhirlpoolAcBits); +} diff --git a/lib/IRremoteESP8266/test/ir_Whynter_test.cpp b/lib/IRremoteESP8266/test/ir_Whynter_test.cpp index ab63417..748a4c9 100644 --- a/lib/IRremoteESP8266/test/ir_Whynter_test.cpp +++ b/lib/IRremoteESP8266/test/ir_Whynter_test.cpp @@ -19,7 +19,8 @@ TEST(TestSendWhynter, SendDataOnly) { "m750s750m750s750m750s750m750s750m750s750m750s750m750s750m750s750" "m750s750m750s750m750s750m750s750m750s750m750s750m750s750m750s750" "m750s750m750s750m750s750m750s750m750s750m750s750m750s750m750s750" - "m750s52050", irsend.outputStr()); + "m750s52050", + irsend.outputStr()); irsend.reset(); irsend.sendWhynter(0xFFFFFFFF); @@ -29,7 +30,8 @@ TEST(TestSendWhynter, SendDataOnly) { "m750s2150m750s2150m750s2150m750s2150m750s2150m750s2150m750s2150m750s2150" "m750s2150m750s2150m750s2150m750s2150m750s2150m750s2150m750s2150m750s2150" "m750s2150m750s2150m750s2150m750s2150m750s2150m750s2150m750s2150m750s2150" - "m750s12200", irsend.outputStr()); + "m750s12200", + irsend.outputStr()); irsend.reset(); irsend.sendWhynter(0x87654321); @@ -39,7 +41,8 @@ TEST(TestSendWhynter, SendDataOnly) { "m750s750m750s2150m750s2150m750s750m750s750m750s2150m750s750m750s2150" "m750s750m750s2150m750s750m750s750m750s750m750s750m750s2150m750s2150" "m750s750m750s750m750s2150m750s750m750s750m750s750m750s750m750s2150" - "m750s33850", irsend.outputStr()); + "m750s33850", + irsend.outputStr()); } // Test sending with different repeats. @@ -48,17 +51,18 @@ TEST(TestSendWhynter, SendWithRepeats) { irsend.begin(); irsend.reset(); - irsend.sendWhynter(0x87654321, WHYNTER_BITS, 0); // 0 repeats. + irsend.sendWhynter(0x87654321, kWhynterBits, 0); // 0 repeats. EXPECT_EQ( "m750s750m2850s2850" "m750s2150m750s750m750s750m750s750m750s750m750s2150m750s2150m750s2150" "m750s750m750s2150m750s2150m750s750m750s750m750s2150m750s750m750s2150" "m750s750m750s2150m750s750m750s750m750s750m750s750m750s2150m750s2150" "m750s750m750s750m750s2150m750s750m750s750m750s750m750s750m750s2150" - "m750s33850", irsend.outputStr()); + "m750s33850", + irsend.outputStr()); irsend.reset(); - irsend.sendWhynter(0x87654321, WHYNTER_BITS, 1); // 1 repeat. + irsend.sendWhynter(0x87654321, kWhynterBits, 1); // 1 repeat. EXPECT_EQ( "m750s750m2850s2850" "m750s2150m750s750m750s750m750s750m750s750m750s2150m750s2150m750s2150" @@ -71,10 +75,11 @@ TEST(TestSendWhynter, SendWithRepeats) { "m750s750m750s2150m750s2150m750s750m750s750m750s2150m750s750m750s2150" "m750s750m750s2150m750s750m750s750m750s750m750s750m750s2150m750s2150" "m750s750m750s750m750s2150m750s750m750s750m750s750m750s750m750s2150" - "m750s33850", irsend.outputStr()); + "m750s33850", + irsend.outputStr()); irsend.reset(); - irsend.sendWhynter(0x87654321, WHYNTER_BITS, 2); // 2 repeats. + irsend.sendWhynter(0x87654321, kWhynterBits, 2); // 2 repeats. EXPECT_EQ( "m750s750m2850s2850" "m750s2150m750s750m750s750m750s750m750s750m750s2150m750s2150m750s2150" @@ -93,7 +98,8 @@ TEST(TestSendWhynter, SendWithRepeats) { "m750s750m750s2150m750s2150m750s750m750s750m750s2150m750s750m750s2150" "m750s750m750s2150m750s750m750s750m750s750m750s750m750s2150m750s2150" "m750s750m750s750m750s2150m750s750m750s750m750s750m750s750m750s2150" - "m750s33850", irsend.outputStr()); + "m750s33850", + irsend.outputStr()); } // Test sending an atypical data size. @@ -106,7 +112,8 @@ TEST(TestSendWhynter, SendUnusualSize) { EXPECT_EQ( "m750s750m2850s2850" "m750s750m750s750m750s750m750s750m750s750m750s750m750s750m750s750" - "m750s88050", irsend.outputStr()); + "m750s88050", + irsend.outputStr()); irsend.reset(); irsend.sendWhynter(0x1234567890ABCDEF, 64); @@ -120,7 +127,8 @@ TEST(TestSendWhynter, SendUnusualSize) { "m750s2150m750s750m750s2150m750s750m750s2150m750s750m750s2150m750s2150" "m750s2150m750s2150m750s750m750s750m750s2150m750s2150m750s750m750s2150" "m750s2150m750s2150m750s2150m750s750m750s2150m750s2150m750s2150m750s2150" - "m750s12200", irsend.outputStr()); + "m750s12200", + irsend.outputStr()); } // Tests for decodeWhynter(). @@ -135,9 +143,9 @@ TEST(TestDecodeWhynter, NormalDecodeWithStrict) { irsend.reset(); irsend.sendWhynter(0x87654321); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodeWhynter(&irsend.capture, WHYNTER_BITS, true)); + ASSERT_TRUE(irrecv.decodeWhynter(&irsend.capture, kWhynterBits, true)); EXPECT_EQ(WHYNTER, irsend.capture.decode_type); - EXPECT_EQ(WHYNTER_BITS, irsend.capture.bits); + EXPECT_EQ(kWhynterBits, irsend.capture.bits); EXPECT_EQ(0x87654321, irsend.capture.value); EXPECT_EQ(0x0, irsend.capture.address); EXPECT_EQ(0x0, irsend.capture.command); @@ -152,24 +160,24 @@ TEST(TestDecodeWhynter, NormalDecodeWithRepeatAndStrict) { // Normal Whynter 32-bit message with 2 repeats. irsend.reset(); - irsend.sendWhynter(0x87654321, WHYNTER_BITS, 2); + irsend.sendWhynter(0x87654321, kWhynterBits, 2); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decodeWhynter(&irsend.capture, WHYNTER_BITS, true)); + ASSERT_TRUE(irrecv.decodeWhynter(&irsend.capture, kWhynterBits, true)); EXPECT_EQ(WHYNTER, irsend.capture.decode_type); - EXPECT_EQ(WHYNTER_BITS, irsend.capture.bits); + EXPECT_EQ(kWhynterBits, irsend.capture.bits); EXPECT_EQ(0x87654321, irsend.capture.value); EXPECT_FALSE(irsend.capture.repeat); - irsend.makeDecodeResult(2 * WHYNTER_BITS + 6); - ASSERT_TRUE(irrecv.decodeWhynter(&irsend.capture, WHYNTER_BITS, true)); + irsend.makeDecodeResult(2 * kWhynterBits + 6); + ASSERT_TRUE(irrecv.decodeWhynter(&irsend.capture, kWhynterBits, true)); EXPECT_EQ(WHYNTER, irsend.capture.decode_type); - EXPECT_EQ(WHYNTER_BITS, irsend.capture.bits); + EXPECT_EQ(kWhynterBits, irsend.capture.bits); EXPECT_EQ(0x87654321, irsend.capture.value); - irsend.makeDecodeResult(2 * (2 * WHYNTER_BITS + 6)); - ASSERT_TRUE(irrecv.decodeWhynter(&irsend.capture, WHYNTER_BITS, true)); + irsend.makeDecodeResult(2 * (2 * kWhynterBits + 6)); + ASSERT_TRUE(irrecv.decodeWhynter(&irsend.capture, kWhynterBits, true)); EXPECT_EQ(WHYNTER, irsend.capture.decode_type); - EXPECT_EQ(WHYNTER_BITS, irsend.capture.bits); + EXPECT_EQ(kWhynterBits, irsend.capture.bits); EXPECT_EQ(0x87654321, irsend.capture.value); } @@ -183,7 +191,7 @@ TEST(TestDecodeWhynter, DecodeWithNonStrictSizes) { irsend.sendWhynter(0x12, 8); // Illegal sized Whynter 8-bit message. irsend.makeDecodeResult(); // Should fail with strict on. - ASSERT_FALSE(irrecv.decodeWhynter(&irsend.capture, WHYNTER_BITS, true)); + ASSERT_FALSE(irrecv.decodeWhynter(&irsend.capture, kWhynterBits, true)); ASSERT_FALSE(irrecv.decodeWhynter(&irsend.capture, 8, true)); // Should pass if strict off. ASSERT_TRUE(irrecv.decodeWhynter(&irsend.capture, 8, false)); @@ -197,7 +205,7 @@ TEST(TestDecodeWhynter, DecodeWithNonStrictSizes) { irsend.sendWhynter(0x1234567890, 40); // Illegal size Whynter 40-bit message. irsend.makeDecodeResult(); // Shouldn't pass with strict when we ask for less bits than we got. - ASSERT_FALSE(irrecv.decodeWhynter(&irsend.capture, WHYNTER_BITS, true)); + ASSERT_FALSE(irrecv.decodeWhynter(&irsend.capture, kWhynterBits, true)); irsend.makeDecodeResult(); // Should fail with strict when we ask for the wrong bit size. @@ -238,12 +246,13 @@ TEST(TestDecodeWhynter, FailToDecodeNonWhynterExample) { irsend.reset(); // Modified a few entries to unexpected values, based on previous test case. - uint16_t gc_test[39] = {38000, 1, 1, 322, 162, 20, 61, 20, 61, 20, 20, 20, 20, - 20, 20, 20, 127, 20, 61, 9, 20, 20, 61, 20, 20, 20, - 61, 20, 61, 20, 61, 20, 20, 20, 20, 20, 20, 20, 884}; + uint16_t gc_test[39] = {38000, 1, 1, 322, 162, 20, 61, 20, 61, 20, + 20, 20, 20, 20, 20, 20, 127, 20, 61, 9, + 20, 20, 61, 20, 20, 20, 61, 20, 61, 20, + 61, 20, 20, 20, 20, 20, 20, 20, 884}; irsend.sendGC(gc_test, 39); irsend.makeDecodeResult(); ASSERT_FALSE(irrecv.decodeWhynter(&irsend.capture)); - ASSERT_FALSE(irrecv.decodeWhynter(&irsend.capture, WHYNTER_BITS, false)); + ASSERT_FALSE(irrecv.decodeWhynter(&irsend.capture, kWhynterBits, false)); } diff --git a/lib/IRremoteESP8266/tools/Makefile b/lib/IRremoteESP8266/tools/Makefile index abf11fc..8bf2892 100644 --- a/lib/IRremoteESP8266/tools/Makefile +++ b/lib/IRremoteESP8266/tools/Makefile @@ -22,7 +22,7 @@ CPPFLAGS += -DUNIT_TEST # Flags passed to the C++ compiler. CXXFLAGS += -g -Wall -Wextra -pthread -all : gc_decode +all : gc_decode mode2_decode run_tests : all failed=""; \ @@ -37,7 +37,7 @@ run_tests : all fi clean : - rm -f *.o *.pyc gc_decode + rm -f *.o *.pyc gc_decode mode2_decode # All the IR protocol object files. @@ -47,7 +47,8 @@ PROTOCOLS = ir_NEC.o ir_Sony.o ir_Samsung.o ir_JVC.o ir_RCMM.o ir_RC5_RC6.o \ ir_Aiwa.o ir_Sherwood.o ir_Kelvinator.o ir_Daikin.o ir_Gree.o \ ir_Pronto.o ir_GlobalCache.o ir_Nikai.o ir_Toshiba.o ir_Midea.o \ ir_Magiquest.o ir_Lasertag.o ir_Carrier.o ir_Haier.o ir_Hitachi.o \ - ir_GICable.o + ir_GICable.o ir_Whirlpool.o ir_Lutron.o ir_Electra.o ir_Pioneer.o \ + ir_MWM.o ir_Vestel.o # Common object files COMMON_OBJ = IRutils.o IRtimer.o IRsend.o IRrecv.o $(PROTOCOLS) @@ -64,6 +65,11 @@ gc_decode.o : gc_decode.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS) gc_decode : $(COMMON_OBJ) gc_decode.o $(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@ +mode2_decode.o : mode2_decode.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS) + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -I$(TEST_DIR) -c mode2_decode.cpp + +mode2_decode : $(COMMON_OBJ) mode2_decode.o + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@ IRutils.o : $(USER_DIR)/IRutils.cpp $(USER_DIR)/IRutils.h $(USER_DIR)/IRremoteESP8266.h $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/IRutils.cpp @@ -90,7 +96,7 @@ ir_Sherwood.o : $(USER_DIR)/ir_Sherwood.cpp $(COMMON_DEPS) ir_Sony.o : $(USER_DIR)/ir_Sony.cpp $(COMMON_DEPS) $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Sony.cpp -ir_Samsung.o : $(USER_DIR)/ir_Samsung.cpp $(COMMON_DEPS) +ir_Samsung.o : $(USER_DIR)/ir_Samsung.cpp $(USER_DIR)/ir_Samsung.h $(COMMON_DEPS) $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Samsung.cpp ir_Kelvinator.o : $(USER_DIR)/ir_Kelvinator.cpp $(USER_DIR)/ir_Kelvinator.h $(COMMON_DEPS) @@ -173,3 +179,21 @@ ir_Hitachi.o : $(USER_DIR)/ir_Hitachi.cpp $(GTEST_HEADERS) ir_GICable.o : $(USER_DIR)/ir_GICable.cpp $(GTEST_HEADERS) $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_GICable.cpp + +ir_Whirlpool.o : $(USER_DIR)/ir_Whirlpool.cpp $(GTEST_HEADERS) + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Whirlpool.cpp + +ir_Lutron.o : $(USER_DIR)/ir_Lutron.cpp $(GTEST_HEADERS) + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Lutron.cpp + +ir_Electra.o : $(USER_DIR)/ir_Electra.cpp $(GTEST_HEADERS) + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Electra.cpp + +ir_Pioneer.o : $(USER_DIR)/ir_Pioneer.cpp $(GTEST_HEADERS) + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Pioneer.cpp + +ir_MWM.o : $(USER_DIR)/ir_MWM.cpp $(USER_DIR)/ir_RC5_RC6.cpp $(COMMON_DEPS) + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_MWM.cpp + +ir_Vestel.o : $(USER_DIR)/ir_Vestel.cpp $(GTEST_HEADERS) + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Vestel.cpp diff --git a/lib/IRremoteESP8266/tools/auto_analyse_raw_data.py b/lib/IRremoteESP8266/tools/auto_analyse_raw_data.py index 522586d..b23cdb4 100644 --- a/lib/IRremoteESP8266/tools/auto_analyse_raw_data.py +++ b/lib/IRremoteESP8266/tools/auto_analyse_raw_data.py @@ -1,7 +1,7 @@ #!/usr/bin/python """Attempt an automatic analysis of IRremoteESP8266's Raw data output. Makes suggestions on key values and tried to break down the message - into likely chuncks.""" + into likely chunks.""" # # Copyright 2018 David Conran import argparse @@ -22,7 +22,9 @@ class RawIRMessage(object): self.gaps = [] self.margin = margin self.marks = [] + self.mark_buckets = {} self.spaces = [] + self.space_buckets = {} self.output = output self.verbose = verbose if len(timings) <= 3: @@ -40,22 +42,26 @@ class RawIRMessage(object): self.marks.append(usecs) else: self.spaces.append(usecs) - self.marks = self._reduce_list(self.marks) - self.spaces = self._reduce_list(self.spaces) + self.marks, self.mark_buckets = self.reduce_list(self.marks) + self.spaces, self.space_buckets = self.reduce_list(self.spaces) - def _reduce_list(self, items): - """Reduce the list of numbers into buckets that are atleast margin apart.""" + def reduce_list(self, items): + """Reduce a list of numbers into buckets that are at least margin apart.""" result = [] last = -1 + buckets = {} for item in sorted(items, reverse=True): if last == -1 or item < last - self.margin: result.append(item) last = item - return result + buckets[last] = [item] + else: + buckets[last].append(item) + return result, buckets def _usec_compare(self, seen, expected): """Compare two usec values and see if they match within a - subtrative margin.""" + subtractive margin.""" return seen <= expected and seen > expected - self.margin def _usec_compares(self, usecs, expecteds): @@ -79,21 +85,22 @@ class RawIRMessage(object): " %s (LSB first)\n" " Bin: 0b%s (MSB first)\n" " 0b%s (LSB first)\n" % - (bits, "0x{0:0{1}X}".format(num, bits / 4), - "0x{0:0{1}X}".format(rev_num, bits / 4), num, rev_num, - binary_str, rev_binary_str)) + (bits, ("0x{0:0%dX}" % (bits / 4)).format(num), + ("0x{0:0%dX}" % (bits / 4)).format(rev_num), num, + rev_num, binary_str, rev_binary_str)) - def add_data_code(self, bin_str): + def add_data_code(self, bin_str, footer=True): """Add the common "data" sequence of code to send the bulk of a message.""" # pylint: disable=no-self-use code = [] code.append(" // Data") code.append(" // e.g. data = 0x%X, nbits = %d" % (int(bin_str, 2), len(bin_str))) - code.append(" sendData(BIT_MARK, ONE_SPACE, BIT_MARK, ZERO_SPACE, data, " + code.append(" sendData(kBitMark, kOneSpace, kBitMark, kZeroSpace, data, " "nbits, true);") - code.append(" // Footer") - code.append(" mark(BIT_MARK);") + if footer: + code.append(" // Footer") + code.append(" mark(kBitMark);") return code def _calc_values(self): @@ -104,7 +111,7 @@ class RawIRMessage(object): "%s\n" "Potential Space Candidates:\n" "%s\n" % (str(self.marks), str(self.spaces))) - # Largest mark is likely the HDR_MARK + # Largest mark is likely the kHdrMark self.hdr_mark = self.marks[0] # The bit mark is likely to be the smallest mark. self.bit_mark = self.marks[-1] @@ -150,8 +157,15 @@ class RawIRMessage(object): return self._usec_compares(usec, self.gaps) +def avg_list(items): + """Return the average of a list of numbers.""" + if items: + return sum(items) / len(items) + return 0 + + def add_bit(so_far, bit, output=sys.stdout): - """Add a bit to the end of the bits collected so far. """ + """Add a bit to the end of the bits collected so far.""" if bit == "reset": return "" output.write(str(bit)) # This effectively displays in LSB first order. @@ -179,30 +193,36 @@ def convert_rawdata(data_str): def dump_constants(message, defines, output=sys.stdout): """Dump the key constants and generate the C++ #defines.""" - output.write("Guessing key value:\n" - "HDR_MARK = %d\n" - "HDR_SPACE = %d\n" - "BIT_MARK = %d\n" - "ONE_SPACE = %d\n" - "ZERO_SPACE = %d\n" % - (message.hdr_mark, message.hdr_space, message.bit_mark, - message.one_space, message.zero_space)) - defines.append("#define HDR_MARK %dU" % message.hdr_mark) - defines.append("#define BIT_MARK %dU" % message.bit_mark) - defines.append("#define HDR_SPACE %dU" % message.hdr_space) - defines.append("#define ONE_SPACE %dU" % message.one_space) - defines.append("#define ZERO_SPACE %dU" % message.zero_space) + hdr_mark = avg_list(message.mark_buckets[message.hdr_mark]) + bit_mark = avg_list(message.mark_buckets[message.bit_mark]) + hdr_space = avg_list(message.space_buckets[message.hdr_space]) + one_space = avg_list(message.space_buckets[message.one_space]) + zero_space = avg_list(message.space_buckets[message.zero_space]) + output.write("Guessing key value:\n" + "kHdrMark = %d\n" + "kHdrSpace = %d\n" + "kBitMark = %d\n" + "kOneSpace = %d\n" + "kZeroSpace = %d\n" % (hdr_mark, hdr_space, bit_mark, one_space, + zero_space)) + defines.append("const uint16_t kHdrMark = %d;" % hdr_mark) + defines.append("const uint16_t kBitMark = %d;" % bit_mark) + defines.append("const uint16_t kHdrSpace = %d;" % hdr_space) + defines.append("const uint16_t kOneSpace = %d;" % one_space) + defines.append("const uint16_t kZeroSpace = %d;" % zero_space) + + avg_gaps = [avg_list(message.space_buckets[x]) for x in message.gaps] if len(message.gaps) == 1: - output.write("SPACE_GAP = %d\n" % message.gaps[0]) - defines.append("#define SPACE_GAP = %dU" % message.gaps[0]) + output.write("kSpaceGap = %d\n" % avg_gaps[0]) + defines.append("const uint16_t kSpaceGap = %d;" % avg_gaps[0]) else: count = 0 - for gap in message.gaps: + for gap in avg_gaps: # We probably (still) have a gap in the protocol. count = count + 1 - output.write("SPACE_GAP%d = %d\n" % (count, gap)) - defines.append("#define SPACE_GAP%d = %dU" % (count, gap)) + output.write("kSpaceGap%d = %d\n" % (count, gap)) + defines.append("const uint16_t kSpaceGap%d = %d;" % (count, gap)) def parse_and_report(rawdata_str, margin, gen_code=False, output=sys.stdout): @@ -244,7 +264,7 @@ def decode_data(message, defines, function_code, output=sys.stdout): function_code.extend([ "// Function should be safe up to 64 bits.", - "void IRsend::sendXYZ(const uint64_t data, const uint16_t" + "void IRsend::sendXyz(const uint64_t data, const uint16_t" " nbits, const uint16_t repeat) {", " enableIROut(38); // A guess. Most common frequency.", " for (uint16_t r = 0; r <= repeat; r++) {" @@ -256,12 +276,12 @@ def decode_data(message, defines, function_code, output=sys.stdout): state = "HM" if binary_value: message.display_binary(binary_value) + function_code.extend(message.add_data_code(binary_value, False)) total_bits = total_bits + binary_value - output.write(state) binary_value = add_bit(binary_value, "reset") - output.write("HDR_MARK+") - function_code.extend([" // Header", " mark(HDR_MARK);"]) - elif (message.is_hdr_space(usec) and not message.is_one_space(usec)): + output.write("kHdrMark+") + function_code.extend([" // Header", " mark(kHdrMark);"]) + elif message.is_hdr_space(usec) and not message.is_one_space(usec): if state != "HM": if binary_value: message.display_binary(binary_value) @@ -270,48 +290,53 @@ def decode_data(message, defines, function_code, output=sys.stdout): binary_value = add_bit(binary_value, "reset") output.write("UNEXPECTED->") state = "HS" - output.write("HDR_SPACE+") - function_code.append(" space(HDR_SPACE);") + output.write("kHdrSpace+") + function_code.append(" space(kHdrSpace);") elif message.is_bit_mark(usec) and count % 2: if state != "HS" and state != "BS": - output.write("BIT_MARK(UNEXPECTED)") + output.write("kBitMark(UNEXPECTED)") state = "BM" elif message.is_zero_space(usec): if state != "BM": - output.write("ZERO_SPACE(UNEXPECTED)") + output.write("kZeroSpace(UNEXPECTED)") state = "BS" binary_value = add_bit(binary_value, 0, output) elif message.is_one_space(usec): if state != "BM": - output.write("ONE_SPACE(UNEXPECTED)") + output.write("kOneSpace(UNEXPECTED)") state = "BS" binary_value = add_bit(binary_value, 1, output) elif message.is_gap(usec): if state != "BM": output.write("UNEXPECTED->") state = "GS" - output.write(" GAP(%d)" % usec) - message.display_binary(binary_value) - function_code.extend(message.add_data_code(binary_value)) - function_code.append(" space(SPACE_GAP);") + output.write("GAP(%d)" % usec) + if binary_value: + message.display_binary(binary_value) + function_code.extend(message.add_data_code(binary_value)) + else: + function_code.extend([" // Gap", " mark(kBitMark);"]) + function_code.append(" space(kSpaceGap);") total_bits = total_bits + binary_value binary_value = add_bit(binary_value, "reset") else: output.write("UNKNOWN(%d)" % usec) state = "UNK" count = count + 1 - message.display_binary(binary_value) - function_code.extend(message.add_data_code(binary_value)) + if binary_value: + message.display_binary(binary_value) + function_code.extend(message.add_data_code(binary_value)) function_code.extend([ " space(100000); // A 100% made up guess of the gap" " between messages.", " }", "}" ]) total_bits = total_bits + binary_value - output.write("Total Nr. of suspected bits: %d\n" % len(total_bits)) - defines.append("#define XYZ_BITS %dU" % len(total_bits)) + output.write("\nTotal Nr. of suspected bits: %d\n" % len(total_bits)) + defines.append("const uint16_t kXyzBits = %d;" % len(total_bits)) if len(total_bits) > 64: - defines.append("#define XYZ_STATE_LENGTH %dU" % (len(total_bits) / 8)) + defines.append("const uint16_t kXyzStateLength = %d;" % + (len(total_bits) / 8)) return total_bits @@ -333,23 +358,24 @@ def generate_irsend_code(defines, normal, bits_str, output=sys.stdout): if len(bits_str) > 64: # Will it fit in a uint64_t? output.write("\n\n// Alternative >64 bit Function\n" - "void IRsend::sendXYZ(uint8_t data[], uint16_t nbytes," + "void IRsend::sendXyz(uint8_t data[], uint16_t nbytes," " uint16_t repeat) {\n" - " // nbytes should typically be XYZ_STATE_LENGTH\n" + " // nbytes should typically be kXyzStateLength\n" " // data should typically be:\n" - " // uint8_t data[XYZ_STATE_LENGTH] = {0x%s};\n" + " // uint8_t data[kXyzStateLength] = {0x%s};\n" " // data[] is assumed to be in MSB order for this code.\n" " for (uint16_t r = 0; r <= repeat; r++) {\n" - " sendGeneric(HDR_MARK, HDR_SPACE,\n" - " BIT_MARK, ONE_SPACE,\n" - " BIT_MARK, ZERO_SPACE,\n" - " BIT_MARK\n" + " sendGeneric(kHdrMark, kHdrSpace,\n" + " kBitMark, kOneSpace,\n" + " kBitMark, kZeroSpace,\n" + " kBitMark,\n" " 100000, // 100%% made-up guess at the" " message gap.\n" " data, nbytes,\n" " 38000, // Complete guess of the modulation" " frequency.\n" " true, 0, 50);\n" + " }\n" "}\n" % ", 0x".join("%02X" % int(bits_str[i:i + 8], 2) for i in range(0, len(bits_str), 8))) diff --git a/lib/IRremoteESP8266/tools/auto_analyse_raw_data_test.py b/lib/IRremoteESP8266/tools/auto_analyse_raw_data_test.py index ac84cab..681ff55 100644 --- a/lib/IRremoteESP8266/tools/auto_analyse_raw_data_test.py +++ b/lib/IRremoteESP8266/tools/auto_analyse_raw_data_test.py @@ -8,6 +8,8 @@ import auto_analyse_raw_data as analyse class TestRawIRMessage(unittest.TestCase): """Unit tests for the RawIRMessage class.""" + # pylint: disable=too-many-public-methods + def test_display_binary(self): """Test the display_binary() method.""" output = StringIO.StringIO() @@ -46,6 +48,8 @@ class TestRawIRMessage(unittest.TestCase): class TestAutoAnalyseRawData(unittest.TestCase): """Unit tests for the functions in AutoAnalyseRawData.""" + # pylint: disable=too-many-public-methods + def test_dump_constants_simple(self): """Simple tests for the dump_constants() function.""" ignore = StringIO.StringIO() @@ -58,16 +62,16 @@ class TestAutoAnalyseRawData(unittest.TestCase): ], ignore) analyse.dump_constants(message, defs, output) self.assertEqual(defs, [ - '#define HDR_MARK 7930U', '#define BIT_MARK 520U', - '#define HDR_SPACE 3978U', '#define ONE_SPACE 1508U', - '#define ZERO_SPACE 520U' + 'const uint16_t kHdrMark = 7930;', 'const uint16_t kBitMark = 496;', + 'const uint16_t kHdrSpace = 3965;', 'const uint16_t kOneSpace = 1485;', + 'const uint16_t kZeroSpace = 520;' ]) self.assertEqual(output.getvalue(), 'Guessing key value:\n' - 'HDR_MARK = 7930\n' - 'HDR_SPACE = 3978\n' - 'BIT_MARK = 520\n' - 'ONE_SPACE = 1508\n' - 'ZERO_SPACE = 520\n') + 'kHdrMark = 7930\n' + 'kHdrSpace = 3965\n' + 'kBitMark = 496\n' + 'kOneSpace = 1485\n' + 'kZeroSpace = 520\n') def test_dump_constants_aircon(self): """More complex tests for the dump_constants() function.""" @@ -89,17 +93,17 @@ class TestAutoAnalyseRawData(unittest.TestCase): ], ignore) analyse.dump_constants(message, defs, output) self.assertEqual(defs, [ - '#define HDR_MARK 9008U', '#define BIT_MARK 676U', - '#define HDR_SPACE 4496U', '#define ONE_SPACE 1680U', - '#define ZERO_SPACE 584U', '#define SPACE_GAP = 19990U' + 'const uint16_t kHdrMark = 9008;', 'const uint16_t kBitMark = 650;', + 'const uint16_t kHdrSpace = 4496;', 'const uint16_t kOneSpace = 1657;', + 'const uint16_t kZeroSpace = 554;', 'const uint16_t kSpaceGap = 19990;' ]) self.assertEqual(output.getvalue(), 'Guessing key value:\n' - 'HDR_MARK = 9008\n' - 'HDR_SPACE = 4496\n' - 'BIT_MARK = 676\n' - 'ONE_SPACE = 1680\n' - 'ZERO_SPACE = 584\n' - 'SPACE_GAP = 19990\n') + 'kHdrMark = 9008\n' + 'kHdrSpace = 4496\n' + 'kBitMark = 650\n' + 'kOneSpace = 1657\n' + 'kZeroSpace = 554\n' + 'kSpaceGap = 19990\n') def test_convert_rawdata(self): """Tests for the convert_rawdata() function.""" @@ -177,16 +181,16 @@ class TestAutoAnalyseRawData(unittest.TestCase): 'Looks like it uses space encoding. Yay!\n' '\n' 'Guessing key value:\n' - 'HDR_MARK = 9008\n' - 'HDR_SPACE = 4496\n' - 'BIT_MARK = 676\n' - 'ONE_SPACE = 1680\n' - 'ZERO_SPACE = 584\n' - 'SPACE_GAP = 19990\n' + 'kHdrMark = 9008\n' + 'kHdrSpace = 4496\n' + 'kBitMark = 650\n' + 'kOneSpace = 1657\n' + 'kZeroSpace = 554\n' + 'kSpaceGap = 19990\n' '\n' 'Decoding protocol based on analysis so far:\n' '\n' - 'HDR_MARK+HDR_SPACE+10011000010100000000011000001010010 GAP(19990)\n' + 'kHdrMark+kHdrSpace+10011000010100000000011000001010010GAP(19990)\n' ' Bits: 35\n' ' Hex: 0x4C2803052 (MSB first)\n' ' 0x250600A19 (LSB first)\n' @@ -194,7 +198,7 @@ class TestAutoAnalyseRawData(unittest.TestCase): ' 9938405913 (LSB first)\n' ' Bin: 0b10011000010100000000011000001010010 (MSB first)\n' ' 0b01001010000011000000000101000011001 (LSB first)\n' - 'BIT_MARK(UNEXPECTED)01000000110001000000000000001111\n' + 'kBitMark(UNEXPECTED)01000000110001000000000000001111\n' ' Bits: 32\n' ' Hex: 0x40C4000F (MSB first)\n' ' 0xF0002302 (LSB first)\n' @@ -202,6 +206,7 @@ class TestAutoAnalyseRawData(unittest.TestCase): ' 4026540802 (LSB first)\n' ' Bin: 0b01000000110001000000000000001111 (MSB first)\n' ' 0b11110000000000000010001100000010 (LSB first)\n' + '\n' 'Total Nr. of suspected bits: 67\n') # With code generation. @@ -223,15 +228,15 @@ class TestAutoAnalyseRawData(unittest.TestCase): 'Looks like it uses space encoding. Yay!\n' '\n' 'Guessing key value:\n' - 'HDR_MARK = 7930\n' - 'HDR_SPACE = 3978\n' - 'BIT_MARK = 520\n' - 'ONE_SPACE = 1508\n' - 'ZERO_SPACE = 520\n' + 'kHdrMark = 7930\n' + 'kHdrSpace = 3965\n' + 'kBitMark = 496\n' + 'kOneSpace = 1485\n' + 'kZeroSpace = 520\n' '\n' 'Decoding protocol based on analysis so far:\n' '\n' - 'HDR_MARK+HDR_SPACE+11101011\n' + 'kHdrMark+kHdrSpace+11101011\n' ' Bits: 8\n' ' Hex: 0xEB (MSB first)\n' ' 0xD7 (LSB first)\n' @@ -239,50 +244,249 @@ class TestAutoAnalyseRawData(unittest.TestCase): ' 215 (LSB first)\n' ' Bin: 0b11101011 (MSB first)\n' ' 0b11010111 (LSB first)\n' - 'UNEXPECTED->HDR_SPACE+00000001\n' - ' Bits: 8\n Hex: 0x01 (MSB first)\n' + 'UNEXPECTED->kHdrSpace+00000001\n' + ' Bits: 8\n' + ' Hex: 0x01 (MSB first)\n' ' 0x80 (LSB first)\n' ' Dec: 1 (MSB first)\n' ' 128 (LSB first)\n' ' Bin: 0b00000001 (MSB first)\n' ' 0b10000000 (LSB first)\n' + '\n' 'Total Nr. of suspected bits: 16\n' '\n' 'Generating a VERY rough code outline:\n' '\n' "// WARNING: This probably isn't directly usable. It's a guide only.\n" - '#define HDR_MARK 7930U\n' - '#define BIT_MARK 520U\n' - '#define HDR_SPACE 3978U\n' - '#define ONE_SPACE 1508U\n' - '#define ZERO_SPACE 520U\n' - '#define XYZ_BITS 16U\n' + 'const uint16_t kHdrMark = 7930;\n' + 'const uint16_t kBitMark = 496;\n' + 'const uint16_t kHdrSpace = 3965;\n' + 'const uint16_t kOneSpace = 1485;\n' + 'const uint16_t kZeroSpace = 520;\n' + 'const uint16_t kXyzBits = 16;\n' '// Function should be safe up to 64 bits.\n' - 'void IRsend::sendXYZ(const uint64_t data, const uint16_t nbits,' + 'void IRsend::sendXyz(const uint64_t data, const uint16_t nbits,' ' const uint16_t repeat) {\n' ' enableIROut(38); // A guess. Most common frequency.\n' ' for (uint16_t r = 0; r <= repeat; r++) {\n' ' // Header\n' - ' mark(HDR_MARK);\n' - ' space(HDR_SPACE);\n' + ' mark(kHdrMark);\n' + ' space(kHdrSpace);\n' ' // Data\n' ' // e.g. data = 0xEB, nbits = 8\n' - ' sendData(BIT_MARK, ONE_SPACE, BIT_MARK, ZERO_SPACE, data, nbits,' + ' sendData(kBitMark, kOneSpace, kBitMark, kZeroSpace, data, nbits,' ' true);\n' ' // Footer\n' - ' mark(BIT_MARK);\n' - ' space(HDR_SPACE);\n' + ' mark(kBitMark);\n' + ' space(kHdrSpace);\n' ' // Data\n' ' // e.g. data = 0x1, nbits = 8\n' - ' sendData(BIT_MARK, ONE_SPACE, BIT_MARK, ZERO_SPACE, data, nbits,' + ' sendData(kBitMark, kOneSpace, kBitMark, kZeroSpace, data, nbits,' ' true);\n' ' // Footer\n' - ' mark(BIT_MARK);\n' + ' mark(kBitMark);\n' ' space(100000); // A 100% made up guess of the gap between' ' messages.\n' ' }\n' '}\n') + def test_unusual_gaps(self): + """Tests for unusual Space Gaps in parse_and_report() function.""" + + # Tests for unusual Gaps. (Issue #482) + output = StringIO.StringIO() + input_str = """ + uint16_t rawbuf[272] = {3485, 3512, 864, 864, 864, 2620, 864, 864, + 864, 2620, 864, 2620, 864, 2620, 864, 2620, 864, 2620, 864, 864, + 864, 2620, 864, 864, 864, 2620, 864, 2620, 864, 2620, 864, 2620, + 864, 2620, 864, 864, 864, 2620, 864, 864, 864, 864, 864, 864, + 864, 864, 864, 864, 864, 864, 864, 864, 864, 2620, 864, 864, + 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, + 3485, 3512, 864, 864, 864, 2620, 864, 864, 864, 2620, 864, 2620, + 864, 2620, 864, 2620, 864, 2620, 864, 864, 864, 2620, 864, 864, + 864, 2620, 864, 2620, 864, 2620, 864, 2620, 864, 2620, 864, 864, + 864, 2620, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, + 864, 864, 864, 864, 2620, 864, 864, 864, 864, 864, 864, 864, 864, + 864, 864, 864, 864, + 3485, 3512, 864, 13996, + 3485, 3512, 864, 864, 864, 864, 864, 2620, 864, 864, 864, 2620, + 864, 2620, 864, 2620, 864, 2620, 864, 864, 864, 864, 864, 2620, + 864, 864, 864, 2620, 864, 2620, 864, 2620, 864, 2620, 864, 864, + 864, 2620, 864, 2620, 864, 864, 864, 2620, 864, 2620, 864, 864, + 864, 864, 864, 864, 864, 2620, 864, 2620, 864, 864, 864, 2620, + 864, 2620, 864, 864, 864, 864, + 3485, 3512, 864, 864, 864, 864, 864, 2620, 864, 864, 864, 2620, + 864, 2620, 864, 2620, 864, 2620, 864, 864, 864, 864, 864, 2620, + 864, 864, 864, 2620, 864, 2620, 864, 2620, 864, 2620, 864, 864, + 864, 2620, 864, 2620, 864, 864, 864, 2620, 864, 2620, 864, 864, + 864, 864, 864, 864, 864, 2620, 864, 2620, 864, 864, 864, 2620, + 864, 2620, 864, 864, 864, 864, 3485, 3512, 864, 13996};""" + analyse.parse_and_report(input_str, 200, True, output) + self.assertEqual( + output.getvalue(), 'Found 272 timing entries.\n' + 'Potential Mark Candidates:\n' + '[3485, 864]\n' + 'Potential Space Candidates:\n' + '[13996, 3512, 2620, 864]\n' + '\n' + 'Guessing encoding type:\n' + 'Looks like it uses space encoding. Yay!\n' + '\n' + 'Guessing key value:\n' + 'kHdrMark = 3485\n' + 'kHdrSpace = 3512\n' + 'kBitMark = 864\n' + 'kOneSpace = 2620\n' + 'kZeroSpace = 864\n' + 'kSpaceGap = 13996\n' + '\n' + 'Decoding protocol based on analysis so far:\n' + '\n' + 'kHdrMark+kHdrSpace+01011111010111110100000001000000\n' + ' Bits: 32\n' + ' Hex: 0x5F5F4040 (MSB first)\n' + ' 0x0202FAFA (LSB first)\n' + ' Dec: 1600077888 (MSB first)\n' + ' 33749754 (LSB first)\n' + ' Bin: 0b01011111010111110100000001000000 (MSB first)\n' + ' 0b00000010000000101111101011111010 (LSB first)\n' + 'kHdrMark+kHdrSpace+01011111010111110100000001000000\n' + ' Bits: 32\n' + ' Hex: 0x5F5F4040 (MSB first)\n' + ' 0x0202FAFA (LSB first)\n' + ' Dec: 1600077888 (MSB first)\n' + ' 33749754 (LSB first)\n' + ' Bin: 0b01011111010111110100000001000000 (MSB first)\n' + ' 0b00000010000000101111101011111010 (LSB first)\n' + 'kHdrMark+kHdrSpace+GAP(13996)' + 'kHdrMark+kHdrSpace+00101111001011110110110001101100\n' + ' Bits: 32\n' + ' Hex: 0x2F2F6C6C (MSB first)\n' + ' 0x3636F4F4 (LSB first)\n' + ' Dec: 791637100 (MSB first)\n' + ' 909571316 (LSB first)\n' + ' Bin: 0b00101111001011110110110001101100 (MSB first)\n' + ' 0b00110110001101101111010011110100 (LSB first)\n' + 'kHdrMark+kHdrSpace+00101111001011110110110001101100\n' + ' Bits: 32\n' + ' Hex: 0x2F2F6C6C (MSB first)\n' + ' 0x3636F4F4 (LSB first)\n' + ' Dec: 791637100 (MSB first)\n' + ' 909571316 (LSB first)\n' + ' Bin: 0b00101111001011110110110001101100 (MSB first)\n' + ' 0b00110110001101101111010011110100 (LSB first)\n' + 'kHdrMark+kHdrSpace+GAP(13996)\n' + 'Total Nr. of suspected bits: 128\n' + '\n' + 'Generating a VERY rough code outline:\n' + '\n' + "// WARNING: This probably isn't directly usable. It's a guide only.\n" + 'const uint16_t kHdrMark = 3485;\n' + 'const uint16_t kBitMark = 864;\n' + 'const uint16_t kHdrSpace = 3512;\n' + 'const uint16_t kOneSpace = 2620;\n' + 'const uint16_t kZeroSpace = 864;\n' + 'const uint16_t kSpaceGap = 13996;\n' + 'const uint16_t kXyzBits = 128;\n' + 'const uint16_t kXyzStateLength = 16;\n' + "// DANGER: More than 64 bits detected. A uint64_t for 'data' won't" + ' work!\n' + '// Function should be safe up to 64 bits.\n' + 'void IRsend::sendXyz(const uint64_t data, const uint16_t nbits,' + ' const uint16_t repeat) {\n' + ' enableIROut(38); // A guess. Most common frequency.\n' + ' for (uint16_t r = 0; r <= repeat; r++) {\n' + ' // Header\n' + ' mark(kHdrMark);\n' + ' space(kHdrSpace);\n' + ' // Data\n' + ' // e.g. data = 0x5F5F4040, nbits = 32\n' + ' sendData(kBitMark, kOneSpace, kBitMark, kZeroSpace, data, nbits,' + ' true);\n' + ' // Header\n' + ' mark(kHdrMark);\n' + ' space(kHdrSpace);\n' + ' // Data\n' + ' // e.g. data = 0x5F5F4040, nbits = 32\n' + ' sendData(kBitMark, kOneSpace, kBitMark, kZeroSpace, data, nbits,' + ' true);\n' + ' // Header\n' + ' mark(kHdrMark);\n' + ' space(kHdrSpace);\n' + ' // Gap\n' + ' mark(kBitMark);\n' + ' space(kSpaceGap);\n' + ' // Header\n' + ' mark(kHdrMark);\n' + ' space(kHdrSpace);\n' + ' // Data\n' + ' // e.g. data = 0x2F2F6C6C, nbits = 32\n' + ' sendData(kBitMark, kOneSpace, kBitMark, kZeroSpace, data, nbits,' + ' true);\n' + ' // Header\n' + ' mark(kHdrMark);\n' + ' space(kHdrSpace);\n' + ' // Data\n' + ' // e.g. data = 0x2F2F6C6C, nbits = 32\n' + ' sendData(kBitMark, kOneSpace, kBitMark, kZeroSpace, data, nbits,' + ' true);\n' + ' // Header\n' + ' mark(kHdrMark);\n' + ' space(kHdrSpace);\n' + ' // Gap\n' + ' mark(kBitMark);\n' + ' space(kSpaceGap);\n' + ' space(100000); // A 100% made up guess of the gap between' + ' messages.\n' + ' }\n' + '}\n' + '\n' + '\n' + '// Alternative >64 bit Function\n' + 'void IRsend::sendXyz(uint8_t data[], uint16_t nbytes, uint16_t repeat)' + ' {\n' + ' // nbytes should typically be kXyzStateLength\n' + ' // data should typically be:\n' + ' // uint8_t data[kXyzStateLength] = {0x5F, 0x5F, 0x40, 0x40, 0x5F,' + ' 0x5F, 0x40, 0x40, 0x2F, 0x2F, 0x6C, 0x6C, 0x2F, 0x2F, 0x6C, 0x6C};\n' + ' // data[] is assumed to be in MSB order for this code.\n' + ' for (uint16_t r = 0; r <= repeat; r++) {\n' + ' sendGeneric(kHdrMark, kHdrSpace,\n' + ' kBitMark, kOneSpace,\n' + ' kBitMark, kZeroSpace,\n' + ' kBitMark,\n' + ' 100000, // 100% made-up guess at the message gap.\n' + ' data, nbytes,\n' + ' 38000, // Complete guess of the modulation' + ' frequency.\n' + ' true, 0, 50);\n' + ' }\n' + '}\n') + + def test_reduce_list(self): + """Tests for the reduce_list method.""" + + ignore = StringIO.StringIO() + message = analyse.RawIRMessage(200, [ + 7930, 3952, 494, 1482, 520, 1482, 494, 1508, 494, 520, 494, 1482, 494, + 520, 494, 1482, 494, 1482, 494, 3978, 494, 520, 494, 520, 494, 520, 494, + 520, 520, 520, 494, 520, 494, 520, 494, 1482, 494 + ], ignore) + test_space_data = [4496, 1660, 530, 558, 1636, 1660, 556] + result_list, result_dict = message.reduce_list(test_space_data) + self.assertEqual([4496, 1660, 558], result_list) + self.assertEqual({ + 558: [558, 556, 530], + 1660: [1660, 1660, 1636], + 4496: [4496] + }, result_dict) + + def test_avg_list(self): + """Tests for the avg_list method.""" + + self.assertEqual(0, analyse.avg_list([])) + self.assertEqual(23, analyse.avg_list([10, 20, 40])) + if __name__ == '__main__': unittest.main(verbosity=2) diff --git a/lib/IRremoteESP8266/tools/gc_decode.cpp b/lib/IRremoteESP8266/tools/gc_decode.cpp index 12b1365..52ffd17 100644 --- a/lib/IRremoteESP8266/tools/gc_decode.cpp +++ b/lib/IRremoteESP8266/tools/gc_decode.cpp @@ -11,24 +11,25 @@ #include "IRsend_test.h" #include "IRutils.h" -#define MAX_GC_CODE_LENGTH 10000 +const uint16_t kMaxGcCodeLength = 10000; void str_to_uint16(char *str, uint16_t *res, uint8_t base) { char *end; errno = 0; intmax_t val = strtoimax(str, &end, base); - if (errno == ERANGE || val < 0 || val > UINT16_MAX || - end == str || *end != '\0') + if (errno == ERANGE || val < 0 || val > UINT16_MAX || end == str || + *end != '\0') return; - *res = (uint16_t) val; + *res = (uint16_t)val; } -void usage_error(char * name) { +void usage_error(char *name) { std::cerr << "Usage: " << name << " [-raw] " << std::endl - << "Usage: " << name << " -prontohex [-raw] " << std::endl; + << "Usage: " << name << " -prontohex [-raw] " + << std::endl; } -int main(int argc, char * argv[]) { +int main(int argc, char *argv[]) { int argv_offset = 1; bool dumpraw = false; bool prontohex = false; @@ -52,7 +53,7 @@ int main(int argc, char * argv[]) { return 1; } - uint16_t gc_test[MAX_GC_CODE_LENGTH]; + uint16_t gc_test[kMaxGcCodeLength]; int index = 0; char *pch; char *saveptr1; @@ -60,12 +61,12 @@ int main(int argc, char * argv[]) { int codebase = 10; if (prontohex) { - sep = const_cast(" "); - codebase = 16; + sep = const_cast(" "); + codebase = 16; } pch = strtok_r(argv[argv_offset], sep, &saveptr1); - while (pch != NULL && index < MAX_GC_CODE_LENGTH) { + while (pch != NULL && index < kMaxGcCodeLength) { str_to_uint16(pch, &gc_test[index], codebase); pch = strtok_r(NULL, sep, &saveptr1); index++; @@ -77,32 +78,32 @@ int main(int argc, char * argv[]) { irsend.reset(); if (prontohex) { - irsend.sendPronto(gc_test, index); + irsend.sendPronto(gc_test, index); } else { - irsend.sendGC(gc_test, index); + irsend.sendGC(gc_test, index); } irsend.makeDecodeResult(); irrecv.decode(&irsend.capture); std::cout << "Code length " << index << std::endl - << "Code type " << irsend.capture.decode_type - << " (" << typeToString(irsend.capture.decode_type) << ")" << std::endl - << "Code bits " << irsend.capture.bits << std::endl; + << "Code type " << irsend.capture.decode_type << " (" + << typeToString(irsend.capture.decode_type) << ")" << std::endl + << "Code bits " << irsend.capture.bits << std::endl; if (hasACState(irsend.capture.decode_type)) { std::cout << "State value 0x"; for (uint16_t i = 0; i < irsend.capture.bits / 8; i++) printf("%02X", irsend.capture.state[i]); std::cout << std::endl; } else { - std::cout << "Code value 0x" << - std::hex << irsend.capture.value << std::endl << - "Code address 0x" << std::hex << irsend.capture.address << std::endl - << "Code command 0x" << std::hex << irsend.capture.command << - std::endl; + std::cout << "Code value 0x" << std::hex << irsend.capture.value + << std::endl + << "Code address 0x" << std::hex << irsend.capture.address + << std::endl + << "Code command 0x" << std::hex << irsend.capture.command + << std::endl; } - if (dumpraw || irsend.capture.decode_type == UNKNOWN) - irsend.dumpRawResult(); + if (dumpraw || irsend.capture.decode_type == UNKNOWN) irsend.dumpRawResult(); return 0; } diff --git a/lib/IRremoteESP8266/tools/mkkeywords b/lib/IRremoteESP8266/tools/mkkeywords index f48d640..a2cdccd 100644 --- a/lib/IRremoteESP8266/tools/mkkeywords +++ b/lib/IRremoteESP8266/tools/mkkeywords @@ -64,6 +64,8 @@ LITERALS=$(grep "^#define [A-Z]" src/*.cpp src/*.h | echo ${define}; done | sort -u | grep -v [\(\)] | grep -v ^_ | grep -v _\$ | grep -v VIRTUAL) +CONSTS=$(grep "^const " src/*.cpp src/*.h | + sed 's/\[.*\] =.*//;s/ =.*//;s/^.* k/k/') ENUMS=$(cat src/*.h | while read a b; do if [[ ${a} == "};" ]]; then ENUM=0; @@ -75,6 +77,6 @@ ENUMS=$(cat src/*.h | while read a b; do ENUM=1; fi; done) -for i in ${LITERALS} ${ENUMS}; do +for i in ${LITERALS} ${CONSTS} ${ENUMS}; do echo -e "${i}\tLITERAL1" done | sort -u diff --git a/lib/IRremoteESP8266/tools/mode2_decode.cpp b/lib/IRremoteESP8266/tools/mode2_decode.cpp new file mode 100644 index 0000000..63dfa62 --- /dev/null +++ b/lib/IRremoteESP8266/tools/mode2_decode.cpp @@ -0,0 +1,122 @@ +// Quick and dirty tool to decode mode2 data from LIRC +// Copyright 2018 Brett T. Warden +// based on c2_decode.cpp, Copyright 2017 Jorge Cisneros + +// Usage example: +// mode2 -H udp -d 5000 | ./mode2_decode + +/* Sample input (alternating space and pulse durations in microseconds): +space 500000 +pulse 915 +space 793 +pulse 488 +space 366 +pulse 915 +space 793 +pulse 427 +space 500000 +*/ + +#include +#include +#include +#include +#include +#include +#include +#include "IRsend.h" +#include "IRsend_test.h" +#include "IRutils.h" + +const uint16_t kMaxGcCodeLength = 10000; + +void str_to_uint16(char *str, uint16_t *res, uint8_t base) { + char *end; + errno = 0; + intmax_t val = strtoimax(str, &end, base); + if (errno == ERANGE || val < 0 || val > UINT16_MAX || end == str || + *end != '\0') + return; + *res = (uint16_t)val; +} + +void usage_error(char *name) { + std::cerr << "Usage: " << name << " [-raw]" << std::endl; +} + +int main(int argc, char *argv[]) { + bool dumpraw = false; + + // Check the invocation/calling usage. + if (argc > 2) { + usage_error(argv[0]); + return 1; + } + + if (argc == 2 && strncmp("-raw", argv[1], 4) == 0) { + dumpraw = true; + } + + int index = 0; + std::string line, type; + std::string pulse = "pulse"; + std::string space = "space"; + int duration; + + IRsendTest irsend(4); + IRrecv irrecv(4); + irsend.begin(); + irsend.reset(); + + while (getline(std::cin, line)) { + std::istringstream iss1(line); + iss1 >> type; + iss1 >> duration; + + // Clamp duration to int16_t + if (duration > 0xFFFF) { + duration = 0xFFFF; + } + if (pulse.compare(type) == 0) { + irsend.mark(duration); + } else if (space.compare(type) == 0) { + irsend.space(duration); + } + index++; + + if (duration > 20000 || index >= kMaxGcCodeLength) { + // Skip long spaces at beginning + if (index > 1) { + irsend.makeDecodeResult(); + irrecv.decode(&irsend.capture); + + std::cout << "Code length " << index << std::endl + << "Code type " << irsend.capture.decode_type << " (" + << typeToString(irsend.capture.decode_type) << ")" + << std::endl + << "Code bits " << irsend.capture.bits << std::endl; + if (hasACState(irsend.capture.decode_type)) { + std::cout << "State value 0x"; + for (uint16_t i = 0; i < irsend.capture.bits / 8; i++) + printf("%02X", irsend.capture.state[i]); + std::cout << std::endl; + } else { + std::cout << "Code value 0x" << std::hex << irsend.capture.value + << std::endl + << "Code address 0x" << std::hex << irsend.capture.address + << std::endl + << "Code command 0x" << std::hex << irsend.capture.command + << std::endl; + } + + if (dumpraw || irsend.capture.decode_type == UNKNOWN) + irsend.dumpRawResult(); + } + + irsend.reset(); + index = 0; + } + } + + return 0; +}