buf(new char[size]);
+
+ configFile.readBytes(buf.get(), size);
+ DynamicJsonBuffer jsonBuffer;
+ JsonObject& json = jsonBuffer.parseObject(buf.get());
+ if (json.success()) {
+ debug("Json config file parsed ok.");
+#if MQTT_ENABLE
+ strncpy(MqttServer, json[kMqttServerKey] | "", kHostnameLength);
+ strncpy(MqttPort, json[kMqttPortKey] | "1883", kPortLength);
+ strncpy(MqttUsername, json[kMqttUserKey] | "", kUsernameLength);
+ strncpy(MqttPassword, json[kMqttPassKey] | "", kPasswordLength);
+ strncpy(MqttPrefix, json[kMqttPrefixKey] | "", kHostnameLength);
+#endif // MQTT_ENABLE
+ strncpy(Hostname, json[kHostnameKey] | "", kHostnameLength);
+ strncpy(HttpUsername, json[kHttpUserKey] | "", kUsernameLength);
+ strncpy(HttpPassword, json[kHttpPassKey] | "", kPasswordLength);
+ debug("Recovered Json fields.");
+ } else {
+ debug("Failed to load json config");
+ }
+ debug("Closing the config file.");
+ configFile.close();
+ }
+ } else {
+ debug("Config file doesn't exist!");
+ }
+ debug("Unmounting SPIFFS.");
+ SPIFFS.end();
+ } else {
+ debug("Failed to mount SPIFFS");
+ }
+}
+
+String msToHumanString(uint32_t const msecs) {
+ uint32_t totalseconds = msecs / 1000;
+ if (totalseconds == 0) return "Now";
+
+ // Note: millis() can only count up to 45 days, so uint8_t is safe.
+ uint8_t days = totalseconds / (60 * 60 * 24);
+ uint8_t hours = (totalseconds / (60 * 60)) % 24;
+ uint8_t minutes = (totalseconds / 60) % 60;
+ uint8_t seconds = totalseconds % 60;
+
+ String result = "";
+ if (days) result += String(days) + " day";
+ if (days > 1) result += 's';
+ if (hours) result += ' ' + String(hours) + " hour";
+ if (hours > 1) result += 's';
+ if (minutes) result += ' ' + String(minutes) + " minute";
+ if (minutes > 1) result += 's';
+ if (seconds) result += ' ' + String(seconds) + " second";
+ if (seconds > 1) result += 's';
+ result.trim();
+ return result;
+}
+
+String timeElapsed(uint32_t const msec) {
+ String result = msToHumanString(msec);
+ if (result.equalsIgnoreCase("Now"))
+ return result;
+ else
+ return result + " ago";
+}
+
+String timeSince(uint32_t const start) {
+ if (start == 0)
+ return "Never";
+ uint32_t diff = 0;
+ uint32_t now = millis();
+ if (start < now)
+ diff = now - start;
+ else
+ diff = UINT32_MAX - start + now;
+ return msToHumanString(diff) + " ago";
+}
+
+// Return a string containing the comma separated list of sending gpios.
+String listOfSendGpios(void) {
+ String result = String(gpioTable[0]);
+ if (kSendTableSize > 1) result += " (default)";
+ for (uint8_t i = 1; i < kSendTableSize; i++) {
+ result += ", " + String(gpioTable[i]);
+ }
+ return result;
+}
+
+String htmlMenu(void) {
+ return F(
+ ""
+ ""
+ "Home"
+ " "
+ ""
+ "Aircon"
+ " "
+ ""
+ "Examples"
+ " "
+ ""
+ "System Info"
+ " "
+ ""
+ "Admin"
+ " "
+ " "
+ " ");
+}
+
+// Root web page with example usage etc.
+void handleRoot(void) {
+#if HTML_PASSWORD_ENABLE
+ if (!server.authenticate(HttpUsername, HttpPassword)) {
+ debug("Basic HTTP authentication failure for /.");
+ return server.requestAuthentication();
+ }
+#endif
+ String html = F(
+ "IR MQTT server "
+ ""
+ "ESP8266 IR MQTT Server "
+ "" _MY_VERSION_ " ");
+ html += htmlMenu();
+ html += F(
+ "Send a simple IR message "
+ "
"
+ " "
+ "Send a complex (Air Conditioner) IR message "
+ "
"
+ " "
+ "Send an IRremote Raw IR message "
+ "
"
+ " "
+ "Send a GlobalCache "
+ " IR message "
+ "
"
+ " "
+ ""
+ "
"
+ " ");
+ server.send(200, "text/html", html);
+}
+
+String addJsReloadUrl(const String url, const uint16_t timeout_s,
+ const bool notify) {
+ String html = F(
+ "\n");
+ return html;
+}
+
+// Web page with hardcoded example usage etc.
+void handleExamples(void) {
+#if HTML_PASSWORD_ENABLE
+ if (!server.authenticate(HttpUsername, HttpPassword)) {
+ debug("Basic HTTP authentication failure for /examples.");
+ return server.requestAuthentication();
+ }
+#endif
+ String html = F(
+ "IR MQTT examples "
+ ""
+ "ESP8266 IR MQTT Server "
+ "" _MY_VERSION_ " ");
+ html += htmlMenu();
+ html += F(
+ "Hardcoded examples "
+ ""
+ "Sherwood Amp On (GlobalCache)
"
+ ""
+ "Sherwood Amp Off (Raw)
"
+ ""
+ "Sherwood Amp Input TAPE (Pronto)
"
+ "TV on (Samsung)
"
+ "Power Off (Sony 12bit)
"
+ ""
+ "Panasonic A/C LKE model, On, Auto mode, Min fan, 23C"
+ " (via HTTP aircon interface)
"
+ ""
+ "Change just the temp to 27C (via HTTP aircon interface)
"
+ ""
+ "Turn OFF the current A/C (via HTTP aircon interface)
"
+ " ");
+ server.send(200, "text/html", html);
+}
+
+String boolToString(const bool value) {
+ return value ? F("on") : F("off");
+}
+
+
+String opmodeToString(const stdAc::opmode_t mode) {
+ switch (mode) {
+ case stdAc::opmode_t::kOff:
+ return F("off");
+ case stdAc::opmode_t::kAuto:
+ return F("auto");
+ case stdAc::opmode_t::kCool:
+ return F("cool");
+ case stdAc::opmode_t::kHeat:
+ return F("heat");
+ case stdAc::opmode_t::kDry:
+ return F("dry");
+ case stdAc::opmode_t::kFan:
+ return F("fan_only");
+ default:
+ return F("unknown");
+ }
+}
+
+String fanspeedToString(const stdAc::fanspeed_t speed) {
+ switch (speed) {
+ case stdAc::fanspeed_t::kAuto:
+ return F("auto");
+ case stdAc::fanspeed_t::kMax:
+ return F("max");
+ case stdAc::fanspeed_t::kHigh:
+ return F("high");
+ case stdAc::fanspeed_t::kMedium:
+ return F("medium");
+ case stdAc::fanspeed_t::kLow:
+ return F("low");
+ case stdAc::fanspeed_t::kMin:
+ return F("min");
+ default:
+ return F("unknown");
+ }
+}
+
+String swingvToString(const stdAc::swingv_t swingv) {
+ switch (swingv) {
+ case stdAc::swingv_t::kOff:
+ return F("off");
+ case stdAc::swingv_t::kAuto:
+ return F("auto");
+ case stdAc::swingv_t::kHighest:
+ return F("highest");
+ case stdAc::swingv_t::kHigh:
+ return F("high");
+ case stdAc::swingv_t::kMiddle:
+ return F("middle");
+ case stdAc::swingv_t::kLow:
+ return F("low");
+ case stdAc::swingv_t::kLowest:
+ return F("lowest");
+ default:
+ return F("unknown");
+ }
+}
+
+String swinghToString(const stdAc::swingh_t swingh) {
+ switch (swingh) {
+ case stdAc::swingh_t::kOff:
+ return F("off");
+ case stdAc::swingh_t::kAuto:
+ return F("auto");
+ case stdAc::swingh_t::kLeftMax:
+ return F("leftmax");
+ case stdAc::swingh_t::kLeft:
+ return F("left");
+ case stdAc::swingh_t::kMiddle:
+ return F("middle");
+ case stdAc::swingh_t::kRight:
+ return F("right");
+ case stdAc::swingh_t::kRightMax:
+ return F("rightmax");
+ default:
+ return F("unknown");
+ }
+}
+
+String htmlSelectBool(const String name, const bool def) {
+ String html = "";
+ for (uint16_t i = 0; i < 2; i++) {
+ html += F("';
+ html += boolToString(i);
+ html += F(" ");
+ }
+ html += F(" ");
+ return html;
+}
+
+String htmlSelectProtocol(const String name, const decode_type_t def) {
+ String html = "";
+ for (uint8_t i = 1; i <= decode_type_t::kLastDecodeType; i++) {
+ if (IRac::isProtocolSupported((decode_type_t)i)) {
+ html += F("';
+ html += typeToString((decode_type_t)i);
+ html += F(" ");
+ }
+ }
+ html += F(" ");
+ return html;
+}
+
+String htmlSelectModel(const String name, const int16_t def) {
+ String html = "";
+ for (int16_t i = -1; i <= 6; i++) {
+ String num = String(i);
+ html += F("';
+ if (i == -1)
+ html += F("Default");
+ else if (i == 0)
+ html += F("Unknown");
+ else
+ html += num;
+ html += F(" ");
+ }
+ html += F(" ");
+ return html;
+}
+
+String htmlSelectMode(const String name, const stdAc::opmode_t def) {
+ String html = "";
+ for (int8_t i = -1; i <= 4; i++) {
+ String mode = opmodeToString((stdAc::opmode_t)i);
+ html += F("';
+ html += mode;
+ html += F(" ");
+ }
+ html += F(" ");
+ return html;
+}
+
+String htmlSelectFanspeed(const String name, const stdAc::fanspeed_t def) {
+ String html = "";
+ for (int8_t i = 0; i <= 5; i++) {
+ String speed = fanspeedToString((stdAc::fanspeed_t)i);
+ html += F("';
+ html += speed;
+ html += F(" ");
+ }
+ html += F(" ");
+ return html;
+}
+
+String htmlSelectSwingv(const String name, const stdAc::swingv_t def) {
+ String html = "";
+ for (int8_t i = -1; i <= 5; i++) {
+ String swing = swingvToString((stdAc::swingv_t)i);
+ html += F("';
+ html += swing;
+ html += F(" ");
+ }
+ html += F(" ");
+ return html;
+}
+
+String htmlSelectSwingh(const String name, const stdAc::swingh_t def) {
+ String html = "";
+ for (int8_t i = -1; i <= 5; i++) {
+ String swing = swinghToString((stdAc::swingh_t)i);
+ html += F("';
+ html += swing;
+ html += F(" ");
+ }
+ html += F(" ");
+ return html;
+}
+
+// Admin web page
+void handleAirCon(void) {
+ String html = F(
+ "AirCon control "
+ ""
+ "Air Conditioner Control ");
+ html += htmlMenu();
+ html += "Current Settings "
+ "";
+ // Display the current settings.
+ html += F("");
+ server.send(200, "text/html", html);
+}
+
+// Parse the URL args to find the Common A/C arguments.
+void handleAirConSet(void) {
+#if HTML_PASSWORD_ENABLE
+ if (!server.authenticate(HttpUsername, HttpPassword)) {
+ debug("Basic HTTP authentication failure for /aircon/set.");
+ return server.requestAuthentication();
+ }
+#endif
+ commonAcState_t result = climate;
+ debug("New common a/c received via HTTP");
+ for (uint16_t i = 0; i < server.args(); i++)
+ result = updateClimate(result, server.argName(i), "", server.arg(i));
+
+#if MQTT_ENABLE
+ sendClimate(climate, result, MqttClimateStat,
+ true, false, false);
+#else // MQTT_ENABLE
+ sendClimate(climate, result, "", false, false, false);
+#endif // MQTT_ENABLE
+ // Update the old climate state with the new one.
+ climate = result;
+ // Redirect back to the aircon page.
+ String html = F(
+ "Update Aircon "
+ ""
+ "Aircon updated! ");
+ html += addJsReloadUrl("/aircon", 2, false);
+ html += F("");
+ server.send(200, "text/html", html);
+}
+
+// Admin web page
+void handleAdmin(void) {
+ String html = F(
+ "IR MQTT server admin "
+ ""
+ "Administration ");
+ html += htmlMenu();
+ html += F(
+ "Special commands "
+#if MQTT_ENABLE
+ ""
+ "Send MQTT Discovery"
+ " "
+ "Send a Climate MQTT discovery message to Home Assistant. "
+#endif // MQTT_ENABLE
+ ""
+ "Reboot"
+ " A simple reboot of the ESP8266. "
+ "ie. No changes "
+ ""
+ "Wipe Settings"
+ " Warning: "
+ "Resets the device back to original settings. "
+ "ie. Goes back to AP/Setup mode. ");
+#if FIRMWARE_OTA
+ html += F("Update firmware "
+ "Warning: ");
+ if (!strlen(HttpPassword)) // Deny if password not set
+ html += F("OTA firmware is disabled until you set a password. "
+ "You will need to wipe & reset to set one."
+ " ");
+ else // default password has been changed, so allow it.
+ html += F(
+ "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). "
+ "
");
+#endif // FIRMWARE_OTA
+ html += F("");
+ server.send(200, "text/html", html);
+}
+
+// Info web page
+void handleInfo(void) {
+ String html =
+ "IR MQTT server info "
+ ""
+ "Information ";
+ html += htmlMenu();
+ html +=
+ "General "
+ "Hostname: " + String(Hostname) + " "
+ "IP address: " + WiFi.localIP().toString() + " "
+ "Booted: " + timeSince(1) + " " +
+ "Version: " _MY_VERSION_ " "
+ "Built: " __DATE__
+ " " __TIME__ " "
+ "Period Offset: " + String(offset) + "us "
+ "IR Lib Version: " _IRREMOTEESP8266_VERSION_ " "
+ "ESP8266 Core Version: " + ESP.getCoreVersion() + " "
+ "IR Send GPIO(s): " + listOfSendGpios() + " "
+ "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
+ "Duplicate Wifi networks: " +
+ String(HIDE_DUPLIATE_NETWORKS ? "Hide" : "Show") + " "
+ "Min Wifi signal required: "
+#ifdef MIN_SIGNAL_STRENGTH
+ + String(static_cast(MIN_SIGNAL_STRENGTH)) +
+#else // MIN_SIGNAL_STRENGTH
+ "8"
+#endif // MIN_SIGNAL_STRENGTH
+ "% "
+ "Serial debugging: "
+#if DEBUG
+ + String(isSerialGpioUsedByIr() ? "Off" : "On") +
+#else // DEBUG
+ "Off"
+#endif // DEBUG
+ " "
+ "
"
+#if MQTT_ENABLE
+ "MQTT Information "
+ "Server: " + String(MqttServer) + ":" + String(MqttPort) + " (" +
+ (mqtt_client.connected() ? "Connected " + timeSince(lastDisconnectedTime)
+ : "Disconnected " + timeSince(lastConnectedTime)) +
+ ") "
+ "Disconnections: " + String(mqttDisconnectCounter - 1) + " "
+ "Client id: " + MqttClientId + " "
+ "Command topic(s): " + listOfCommandTopics() + " "
+ "Acknowledgements topic: " + MqttAck + " "
+#ifdef IR_RX
+ "IR Received topic: " + MqttRecv + " "
+#endif // IR_RX
+ "Log topic: " + MqttLog + " "
+ "LWT topic: " + MqttLwt + " "
+ "QoS: " + String(QOS) + " "
+ // lastMqttCmd* is unescaped untrusted input.
+ // Avoid any possible HTML/XSS when displaying it.
+ "Last MQTT command seen: (topic) '" + htmlEscape(lastMqttCmdTopic) +
+ "' (payload) '" + htmlEscape(lastMqttCmd) + "' (" +
+ timeSince(lastMqttCmdTime) + ") "
+ "Total published: " + String(mqttSentCounter) + " "
+ "Total received: " + String(mqttRecvCounter) + " "
+ "
"
+#endif // MQTT_ENABLE
+ "Climate Information "
+ ""
+ "IR Send GPIO: " + String(gpioTable[0]) + " "
+ "Total sent: " + String(irClimateCounter) + " "
+ "Last send: " + String(hasClimateBeenSent ?
+ (String(lastClimateSucceeded ? "Ok" : "FAILED") +
+ " (" + timeElapsed(lastClimateIr.elapsed()) + ") ") :
+ "Never ") + " "
+#if MQTT_ENABLE
+ "State listen period: " + msToHumanString(kStatListenPeriodMs) + " "
+ "State broadcast period: " + msToHumanString(kBroadcastPeriodMs) + " "
+ "Last state broadcast: " + (hasBroadcastBeenSent ?
+ timeElapsed(lastBroadcast.elapsed()) :
+ String("Never ")) + " "
+ "Last discovery sent: " + (lockMqttBroadcast ?
+ String("Locked ") :
+ (hasDiscoveryBeenSent ?
+ timeElapsed(lastDiscovery.elapsed()) :
+ String("Never "))) +
+ " "
+ "Command topics: " + MqttClimateCmnd +
+ "(" KEY_PROTOCOL "|" KEY_MODEL "|" KEY_POWER "|" KEY_MODE "|" KEY_TEMP "|"
+ KEY_FANSPEED "|" KEY_SWINGV "|" KEY_SWINGH "|" KEY_QUIET "|"
+ KEY_TURBO "|" KEY_LIGHT "|" KEY_BEEP "|" KEY_ECONO "|" KEY_SLEEP "|"
+ KEY_CLOCK "|" KEY_FILTER "|" KEY_CLEAN "|" KEY_CELSIUS ") "
+ "State topics: " + MqttClimateStat +
+ "(" KEY_PROTOCOL "|" KEY_MODEL "|" KEY_POWER "|" KEY_MODE "|" KEY_TEMP "|"
+ KEY_FANSPEED "|" KEY_SWINGV "|" KEY_SWINGH "|" KEY_QUIET "|"
+ KEY_TURBO "|" KEY_LIGHT "|" KEY_BEEP "|" KEY_ECONO "|" KEY_SLEEP "|"
+ KEY_CLOCK "|" KEY_FILTER "|" KEY_CLEAN "|" KEY_CELSIUS ") "
+#endif // MQTT_ENABLE
+ "
"
+ // Page footer
+ ""
+ "(Note: Page will refresh every 60 seconds.) "
+ "
";
+ html += addJsReloadUrl("/info", 60, false);
+ html += "";
+ server.send(200, "text/html", html);
+}
+// Reset web page
+void handleReset(void) {
+#if HTML_PASSWORD_ENABLE
+ if (!server.authenticate(HttpUsername, HttpPassword)) {
+ debug("Basic HTTP authentication failure for /reset.");
+ return server.requestAuthentication();
+ }
+#endif
+ server.send(200, "text/html",
+ "Reset WiFi Config "
+ ""
+ "Resetting the WiFiManager config back to defaults. "
+ "Device restarting. Try connecting in a few seconds.
" +
+ addJsReloadUrl("/", 10, true) +
+ "");
+ // Do the reset.
+#if MQTT_ENABLE
+ mqttLog("Wiping all saved config settings.");
+#endif // MQTT_ENABLE
+ debug("Trying to mount SPIFFS");
+ if (SPIFFS.begin()) {
+ debug("Removing JSON config file");
+ SPIFFS.remove(kConfigFile);
+ SPIFFS.end();
+ }
+ delay(1000);
+ debug("Reseting wifiManager's settings.");
+ wifiManager.resetSettings();
+ delay(1000);
+ debug("rebooting...");
+ ESP.restart();
+ delay(1000);
+}
+
+// Reboot web page
+void handleReboot() {
+#if HTML_PASSWORD_ENABLE
+ if (!server.authenticate(HttpUsername, HttpPassword)) {
+ debug("Basic HTTP authentication failure for /quitquitquit.");
+ return server.requestAuthentication();
+ }
+#endif
+ server.send(200, "text/html",
+ "Rebooting "
+ ""
+ "Device restarting. "
+ "Try connecting in a few seconds.
" +
+ addJsReloadUrl("/", 15, true) +
+ "");
+#if MQTT_ENABLE
+ mqttLog("Reboot requested");
+#endif // MQTT_ENABLE
+ // Do the reset.
+ delay(1000);
+ ESP.restart();
+ delay(1000);
+}
+
+// Parse an Air Conditioner A/C Hex String/code and send it.
+// Args:
+// irsend: A Ptr to the IRsend object to transmit via.
+// irType: Nr. of the protocol we need to send.
+// str: A hexadecimal string containing the state to be sent.
+// Returns:
+// bool: Successfully sent or not.
+bool parseStringAndSendAirCon(IRsend *irsend, const uint16_t irType,
+ const String str) {
+ uint8_t strOffset = 0;
+ uint8_t state[kStateSizeMax] = {0}; // All array elements are set to 0.
+ uint16_t stateSize = 0;
+
+ if (str.startsWith("0x") || str.startsWith("0X"))
+ strOffset = 2;
+ // Calculate how many hexadecimal characters there are.
+ uint16_t inputLength = str.length() - strOffset;
+ if (inputLength == 0) {
+ debug("Zero length AirCon code encountered. Ignored.");
+ return false; // No input. Abort.
+ }
+
+ switch (irType) { // Get the correct state size for the protocol.
+ case KELVINATOR:
+ stateSize = kKelvinatorStateLength;
+ break;
+ case TOSHIBA_AC:
+ stateSize = kToshibaACStateLength;
+ break;
+ case DAIKIN:
+ // Daikin has 2 different possible size states.
+ // (The correct size, and a legacy shorter size.)
+ // 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.
+ // This should provide backward compatiblity with legacy messages.
+ stateSize = inputLength / 2; // Every two hex chars is a byte.
+ // Use at least the minimum size.
+ stateSize = std::max(stateSize, kDaikinStateLengthShort);
+ // If we think it isn't a "short" message.
+ if (stateSize > kDaikinStateLengthShort)
+ // Then it has to be at least the version of the "normal" size.
+ stateSize = std::max(stateSize, kDaikinStateLength);
+ // Lastly, it should never exceed the "normal" size.
+ stateSize = std::min(stateSize, kDaikinStateLength);
+ break;
+ case DAIKIN2:
+ stateSize = kDaikin2StateLength;
+ break;
+ case DAIKIN216:
+ stateSize = kDaikin216StateLength;
+ break;
+ case ELECTRA_AC:
+ stateSize = kElectraAcStateLength;
+ break;
+ case MITSUBISHI_AC:
+ stateSize = kMitsubishiACStateLength;
+ break;
+ case MITSUBISHI_HEAVY_88:
+ stateSize = kMitsubishiHeavy88StateLength;
+ break;
+ case MITSUBISHI_HEAVY_152:
+ stateSize = kMitsubishiHeavy152StateLength;
+ break;
+ case PANASONIC_AC:
+ stateSize = kPanasonicAcStateLength;
+ break;
+ case TROTEC:
+ stateSize = kTrotecStateLength;
+ break;
+ case ARGO:
+ stateSize = kArgoStateLength;
+ break;
+ case GREE:
+ stateSize = kGreeStateLength;
+ break;
+ case FUJITSU_AC:
+ // Fujitsu has four 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) (kFujitsuAcStateLengthShort - 1));
+ // If we think it isn't a "short" message.
+ if (stateSize > kFujitsuAcStateLengthShort)
+ // Then it has to be at least the smaller version of the "normal" size.
+ stateSize = std::max(stateSize, (uint16_t) (kFujitsuAcStateLength - 1));
+ // Lastly, it should never exceed the maximum "normal" size.
+ stateSize = std::min(stateSize, kFujitsuAcStateLength);
+ break;
+ case HAIER_AC:
+ stateSize = kHaierACStateLength;
+ break;
+ case HAIER_AC_YRW02:
+ stateSize = kHaierACYRW02StateLength;
+ break;
+ case HITACHI_AC:
+ stateSize = kHitachiAcStateLength;
+ break;
+ case HITACHI_AC1:
+ stateSize = kHitachiAc1StateLength;
+ break;
+ case HITACHI_AC2:
+ 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;
+ case TCL112AC:
+ stateSize = kTcl112AcStateLength;
+ break;
+ default: // Not a protocol we expected. Abort.
+ debug("Unexpected AirCon protocol detected. Ignoring.");
+ return false;
+ }
+ if (inputLength > stateSize * 2) {
+ debug("AirCon code to large for the given protocol.");
+ return false;
+ }
+
+ // Ptr to the least significant byte of the resulting state for this protocol.
+ uint8_t *statePtr = &state[stateSize - 1];
+
+ // Convert the string into a state array of the correct length.
+ for (uint16_t i = 0; i < inputLength; i++) {
+ // Grab the next least sigificant hexadecimal digit from the string.
+ uint8_t c = tolower(str[inputLength + strOffset - i - 1]);
+ if (isxdigit(c)) {
+ if (isdigit(c))
+ c -= '0';
+ else
+ c = c - 'a' + 10;
+ } else {
+ debug("Aborting! Non-hexadecimal char found in AirCon state:");
+ debug(str.c_str());
+ return false;
+ }
+ if (i % 2 == 1) { // Odd: Upper half of the byte.
+ *statePtr += (c << 4);
+ statePtr--; // Advance up to the next least significant byte of state.
+ } else { // Even: Lower half of the byte.
+ *statePtr = c;
+ }
+ }
+
+ // Make the appropriate call for the protocol type.
+ switch (irType) {
+#if SEND_KELVINATOR
+ case KELVINATOR:
+ irsend->sendKelvinator(reinterpret_cast(state));
+ break;
+#endif
+#if SEND_TOSHIBA_AC
+ case TOSHIBA_AC:
+ irsend->sendToshibaAC(reinterpret_cast(state));
+ break;
+#endif
+#if SEND_DAIKIN
+ case DAIKIN:
+ irsend->sendDaikin(reinterpret_cast(state));
+ break;
+#endif
+#if SEND_DAIKIN2
+ case DAIKIN2:
+ irsend->sendDaikin2(reinterpret_cast(state));
+ break;
+#endif
+#if SEND_DAIKIN216
+ case DAIKIN216:
+ irsend->sendDaikin216(reinterpret_cast(state));
+ break;
+#endif // SEND_DAIKIN216
+#if SEND_MITSUBISHI_AC
+ case MITSUBISHI_AC:
+ irsend->sendMitsubishiAC(reinterpret_cast(state));
+ break;
+#endif
+#if SEND_MITSUBISHIHEAVY
+ case MITSUBISHI_HEAVY_88: // 59
+ irsend->sendMitsubishiHeavy88(reinterpret_cast(state));
+ break;
+ case MITSUBISHI_HEAVY_152: // 60
+ irsend->sendMitsubishiHeavy152(reinterpret_cast(state));
+ break;
+#endif // SEND_MITSUBISHIHEAVY
+#if SEND_TROTEC
+ case TROTEC:
+ irsend->sendTrotec(reinterpret_cast(state));
+ break;
+#endif
+#if SEND_ARGO
+ case ARGO:
+ irsend->sendArgo(reinterpret_cast(state));
+ break;
+#endif
+#if SEND_GREE
+ case GREE:
+ irsend->sendGree(reinterpret_cast(state));
+ break;
+#endif
+#if SEND_FUJITSU_AC
+ case FUJITSU_AC:
+ irsend->sendFujitsuAC(reinterpret_cast(state), stateSize);
+ break;
+#endif
+#if SEND_HAIER_AC
+ case HAIER_AC:
+ 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));
+ break;
+#endif
+#if SEND_HITACHI_AC1
+ case HITACHI_AC1:
+ irsend->sendHitachiAC1(reinterpret_cast(state));
+ break;
+#endif
+#if SEND_HITACHI_AC2
+ case HITACHI_AC2:
+ 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
+#if SEND_TCL112AC
+ case TCL112AC:
+ irsend->sendTcl112Ac(reinterpret_cast(state));
+ 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.
+// Args:
+// str: String containing the values.
+// sep: Character that separates the values.
+// Returns:
+// The number of values found in the String.
+uint16_t countValuesInStr(const String str, char sep) {
+ int16_t index = -1;
+ uint16_t count = 1;
+ do {
+ index = str.indexOf(sep, index + 1);
+ count++;
+ } while (index != -1);
+ return count;
+}
+
+// Dynamically allocate an array of uint16_t's.
+// Args:
+// size: Nr. of uint16_t's need to be in the new array.
+// Returns:
+// A Ptr to the new array. Restarts the ESP8266 if it fails.
+uint16_t * newCodeArray(const uint16_t size) {
+ uint16_t *result;
+
+ result = reinterpret_cast(malloc(size * sizeof(uint16_t)));
+ // Check we malloc'ed successfully.
+ if (result == NULL) { // malloc failed, so give up.
+ Serial.printf("\nCan't allocate %d bytes. (%d bytes free)\n",
+ size * sizeof(uint16_t), ESP.getFreeHeap());
+ Serial.println("Giving up & forcing a reboot.");
+ ESP.restart(); // Reboot.
+ delay(500); // Wait for the restart to happen.
+ return result; // Should never get here, but just in case.
+ }
+ return result;
+}
+
+#if SEND_GLOBALCACHE
+// Parse a GlobalCache String/code and send it.
+// Args:
+// irsend: A ptr to the IRsend object to transmit via.
+// str: A GlobalCache formatted String of comma separated numbers.
+// e.g. "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"
+// Note: The leading "1:1,1," of normal GC codes should be removed.
+// Returns:
+// bool: Successfully sent or not.
+bool parseStringAndSendGC(IRsend *irsend, const String str) {
+ uint16_t count;
+ uint16_t *code_array;
+ String tmp_str;
+
+ // Remove the leading "1:1,1," if present.
+ if (str.startsWith("1:1,1,"))
+ tmp_str = str.substring(6);
+ else
+ tmp_str = str;
+
+ // Find out how many items there are in the string.
+ count = countValuesInStr(tmp_str, ',');
+
+ // Now we know how many there are, allocate the memory to store them all.
+ code_array = newCodeArray(count);
+
+ // Now convert the strings to integers and place them in code_array.
+ count = 0;
+ uint16_t start_from = 0;
+ int16_t index = -1;
+ do {
+ index = tmp_str.indexOf(',', start_from);
+ code_array[count] = tmp_str.substring(start_from, index).toInt();
+ start_from = index + 1;
+ count++;
+ } while (index != -1);
+
+ 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
+
+#if SEND_PRONTO
+// Parse a Pronto Hex String/code and send it.
+// Args:
+// irsend: A ptr to the IRsend object to transmit via.
+// str: A comma-separated String of nr. of repeats, then hexadecimal numbers.
+// e.g. "R1,0000,0067,0000,0015,0060,0018,0018,0018,0030,0018,0030,0018,
+// 0030,0018,0018,0018,0030,0018,0018,0018,0018,0018,0030,0018,
+// 0018,0018,0030,0018,0030,0018,0030,0018,0018,0018,0018,0018,
+// 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 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.
+// Returns:
+// bool: Successfully sent or not.
+bool parseStringAndSendPronto(IRsend *irsend, const String str,
+ uint16_t repeats) {
+ uint16_t count;
+ uint16_t *code_array;
+ int16_t index = -1;
+ uint16_t start_from = 0;
+
+ // Find out how many items there are in the string.
+ count = countValuesInStr(str, ',');
+
+ // Check if we have the optional embedded repeats value in the code string.
+ if (str.startsWith("R") || str.startsWith("r")) {
+ // Grab the first value from the string, as it is the nr. of repeats.
+ index = str.indexOf(',', start_from);
+ repeats = str.substring(start_from + 1, index).toInt(); // Skip the 'R'.
+ start_from = index + 1;
+ count--; // We don't count the repeats value as part of the code array.
+ }
+
+ // 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);
+
+ // Rest of the string are values for the code array.
+ // Now convert the hex strings to integers and place them in code_array.
+ count = 0;
+ do {
+ index = str.indexOf(',', start_from);
+ // Convert the hexadecimal value string to an unsigned integer.
+ code_array[count] = strtoul(str.substring(start_from, index).c_str(),
+ NULL, 16);
+ start_from = index + 1;
+ count++;
+ } while (index != -1);
+
+ 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
+
+#if SEND_RAW
+// Parse an IRremote Raw Hex String/code and send it.
+// Args:
+// irsend: A ptr to the IRsend object to transmit via.
+// str: A comma-separated String containing the freq and raw IR data.
+// 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.
+// Returns:
+// bool: Successfully sent or not.
+bool parseStringAndSendRaw(IRsend *irsend, const String str) {
+ uint16_t count;
+ uint16_t freq = 38000; // Default to 38kHz.
+ uint16_t *raw_array;
+
+ // Find out how many items there are in the string.
+ count = countValuesInStr(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 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.
+ raw_array = newCodeArray(count);
+
+ // Grab the first value from the string, as it is the frequency.
+ int16_t index = str.indexOf(',', 0);
+ freq = str.substring(0, index).toInt();
+ uint16_t start_from = index + 1;
+ // Rest of the string are values for the raw array.
+ // Now convert the strings to integers and place them in raw_array.
+ count = 0;
+ do {
+ index = str.indexOf(',', start_from);
+ raw_array[count] = str.substring(start_from, index).toInt();
+ start_from = index + 1;
+ count++;
+ } while (index != -1);
+
+ 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(void) {
+#if HTML_PASSWORD_ENABLE
+ if (!server.authenticate(HttpUsername, HttpPassword)) {
+ debug("Basic HTTP authentication failure for /ir.");
+ return server.requestAuthentication();
+ }
+#endif
+ uint64_t data = 0;
+ String data_str = "";
+ int16_t ir_type = decode_type_t::NEC; // Default to NEC codes.
+ uint16_t nbits = 0;
+ uint16_t repeat = 0;
+
+ for (uint16_t i = 0; i < server.args(); i++) {
+ if (server.argName(i).equals(KEY_TYPE) ||
+ server.argName(i).equals(KEY_PROTOCOL)) {
+ ir_type = strToDecodeType(server.arg(i).c_str());
+ } else if (server.argName(i).equals(KEY_CODE)) {
+ data = getUInt64fromHex(server.arg(i).c_str());
+ data_str = server.arg(i);
+ } else if (server.argName(i).equals(KEY_BITS)) {
+ nbits = server.arg(i).toInt();
+ } else if (server.argName(i).equals(KEY_REPEAT)) {
+ repeat = server.arg(i).toInt();
+ }
+ }
+ debug("New code received via HTTP");
+ lastSendSucceeded = sendIRCode(IrSendTable[0], ir_type, data,
+ data_str.c_str(), nbits, repeat);
+ String html = F(
+ "Send IR command "
+ ""
+ "IR command sent! ");
+ html += addJsReloadUrl("/", 2, true);
+ html += F("");
+ server.send(200, "text/html", html);
+}
+
+void handleNotFound(void) {
+ String message = "File Not Found\n\n";
+ message += "URI: ";
+ message += server.uri();
+ message += "\nMethod: ";
+ message += (server.method() == HTTP_GET)?"GET":"POST";
+ message += "\nArguments: ";
+ message += server.args();
+ message += "\n";
+ for (uint8_t i=0; i < server.args(); i++)
+ message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
+ server.send(404, "text/plain", message);
+}
+
+void setup_wifi(void) {
+ delay(10);
+ loadWifiConfigFile();
+ // We start by connecting to a WiFi network
+ wifiManager.setTimeout(300); // Time out after 5 mins.
+ // Set up additional parameters for WiFiManager config menu page.
+ wifiManager.setSaveConfigCallback(saveWifiConfigCallback);
+ WiFiManagerParameter custom_hostname_text(
+ "Hostname ");
+ wifiManager.addParameter(&custom_hostname_text);
+ WiFiManagerParameter custom_hostname(
+ kHostnameKey, kHostnameKey, Hostname, kHostnameLength);
+ wifiManager.addParameter(&custom_hostname);
+ WiFiManagerParameter custom_authentication_text(
+ "Web/OTA authentication ");
+ wifiManager.addParameter(&custom_authentication_text);
+ WiFiManagerParameter custom_http_username(
+ kHttpUserKey, "username", HttpUsername, kUsernameLength);
+ wifiManager.addParameter(&custom_http_username);
+ WiFiManagerParameter custom_http_password(
+ kHttpPassKey, "password (No OTA if blank)", HttpPassword, kPasswordLength,
+ " type='password'");
+ wifiManager.addParameter(&custom_http_password);
+#if MQTT_ENABLE
+ WiFiManagerParameter custom_mqtt_text(
+ "MQTT Broker details ");
+ wifiManager.addParameter(&custom_mqtt_text);
+ WiFiManagerParameter custom_mqtt_server(
+ kMqttServerKey, "mqtt server", MqttServer, kHostnameLength);
+ wifiManager.addParameter(&custom_mqtt_server);
+ WiFiManagerParameter custom_mqtt_port(
+ kMqttPortKey, "mqtt port", MqttPort, kPortLength,
+ " input type='number' min='1' max='65535'");
+ wifiManager.addParameter(&custom_mqtt_port);
+ WiFiManagerParameter custom_mqtt_user(
+ kMqttUserKey, "mqtt username", MqttUsername, kUsernameLength);
+ wifiManager.addParameter(&custom_mqtt_user);
+ WiFiManagerParameter custom_mqtt_pass(
+ kMqttPassKey, "mqtt password", MqttPassword, kPasswordLength,
+ " type='password'");
+ wifiManager.addParameter(&custom_mqtt_pass);
+ WiFiManagerParameter custom_prefix_text(
+ "MQTT Prefix ");
+ wifiManager.addParameter(&custom_prefix_text);
+ WiFiManagerParameter custom_mqtt_prefix(
+ kMqttPrefixKey, "Leave empty to use Hostname", MqttPrefix,
+ kHostnameLength);
+ wifiManager.addParameter(&custom_mqtt_prefix);
+ #endif // MQTT_ENABLE
+#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 MIN_SIGNAL_STRENGTH
+ wifiManager.setMinimumSignalQuality(MIN_SIGNAL_STRENGTH);
+#endif // MIN_SIGNAL_STRENGTH
+ wifiManager.setRemoveDuplicateAPs(HIDE_DUPLIATE_NETWORKS);
+
+ if (!wifiManager.autoConnect()) {
+ debug("Wifi failed to connect and hit timeout. Rebooting...");
+ delay(3000);
+ // Reboot. A.k.a. "Have you tried turning it Off and On again?"
+ ESP.reset();
+ delay(5000);
+ }
+
+#if MQTT_ENABLE
+ strncpy(MqttServer, custom_mqtt_server.getValue(), kHostnameLength);
+ strncpy(MqttPort, custom_mqtt_port.getValue(), kPortLength);
+ strncpy(MqttUsername, custom_mqtt_user.getValue(), kUsernameLength);
+ strncpy(MqttPassword, custom_mqtt_pass.getValue(), kPasswordLength);
+ strncpy(MqttPrefix, custom_mqtt_prefix.getValue(), kHostnameLength);
+#endif // MQTT_ENABLE
+ strncpy(Hostname, custom_hostname.getValue(), kHostnameLength);
+ strncpy(HttpUsername, custom_http_username.getValue(), kUsernameLength);
+ strncpy(HttpPassword, custom_http_password.getValue(), kPasswordLength);
+ if (flagSaveWifiConfig) {
+ saveWifiConfig();
+ }
+ debug("WiFi connected. IP address:");
+ debug(WiFi.localIP().toString().c_str());
+}
+
+void init_vars(void) {
+#if MQTT_ENABLE
+ // If we have a prefix already, use it. Otherwise use the hostname.
+ if (!strlen(MqttPrefix)) strncpy(MqttPrefix, Hostname, kHostnameLength);
+ // Topic we send back acknowledgements on.
+ MqttAck = String(MqttPrefix) + '/' + MQTT_ACK;
+ // Sub-topic we get new commands from.
+ MqttSend = String(MqttPrefix) + '/' + MQTT_SEND;
+ // Topic we send received IRs to.
+ MqttRecv = String(MqttPrefix) + '/' + MQTT_RECV;
+ // Topic we send log messages to.
+ MqttLog = String(MqttPrefix) + '/' + MQTT_LOG;
+ // Topic for the Last Will & Testament.
+ MqttLwt = String(MqttPrefix) + '/' + MQTT_LWT;
+ // Sub-topic for the climate topics.
+ MqttClimate = String(MqttPrefix) + '/' + MQTT_CLIMATE;
+ // Sub-topic for the climate command topics.
+ MqttClimateCmnd = MqttClimate + '/' + MQTT_CLIMATE_CMND + '/';
+ // Sub-topic for the climate stat topics.
+ MqttClimateStat = MqttClimate + '/' + MQTT_CLIMATE_STAT + '/';
+ MqttDiscovery = "homeassistant/climate/" + String(Hostname) + "/config";
+ MqttHAName = String(Hostname) + "_aircon";
+ // Create a unique MQTT client id.
+ MqttClientId = String(Hostname) + String(ESP.getChipId(), HEX);
+#endif // MQTT_ENABLE
+}
+
+void setup(void) {
+ // Set the default climate settings.
+ climate.protocol = decode_type_t::UNKNOWN;
+ climate.model = -1; // Unknown.
+ climate.power = false;
+ climate.mode = stdAc::opmode_t::kAuto;
+ climate.celsius = true;
+ climate.degrees = 25; // 25C
+ climate.fanspeed = stdAc::fanspeed_t::kAuto;
+ climate.swingv = stdAc::swingv_t::kAuto;
+ climate.swingh = stdAc::swingh_t::kAuto;
+ climate.quiet = false;
+ climate.turbo = false;
+ climate.econo = false;
+ climate.light = false;
+ climate.filter = false;
+ climate.clean = false;
+ climate.beep = false;
+ climate.sleep = -1; // Off
+ climate.clock = -1; // Don't set.
+ climate_prev = climate;
+
+ // Initialise all the IR transmitters.
+ for (uint8_t i = 0; i < kSendTableSize; i++) {
+ IrSendTable[i] = new IRsend(gpioTable[i]);
+ IrSendTable[i]->begin();
+ offset = IrSendTable[i]->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
+
+#if DEBUG
+ if (!isSerialGpioUsedByIr()) {
+ // 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
+
+ setup_wifi();
+
+ // Wait a bit for things to settle.
+ delay(500);
+
+ lastReconnectAttempt = 0;
+
+ if (mdns.begin(Hostname, WiFi.localIP())) {
+ debug("MDNS responder started");
+ }
+
+ // Setup the root web page.
+ server.on("/", handleRoot);
+ // Setup the examples web page.
+ server.on("/examples", handleExamples);
+ // Setup the page to handle web-based IR codes.
+ server.on("/ir", handleIr);
+ // Setup the aircon page.
+ server.on("/aircon", handleAirCon);
+ // Setup the aircon update page.
+ server.on("/aircon/set", handleAirConSet);
+ // Setup the info page.
+ server.on("/info", handleInfo);
+ // Setup the admin page.
+ server.on("/admin", handleAdmin);
+ // Setup a reset page to cause WiFiManager information to be reset.
+ server.on("/reset", handleReset);
+ // Reboot url
+ server.on("/quitquitquit", handleReboot);
+#if MQTT_ENABLE
+ // MQTT Discovery url
+ server.on("/send_discovery", handleSendMqttDiscovery);
+ // Finish setup of the mqtt clent object.
+ mqtt_client.setServer(MqttServer, atoi(MqttPort));
+ mqtt_client.setCallback(mqttCallback);
+ // Set various variables
+ init_vars();
+#endif // MQTT_ENABLE
+
+#if FIRMWARE_OTA
+ // Setup the URL to allow Over-The-Air (OTA) firmware updates.
+ if (strlen(HttpPassword)) { // Allow if password is set.
+ server.on("/update", HTTP_POST, [](){
+#if MQTT_ENABLE
+ mqttLog("Attempting firmware update & reboot");
+ delay(1000);
+#endif // MQTT_ENABLE
+ server.send(200, "text/html",
+ "Updating firmware. "
+ ""
+ "Updating firmware "
+ " "
+ "Warning! Don't power off the device for 60 seconds! "
+ "The firmware is uploading and will try to flash itself. "
+ "It is important to not interrupt the process.
"
+ "The firmware upload seems to have " +
+ String(Update.hasError() ? "FAILED!" : "SUCCEEDED!") +
+ " Rebooting!
" +
+ addJsReloadUrl("/", 20, true) +
+ "");
+ delay(1000);
+ ESP.restart();
+ delay(1000);
+ }, [](){
+ if (!server.authenticate(HttpUsername, HttpPassword)) {
+ debug("Basic HTTP authentication failure for /update.");
+ return server.requestAuthentication();
+ }
+ HTTPUpload& upload = server.upload();
+ if (upload.status == UPLOAD_FILE_START) {
+ WiFiUDP::stopAll();
+ debug("Update:");
+ debug(upload.filename.c_str());
+ uint32_t maxSketchSpace = (ESP.getFreeSketchSpace() - 0x1000) &
+ 0xFFFFF000;
+ if (!Update.begin(maxSketchSpace)) { // start with max available size
+#if DEBUG
+ if (!isSerialGpioUsedByIr())
+ Update.printError(Serial);
+#endif // DEBUG
+ }
+ } else if (upload.status == UPLOAD_FILE_WRITE) {
+ if (Update.write(upload.buf, upload.currentSize) !=
+ upload.currentSize) {
+#if DEBUG
+ if (!isSerialGpioUsedByIr())
+ 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:");
+ debug(String(upload.totalSize).c_str());
+ debug("Rebooting...");
+ }
+ }
+ yield();
+ });
+ }
+#endif // FIRMWARE_OTA
+
+ // Set up an error page.
+ server.onNotFound(handleNotFound);
+
+ server.begin();
+ debug("HTTP server started");
+}
+
+#if MQTT_ENABLE
+// MQTT subscribing to topic
+void subscribing(const String topic_name) {
+ // subscription to topic for receiving data with QoS.
+ if (mqtt_client.subscribe(topic_name.c_str(), QOS))
+ debug("Subscription OK to:");
+ else
+ debug("Subscription FAILED to:");
+ debug(topic_name.c_str());
+}
+
+// Un-subscribe from a MQTT topic
+void unsubscribing(const String topic_name) {
+ // subscription to topic for receiving data with QoS.
+ if (mqtt_client.unsubscribe(topic_name.c_str()))
+ debug("Unsubscribed OK from:");
+ else
+ debug("FAILED to unsubscribe from:");
+ debug(topic_name.c_str());
+}
+
+void mqttLog(const String mesg) {
+ debug(mesg.c_str());
+ mqtt_client.publish(MqttLog.c_str(), mesg.c_str());
+ mqttSentCounter++;
+}
+
+bool reconnect(void) {
+ // Loop a few times or until we're reconnected
+ uint16_t tries = 1;
+ while (!mqtt_client.connected() && tries <= 3) {
+ int connected = false;
+ // Attempt to connect
+ debug(("Attempting MQTT connection to " + String(MqttServer) + ":" +
+ String(MqttPort) + "... ").c_str());
+ if (strcmp(MqttUsername, "") && strcmp(MqttPassword, "")) {
+ debug("Using mqtt username/password to connect.");
+ connected = mqtt_client.connect(MqttClientId.c_str(),
+ MqttUsername, MqttPassword,
+ MqttLwt.c_str(),
+ QOS, true, kLwtOffline);
+
+ } else {
+ debug("Using password-less mqtt connection.");
+ connected = mqtt_client.connect(MqttClientId.c_str(), MqttLwt.c_str(),
+ QOS, true, kLwtOffline);
+ }
+ if (connected) {
+ // Once connected, publish an announcement...
+ mqttLog("(Re)Connected.");
+
+ // Update Last Will & Testament to say we are back online.
+ mqtt_client.publish(MqttLwt.c_str(), kLwtOnline, true);
+ mqttSentCounter++;
+
+ // Subscribing to topic(s)
+ subscribing(MqttSend);
+ for (uint8_t i = 0; i < kSendTableSize; i++) {
+ subscribing(MqttSend + '_' + String(static_cast(i)));
+ }
+ // Climate command topics.
+ subscribing(MqttClimateCmnd + '+');
+ } else {
+ debug(("failed, rc=" + String(mqtt_client.state()) +
+ " Try again in a bit.").c_str());
+ // Wait for a bit before retrying
+ delay(tries << 7); // Linear increasing back-off (x128)
+ }
+ tries++;
+ }
+ return mqtt_client.connected();
+}
+
+// Return a string containing the comma separated list of MQTT command topics.
+String listOfCommandTopics(void) {
+ String result = MqttSend;
+ for (uint16_t i = 0; i < kSendTableSize; i++) {
+ result += ", " + MqttSend + '_' + String(i);
+ }
+ return result;
+}
+
+// MQTT Discovery web page
+void handleSendMqttDiscovery(void) {
+#if HTML_PASSWORD_ENABLE
+ if (!server.authenticate(HttpUsername, HttpPassword)) {
+ debug("Basic HTTP authentication failure for /send_discovery.");
+ return server.requestAuthentication();
+ }
+#endif // HTML_PASSWORD_ENABLE
+ server.send(200, "text/html",
+ "Sending MQTT Discovery message "
+ ""
+ "Sending MQTT Discovery message. " +
+ htmlMenu() +
+ "The Home Assistant MQTT Discovery message is being sent to topic: " +
+ MqttDiscovery + ". It will show up in Home Assistant in a few seconds."
+ "
"
+ "Warning! "
+ "Home Assistant's config for this device is reset each time this is "
+ " is sent.
" +
+ addJsReloadUrl("/", 15, true) +
+ "");
+ sendMQTTDiscovery(MqttDiscovery.c_str());
+}
+
+void doBroadcast(TimerMs *timer, const uint32_t interval,
+ const commonAcState_t state, const bool retain,
+ const bool force) {
+ if (force || (!lockMqttBroadcast && timer->elapsed() > interval)) {
+ debug("Sending MQTT stat update broadcast.");
+ sendClimate(state, state, MqttClimateStat,
+ retain, true, false);
+ timer->reset(); // It's been sent, so reset the timer.
+ hasBroadcastBeenSent = true;
+ }
+}
+
+void receivingMQTT(String const topic_name, String const callback_str) {
+ char* tok_ptr;
+ uint64_t code = 0;
+ uint16_t nbits = 0;
+ uint16_t repeat = 0;
+ uint8_t channel = 0; // Default to the first channel. e.g. "*_0"
+
+ debug("Receiving data by MQTT topic:");
+ debug(topic_name.c_str());
+ debug("with payload:");
+ debug(callback_str.c_str());
+ // Save the message as the last command seen (global).
+ lastMqttCmdTopic = topic_name;
+ lastMqttCmd = callback_str;
+ lastMqttCmdTime = millis();
+ mqttRecvCounter++;
+
+ if (topic_name.startsWith(MqttClimate)) {
+ if (topic_name.startsWith(MqttClimateCmnd)) {
+ debug("It's a climate command topic");
+ commonAcState_t updated = updateClimate(
+ climate, topic_name, MqttClimateCmnd, callback_str);
+ sendClimate(climate, updated, MqttClimateStat,
+ true, false, false);
+ climate = updated;
+ } else if (topic_name.startsWith(MqttClimateStat)) {
+ debug("It's a climate state topic. Update internal state and DON'T send");
+ climate = updateClimate(
+ climate, topic_name, MqttClimateStat, callback_str);
+ }
+ return; // We are done for now.
+ }
+ // Check if a specific channel was requested by looking for a "*_[0-9]" suffix
+ for (uint8_t i = 0; i < kSendTableSize; i++) {
+ debug(("Checking if " + topic_name + " ends with _" + String(i)).c_str());
+ if (topic_name.endsWith("_" + String(i))) {
+ channel = i;
+ debug("It does!");
+ break;
+ }
+ }
+
+ debug(("Using transmit channel " + String(static_cast(channel)) +
+ " / GPIO " + String(static_cast(gpioTable[channel]))).c_str());
+ // Make a copy of the callback string as strtok destroys it.
+ char* callback_c_str = strdup(callback_str.c_str());
+ debug("MQTT Payload (raw):");
+ debug(callback_c_str);
+
+ // Get the numeric protocol type.
+ int ir_type = strtoul(strtok_r(callback_c_str, ",", &tok_ptr), NULL, 10);
+ char* next = strtok_r(NULL, ",", &tok_ptr);
+ // If there is unparsed string left, try to convert it assuming it's hex.
+ if (next != NULL) {
+ code = getUInt64fromHex(next);
+ next = strtok_r(NULL, ",", &tok_ptr);
+ } else {
+ // We require at least two value in the string. Give up.
+ return;
+ }
+ // If there is still string left, assume it is the bit size.
+ if (next != NULL) {
+ nbits = atoi(next);
+ next = strtok_r(NULL, ",", &tok_ptr);
+ }
+ // If there is still string left, assume it is the repeat count.
+ if (next != NULL)
+ repeat = atoi(next);
+
+ free(callback_c_str);
+
+ // send received MQTT value by IR signal
+ lastSendSucceeded = sendIRCode(
+ IrSendTable[channel], ir_type, code,
+ callback_str.substring(callback_str.indexOf(",") + 1).c_str(),
+ nbits, repeat);
+}
+
+// Callback function, when we receive an MQTT value on the topics
+// subscribed this function is called
+void mqttCallback(char* topic, byte* payload, unsigned int length) {
+ // In order to republish this payload, a copy must be made
+ // as the orignal payload buffer will be overwritten whilst
+ // constructing the PUBLISH packet.
+ // Allocate the correct amount of memory for the payload copy
+ byte* payload_copy = reinterpret_cast(malloc(length + 1));
+ // Copy the payload to the new buffer
+ memcpy(payload_copy, payload, length);
+
+ // Conversion to a printable string
+ payload_copy[length] = '\0';
+ String callback_string = String(reinterpret_cast(payload_copy));
+ String topic_name = String(reinterpret_cast(topic));
+
+ // launch the function to treat received data
+ receivingMQTT(topic_name, callback_string);
+
+ // Free the memory
+ free(payload_copy);
+}
+
+void sendMQTTDiscovery(const char *topic) {
+ if (mqtt_client.publish(
+ topic, String(
+ "{"
+ "\"~\":\"" + MqttClimate + "\","
+ "\"name\":\"" + MqttHAName + "\","
+ "\"pow_cmd_t\":\"~" MQTT_CLIMATE "/" MQTT_CLIMATE_CMND "/" KEY_POWER "\","
+ "\"mode_cmd_t\":\"~" MQTT_CLIMATE "/" MQTT_CLIMATE_CMND "/" KEY_MODE "\","
+ "\"mode_stat_t\":\"~" MQTT_CLIMATE "/" MQTT_CLIMATE_STAT "/" KEY_MODE
+ "\","
+ "\"modes\":[\"off\",\"auto\",\"cool\",\"heat\",\"dry\",\"fan_only\"],"
+ "\"temp_cmd_t\":\"~" MQTT_CLIMATE "/" MQTT_CLIMATE_CMND "/" KEY_TEMP "\","
+ "\"temp_stat_t\":\"~" MQTT_CLIMATE "/" MQTT_CLIMATE_STAT "/" KEY_TEMP
+ "\","
+ "\"min_temp\":\"16\","
+ "\"max_temp\":\"30\","
+ "\"temp_step\":\"1\","
+ "\"fan_mode_cmd_t\":\"~" MQTT_CLIMATE "/" MQTT_CLIMATE_CMND "/"
+ KEY_FANSPEED "\","
+ "\"fan_mode_stat_t\":\"~" MQTT_CLIMATE "/" MQTT_CLIMATE_STAT "/"
+ KEY_FANSPEED "\","
+ "\"fan_modes\":[\"auto\",\"min\",\"low\",\"medium\",\"high\",\"max\"],"
+ "\"swing_mode_cmd_t\":\"~" MQTT_CLIMATE "/" MQTT_CLIMATE_CMND "/"
+ KEY_SWINGV "\","
+ "\"swing_mode_stat_t\":\"~" MQTT_CLIMATE "/" MQTT_CLIMATE_STAT "/"
+ KEY_SWINGV "\","
+ "\"swing_modes\":["
+ "\"off\",\"auto\",\"highest\",\"high\",\"middle\",\"low\",\"lowest\""
+ "]"
+ "}").c_str())) {
+ mqttLog("MQTT climate discovery successful sent.");
+ hasDiscoveryBeenSent = true;
+ lastDiscovery.reset();
+ mqttSentCounter++;
+ } else {
+ mqttLog("MQTT climate discovery FAILED to send.");
+ }
+}
+#endif // MQTT_ENABLE
+
+void loop(void) {
+ server.handleClient(); // Handle any web activity
+
+#if MQTT_ENABLE
+ uint32_t now = millis();
+ // MQTT client connection management
+ if (!mqtt_client.connected()) {
+ 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) {
+ mqttLog("IR Server just booted");
+ boot = false;
+ } else {
+ mqttLog("IR Server just (re)connected to MQTT. "
+ "Lost connection about " + timeSince(lastConnectedTime));
+ }
+ lastConnectedTime = now;
+ debug("successful client mqtt connection");
+ if (lockMqttBroadcast) {
+ // Attempt to fetch back any Climate state stored in MQTT retained
+ // messages on the MQTT broker.
+ mqttLog("Started listening for previous state.");
+ climate_prev = climate; // Make a copy so we can compare afterwards.
+ subscribing(MqttClimateStat + '+');
+ statListenTime.reset();
+ }
+ }
+ }
+ } else {
+ // MQTT loop
+ lastConnectedTime = now;
+ mqtt_client.loop();
+ if (lockMqttBroadcast && statListenTime.elapsed() > kStatListenPeriodMs) {
+ unsubscribing(MqttClimateStat + '+');
+ mqttLog("Finished listening for previous state.");
+ if (cmpClimate(climate, climate_prev)) { // Something changed.
+ mqttLog("The state was recovered from MQTT broker. Updating.");
+ sendClimate(climate_prev, climate, MqttClimateStat,
+ true, false, false);
+ }
+ lockMqttBroadcast = false; // Release the lock so we can broadcast again.
+ }
+ // Periodically send all of the climate state via MQTT.
+ doBroadcast(&lastBroadcast, kBroadcastPeriodMs, climate, false, false);
+ }
+#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 // REPORT_UNKNOWNS
+ 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);
+#if MQTT_ENABLE
+ mqtt_client.publish(MqttRecv.c_str(), lastIrReceived.c_str());
+ mqttSentCounter++;
+#endif // MQTT_ENABLE
+ irRecvCounter++;
+ debug("Incoming IR message sent to MQTT:");
+ debug(lastIrReceived.c_str());
+ }
+#endif // IR_RX
+ delay(100);
+}
+
+// Arduino framework doesn't support strtoull(), so make our own one.
+uint64_t getUInt64fromHex(char const *str) {
+ uint64_t result = 0;
+ uint16_t offset = 0;
+ // Skip any leading '0x' or '0X' prefix.
+ if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X'))
+ offset = 2;
+ for (; isxdigit((unsigned char)str[offset]); offset++) {
+ char c = str[offset];
+ result *= 16;
+ if (isdigit(c)) /* '0' .. '9' */
+ result += c - '0';
+ else if (isupper(c)) /* 'A' .. 'F' */
+ result += c - 'A' + 10;
+ else /* 'a' .. 'f'*/
+ result += c - 'a' + 10;
+ }
+ return result;
+}
+
+// Transmit the given IR message.
+//
+// Args:
+// irsend: A pointer to a IRsend object to transmit via.
+// ir_type: enum of the protocol to be sent.
+// code: Numeric payload of the IR message. Most protocols use this.
+// 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.)
+// Returns:
+// bool: Successfully sent or not.
+bool sendIRCode(IRsend *irsend, 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 (lockIr)
+ delay(20);
+ lockIr = true;
+
+ bool success = true; // Assume success.
+
+ // send the IR message.
+ switch (ir_type) {
+#if SEND_RC5
+ case RC5: // 1
+ if (bits == 0)
+ bits = kRC5Bits;
+ irsend->sendRC5(code, bits, repeat);
+ break;
+#endif
+#if SEND_RC6
+ case RC6: // 2
+ if (bits == 0)
+ bits = kRC6Mode0Bits;
+ irsend->sendRC6(code, bits, repeat);
+ break;
+#endif
+#if SEND_NEC
+ case NEC: // 3
+ if (bits == 0)
+ bits = kNECBits;
+ irsend->sendNEC(code, bits, repeat);
+ break;
+#endif
+#if SEND_SONY
+ case SONY: // 4
+ if (bits == 0)
+ bits = kSony12Bits;
+ repeat = std::max(repeat, kSonyMinRepeat);
+ irsend->sendSony(code, bits, repeat);
+ break;
+#endif
+#if SEND_PANASONIC
+ case PANASONIC: // 5
+ if (bits == 0)
+ bits = kPanasonicBits;
+ irsend->sendPanasonic64(code, bits, repeat);
+ break;
+#endif
+#if SEND_JVC
+ case JVC: // 6
+ if (bits == 0)
+ bits = kJvcBits;
+ irsend->sendJVC(code, bits, repeat);
+ break;
+#endif
+#if SEND_SAMSUNG
+ case SAMSUNG: // 7
+ if (bits == 0)
+ bits = kSamsungBits;
+ irsend->sendSAMSUNG(code, bits, repeat);
+ break;
+#endif
+#if SEND_SAMSUNG36
+ case SAMSUNG36: // 56
+ if (bits == 0)
+ bits = kSamsung36Bits;
+ irsend->sendSamsung36(code, bits, repeat);
+ break;
+#endif
+#if SEND_WHYNTER
+ case WHYNTER: // 8
+ if (bits == 0)
+ bits = kWhynterBits;
+ irsend->sendWhynter(code, bits, repeat);
+ break;
+#endif
+#if SEND_AIWA_RC_T501
+ case AIWA_RC_T501: // 9
+ if (bits == 0)
+ bits = kAiwaRcT501Bits;
+ repeat = std::max(repeat, kAiwaRcT501MinRepeats);
+ irsend->sendAiwaRCT501(code, bits, repeat);
+ break;
+#endif
+#if SEND_LG
+ case LG: // 10
+ if (bits == 0)
+ bits = kLgBits;
+ irsend->sendLG(code, bits, repeat);
+ break;
+#endif
+#if SEND_MITSUBISHI
+ case MITSUBISHI: // 12
+ if (bits == 0)
+ bits = kMitsubishiBits;
+ repeat = std::max(repeat, kMitsubishiMinRepeat);
+ irsend->sendMitsubishi(code, bits, repeat);
+ break;
+#endif
+#if SEND_DISH
+ case DISH: // 13
+ if (bits == 0)
+ bits = kDishBits;
+ repeat = std::max(repeat, kDishMinRepeat);
+ irsend->sendDISH(code, bits, repeat);
+ break;
+#endif
+#if SEND_SHARP
+ case SHARP: // 14
+ if (bits == 0)
+ bits = kSharpBits;
+ irsend->sendSharpRaw(code, bits, repeat);
+ break;
+#endif
+#if SEND_COOLIX
+ case COOLIX: // 15
+ if (bits == 0)
+ bits = kCoolixBits;
+ irsend->sendCOOLIX(code, bits, repeat);
+ break;
+#endif
+ case DAIKIN: // 16
+ case DAIKIN2: // 53
+ case DAIKIN216: // 61
+ case KELVINATOR: // 18
+ case MITSUBISHI_AC: // 20
+ case GREE: // 24
+ case ARGO: // 27
+ case TROTEC: // 28
+ 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
+ case WHIRLPOOL_AC: // 45
+ case SAMSUNG_AC: // 46
+ case ELECTRA_AC: // 48
+ case PANASONIC_AC: // 49
+ case MWM: // 52
+ success = parseStringAndSendAirCon(irsend, ir_type, code_str);
+ break;
+#if SEND_DENON
+ case DENON: // 17
+ if (bits == 0)
+ bits = DENON_BITS;
+ irsend->sendDenon(code, bits, repeat);
+ break;
+#endif
+#if SEND_SHERWOOD
+ case SHERWOOD: // 19
+ if (bits == 0)
+ bits = kSherwoodBits;
+ repeat = std::max(repeat, kSherwoodMinRepeat);
+ irsend->sendSherwood(code, bits, repeat);
+ break;
+#endif
+#if SEND_RCMM
+ case RCMM: // 21
+ if (bits == 0)
+ bits = kRCMMBits;
+ irsend->sendRCMM(code, bits, repeat);
+ break;
+#endif
+#if SEND_SANYO
+ case SANYO_LC7461: // 22
+ if (bits == 0)
+ bits = kSanyoLC7461Bits;
+ irsend->sendSanyoLC7461(code, bits, repeat);
+ break;
+#endif
+#if SEND_RC5
+ case RC5X: // 23
+ if (bits == 0)
+ bits = kRC5XBits;
+ irsend->sendRC5(code, bits, repeat);
+ break;
+#endif
+#if SEND_PRONTO
+ case PRONTO: // 25
+ success = parseStringAndSendPronto(irsend, code_str, repeat);
+ break;
+#endif
+#if SEND_NIKAI
+ case NIKAI: // 29
+ if (bits == 0)
+ bits = kNikaiBits;
+ irsend->sendNikai(code, bits, repeat);
+ break;
+#endif
+#if SEND_RAW
+ case RAW: // 30
+ success = parseStringAndSendRaw(irsend, code_str);
+ break;
+#endif
+#if SEND_GLOBALCACHE
+ case GLOBALCACHE: // 31
+ success = parseStringAndSendGC(irsend, code_str);
+ break;
+#endif
+#if SEND_MIDEA
+ case MIDEA: // 34
+ if (bits == 0)
+ bits = kMideaBits;
+ irsend->sendMidea(code, bits, repeat);
+ break;
+#endif
+#if SEND_MAGIQUEST
+ case MAGIQUEST: // 35
+ if (bits == 0)
+ bits = kMagiquestBits;
+ irsend->sendMagiQuest(code, bits, repeat);
+ break;
+#endif
+#if SEND_LASERTAG
+ case LASERTAG: // 36
+ if (bits == 0)
+ bits = kLasertagBits;
+ irsend->sendLasertag(code, bits, repeat);
+ break;
+#endif
+#if SEND_CARRIER_AC
+ case CARRIER_AC: // 37
+ if (bits == 0)
+ bits = kCarrierAcBits;
+ irsend->sendCarrierAC(code, bits, repeat);
+ break;
+#endif
+#if SEND_MITSUBISHI2
+ case MITSUBISHI2: // 39
+ if (bits == 0)
+ bits = kMitsubishiBits;
+ repeat = std::max(repeat, kMitsubishiMinRepeat);
+ irsend->sendMitsubishi2(code, bits, repeat);
+ break;
+#endif
+#if SEND_GICABLE
+ case GICABLE: // 43
+ if (bits == 0)
+ 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
+#if SEND_TECO
+ case TECO: // 55
+ if (bits == 0)
+ bits = kTecoBits;
+ irsend->sendTeco(code, bits, repeat);
+ break;
+#endif
+#if SEND_LEGOPF
+ case LEGOPF: // 58
+ if (bits == 0)
+ bits = kLegoPfBits;
+ irsend->sendLegoPf(code, bits, repeat);
+ break;
+#endif
+ default:
+ // If we got here, we didn't know how to send it.
+ success = false;
+ }
+ lastSendTime = millis();
+ // Release the lock.
+ lockIr = false;
+
+ // 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:");
+ debug(String(ir_type).c_str());
+ // For "long" codes we basically repeat what we got.
+ if (hasACState((decode_type_t) ir_type) ||
+ ir_type == PRONTO ||
+ ir_type == RAW ||
+ ir_type == GLOBALCACHE) {
+ debug("Code: ");
+ debug(code_str);
+ // Confirm what we were asked to send was sent.
+#if MQTT_ENABLE
+ if (success) {
+ if (ir_type == PRONTO && repeat > 0)
+ mqtt_client.publish(MqttAck.c_str(), (String(ir_type) + ",R" +
+ String(repeat) + "," +
+ String(code_str)).c_str());
+ else
+ mqtt_client.publish(MqttAck.c_str(), (String(ir_type) + "," +
+ String(code_str)).c_str());
+ mqttSentCounter++;
+ }
+#endif // MQTT_ENABLE
+ } else { // For "short" codes, we break it down a bit more before we report.
+ debug(("Code: 0x" + uint64ToString(code, 16)).c_str());
+ debug(("Bits: " + String(bits)).c_str());
+ debug(("Repeats: " + String(repeat)).c_str());
+#if MQTT_ENABLE
+ if (success) {
+ mqtt_client.publish(MqttAck.c_str(), (String(ir_type) + "," +
+ uint64ToString(code, 16)
+ + "," + String(bits) + "," +
+ String(repeat)).c_str());
+ mqttSentCounter++;
+ }
+#endif // MQTT_ENABLE
+ }
+ return success;
+}
+
+bool sendInt(const String topic, const int32_t num, const bool retain) {
+#if MQTT_ENABLE
+ mqttSentCounter++;
+ return mqtt_client.publish(topic.c_str(), String(num).c_str(), retain);
+#else // MQTT_ENABLE
+ return true;
+#endif // MQTT_ENABLE
+}
+
+bool sendBool(const String topic, const bool on, const bool retain) {
+#if MQTT_ENABLE
+ mqttSentCounter++;
+ return mqtt_client.publish(topic.c_str(), (on ? "on" : "off"), retain);
+#else // MQTT_ENABLE
+ return true;
+#endif // MQTT_ENABLE
+}
+
+bool sendString(const String topic, const String str, const bool retain) {
+#if MQTT_ENABLE
+ mqttSentCounter++;
+ return mqtt_client.publish(topic.c_str(), str.c_str(), retain);
+#else // MQTT_ENABLE
+ return true;
+#endif // MQTT_ENABLE
+}
+
+bool sendFloat(const String topic, const float_t temp, const bool retain) {
+#if MQTT_ENABLE
+ mqttSentCounter++;
+ return mqtt_client.publish(topic.c_str(), String(temp, 1).c_str(), retain);
+#else // MQTT_ENABLE
+ return true;
+#endif // MQTT_ENABLE
+}
+
+commonAcState_t updateClimate(commonAcState_t current, const String str,
+ const String prefix, const String payload) {
+ commonAcState_t result = current;
+ String value = payload;
+ value.toUpperCase();
+ if (str.equals(prefix + KEY_PROTOCOL))
+ result.protocol = strToDecodeType(value.c_str());
+ else if (str.equals(prefix + KEY_MODEL))
+ result.model = IRac::strToModel(value.c_str());
+ else if (str.equals(prefix + KEY_POWER))
+ result.power = IRac::strToBool(value.c_str());
+ else if (str.equals(prefix + KEY_MODE))
+ result.mode = IRac::strToOpmode(value.c_str());
+ else if (str.equals(prefix + KEY_TEMP))
+ result.degrees = value.toFloat();
+ else if (str.equals(prefix + KEY_FANSPEED))
+ result.fanspeed = IRac::strToFanspeed(value.c_str());
+ else if (str.equals(prefix + KEY_SWINGV))
+ result.swingv = IRac::strToSwingV(value.c_str());
+ else if (str.equals(prefix + KEY_SWINGH))
+ result.swingh = IRac::strToSwingH(value.c_str());
+ else if (str.equals(prefix + KEY_QUIET))
+ result.quiet = IRac::strToBool(value.c_str());
+ else if (str.equals(prefix + KEY_TURBO))
+ result.turbo = IRac::strToBool(value.c_str());
+ else if (str.equals(prefix + KEY_ECONO))
+ result.econo = IRac::strToBool(value.c_str());
+ else if (str.equals(prefix + KEY_LIGHT))
+ result.light = IRac::strToBool(value.c_str());
+ else if (str.equals(prefix + KEY_BEEP))
+ result.beep = IRac::strToBool(value.c_str());
+ else if (str.equals(prefix + KEY_FILTER))
+ result.filter = IRac::strToBool(value.c_str());
+ else if (str.equals(prefix + KEY_CLEAN))
+ result.clean = IRac::strToBool(value.c_str());
+ else if (str.equals(prefix + KEY_SLEEP))
+ result.sleep = value.toInt();
+ else if (str.equals(prefix + KEY_CLOCK))
+ result.clock = value.toInt();
+ return result;
+}
+
+// Compare two AirCon states (climates).
+// Returns: True if they differ, False if they don't.
+bool cmpClimate(const commonAcState_t a, const commonAcState_t b) {
+ return a.protocol != b.protocol || a.model != b.model || a.power != b.power ||
+ a.mode != b.mode || a.degrees != b.degrees || a.celsius != b.celsius ||
+ a.fanspeed != b.fanspeed || a.swingv != b.swingv ||
+ a.swingh != b.swingh || a.quiet != b.quiet || a.turbo != b.turbo ||
+ a.econo != b.econo || a.light != b.light || a.filter != b.filter ||
+ a.clean != b.clean || a.beep != b.beep || a.sleep != b.sleep;
+}
+
+bool sendClimate(const commonAcState_t prev, const commonAcState_t next,
+ const String topic_prefix, const bool retain,
+ const bool forceMQTT, const bool forceIR) {
+ bool diff = false;
+ bool success = true;
+
+ if (prev.protocol != next.protocol || forceMQTT) {
+ diff = true;
+ success &= sendString(topic_prefix + KEY_PROTOCOL,
+ typeToString(next.protocol), retain);
+ }
+ if (prev.model != next.model || forceMQTT) {
+ diff = true;
+ success &= sendInt(topic_prefix + KEY_MODEL, next.model, retain);
+ }
+ if (prev.power != next.power || prev.mode != next.mode || forceMQTT) {
+ diff = true;
+ success &= sendBool(topic_prefix + KEY_POWER, next.power, retain);
+ success &= sendString(topic_prefix + KEY_MODE,
+ (next.power ? opmodeToString(next.mode) : F("off")),
+ retain);
+ }
+ if (prev.degrees != next.degrees || forceMQTT) {
+ diff = true;
+ success &= sendFloat(topic_prefix + KEY_TEMP, next.degrees, retain);
+ }
+ if (prev.celsius != next.celsius || forceMQTT) {
+ diff = true;
+ success &= sendBool(topic_prefix + KEY_CELSIUS, next.celsius, retain);
+ }
+ if (prev.fanspeed != next.fanspeed || forceMQTT) {
+ diff = true;
+ success &= sendString(topic_prefix + KEY_FANSPEED,
+ fanspeedToString(next.fanspeed), retain);
+ }
+ if (prev.swingv != next.swingv || forceMQTT) {
+ diff = true;
+ success &= sendString(topic_prefix + KEY_SWINGV,
+ swingvToString(next.swingv), retain);
+ }
+ if (prev.swingh != next.swingh || forceMQTT) {
+ diff = true;
+ success &= sendString(topic_prefix + KEY_SWINGH,
+ swinghToString(next.swingh), retain);
+ }
+ if (prev.quiet != next.quiet || forceMQTT) {
+ diff = true;
+ success &= sendBool(topic_prefix + KEY_QUIET, next.quiet, retain);
+ }
+ if (prev.turbo != next.turbo || forceMQTT) {
+ diff = true;
+ success &= sendBool(topic_prefix + KEY_TURBO, next.turbo, retain);
+ }
+ if (prev.econo != next.econo || forceMQTT) {
+ diff = true;
+ success &= sendBool(topic_prefix + KEY_ECONO, next.econo, retain);
+ }
+ if (prev.light != next.light || forceMQTT) {
+ diff = true;
+ success &= sendBool(topic_prefix + KEY_LIGHT, next.light, retain);
+ }
+ if (prev.filter != next.filter || forceMQTT) {
+ diff = true;
+ success &= sendBool(topic_prefix + KEY_FILTER, next.filter, retain);
+ }
+ if (prev.clean != next.clean || forceMQTT) {
+ diff = true;
+ success &= sendBool(topic_prefix + KEY_CLEAN, next.clean, retain);
+ }
+ if (prev.beep != next.beep || forceMQTT) {
+ diff = true;
+ success &= sendBool(topic_prefix + KEY_BEEP, next.beep, retain);
+ }
+ if (prev.sleep != next.sleep || forceMQTT) {
+ diff = true;
+ success &= sendInt(topic_prefix + KEY_SLEEP, next.sleep, retain);
+ }
+ if (diff && !forceMQTT)
+ debug("Difference in common A/C state detected.");
+ else
+ debug("NO difference in common A/C state detected.");
+ // Only send an IR message if we need to.
+ if ((diff && !forceMQTT) || forceIR) {
+ debug("Sending common A/C state via IR.");
+ lastClimateSucceeded = commonAc.sendAc(
+ next.protocol, next.model, next.power, next.mode,
+ next.degrees, next.celsius, next.fanspeed, next.swingv, next.swingh,
+ next.quiet, next.turbo, next.econo, next.light, next.filter, next.clean,
+ next.beep, next.sleep, -1);
+ if (lastClimateSucceeded) hasClimateBeenSent = true;
+ success &= lastClimateSucceeded;
+ lastClimateIr.reset();
+ irClimateCounter++;
+ sendReqCounter++;
+ }
+ return success;
+}
diff --git a/lib/IRremoteESP8266-2.5.2.03/examples/IRMQTTServer/platformio.ini b/lib/IRremoteESP8266-2.6.0/examples/IRMQTTServer/platformio.ini
similarity index 55%
rename from lib/IRremoteESP8266-2.5.2.03/examples/IRMQTTServer/platformio.ini
rename to lib/IRremoteESP8266-2.6.0/examples/IRMQTTServer/platformio.ini
index 27b44ddca..243b36a99 100644
--- a/lib/IRremoteESP8266-2.5.2.03/examples/IRMQTTServer/platformio.ini
+++ b/lib/IRremoteESP8266-2.6.0/examples/IRMQTTServer/platformio.ini
@@ -3,16 +3,19 @@ lib_extra_dirs = ../../
src_dir=.
[common]
-build_flags = -DMQTT_MAX_PACKET_SIZE=512
+build_flags = -DMQTT_MAX_PACKET_SIZE=768
+lib_ldf_mode = chain+
lib_deps_builtin =
lib_deps_external =
PubSubClient
WifiManager@0.14
+ ArduinoJson
[env:nodemcuv2]
platform = espressif8266
framework = arduino
board = nodemcuv2
+lib_ldf_mode = ${common.lib_ldf_mode}
build_flags = ${common.build_flags}
lib_deps =
${common.lib_deps_builtin}
@@ -22,7 +25,18 @@ lib_deps =
platform=espressif8266
framework=arduino
board=d1_mini
+lib_ldf_mode = ${common.lib_ldf_mode}
build_flags = ${common.build_flags}
lib_deps =
${common.lib_deps_builtin}
${common.lib_deps_external}
+
+[env:d1_mini_no_mqtt]
+platform=espressif8266
+framework=arduino
+board=d1_mini
+lib_ldf_mode = ${common.lib_ldf_mode}
+build_flags = ${common.build_flags} -DMQTT_ENABLE=false
+lib_deps =
+ ${common.lib_deps_builtin}
+ ${common.lib_deps_external}
diff --git a/lib/IRremoteESP8266-2.5.2.03/examples/IRServer/IRServer.ino b/lib/IRremoteESP8266-2.6.0/examples/IRServer/IRServer.ino
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/examples/IRServer/IRServer.ino
rename to lib/IRremoteESP8266-2.6.0/examples/IRServer/IRServer.ino
diff --git a/lib/IRremoteESP8266-2.5.2.03/examples/IRServer/platformio.ini b/lib/IRremoteESP8266-2.6.0/examples/IRServer/platformio.ini
similarity index 83%
rename from lib/IRremoteESP8266-2.5.2.03/examples/IRServer/platformio.ini
rename to lib/IRremoteESP8266-2.6.0/examples/IRServer/platformio.ini
index eeb8d1f2e..ec84f22f3 100644
--- a/lib/IRremoteESP8266-2.5.2.03/examples/IRServer/platformio.ini
+++ b/lib/IRremoteESP8266-2.6.0/examples/IRServer/platformio.ini
@@ -6,11 +6,13 @@ src_dir=.
build_flags =
lib_deps_builtin =
lib_deps_external =
+lib_ldf_mode = chain+
[env:nodemcuv2]
platform = espressif8266
framework = arduino
board = nodemcuv2
+lib_ldf_mode = ${common.lib_ldf_mode}
build_flags = ${common.build_flags}
lib_deps =
${common.lib_deps_builtin}
diff --git a/lib/IRremoteESP8266-2.5.2.03/examples/IRrecvDemo/IRrecvDemo.ino b/lib/IRremoteESP8266-2.6.0/examples/IRrecvDemo/IRrecvDemo.ino
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/examples/IRrecvDemo/IRrecvDemo.ino
rename to lib/IRremoteESP8266-2.6.0/examples/IRrecvDemo/IRrecvDemo.ino
diff --git a/lib/IRremoteESP8266-2.6.0/examples/IRrecvDemo/platformio.ini b/lib/IRremoteESP8266-2.6.0/examples/IRrecvDemo/platformio.ini
new file mode 100644
index 000000000..ec84f22f3
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/examples/IRrecvDemo/platformio.ini
@@ -0,0 +1,19 @@
+[platformio]
+lib_extra_dirs = ../../
+src_dir=.
+
+[common]
+build_flags =
+lib_deps_builtin =
+lib_deps_external =
+lib_ldf_mode = chain+
+
+[env:nodemcuv2]
+platform = espressif8266
+framework = arduino
+board = nodemcuv2
+lib_ldf_mode = ${common.lib_ldf_mode}
+build_flags = ${common.build_flags}
+lib_deps =
+ ${common.lib_deps_builtin}
+ ${common.lib_deps_external}
diff --git a/lib/IRremoteESP8266-2.5.2.03/examples/IRrecvDump/IRrecvDump.ino b/lib/IRremoteESP8266-2.6.0/examples/IRrecvDump/IRrecvDump.ino
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/examples/IRrecvDump/IRrecvDump.ino
rename to lib/IRremoteESP8266-2.6.0/examples/IRrecvDump/IRrecvDump.ino
diff --git a/lib/IRremoteESP8266-2.6.0/examples/IRrecvDump/platformio.ini b/lib/IRremoteESP8266-2.6.0/examples/IRrecvDump/platformio.ini
new file mode 100644
index 000000000..ec84f22f3
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/examples/IRrecvDump/platformio.ini
@@ -0,0 +1,19 @@
+[platformio]
+lib_extra_dirs = ../../
+src_dir=.
+
+[common]
+build_flags =
+lib_deps_builtin =
+lib_deps_external =
+lib_ldf_mode = chain+
+
+[env:nodemcuv2]
+platform = espressif8266
+framework = arduino
+board = nodemcuv2
+lib_ldf_mode = ${common.lib_ldf_mode}
+build_flags = ${common.build_flags}
+lib_deps =
+ ${common.lib_deps_builtin}
+ ${common.lib_deps_external}
diff --git a/lib/IRremoteESP8266-2.5.2.03/examples/IRrecvDumpV2/IRrecvDumpV2.ino b/lib/IRremoteESP8266-2.6.0/examples/IRrecvDumpV2/IRrecvDumpV2.ino
similarity index 84%
rename from lib/IRremoteESP8266-2.5.2.03/examples/IRrecvDumpV2/IRrecvDumpV2.ino
rename to lib/IRremoteESP8266-2.6.0/examples/IRrecvDumpV2/IRrecvDumpV2.ino
index d72e0814c..2dee0597c 100644
--- a/lib/IRremoteESP8266-2.5.2.03/examples/IRrecvDumpV2/IRrecvDumpV2.ino
+++ b/lib/IRremoteESP8266-2.6.0/examples/IRrecvDumpV2/IRrecvDumpV2.ino
@@ -35,9 +35,15 @@
#include
#include
#include
+#include
#include
#include
+#include
+#include
#include
+#include
+#include
+
// ==================== start of TUNEABLE PARAMETERS ====================
// An IR detector/demodulator is connected to GPIO pin 14
@@ -121,6 +127,20 @@ 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_DAIKIN216
+ if (results->decode_type == DAIKIN216) {
+ IRDaikin216 ac(0);
+ ac.setRaw(results->state);
+ description = ac.toString();
+ }
+#endif // DECODE_DAIKIN216
#if DECODE_FUJITSU_AC
if (results->decode_type == FUJITSU_AC) {
IRFujitsuAC ac(0);
@@ -142,6 +162,18 @@ void dumpACInfo(decode_results *results) {
description = ac.toString();
}
#endif // DECODE_MITSUBISHI_AC
+#if DECODE_MITSUBISHIHEAVY
+ if (results->decode_type == MITSUBISHI_HEAVY_88) {
+ IRMitsubishiHeavy88Ac ac(0);
+ ac.setRaw(results->state);
+ description = ac.toString();
+ }
+ if (results->decode_type == MITSUBISHI_HEAVY_152) {
+ IRMitsubishiHeavy152Ac ac(0);
+ ac.setRaw(results->state);
+ description = ac.toString();
+ }
+#endif // DECODE_MITSUBISHIHEAVY
#if DECODE_TOSHIBA_AC
if (results->decode_type == TOSHIBA_AC) {
IRToshibaAC ac(0);
@@ -180,7 +212,7 @@ void dumpACInfo(decode_results *results) {
#if DECODE_SAMSUNG_AC
if (results->decode_type == SAMSUNG_AC) {
IRSamsungAc ac(0);
- ac.setRaw(results->state);
+ ac.setRaw(results->state, results->bits / 8);
description = ac.toString();
}
#endif // DECODE_SAMSUNG_AC
@@ -206,6 +238,34 @@ void dumpACInfo(decode_results *results) {
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 DECODE_TECO
+ if (results->decode_type == TECO) {
+ IRTecoAc ac(0);
+ ac.setRaw(results->value); // Like Coolix, use value instead of state.
+ description = ac.toString();
+ }
+#endif // DECODE_TECO
+#if DECODE_TCL112AC
+ if (results->decode_type == TCL112AC) {
+ IRTcl112Ac ac(0);
+ ac.setRaw(results->state);
+ description = ac.toString();
+ }
+#endif // DECODE_TCL112AC
// If we got a human-readable description of the message, display it.
if (description != "") Serial.println("Mesg Desc.: " + description);
}
diff --git a/lib/IRremoteESP8266-2.6.0/examples/IRrecvDumpV2/platformio.ini b/lib/IRremoteESP8266-2.6.0/examples/IRrecvDumpV2/platformio.ini
new file mode 100644
index 000000000..ec84f22f3
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/examples/IRrecvDumpV2/platformio.ini
@@ -0,0 +1,19 @@
+[platformio]
+lib_extra_dirs = ../../
+src_dir=.
+
+[common]
+build_flags =
+lib_deps_builtin =
+lib_deps_external =
+lib_ldf_mode = chain+
+
+[env:nodemcuv2]
+platform = espressif8266
+framework = arduino
+board = nodemcuv2
+lib_ldf_mode = ${common.lib_ldf_mode}
+build_flags = ${common.build_flags}
+lib_deps =
+ ${common.lib_deps_builtin}
+ ${common.lib_deps_external}
diff --git a/lib/IRremoteESP8266-2.5.2.03/examples/IRsendDemo/IRsendDemo.ino b/lib/IRremoteESP8266-2.6.0/examples/IRsendDemo/IRsendDemo.ino
similarity index 85%
rename from lib/IRremoteESP8266-2.5.2.03/examples/IRsendDemo/IRsendDemo.ino
rename to lib/IRremoteESP8266-2.6.0/examples/IRsendDemo/IRsendDemo.ino
index 892016b3e..19f118671 100644
--- a/lib/IRremoteESP8266-2.5.2.03/examples/IRsendDemo/IRsendDemo.ino
+++ b/lib/IRremoteESP8266-2.6.0/examples/IRsendDemo/IRsendDemo.ino
@@ -1,6 +1,6 @@
/* 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
*
@@ -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-2.6.0/examples/IRsendDemo/platformio.ini b/lib/IRremoteESP8266-2.6.0/examples/IRsendDemo/platformio.ini
new file mode 100644
index 000000000..ec84f22f3
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/examples/IRsendDemo/platformio.ini
@@ -0,0 +1,19 @@
+[platformio]
+lib_extra_dirs = ../../
+src_dir=.
+
+[common]
+build_flags =
+lib_deps_builtin =
+lib_deps_external =
+lib_ldf_mode = chain+
+
+[env:nodemcuv2]
+platform = espressif8266
+framework = arduino
+board = nodemcuv2
+lib_ldf_mode = ${common.lib_ldf_mode}
+build_flags = ${common.build_flags}
+lib_deps =
+ ${common.lib_deps_builtin}
+ ${common.lib_deps_external}
diff --git a/lib/IRremoteESP8266-2.5.2.03/examples/IRsendProntoDemo/IRsendProntoDemo.ino b/lib/IRremoteESP8266-2.6.0/examples/IRsendProntoDemo/IRsendProntoDemo.ino
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/examples/IRsendProntoDemo/IRsendProntoDemo.ino
rename to lib/IRremoteESP8266-2.6.0/examples/IRsendProntoDemo/IRsendProntoDemo.ino
diff --git a/lib/IRremoteESP8266-2.6.0/examples/IRsendProntoDemo/platformio.ini b/lib/IRremoteESP8266-2.6.0/examples/IRsendProntoDemo/platformio.ini
new file mode 100644
index 000000000..ec84f22f3
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/examples/IRsendProntoDemo/platformio.ini
@@ -0,0 +1,19 @@
+[platformio]
+lib_extra_dirs = ../../
+src_dir=.
+
+[common]
+build_flags =
+lib_deps_builtin =
+lib_deps_external =
+lib_ldf_mode = chain+
+
+[env:nodemcuv2]
+platform = espressif8266
+framework = arduino
+board = nodemcuv2
+lib_ldf_mode = ${common.lib_ldf_mode}
+build_flags = ${common.build_flags}
+lib_deps =
+ ${common.lib_deps_builtin}
+ ${common.lib_deps_external}
diff --git a/lib/IRremoteESP8266-2.5.2.03/examples/JVCPanasonicSendDemo/JVCPanasonicSendDemo.ino b/lib/IRremoteESP8266-2.6.0/examples/JVCPanasonicSendDemo/JVCPanasonicSendDemo.ino
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/examples/JVCPanasonicSendDemo/JVCPanasonicSendDemo.ino
rename to lib/IRremoteESP8266-2.6.0/examples/JVCPanasonicSendDemo/JVCPanasonicSendDemo.ino
diff --git a/lib/IRremoteESP8266-2.6.0/examples/JVCPanasonicSendDemo/platformio.ini b/lib/IRremoteESP8266-2.6.0/examples/JVCPanasonicSendDemo/platformio.ini
new file mode 100644
index 000000000..ec84f22f3
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/examples/JVCPanasonicSendDemo/platformio.ini
@@ -0,0 +1,19 @@
+[platformio]
+lib_extra_dirs = ../../
+src_dir=.
+
+[common]
+build_flags =
+lib_deps_builtin =
+lib_deps_external =
+lib_ldf_mode = chain+
+
+[env:nodemcuv2]
+platform = espressif8266
+framework = arduino
+board = nodemcuv2
+lib_ldf_mode = ${common.lib_ldf_mode}
+build_flags = ${common.build_flags}
+lib_deps =
+ ${common.lib_deps_builtin}
+ ${common.lib_deps_external}
diff --git a/lib/IRremoteESP8266-2.5.2.03/examples/LGACSend/LGACSend.ino b/lib/IRremoteESP8266-2.6.0/examples/LGACSend/LGACSend.ino
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/examples/LGACSend/LGACSend.ino
rename to lib/IRremoteESP8266-2.6.0/examples/LGACSend/LGACSend.ino
diff --git a/lib/IRremoteESP8266-2.6.0/examples/LGACSend/platformio.ini b/lib/IRremoteESP8266-2.6.0/examples/LGACSend/platformio.ini
new file mode 100644
index 000000000..ec84f22f3
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/examples/LGACSend/platformio.ini
@@ -0,0 +1,19 @@
+[platformio]
+lib_extra_dirs = ../../
+src_dir=.
+
+[common]
+build_flags =
+lib_deps_builtin =
+lib_deps_external =
+lib_ldf_mode = chain+
+
+[env:nodemcuv2]
+platform = espressif8266
+framework = arduino
+board = nodemcuv2
+lib_ldf_mode = ${common.lib_ldf_mode}
+build_flags = ${common.build_flags}
+lib_deps =
+ ${common.lib_deps_builtin}
+ ${common.lib_deps_external}
diff --git a/lib/IRremoteESP8266-2.5.2.03/examples/TurnOnArgoAC/TurnOnArgoAC.ino b/lib/IRremoteESP8266-2.6.0/examples/TurnOnArgoAC/TurnOnArgoAC.ino
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/examples/TurnOnArgoAC/TurnOnArgoAC.ino
rename to lib/IRremoteESP8266-2.6.0/examples/TurnOnArgoAC/TurnOnArgoAC.ino
diff --git a/lib/IRremoteESP8266-2.6.0/examples/TurnOnArgoAC/platformio.ini b/lib/IRremoteESP8266-2.6.0/examples/TurnOnArgoAC/platformio.ini
new file mode 100644
index 000000000..ec84f22f3
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/examples/TurnOnArgoAC/platformio.ini
@@ -0,0 +1,19 @@
+[platformio]
+lib_extra_dirs = ../../
+src_dir=.
+
+[common]
+build_flags =
+lib_deps_builtin =
+lib_deps_external =
+lib_ldf_mode = chain+
+
+[env:nodemcuv2]
+platform = espressif8266
+framework = arduino
+board = nodemcuv2
+lib_ldf_mode = ${common.lib_ldf_mode}
+build_flags = ${common.build_flags}
+lib_deps =
+ ${common.lib_deps_builtin}
+ ${common.lib_deps_external}
diff --git a/lib/IRremoteESP8266-2.5.2.03/examples/TurnOnDaikinAC/TurnOnDaikinAC.ino b/lib/IRremoteESP8266-2.6.0/examples/TurnOnDaikinAC/TurnOnDaikinAC.ino
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/examples/TurnOnDaikinAC/TurnOnDaikinAC.ino
rename to lib/IRremoteESP8266-2.6.0/examples/TurnOnDaikinAC/TurnOnDaikinAC.ino
diff --git a/lib/IRremoteESP8266-2.6.0/examples/TurnOnDaikinAC/platformio.ini b/lib/IRremoteESP8266-2.6.0/examples/TurnOnDaikinAC/platformio.ini
new file mode 100644
index 000000000..ec84f22f3
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/examples/TurnOnDaikinAC/platformio.ini
@@ -0,0 +1,19 @@
+[platformio]
+lib_extra_dirs = ../../
+src_dir=.
+
+[common]
+build_flags =
+lib_deps_builtin =
+lib_deps_external =
+lib_ldf_mode = chain+
+
+[env:nodemcuv2]
+platform = espressif8266
+framework = arduino
+board = nodemcuv2
+lib_ldf_mode = ${common.lib_ldf_mode}
+build_flags = ${common.build_flags}
+lib_deps =
+ ${common.lib_deps_builtin}
+ ${common.lib_deps_external}
diff --git a/lib/IRremoteESP8266-2.5.2.03/examples/TurnOnFujitsuAC/TurnOnFujitsuAC.ino b/lib/IRremoteESP8266-2.6.0/examples/TurnOnFujitsuAC/TurnOnFujitsuAC.ino
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/examples/TurnOnFujitsuAC/TurnOnFujitsuAC.ino
rename to lib/IRremoteESP8266-2.6.0/examples/TurnOnFujitsuAC/TurnOnFujitsuAC.ino
diff --git a/lib/IRremoteESP8266-2.6.0/examples/TurnOnFujitsuAC/platformio.ini b/lib/IRremoteESP8266-2.6.0/examples/TurnOnFujitsuAC/platformio.ini
new file mode 100644
index 000000000..ec84f22f3
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/examples/TurnOnFujitsuAC/platformio.ini
@@ -0,0 +1,19 @@
+[platformio]
+lib_extra_dirs = ../../
+src_dir=.
+
+[common]
+build_flags =
+lib_deps_builtin =
+lib_deps_external =
+lib_ldf_mode = chain+
+
+[env:nodemcuv2]
+platform = espressif8266
+framework = arduino
+board = nodemcuv2
+lib_ldf_mode = ${common.lib_ldf_mode}
+build_flags = ${common.build_flags}
+lib_deps =
+ ${common.lib_deps_builtin}
+ ${common.lib_deps_external}
diff --git a/lib/IRremoteESP8266-2.5.2.03/examples/TurnOnKelvinatorAC/TurnOnKelvinatorAC.ino b/lib/IRremoteESP8266-2.6.0/examples/TurnOnKelvinatorAC/TurnOnKelvinatorAC.ino
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/examples/TurnOnKelvinatorAC/TurnOnKelvinatorAC.ino
rename to lib/IRremoteESP8266-2.6.0/examples/TurnOnKelvinatorAC/TurnOnKelvinatorAC.ino
diff --git a/lib/IRremoteESP8266-2.6.0/examples/TurnOnKelvinatorAC/platformio.ini b/lib/IRremoteESP8266-2.6.0/examples/TurnOnKelvinatorAC/platformio.ini
new file mode 100644
index 000000000..ec84f22f3
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/examples/TurnOnKelvinatorAC/platformio.ini
@@ -0,0 +1,19 @@
+[platformio]
+lib_extra_dirs = ../../
+src_dir=.
+
+[common]
+build_flags =
+lib_deps_builtin =
+lib_deps_external =
+lib_ldf_mode = chain+
+
+[env:nodemcuv2]
+platform = espressif8266
+framework = arduino
+board = nodemcuv2
+lib_ldf_mode = ${common.lib_ldf_mode}
+build_flags = ${common.build_flags}
+lib_deps =
+ ${common.lib_deps_builtin}
+ ${common.lib_deps_external}
diff --git a/lib/IRremoteESP8266-2.5.2.03/examples/TurnOnMitsubishiAC/TurnOnMitsubishiAC.ino b/lib/IRremoteESP8266-2.6.0/examples/TurnOnMitsubishiAC/TurnOnMitsubishiAC.ino
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/examples/TurnOnMitsubishiAC/TurnOnMitsubishiAC.ino
rename to lib/IRremoteESP8266-2.6.0/examples/TurnOnMitsubishiAC/TurnOnMitsubishiAC.ino
diff --git a/lib/IRremoteESP8266-2.6.0/examples/TurnOnMitsubishiAC/platformio.ini b/lib/IRremoteESP8266-2.6.0/examples/TurnOnMitsubishiAC/platformio.ini
new file mode 100644
index 000000000..ec84f22f3
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/examples/TurnOnMitsubishiAC/platformio.ini
@@ -0,0 +1,19 @@
+[platformio]
+lib_extra_dirs = ../../
+src_dir=.
+
+[common]
+build_flags =
+lib_deps_builtin =
+lib_deps_external =
+lib_ldf_mode = chain+
+
+[env:nodemcuv2]
+platform = espressif8266
+framework = arduino
+board = nodemcuv2
+lib_ldf_mode = ${common.lib_ldf_mode}
+build_flags = ${common.build_flags}
+lib_deps =
+ ${common.lib_deps_builtin}
+ ${common.lib_deps_external}
diff --git a/lib/IRremoteESP8266-2.6.0/examples/TurnOnMitsubishiHeavyAc/TurnOnMitsubishiHeavyAc.ino b/lib/IRremoteESP8266-2.6.0/examples/TurnOnMitsubishiHeavyAc/TurnOnMitsubishiHeavyAc.ino
new file mode 100644
index 000000000..2ad2d7bc3
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/examples/TurnOnMitsubishiHeavyAc/TurnOnMitsubishiHeavyAc.ino
@@ -0,0 +1,72 @@
+/* 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).
+IRMitsubishiHeavy152Ac ac(kIrLed); // Set the GPIO used for sending messages.
+
+void printState() {
+ // Display the settings.
+ Serial.println("Mitsubishi Heavy A/C remote is in the following state:");
+ Serial.printf(" %s\n", ac.toString().c_str());
+ // Display the encoded IR sequence.
+ unsigned char* ir_code = ac.getRaw();
+ Serial.print("IR Code: 0x");
+ for (uint8_t i = 0; i < kMitsubishiHeavy152StateLength; i++)
+ Serial.printf("%02X", ir_code[i]);
+ Serial.println();
+}
+
+void setup() {
+ ac.begin();
+ Serial.begin(115200);
+ delay(200);
+
+ // Set up what we want to send. See ir_MitsubishiHeavy.(cpp|h) for all the
+ // options.
+ Serial.println("Default state of the remote.");
+ printState();
+ Serial.println("Setting desired state for A/C.");
+ ac.setPower(true); // Turn it on.
+ ac.setFan(kMitsubishiHeavy152FanMed); // Medium Fan
+ ac.setMode(kMitsubishiHeavyCool); // Cool mode
+ ac.setTemp(26); // Celsius
+ ac.setSwingVertical(kMitsubishiHeavy152SwingVAuto); // Swing vertically
+ ac.setSwingHorizontal(kMitsubishiHeavy152SwingHMiddle); // Swing Horizontally
+}
+
+void loop() {
+ // Now send the IR signal.
+ Serial.println("Sending IR command to A/C ...");
+ ac.send();
+ printState();
+ delay(5000);
+}
diff --git a/lib/IRremoteESP8266-2.6.0/examples/TurnOnMitsubishiHeavyAc/platformio.ini b/lib/IRremoteESP8266-2.6.0/examples/TurnOnMitsubishiHeavyAc/platformio.ini
new file mode 100644
index 000000000..ec84f22f3
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/examples/TurnOnMitsubishiHeavyAc/platformio.ini
@@ -0,0 +1,19 @@
+[platformio]
+lib_extra_dirs = ../../
+src_dir=.
+
+[common]
+build_flags =
+lib_deps_builtin =
+lib_deps_external =
+lib_ldf_mode = chain+
+
+[env:nodemcuv2]
+platform = espressif8266
+framework = arduino
+board = nodemcuv2
+lib_ldf_mode = ${common.lib_ldf_mode}
+build_flags = ${common.build_flags}
+lib_deps =
+ ${common.lib_deps_builtin}
+ ${common.lib_deps_external}
diff --git a/lib/IRremoteESP8266-2.6.0/examples/TurnOnPanasonicAC/TurnOnPanasonicAC.ino b/lib/IRremoteESP8266-2.6.0/examples/TurnOnPanasonicAC/TurnOnPanasonicAC.ino
new file mode 100644
index 000000000..ea39ac5e2
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/examples/TurnOnPanasonicAC/TurnOnPanasonicAC.ino
@@ -0,0 +1,74 @@
+/* Copyright 2017, 2018 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).
+IRPanasonicAc ac(kIrLed); // Set the GPIO used for sending messages.
+
+void printState() {
+ // Display the settings.
+ Serial.println("Panasonic A/C remote is in the following state:");
+ Serial.printf(" %s\n", ac.toString().c_str());
+ // Display the encoded IR sequence.
+ unsigned char* ir_code = ac.getRaw();
+ Serial.print("IR Code: 0x");
+ for (uint8_t i = 0; i < kPanasonicAcStateLength; i++)
+ Serial.printf("%02X", ir_code[i]);
+ Serial.println();
+}
+
+void setup() {
+ ac.begin();
+ Serial.begin(115200);
+ delay(200);
+
+ // Set up what we want to send. See ir_Panasonic.cpp for all the options.
+ Serial.println("Default state of the remote.");
+ printState();
+ Serial.println("Setting desired state for A/C.");
+ ac.setModel(kPanasonicRkr);
+ ac.on();
+ ac.setFan(kPanasonicAcFanAuto);
+ ac.setMode(kPanasonicAcCool);
+ ac.setTemp(26);
+ ac.setSwingVertical(kPanasonicAcSwingVAuto);
+ ac.setSwingHorizontal(kPanasonicAcSwingHAuto);
+}
+
+void loop() {
+ // Now send the IR signal.
+#if SEND_PANASONIC_AC
+ Serial.println("Sending IR command to A/C ...");
+ ac.send();
+#endif // SEND_PANASONIC_AC
+ printState();
+ delay(5000);
+}
diff --git a/lib/IRremoteESP8266-2.6.0/examples/TurnOnPanasonicAC/platformio.ini b/lib/IRremoteESP8266-2.6.0/examples/TurnOnPanasonicAC/platformio.ini
new file mode 100644
index 000000000..ec84f22f3
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/examples/TurnOnPanasonicAC/platformio.ini
@@ -0,0 +1,19 @@
+[platformio]
+lib_extra_dirs = ../../
+src_dir=.
+
+[common]
+build_flags =
+lib_deps_builtin =
+lib_deps_external =
+lib_ldf_mode = chain+
+
+[env:nodemcuv2]
+platform = espressif8266
+framework = arduino
+board = nodemcuv2
+lib_ldf_mode = ${common.lib_ldf_mode}
+build_flags = ${common.build_flags}
+lib_deps =
+ ${common.lib_deps_builtin}
+ ${common.lib_deps_external}
diff --git a/lib/IRremoteESP8266-2.5.2.03/examples/TurnOnToshibaAC/TurnOnToshibaAC.ino b/lib/IRremoteESP8266-2.6.0/examples/TurnOnToshibaAC/TurnOnToshibaAC.ino
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/examples/TurnOnToshibaAC/TurnOnToshibaAC.ino
rename to lib/IRremoteESP8266-2.6.0/examples/TurnOnToshibaAC/TurnOnToshibaAC.ino
diff --git a/lib/IRremoteESP8266-2.6.0/examples/TurnOnToshibaAC/platformio.ini b/lib/IRremoteESP8266-2.6.0/examples/TurnOnToshibaAC/platformio.ini
new file mode 100644
index 000000000..ec84f22f3
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/examples/TurnOnToshibaAC/platformio.ini
@@ -0,0 +1,19 @@
+[platformio]
+lib_extra_dirs = ../../
+src_dir=.
+
+[common]
+build_flags =
+lib_deps_builtin =
+lib_deps_external =
+lib_ldf_mode = chain+
+
+[env:nodemcuv2]
+platform = espressif8266
+framework = arduino
+board = nodemcuv2
+lib_ldf_mode = ${common.lib_ldf_mode}
+build_flags = ${common.build_flags}
+lib_deps =
+ ${common.lib_deps_builtin}
+ ${common.lib_deps_external}
diff --git a/lib/IRremoteESP8266-2.5.2.03/examples/TurnOnTrotecAC/TurnOnTrotecAC.ino b/lib/IRremoteESP8266-2.6.0/examples/TurnOnTrotecAC/TurnOnTrotecAC.ino
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/examples/TurnOnTrotecAC/TurnOnTrotecAC.ino
rename to lib/IRremoteESP8266-2.6.0/examples/TurnOnTrotecAC/TurnOnTrotecAC.ino
diff --git a/lib/IRremoteESP8266-2.6.0/examples/TurnOnTrotecAC/platformio.ini b/lib/IRremoteESP8266-2.6.0/examples/TurnOnTrotecAC/platformio.ini
new file mode 100644
index 000000000..ec84f22f3
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/examples/TurnOnTrotecAC/platformio.ini
@@ -0,0 +1,19 @@
+[platformio]
+lib_extra_dirs = ../../
+src_dir=.
+
+[common]
+build_flags =
+lib_deps_builtin =
+lib_deps_external =
+lib_ldf_mode = chain+
+
+[env:nodemcuv2]
+platform = espressif8266
+framework = arduino
+board = nodemcuv2
+lib_ldf_mode = ${common.lib_ldf_mode}
+build_flags = ${common.build_flags}
+lib_deps =
+ ${common.lib_deps_builtin}
+ ${common.lib_deps_external}
diff --git a/lib/IRremoteESP8266-2.5.2.03/keywords.txt b/lib/IRremoteESP8266-2.6.0/keywords.txt
similarity index 74%
rename from lib/IRremoteESP8266-2.5.2.03/keywords.txt
rename to lib/IRremoteESP8266-2.6.0/keywords.txt
index ac3f43fe1..a498c5d61 100644
--- a/lib/IRremoteESP8266-2.5.2.03/keywords.txt
+++ b/lib/IRremoteESP8266-2.6.0/keywords.txt
@@ -22,21 +22,32 @@
IRArgoAC KEYWORD1
IRCoolixAC KEYWORD1
+IRDaikin2 KEYWORD1
+IRDaikin216 KEYWORD1
IRDaikinESP KEYWORD1
IRFujitsuAC KEYWORD1
IRGreeAC KEYWORD1
IRHaierAC KEYWORD1
IRHaierACYRW02 KEYWORD1
+IRHitachiAc KEYWORD1
IRKelvinatorAC KEYWORD1
IRMideaAC KEYWORD1
IRMitsubishiAC KEYWORD1
+IRMitsubishiHeavy152Ac KEYWORD1
+IRMitsubishiHeavy88Ac KEYWORD1
IRPanasonicAc KEYWORD1
IRSamsungAc KEYWORD1
+IRTcl112Ac KEYWORD1
+IRTecoAc KEYWORD1
IRToshibaAC KEYWORD1
IRTrotecESP KEYWORD1
+IRVestelAc KEYWORD1
+IRWhirlpoolAc KEYWORD1
+IRac KEYWORD1
IRrecv KEYWORD1
IRsend KEYWORD1
IRtimer KEYWORD1
+TimerMs KEYWORD1
decode_results KEYWORD1
ir_params_t KEYWORD1
match_result_t KEYWORD1
@@ -46,8 +57,10 @@ match_result_t KEYWORD1
#######################################
_delayMicroseconds KEYWORD2
+_setMode KEYWORD2
+_setTemp KEYWORD2
add KEYWORD2
-addbit KEYWORD2
+argo KEYWORD2
begin KEYWORD2
buildFromState KEYWORD2
buildState KEYWORD2
@@ -60,18 +73,27 @@ calibrate KEYWORD2
cancelOffTimer KEYWORD2
cancelOnTimer KEYWORD2
cancelTimers KEYWORD2
-checkheader KEYWORD2
+checkZjsSig KEYWORD2
+checkZmsSig KEYWORD2
checksum KEYWORD2
-clearBit KEYWORD2
+clearOnTimerFlag KEYWORD2
clearSensorTemp KEYWORD2
+clearSleepTimerFlag KEYWORD2
compare KEYWORD2
+coolix KEYWORD2
copyIrParams KEYWORD2
+countBits KEYWORD2
+daikin KEYWORD2
+daikin2 KEYWORD2
+daikin216 KEYWORD2
decode KEYWORD2
decodeAiwaRCT501 KEYWORD2
decodeCOOLIX KEYWORD2
decodeCarrierAC KEYWORD2
decodeDISH KEYWORD2
decodeDaikin KEYWORD2
+decodeDaikin2 KEYWORD2
+decodeDaikin216 KEYWORD2
decodeDenon KEYWORD2
decodeElectraAC KEYWORD2
decodeFujitsuAC KEYWORD2
@@ -85,6 +107,7 @@ decodeJVC KEYWORD2
decodeKelvinator KEYWORD2
decodeLG KEYWORD2
decodeLasertag KEYWORD2
+decodeLegoPf KEYWORD2
decodeLutron KEYWORD2
decodeMWM KEYWORD2
decodeMagiQuest KEYWORD2
@@ -92,6 +115,7 @@ decodeMidea KEYWORD2
decodeMitsubishi KEYWORD2
decodeMitsubishi2 KEYWORD2
decodeMitsubishiAC KEYWORD2
+decodeMitsubishiHeavy KEYWORD2
decodeNEC KEYWORD2
decodeNikai KEYWORD2
decodePanasonic KEYWORD2
@@ -101,22 +125,29 @@ decodeRC5 KEYWORD2
decodeRC6 KEYWORD2
decodeRCMM KEYWORD2
decodeSAMSUNG KEYWORD2
+decodeSamsung36 KEYWORD2
decodeSamsungAC KEYWORD2
decodeSanyo KEYWORD2
decodeSanyoLC7461 KEYWORD2
decodeSharp KEYWORD2
decodeSony KEYWORD2
+decodeTcl112Ac KEYWORD2
+decodeTeco 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
@@ -131,15 +162,18 @@ encodeSanyoLC7461 KEYWORD2
encodeSharp KEYWORD2
encodeSony KEYWORD2
encodeTime KEYWORD2
+fanspeed_t KEYWORD2
fixChecksum KEYWORD2
fixup KEYWORD2
+fujitsu KEYWORD2
+get3D KEYWORD2
getBeep KEYWORD2
-getBit KEYWORD2
getBufSize KEYWORD2
getButton KEYWORD2
getClean KEYWORD2
getClock KEYWORD2
getCmd KEYWORD2
+getComfort KEYWORD2
getCommand KEYWORD2
getCoolMode KEYWORD2
getCorrectedRawLength KEYWORD2
@@ -147,11 +181,16 @@ getCurrTime KEYWORD2
getCurrentTime KEYWORD2
getEcono KEYWORD2
getEye KEYWORD2
+getEyeAuto KEYWORD2
getFan KEYWORD2
getFanSpeed KEYWORD2
+getFilter KEYWORD2
getFlap KEYWORD2
+getFreshAir KEYWORD2
+getFreshAirHigh KEYWORD2
getHealth KEYWORD2
getHeatMode KEYWORD2
+getIon KEYWORD2
getIonFilter KEYWORD2
getLed KEYWORD2
getLight KEYWORD2
@@ -159,6 +198,7 @@ getMax KEYWORD2
getMode KEYWORD2
getMold KEYWORD2
getNight KEYWORD2
+getNormalState KEYWORD2
getOffTime KEYWORD2
getOffTimer KEYWORD2
getOffTimerEnabled KEYWORD2
@@ -166,23 +206,30 @@ getOnTime KEYWORD2
getOnTimer KEYWORD2
getOnTimerEnabled KEYWORD2
getPower KEYWORD2
+getPowerToggle KEYWORD2
getPowerful KEYWORD2
+getPurify KEYWORD2
getQuiet KEYWORD2
getRClevel KEYWORD2
getRaw KEYWORD2
getSensor KEYWORD2
getSensorTemp KEYWORD2
+getSilent 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
@@ -191,10 +238,23 @@ getVane KEYWORD2
getXFan KEYWORD2
getZoneFollow KEYWORD2
getiFeel KEYWORD2
+gree KEYWORD2
+haier KEYWORD2
+haierYrwo2 KEYWORD2
hasACState KEYWORD2
+hitachi KEYWORD2
+htmlEscape KEYWORD2
invertBits KEYWORD2
+isOffTimerActive KEYWORD2
isOffTimerEnabled KEYWORD2
+isOnTimerActive KEYWORD2
isOnTimerEnabled KEYWORD2
+isProtocolSupported KEYWORD2
+isSpecialState KEYWORD2
+isTimeCommand KEYWORD2
+isTimerActive KEYWORD2
+isTimerEnabled KEYWORD2
+kelvinator KEYWORD2
ledOff KEYWORD2
ledOn KEYWORD2
mark KEYWORD2
@@ -203,10 +263,17 @@ matchAtLeast KEYWORD2
matchData KEYWORD2
matchMark KEYWORD2
matchSpace KEYWORD2
+midea KEYWORD2
+mitsubishi KEYWORD2
+mitsubishiHeavy152 KEYWORD2
+mitsubishiHeavy88 KEYWORD2
+mode) KEYWORD2
off KEYWORD2
on KEYWORD2
-printState KEYWORD2
-readbits KEYWORD2
+opmode_t KEYWORD2
+panasonic KEYWORD2
+position) KEYWORD2
+recoverSavedState KEYWORD2
renderTime KEYWORD2
reset KEYWORD2
resultToHexidecimal KEYWORD2
@@ -215,13 +282,17 @@ resultToSourceCode KEYWORD2
resultToTimingInfo KEYWORD2
resume KEYWORD2
reverseBits KEYWORD2
+samsung KEYWORD2
send KEYWORD2
+sendAc KEYWORD2
sendAiwaRCT501 KEYWORD2
sendArgo KEYWORD2
sendCOOLIX KEYWORD2
sendCarrierAC KEYWORD2
sendDISH KEYWORD2
sendDaikin KEYWORD2
+sendDaikin2 KEYWORD2
+sendDaikin216 KEYWORD2
sendData KEYWORD2
sendDenon KEYWORD2
sendElectraAC KEYWORD2
@@ -241,6 +312,7 @@ sendKelvinator KEYWORD2
sendLG KEYWORD2
sendLG2 KEYWORD2
sendLasertag KEYWORD2
+sendLegoPf KEYWORD2
sendLutron KEYWORD2
sendMWM KEYWORD2
sendMagiQuest KEYWORD2
@@ -248,8 +320,12 @@ sendMidea KEYWORD2
sendMitsubishi KEYWORD2
sendMitsubishi2 KEYWORD2
sendMitsubishiAC KEYWORD2
+sendMitsubishiHeavy152 KEYWORD2
+sendMitsubishiHeavy88 KEYWORD2
sendNEC KEYWORD2
sendNikai KEYWORD2
+sendOff KEYWORD2
+sendOn KEYWORD2
sendPanasonic KEYWORD2
sendPanasonic64 KEYWORD2
sendPanasonicAC KEYWORD2
@@ -260,34 +336,45 @@ sendRC6 KEYWORD2
sendRCMM KEYWORD2
sendRaw KEYWORD2
sendSAMSUNG KEYWORD2
+sendSamsung36 KEYWORD2
sendSamsungAC KEYWORD2
sendSanyoLC7461 KEYWORD2
sendSharp KEYWORD2
sendSharpRaw KEYWORD2
sendSherwood KEYWORD2
sendSony KEYWORD2
+sendTcl112Ac KEYWORD2
+sendTeco KEYWORD2
sendToshibaAC KEYWORD2
sendTrotec KEYWORD2
+sendVestelAc KEYWORD2
sendWhirlpoolAC KEYWORD2
sendWhynter KEYWORD2
serialPrintUint64 KEYWORD2
+set3D KEYWORD2
+setAuto KEYWORD2
setBeep KEYWORD2
-setBit KEYWORD2
setButton KEYWORD2
setClean KEYWORD2
setClock KEYWORD2
setCmd KEYWORD2
+setComfort KEYWORD2
setCommand KEYWORD2
setCoolMode KEYWORD2
setCurrTime KEYWORD2
setCurrentTime KEYWORD2
setEcono KEYWORD2
setEye KEYWORD2
+setEyeAuto KEYWORD2
setFan KEYWORD2
setFanSpeed KEYWORD2
+setFilter KEYWORD2
setFlap KEYWORD2
+setFreshAir KEYWORD2
+setFreshAirHigh KEYWORD2
setHealth KEYWORD2
setHeatMode KEYWORD2
+setIon KEYWORD2
setIonFilter KEYWORD2
setLed KEYWORD2
setLight KEYWORD2
@@ -297,19 +384,25 @@ setModel KEYWORD2
setMold KEYWORD2
setNight KEYWORD2
setOffTimer KEYWORD2
+setOffTimerActive KEYWORD2
setOnTimer KEYWORD2
+setOnTimerActive KEYWORD2
setPower KEYWORD2
+setPowerToggle KEYWORD2
setPowerful KEYWORD2
+setPurify KEYWORD2
setQuiet KEYWORD2
setRaw KEYWORD2
setRoomTemp KEYWORD2
setSensor KEYWORD2
setSensorTemp KEYWORD2
setSensorTempRaw KEYWORD2
+setSilent KEYWORD2
setSleep KEYWORD2
setSpeed KEYWORD2
setStartClock KEYWORD2
setStopClock KEYWORD2
+setSuper KEYWORD2
setSwing KEYWORD2
setSwingHorizontal KEYWORD2
setSwingVertical KEYWORD2
@@ -317,6 +410,7 @@ setTemp KEYWORD2
setTempRaw KEYWORD2
setTime KEYWORD2
setTimer KEYWORD2
+setTimerActive KEYWORD2
setTurbo KEYWORD2
setUnknownThreshold KEYWORD2
setVane KEYWORD2
@@ -324,19 +418,33 @@ setXFan KEYWORD2
setZoneFollow KEYWORD2
setiFeel KEYWORD2
space KEYWORD2
+speed) KEYWORD2
stateReset KEYWORD2
stepHoriz KEYWORD2
stepVert KEYWORD2
+strToBool KEYWORD2
+strToModel KEYWORD2
sumBytes KEYWORD2
+swingh_t KEYWORD2
+swingv) KEYWORD2
+swingv_t KEYWORD2
+tcl112 KEYWORD2
+teco KEYWORD2
ticksHigh KEYWORD2
ticksLow KEYWORD2
timeToString KEYWORD2
toString KEYWORD2
toggleRC5 KEYWORD2
toggleRC6 KEYWORD2
+toshiba KEYWORD2
+trotec KEYWORD2
typeToString KEYWORD2
uint64ToString KEYWORD2
+updateSavedState KEYWORD2
validChecksum KEYWORD2
+vestel KEYWORD2
+whirlpool KEYWORD2
+xorBytes KEYWORD2
#######################################
# Constants (LITERAL1)
@@ -349,9 +457,9 @@ ARDB1 LITERAL1
ARGO LITERAL1
ARGO_COMMAND_LENGTH LITERAL1
ARGO_COOL_AUTO LITERAL1
+ARGO_COOL_HUM LITERAL1
ARGO_COOL_OFF LITERAL1
ARGO_COOL_ON LITERAL1
-ARGO_COOl_HUM LITERAL1
ARGO_FAN_1 LITERAL1
ARGO_FAN_2 LITERAL1
ARGO_FAN_3 LITERAL1
@@ -375,10 +483,11 @@ CARRIER_AC_BITS LITERAL1
COOLIX LITERAL1
COOLIX_BITS LITERAL1
DAIKIN LITERAL1
+DAIKIN2 LITERAL1
+DAIKIN216 LITERAL1
DAIKIN_AUTO LITERAL1
DAIKIN_COMMAND_LENGTH LITERAL1
DAIKIN_COOL LITERAL1
-DAIKIN_DEBUG LITERAL1
DAIKIN_DRY LITERAL1
DAIKIN_FAN LITERAL1
DAIKIN_FAN_AUTO LITERAL1
@@ -394,6 +503,8 @@ DECODE_ARGO LITERAL1
DECODE_CARRIER_AC LITERAL1
DECODE_COOLIX LITERAL1
DECODE_DAIKIN LITERAL1
+DECODE_DAIKIN2 LITERAL1
+DECODE_DAIKIN216 LITERAL1
DECODE_DENON LITERAL1
DECODE_DISH LITERAL1
DECODE_ELECTRA_AC LITERAL1
@@ -410,12 +521,14 @@ DECODE_HITACHI_AC2 LITERAL1
DECODE_JVC LITERAL1
DECODE_KELVINATOR LITERAL1
DECODE_LASERTAG LITERAL1
+DECODE_LEGOPF LITERAL1
DECODE_LG LITERAL1
DECODE_LUTRON LITERAL1
DECODE_MAGIQUEST LITERAL1
DECODE_MIDEA LITERAL1
DECODE_MITSUBISHI LITERAL1
DECODE_MITSUBISHI2 LITERAL1
+DECODE_MITSUBISHIHEAVY LITERAL1
DECODE_MITSUBISHI_AC LITERAL1
DECODE_MWM LITERAL1
DECODE_NEC LITERAL1
@@ -428,19 +541,25 @@ DECODE_RC5 LITERAL1
DECODE_RC6 LITERAL1
DECODE_RCMM LITERAL1
DECODE_SAMSUNG LITERAL1
+DECODE_SAMSUNG36 LITERAL1
DECODE_SAMSUNG_AC LITERAL1
DECODE_SANYO LITERAL1
DECODE_SHARP LITERAL1
DECODE_SHERWOOD LITERAL1
DECODE_SONY LITERAL1
+DECODE_TCL112AC LITERAL1
+DECODE_TECO 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_LEGACY_BITS LITERAL1
+DG11J13A LITERAL1
+DG11J191 LITERAL1
DISH LITERAL1
DISH_BITS LITERAL1
ELECTRA_AC LITERAL1
@@ -580,6 +699,7 @@ KELVINATOR_MIN_TEMP LITERAL1
KELVINATOR_STATE_LENGTH LITERAL1
LASERTAG LITERAL1
LASERTAG_BITS LITERAL1
+LEGOPF LITERAL1
LG LITERAL1
LG2 LITERAL1
LG32_BITS LITERAL1
@@ -623,6 +743,8 @@ MITSUBISHI_AC_STATE_LENGTH LITERAL1
MITSUBISHI_AC_VANE_AUTO LITERAL1
MITSUBISHI_AC_VANE_AUTO_MOVE LITERAL1
MITSUBISHI_BITS LITERAL1
+MITSUBISHI_HEAVY_152 LITERAL1
+MITSUBISHI_HEAVY_88 LITERAL1
MWM LITERAL1
NEC LITERAL1
NEC_BITS LITERAL1
@@ -647,6 +769,7 @@ RC6_MODE0_BITS LITERAL1
RCMM LITERAL1
RCMM_BITS LITERAL1
SAMSUNG LITERAL1
+SAMSUNG36 LITERAL1
SAMSUNG_AC LITERAL1
SAMSUNG_BITS LITERAL1
SANYO LITERAL1
@@ -658,6 +781,8 @@ SEND_ARGO LITERAL1
SEND_CARRIER_AC LITERAL1
SEND_COOLIX LITERAL1
SEND_DAIKIN LITERAL1
+SEND_DAIKIN2 LITERAL1
+SEND_DAIKIN216 LITERAL1
SEND_DENON LITERAL1
SEND_DISH LITERAL1
SEND_ELECTRA_AC LITERAL1
@@ -673,12 +798,14 @@ SEND_HITACHI_AC2 LITERAL1
SEND_JVC LITERAL1
SEND_KELVINATOR LITERAL1
SEND_LASERTAG LITERAL1
+SEND_LEGOPF LITERAL1
SEND_LG LITERAL1
SEND_LUTRON LITERAL1
SEND_MAGIQUEST LITERAL1
SEND_MIDEA LITERAL1
SEND_MITSUBISHI LITERAL1
SEND_MITSUBISHI2 LITERAL1
+SEND_MITSUBISHIHEAVY LITERAL1
SEND_MITSUBISHI_AC LITERAL1
SEND_MWM LITERAL1
SEND_NEC LITERAL1
@@ -692,13 +819,17 @@ SEND_RC5 LITERAL1
SEND_RC6 LITERAL1
SEND_RCMM LITERAL1
SEND_SAMSUNG LITERAL1
+SEND_SAMSUNG36 LITERAL1
SEND_SAMSUNG_AC LITERAL1
SEND_SANYO LITERAL1
SEND_SHARP LITERAL1
SEND_SHERWOOD LITERAL1
SEND_SONY LITERAL1
+SEND_TCL112AC LITERAL1
+SEND_TECO LITERAL1
SEND_TOSHIBA_AC LITERAL1
SEND_TROTEC LITERAL1
+SEND_VESTEL_AC LITERAL1
SEND_WHIRLPOOL_AC LITERAL1
SEND_WHYNTER LITERAL1
SHARP LITERAL1
@@ -709,6 +840,8 @@ SONY LITERAL1
SONY_12_BITS LITERAL1
SONY_15_BITS LITERAL1
SONY_20_BITS LITERAL1
+TCL112AC LITERAL1
+TECO LITERAL1
TIMEOUT_MS LITERAL1
TOSHIBA_AC LITERAL1
TOSHIBA_AC_AUTO LITERAL1
@@ -733,9 +866,9 @@ TROTEC_FAN_MED LITERAL1
TROTEC_MAX_TEMP LITERAL1
TROTEC_MAX_TIMER LITERAL1
TROTEC_MIN_TEMP LITERAL1
-TROTEC_MIN_TIMER LITERAL1
UNKNOWN LITERAL1
UNUSED LITERAL1
+VESTEL_AC LITERAL1
WHIRLPOOL_AC LITERAL1
WHYNTER LITERAL1
WHYNTER_BITS LITERAL1
@@ -750,6 +883,7 @@ kArgoCoolAuto LITERAL1
kArgoCoolHum LITERAL1
kArgoCoolOff LITERAL1
kArgoCoolOn LITERAL1
+kArgoDefaultRepeat LITERAL1
kArgoFan1 LITERAL1
kArgoFan2 LITERAL1
kArgoFan3 LITERAL1
@@ -772,6 +906,7 @@ kArgoMinTemp LITERAL1
kArgoOneSpace LITERAL1
kArgoStateLength LITERAL1
kArgoZeroSpace LITERAL1
+kAuto LITERAL1
kCarrierAcBitMark LITERAL1
kCarrierAcBits LITERAL1
kCarrierAcGap LITERAL1
@@ -780,16 +915,19 @@ kCarrierAcHdrSpace LITERAL1
kCarrierAcMinRepeat LITERAL1
kCarrierAcOneSpace LITERAL1
kCarrierAcZeroSpace LITERAL1
+kCool 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
@@ -827,7 +965,70 @@ kCoolixUnknown LITERAL1
kCoolixZeroSpace LITERAL1
kCoolixZeroSpaceTicks LITERAL1
kCoolixZoneFollowMask LITERAL1
+kDaikin216BitMark LITERAL1
+kDaikin216Bits LITERAL1
+kDaikin216ByteFan LITERAL1
+kDaikin216ByteMode LITERAL1
+kDaikin216BytePower LITERAL1
+kDaikin216ByteSwingH LITERAL1
+kDaikin216ByteSwingV LITERAL1
+kDaikin216ByteTemp LITERAL1
+kDaikin216DefaultRepeat LITERAL1
+kDaikin216Freq LITERAL1
+kDaikin216Gap LITERAL1
+kDaikin216HdrMark LITERAL1
+kDaikin216HdrSpace LITERAL1
+kDaikin216MaskFan LITERAL1
+kDaikin216MaskMode LITERAL1
+kDaikin216MaskSwingH LITERAL1
+kDaikin216MaskSwingV LITERAL1
+kDaikin216MaskTemp LITERAL1
+kDaikin216OneSpace LITERAL1
+kDaikin216Section1Length LITERAL1
+kDaikin216Section2Length LITERAL1
+kDaikin216Sections LITERAL1
+kDaikin216StateLength LITERAL1
+kDaikin216ZeroSpace LITERAL1
+kDaikin2BeepMask LITERAL1
+kDaikin2BitClean LITERAL1
+kDaikin2BitEye LITERAL1
+kDaikin2BitEyeAuto LITERAL1
+kDaikin2BitFreshAir LITERAL1
+kDaikin2BitFreshAirHigh LITERAL1
+kDaikin2BitMark LITERAL1
+kDaikin2BitMold LITERAL1
+kDaikin2BitPower LITERAL1
+kDaikin2BitPurify LITERAL1
+kDaikin2BitSleepTimer LITERAL1
+kDaikin2Bits LITERAL1
+kDaikin2DefaultRepeat LITERAL1
+kDaikin2Freq LITERAL1
+kDaikin2Gap LITERAL1
+kDaikin2HdrMark LITERAL1
+kDaikin2HdrSpace LITERAL1
+kDaikin2LeaderMark LITERAL1
+kDaikin2LeaderSpace LITERAL1
+kDaikin2LightMask LITERAL1
+kDaikin2MinCoolTemp 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
+kDaikin2Tolerance LITERAL1
+kDaikin2ZeroSpace LITERAL1
kDaikinAuto LITERAL1
+kDaikinBeepLoud LITERAL1
+kDaikinBeepOff LITERAL1
+kDaikinBeepQuiet LITERAL1
+kDaikinBitComfort LITERAL1
kDaikinBitEcono LITERAL1
kDaikinBitEye LITERAL1
kDaikinBitMark LITERAL1
@@ -839,18 +1040,33 @@ kDaikinBitPowerful LITERAL1
kDaikinBitSensor LITERAL1
kDaikinBitSilent LITERAL1
kDaikinBits LITERAL1
+kDaikinBitsShort LITERAL1
+kDaikinByteChecksum1 LITERAL1
+kDaikinByteChecksum2 LITERAL1
+kDaikinByteChecksum3 LITERAL1
+kDaikinByteClockMinsHigh LITERAL1
+kDaikinByteClockMinsLow LITERAL1
+kDaikinByteComfort LITERAL1
kDaikinByteEcono LITERAL1
kDaikinByteEye LITERAL1
+kDaikinByteFan LITERAL1
kDaikinByteMold LITERAL1
kDaikinByteOffTimer LITERAL1
+kDaikinByteOffTimerMinsHigh LITERAL1
+kDaikinByteOffTimerMinsLow LITERAL1
kDaikinByteOnTimer LITERAL1
+kDaikinByteOnTimerMinsHigh LITERAL1
+kDaikinByteOnTimerMinsLow LITERAL1
kDaikinBytePower LITERAL1
kDaikinBytePowerful LITERAL1
kDaikinByteSensor LITERAL1
kDaikinByteSilent LITERAL1
+kDaikinByteSwingH LITERAL1
+kDaikinByteTemp LITERAL1
kDaikinCool LITERAL1
kDaikinCurBit LITERAL1
kDaikinCurIndex LITERAL1
+kDaikinDefaultRepeat LITERAL1
kDaikinDry LITERAL1
kDaikinFan LITERAL1
kDaikinFanAuto LITERAL1
@@ -861,15 +1077,25 @@ kDaikinFirstHeader64 LITERAL1
kDaikinGap LITERAL1
kDaikinHdrMark LITERAL1
kDaikinHdrSpace LITERAL1
+kDaikinHeaderLength LITERAL1
kDaikinHeat LITERAL1
+kDaikinLightBright LITERAL1
+kDaikinLightDim LITERAL1
+kDaikinLightOff LITERAL1
kDaikinMarkExcess LITERAL1
kDaikinMaxTemp LITERAL1
kDaikinMinTemp LITERAL1
kDaikinOneSpace LITERAL1
-kDaikinRawBits LITERAL1
+kDaikinSection1Length LITERAL1
+kDaikinSection2Length LITERAL1
+kDaikinSection3Length LITERAL1
+kDaikinSections LITERAL1
kDaikinStateLength LITERAL1
+kDaikinStateLengthShort LITERAL1
kDaikinTolerance LITERAL1
+kDaikinUnusedTime LITERAL1
kDaikinZeroSpace LITERAL1
+kDefaultMessageGap LITERAL1
kDenonBitMark LITERAL1
kDenonBitMarkTicks LITERAL1
kDenonBits LITERAL1
@@ -902,6 +1128,7 @@ kDishRptSpaceTicks LITERAL1
kDishTick LITERAL1
kDishZeroSpace LITERAL1
kDishZeroSpaceTicks LITERAL1
+kDry LITERAL1
kDutyDefault LITERAL1
kDutyMax LITERAL1
kElectraAcBitMark LITERAL1
@@ -912,6 +1139,7 @@ kElectraAcMessageGap LITERAL1
kElectraAcOneSpace LITERAL1
kElectraAcStateLength LITERAL1
kElectraAcZeroSpace LITERAL1
+kFan LITERAL1
kFnvBasis32 LITERAL1
kFnvPrime32 LITERAL1
kFooter LITERAL1
@@ -969,10 +1197,13 @@ kGreeBits LITERAL1
kGreeBlockFooter LITERAL1
kGreeBlockFooterBits LITERAL1
kGreeCool LITERAL1
+kGreeDefaultRepeat LITERAL1
kGreeDry LITERAL1
kGreeFan LITERAL1
+kGreeFanAuto LITERAL1
kGreeFanMask LITERAL1
kGreeFanMax LITERAL1
+kGreeFanMin LITERAL1
kGreeHdrMark LITERAL1
kGreeHdrSpace LITERAL1
kGreeHeat LITERAL1
@@ -1020,6 +1251,7 @@ kHaierAcCmdTimerCancel LITERAL1
kHaierAcCmdTimerSet LITERAL1
kHaierAcCool LITERAL1
kHaierAcDefTemp LITERAL1
+kHaierAcDefaultRepeat LITERAL1
kHaierAcDry LITERAL1
kHaierAcFan LITERAL1
kHaierAcFanAuto LITERAL1
@@ -1050,6 +1282,7 @@ kHaierAcYrw02ButtonTempDown LITERAL1
kHaierAcYrw02ButtonTempUp LITERAL1
kHaierAcYrw02ButtonTurbo LITERAL1
kHaierAcYrw02Cool LITERAL1
+kHaierAcYrw02DefaultRepeat LITERAL1
kHaierAcYrw02Dry LITERAL1
kHaierAcYrw02Fan LITERAL1
kHaierAcYrw02FanAuto LITERAL1
@@ -1071,17 +1304,32 @@ kHaierAcYrw02TurboLow LITERAL1
kHaierAcYrw02TurboOff LITERAL1
kHaierAcZeroSpace LITERAL1
kHeader LITERAL1
+kHeat LITERAL1
+kHigh LITERAL1
+kHighest 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
@@ -1113,6 +1361,7 @@ kKelvinatorChecksumStart LITERAL1
kKelvinatorCmdFooter LITERAL1
kKelvinatorCmdFooterBits LITERAL1
kKelvinatorCool LITERAL1
+kKelvinatorDefaultRepeat LITERAL1
kKelvinatorDry LITERAL1
kKelvinatorFan LITERAL1
kKelvinatorFanAuto LITERAL1
@@ -1159,6 +1408,16 @@ kLasertagMinRepeat LITERAL1
kLasertagMinSamples LITERAL1
kLasertagTick LITERAL1
kLasertagTolerance LITERAL1
+kLastDecodeType LITERAL1
+kLeft LITERAL1
+kLeftMax LITERAL1
+kLegoPfBitMark LITERAL1
+kLegoPfBits LITERAL1
+kLegoPfHdrSpace LITERAL1
+kLegoPfMinCommandLength LITERAL1
+kLegoPfMinRepeat LITERAL1
+kLegoPfOneSpace LITERAL1
+kLegoPfZeroSpace LITERAL1
kLg2BitMark LITERAL1
kLg2BitMarkTicks LITERAL1
kLg2HdrMark LITERAL1
@@ -1190,6 +1449,8 @@ kLgRptSpaceTicks LITERAL1
kLgTick LITERAL1
kLgZeroSpace LITERAL1
kLgZeroSpaceTicks LITERAL1
+kLow LITERAL1
+kLowest LITERAL1
kLutronBits LITERAL1
kLutronDelta LITERAL1
kLutronGap LITERAL1
@@ -1213,8 +1474,11 @@ kMagiquestBits LITERAL1
kMark LITERAL1
kMarkExcess LITERAL1
kMarkState LITERAL1
+kMax LITERAL1
kMaxAccurateUsecDelay LITERAL1
kMaxTimeoutMs LITERAL1
+kMedium LITERAL1
+kMiddle LITERAL1
kMideaACAuto LITERAL1
kMideaACChecksumMask LITERAL1
kMideaACCool LITERAL1
@@ -1251,6 +1515,7 @@ kMideaTick LITERAL1
kMideaTolerance LITERAL1
kMideaZeroSpace LITERAL1
kMideaZeroSpaceTicks LITERAL1
+kMin LITERAL1
kMitsubishi2BitMark LITERAL1
kMitsubishi2HdrMark LITERAL1
kMitsubishi2HdrSpace LITERAL1
@@ -1287,6 +1552,91 @@ kMitsubishiAcZeroSpace LITERAL1
kMitsubishiBitMark LITERAL1
kMitsubishiBitMarkTicks LITERAL1
kMitsubishiBits LITERAL1
+kMitsubishiHeavy152Bits LITERAL1
+kMitsubishiHeavy152FanAuto LITERAL1
+kMitsubishiHeavy152FanEcono LITERAL1
+kMitsubishiHeavy152FanHigh LITERAL1
+kMitsubishiHeavy152FanLow LITERAL1
+kMitsubishiHeavy152FanMax LITERAL1
+kMitsubishiHeavy152FanMed LITERAL1
+kMitsubishiHeavy152FanTurbo LITERAL1
+kMitsubishiHeavy152MinRepeat LITERAL1
+kMitsubishiHeavy152StateLength LITERAL1
+kMitsubishiHeavy152SwingHAuto LITERAL1
+kMitsubishiHeavy152SwingHLeft LITERAL1
+kMitsubishiHeavy152SwingHLeftMax LITERAL1
+kMitsubishiHeavy152SwingHLeftRight LITERAL1
+kMitsubishiHeavy152SwingHMask LITERAL1
+kMitsubishiHeavy152SwingHMiddle LITERAL1
+kMitsubishiHeavy152SwingHOff LITERAL1
+kMitsubishiHeavy152SwingHRight LITERAL1
+kMitsubishiHeavy152SwingHRightLeft LITERAL1
+kMitsubishiHeavy152SwingHRightMax LITERAL1
+kMitsubishiHeavy152SwingVAuto LITERAL1
+kMitsubishiHeavy152SwingVHigh LITERAL1
+kMitsubishiHeavy152SwingVHighest LITERAL1
+kMitsubishiHeavy152SwingVLow LITERAL1
+kMitsubishiHeavy152SwingVLowest LITERAL1
+kMitsubishiHeavy152SwingVMask LITERAL1
+kMitsubishiHeavy152SwingVMiddle LITERAL1
+kMitsubishiHeavy152SwingVOff LITERAL1
+kMitsubishiHeavy3DMask LITERAL1
+kMitsubishiHeavy88Bits LITERAL1
+kMitsubishiHeavy88CleanBit LITERAL1
+kMitsubishiHeavy88FanAuto LITERAL1
+kMitsubishiHeavy88FanEcono LITERAL1
+kMitsubishiHeavy88FanHigh LITERAL1
+kMitsubishiHeavy88FanLow LITERAL1
+kMitsubishiHeavy88FanMask LITERAL1
+kMitsubishiHeavy88FanMed LITERAL1
+kMitsubishiHeavy88FanTurbo LITERAL1
+kMitsubishiHeavy88MinRepeat LITERAL1
+kMitsubishiHeavy88StateLength LITERAL1
+kMitsubishiHeavy88SwingH3D LITERAL1
+kMitsubishiHeavy88SwingHAuto LITERAL1
+kMitsubishiHeavy88SwingHLeft LITERAL1
+kMitsubishiHeavy88SwingHLeftMax LITERAL1
+kMitsubishiHeavy88SwingHLeftRight LITERAL1
+kMitsubishiHeavy88SwingHMask LITERAL1
+kMitsubishiHeavy88SwingHMiddle LITERAL1
+kMitsubishiHeavy88SwingHOff LITERAL1
+kMitsubishiHeavy88SwingHRight LITERAL1
+kMitsubishiHeavy88SwingHRightLeft LITERAL1
+kMitsubishiHeavy88SwingHRightMax LITERAL1
+kMitsubishiHeavy88SwingVAuto LITERAL1
+kMitsubishiHeavy88SwingVHigh LITERAL1
+kMitsubishiHeavy88SwingVHighest LITERAL1
+kMitsubishiHeavy88SwingVLow LITERAL1
+kMitsubishiHeavy88SwingVLowest LITERAL1
+kMitsubishiHeavy88SwingVMask LITERAL1
+kMitsubishiHeavy88SwingVMaskByte5 LITERAL1
+kMitsubishiHeavy88SwingVMaskByte7 LITERAL1
+kMitsubishiHeavy88SwingVMiddle LITERAL1
+kMitsubishiHeavy88SwingVOff LITERAL1
+kMitsubishiHeavyAuto LITERAL1
+kMitsubishiHeavyBitMark LITERAL1
+kMitsubishiHeavyCleanBit LITERAL1
+kMitsubishiHeavyCool LITERAL1
+kMitsubishiHeavyDry LITERAL1
+kMitsubishiHeavyFan LITERAL1
+kMitsubishiHeavyFanMask LITERAL1
+kMitsubishiHeavyFilterBit LITERAL1
+kMitsubishiHeavyGap LITERAL1
+kMitsubishiHeavyHdrMark LITERAL1
+kMitsubishiHeavyHdrSpace LITERAL1
+kMitsubishiHeavyHeat LITERAL1
+kMitsubishiHeavyMaxTemp LITERAL1
+kMitsubishiHeavyMinTemp LITERAL1
+kMitsubishiHeavyModeMask LITERAL1
+kMitsubishiHeavyNightBit LITERAL1
+kMitsubishiHeavyOneSpace LITERAL1
+kMitsubishiHeavyPowerBit LITERAL1
+kMitsubishiHeavySigLength LITERAL1
+kMitsubishiHeavySilentBit LITERAL1
+kMitsubishiHeavyTempMask LITERAL1
+kMitsubishiHeavyZeroSpace LITERAL1
+kMitsubishiHeavyZjsSig LITERAL1
+kMitsubishiHeavyZmsSig LITERAL1
kMitsubishiMinCommandLength LITERAL1
kMitsubishiMinCommandLengthTicks LITERAL1
kMitsubishiMinGap LITERAL1
@@ -1331,10 +1681,12 @@ kNikaiTick LITERAL1
kNikaiZeroSpace LITERAL1
kNikaiZeroSpaceTicks LITERAL1
kNoRepeat LITERAL1
+kOff LITERAL1
kPanasonicAcAuto LITERAL1
kPanasonicAcBits LITERAL1
kPanasonicAcChecksumInit LITERAL1
kPanasonicAcCool LITERAL1
+kPanasonicAcDefaultRepeat LITERAL1
kPanasonicAcDry LITERAL1
kPanasonicAcExcess LITERAL1
kPanasonicAcFan LITERAL1
@@ -1393,6 +1745,7 @@ kPanasonicMinGapTicks LITERAL1
kPanasonicNke LITERAL1
kPanasonicOneSpace LITERAL1
kPanasonicOneSpaceTicks LITERAL1
+kPanasonicRkr LITERAL1
kPanasonicTick LITERAL1
kPanasonicUnknown LITERAL1
kPanasonicZeroSpace LITERAL1
@@ -1450,6 +1803,9 @@ kRcmmRptLengthTicks LITERAL1
kRcmmTick LITERAL1
kRcmmTolerance LITERAL1
kRepeat LITERAL1
+kRight LITERAL1
+kRightMax LITERAL1
+kSamsung36Bits LITERAL1
kSamsungACSectionLength LITERAL1
kSamsungAcAuto LITERAL1
kSamsungAcAutoTemp LITERAL1
@@ -1459,6 +1815,7 @@ kSamsungAcBits LITERAL1
kSamsungAcCleanMask10 LITERAL1
kSamsungAcCleanMask11 LITERAL1
kSamsungAcCool LITERAL1
+kSamsungAcDefaultRepeat LITERAL1
kSamsungAcDry LITERAL1
kSamsungAcExtendedBits LITERAL1
kSamsungAcExtendedStateLength LITERAL1
@@ -1569,6 +1926,65 @@ kSpaceState LITERAL1
kStartOffset LITERAL1
kStateSizeMax LITERAL1
kStopState LITERAL1
+kTcl112AcAuto LITERAL1
+kTcl112AcBitEcono LITERAL1
+kTcl112AcBitHealth LITERAL1
+kTcl112AcBitLight LITERAL1
+kTcl112AcBitMark LITERAL1
+kTcl112AcBitSwingH LITERAL1
+kTcl112AcBitSwingV LITERAL1
+kTcl112AcBitTurbo LITERAL1
+kTcl112AcBits LITERAL1
+kTcl112AcCool LITERAL1
+kTcl112AcDefaultRepeat LITERAL1
+kTcl112AcDry LITERAL1
+kTcl112AcFan LITERAL1
+kTcl112AcFanAuto LITERAL1
+kTcl112AcFanHigh LITERAL1
+kTcl112AcFanLow LITERAL1
+kTcl112AcFanMask LITERAL1
+kTcl112AcFanMed LITERAL1
+kTcl112AcGap LITERAL1
+kTcl112AcHalfDegree LITERAL1
+kTcl112AcHdrMark LITERAL1
+kTcl112AcHdrSpace LITERAL1
+kTcl112AcHeat LITERAL1
+kTcl112AcOneSpace LITERAL1
+kTcl112AcPowerMask LITERAL1
+kTcl112AcStateLength LITERAL1
+kTcl112AcTempMax LITERAL1
+kTcl112AcTempMin LITERAL1
+kTcl112AcZeroSpace LITERAL1
+kTecoAuto LITERAL1
+kTecoBitMark LITERAL1
+kTecoBits LITERAL1
+kTecoCool LITERAL1
+kTecoDefaultRepeat LITERAL1
+kTecoDry LITERAL1
+kTecoFan LITERAL1
+kTecoFanAuto LITERAL1
+kTecoFanHigh LITERAL1
+kTecoFanLow LITERAL1
+kTecoFanMask LITERAL1
+kTecoFanMed LITERAL1
+kTecoGap LITERAL1
+kTecoHdrMark LITERAL1
+kTecoHdrSpace LITERAL1
+kTecoHeat LITERAL1
+kTecoMaxTemp LITERAL1
+kTecoMinTemp LITERAL1
+kTecoModeMask LITERAL1
+kTecoOneSpace LITERAL1
+kTecoPower LITERAL1
+kTecoReset LITERAL1
+kTecoSleep LITERAL1
+kTecoSwing LITERAL1
+kTecoTempMask LITERAL1
+kTecoTimerHalfH LITERAL1
+kTecoTimerOn LITERAL1
+kTecoTimerTenHr LITERAL1
+kTecoTimerUniHr LITERAL1
+kTecoZeroSpace LITERAL1
kTimeoutMs LITERAL1
kTolerance LITERAL1
kToshibaACBits LITERAL1
@@ -1592,6 +2008,7 @@ kToshibaAcZeroSpace LITERAL1
kTrotecAuto LITERAL1
kTrotecCool LITERAL1
kTrotecDefTemp LITERAL1
+kTrotecDefaultRepeat LITERAL1
kTrotecDry LITERAL1
kTrotecFan LITERAL1
kTrotecFanHigh LITERAL1
@@ -1606,26 +2023,119 @@ kTrotecIntro2 LITERAL1
kTrotecMaxTemp LITERAL1
kTrotecMaxTimer LITERAL1
kTrotecMinTemp LITERAL1
-kTrotecMinTimer LITERAL1
-kTrotecOff LITERAL1
-kTrotecOn LITERAL1
kTrotecOneMark LITERAL1
kTrotecOneSpace LITERAL1
-kTrotecSleepOn LITERAL1
+kTrotecPowerBit LITERAL1
+kTrotecSleepBit LITERAL1
kTrotecStateLength LITERAL1
-kTrotecTimerOn LITERAL1
+kTrotecTimerBit LITERAL1
kTrotecZeroMark LITERAL1
kTrotecZeroSpace LITERAL1
kUnknownThreshold LITERAL1
+kVestelAcAuto LITERAL1
+kVestelAcBitMark LITERAL1
+kVestelAcBits LITERAL1
+kVestelAcCRCMask LITERAL1
+kVestelAcChecksumOffset LITERAL1
+kVestelAcCool LITERAL1
+kVestelAcDry LITERAL1
+kVestelAcFan LITERAL1
+kVestelAcFanAuto LITERAL1
+kVestelAcFanAutoCool LITERAL1
+kVestelAcFanAutoHot LITERAL1
+kVestelAcFanHigh LITERAL1
+kVestelAcFanLow LITERAL1
+kVestelAcFanMed LITERAL1
+kVestelAcFanOffset LITERAL1
+kVestelAcHdrMark LITERAL1
+kVestelAcHdrSpace LITERAL1
+kVestelAcHeat LITERAL1
+kVestelAcHourOffset LITERAL1
+kVestelAcIon LITERAL1
+kVestelAcIonOffset LITERAL1
+kVestelAcMaxTemp LITERAL1
+kVestelAcMinTempC LITERAL1
+kVestelAcMinTempH LITERAL1
+kVestelAcMinuteOffset LITERAL1
+kVestelAcModeOffset LITERAL1
+kVestelAcNormal LITERAL1
+kVestelAcOffTimeOffset LITERAL1
+kVestelAcOffTimerFlagOffset LITERAL1
+kVestelAcOnTimeOffset LITERAL1
+kVestelAcOnTimerFlagOffset LITERAL1
+kVestelAcOneSpace LITERAL1
+kVestelAcPowerOffset LITERAL1
+kVestelAcSleep LITERAL1
+kVestelAcStateDefault LITERAL1
+kVestelAcSwing LITERAL1
+kVestelAcSwingOffset LITERAL1
+kVestelAcTempOffset LITERAL1
+kVestelAcTimeStateDefault LITERAL1
+kVestelAcTimerFlagOffset LITERAL1
+kVestelAcTolerance LITERAL1
+kVestelAcTurbo LITERAL1
+kVestelAcTurboSleepOffset 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
diff --git a/lib/IRremoteESP8266-2.5.2.03/library.json b/lib/IRremoteESP8266-2.6.0/library.json
similarity index 97%
rename from lib/IRremoteESP8266-2.5.2.03/library.json
rename to lib/IRremoteESP8266-2.6.0/library.json
index 3fc14f027..95867de1d 100644
--- a/lib/IRremoteESP8266-2.5.2.03/library.json
+++ b/lib/IRremoteESP8266-2.6.0/library.json
@@ -1,6 +1,6 @@
{
"name": "IRremoteESP8266",
- "version": "2.5.2",
+ "version": "2.6.0",
"keywords": "infrared, ir, remote, esp8266",
"description": "Send and receive infrared signals with multiple protocols (ESP8266)",
"repository":
diff --git a/lib/IRremoteESP8266-2.5.2.03/library.properties b/lib/IRremoteESP8266-2.6.0/library.properties
similarity index 96%
rename from lib/IRremoteESP8266-2.5.2.03/library.properties
rename to lib/IRremoteESP8266-2.6.0/library.properties
index e71dc4154..f122067c5 100644
--- a/lib/IRremoteESP8266-2.5.2.03/library.properties
+++ b/lib/IRremoteESP8266-2.6.0/library.properties
@@ -1,5 +1,5 @@
name=IRremoteESP8266
-version=2.5.2
+version=2.6.0
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-2.5.2.03/platformio.ini b/lib/IRremoteESP8266-2.6.0/platformio.ini
similarity index 83%
rename from lib/IRremoteESP8266-2.5.2.03/platformio.ini
rename to lib/IRremoteESP8266-2.6.0/platformio.ini
index 63c3781e1..b6020c165 100644
--- a/lib/IRremoteESP8266-2.5.2.03/platformio.ini
+++ b/lib/IRremoteESP8266-2.6.0/platformio.ini
@@ -6,11 +6,13 @@ src_dir = examples/IRrecvDumpV2
build_flags =
lib_deps_builtin =
lib_deps_external =
+lib_ldf_mode = chain+
[env:nodemcuv2]
platform = espressif8266
framework = arduino
board = nodemcuv2
+lib_ldf_mode = ${common.lib_ldf_mode}
build_flags = ${common.build_flags}
lib_deps =
${common.lib_deps_builtin}
@@ -20,6 +22,7 @@ lib_deps =
platform = espressif8266
framework = arduino
board = d1_mini
+lib_ldf_mode = ${common.lib_ldf_mode}
build_flags = ${common.build_flags}
lib_deps =
${common.lib_deps_builtin}
diff --git a/lib/IRremoteESP8266-2.5.2.03/pylintrc b/lib/IRremoteESP8266-2.6.0/pylintrc
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/pylintrc
rename to lib/IRremoteESP8266-2.6.0/pylintrc
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/CPPLINT.cfg b/lib/IRremoteESP8266-2.6.0/src/CPPLINT.cfg
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/src/CPPLINT.cfg
rename to lib/IRremoteESP8266-2.6.0/src/CPPLINT.cfg
diff --git a/lib/IRremoteESP8266-2.6.0/src/IRac.cpp b/lib/IRremoteESP8266-2.6.0/src/IRac.cpp
new file mode 100644
index 000000000..782c147c2
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/src/IRac.cpp
@@ -0,0 +1,1125 @@
+// Copyright 2019 David Conran
+
+// Provide a universal/standard interface for sending A/C nessages.
+// It does not provide complete and maximum granular control but tries
+// to off most common functionallity across all supported devices.
+
+#include "IRac.h"
+#ifndef UNIT_TEST
+#include
+#endif
+
+#include
+#ifndef ARDUINO
+#include
+#endif
+#include "IRsend.h"
+#include "IRremoteESP8266.h"
+#include "ir_Argo.h"
+#include "ir_Coolix.h"
+#include "ir_Daikin.h"
+#include "ir_Fujitsu.h"
+#include "ir_Haier.h"
+#include "ir_Hitachi.h"
+#include "ir_Kelvinator.h"
+#include "ir_Midea.h"
+#include "ir_Mitsubishi.h"
+#include "ir_MitsubishiHeavy.h"
+#include "ir_Panasonic.h"
+#include "ir_Samsung.h"
+#include "ir_Tcl.h"
+#include "ir_Teco.h"
+#include "ir_Toshiba.h"
+#include "ir_Trotec.h"
+#include "ir_Vestel.h"
+#include "ir_Whirlpool.h"
+
+IRac::IRac(uint8_t pin) { _pin = pin; }
+
+// Is the given protocol supported by the IRac class?
+bool IRac::isProtocolSupported(const decode_type_t protocol) {
+ switch (protocol) {
+#if SEND_ARGO
+ case decode_type_t::ARGO:
+#endif
+#if SEND_COOLIX
+ case decode_type_t::COOLIX:
+#endif
+#if SEND_DAIKIN
+ case decode_type_t::DAIKIN:
+#endif
+#if SEND_DAIKIN2
+ case decode_type_t::DAIKIN2:
+#endif
+#if SEND_DAIKIN216
+ case decode_type_t::DAIKIN216:
+#endif
+#if SEND_FUJITSU_AC
+ case decode_type_t::FUJITSU_AC:
+#endif
+#if SEND_GREE
+ case decode_type_t::GREE:
+#endif
+#if SEND_HAIER_AC
+ case decode_type_t::HAIER_AC:
+#endif
+#if SEND_HAIER_AC_YRW02
+ case decode_type_t::HAIER_AC_YRW02:
+#endif
+#if SEND_HITACHI_AC
+ case decode_type_t::HITACHI_AC:
+#endif
+#if SEND_KELVINATOR
+ case decode_type_t::KELVINATOR:
+#endif
+#if SEND_MIDEA
+ case decode_type_t::MIDEA:
+#endif
+#if SEND_MITSUBISHI_AC
+ case decode_type_t::MITSUBISHI_AC:
+#endif
+#if SEND_MITSUBISHIHEAVY
+ case decode_type_t::MITSUBISHI_HEAVY_88:
+ case decode_type_t::MITSUBISHI_HEAVY_152:
+#endif
+#if SEND_PANASONIC_AC
+ case decode_type_t::PANASONIC_AC:
+#endif
+#if SEND_SAMSUNG_AC
+ case decode_type_t::SAMSUNG_AC:
+#endif
+#if SEND_TCL112AC
+ case decode_type_t::TCL112AC:
+#endif
+#if SEND_TECO
+ case decode_type_t::TECO:
+#endif
+#if SEND_TOSHIBA_AC
+ case decode_type_t::TOSHIBA_AC:
+#endif
+#if SEND_TROTEC
+ case decode_type_t::TROTEC:
+#endif
+#if SEND_VESTEL_AC
+ case decode_type_t::VESTEL_AC:
+#endif
+#if SEND_WHIRLPOOL_AC
+ case decode_type_t::WHIRLPOOL_AC:
+#endif
+ return true;
+ default:
+ return false;
+ }
+}
+
+#if SEND_ARGO
+void IRac::argo(IRArgoAC *ac,
+ const bool on, const stdAc::opmode_t mode, const float degrees,
+ const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv,
+ const bool turbo, const int16_t sleep) {
+ ac->setPower(on);
+ switch (mode) {
+ case stdAc::opmode_t::kCool:
+ ac->setCoolMode(kArgoCoolOn);
+ break;
+ case stdAc::opmode_t::kHeat:
+ ac->setHeatMode(kArgoHeatOn);
+ break;
+ case stdAc::opmode_t::kDry:
+ ac->setCoolMode(kArgoCoolHum);
+ break;
+ default: // No idea how to set Fan mode.
+ ac->setCoolMode(kArgoCoolAuto);
+ }
+ ac->setTemp(degrees);
+ ac->setFan(ac->convertFan(fan));
+ ac->setFlap(ac->convertSwingV(swingv));
+ // No Quiet setting available.
+ // No Light setting available.
+ // No Filter setting available.
+ ac->setMax(turbo);
+ // No Economy setting available.
+ // No Clean setting available.
+ // No Beep setting available.
+ ac->setNight(sleep >= 0); // Convert to a boolean.
+ ac->send();
+}
+#endif // SEND_ARGO
+
+#if SEND_COOLIX
+void IRac::coolix(IRCoolixAC *ac,
+ const bool on, const stdAc::opmode_t mode,
+ const float degrees, const stdAc::fanspeed_t fan,
+ const stdAc::swingv_t swingv, const stdAc::swingh_t swingh,
+ const bool turbo, const bool light, const bool clean,
+ const int16_t sleep) {
+ ac->setMode(ac->convertMode(mode));
+ ac->setTemp(degrees);
+ ac->setFan(ac->convertFan(fan));
+ // No Filter setting available.
+ // No Beep setting available.
+ // No Clock setting available.
+ // No Econo setting available.
+ // No Quiet setting available.
+ if (swingv != stdAc::swingv_t::kOff || swingh != stdAc::swingh_t::kOff) {
+ // Swing has a special command that needs to be sent independently.
+ ac->setSwing();
+ ac->send();
+ }
+ if (turbo) {
+ // Turbo has a special command that needs to be sent independently.
+ ac->setTurbo();
+ ac->send();
+ }
+ if (sleep > 0) {
+ // Sleep has a special command that needs to be sent independently.
+ ac->setSleep();
+ ac->send();
+ }
+ if (light) {
+ // Light has a special command that needs to be sent independently.
+ ac->setLed();
+ ac->send();
+ }
+ if (clean) {
+ // Clean has a special command that needs to be sent independently.
+ ac->setClean();
+ ac->send();
+ }
+ // Power gets done last, as off has a special command.
+ ac->setPower(on);
+ ac->send();
+}
+#endif // SEND_COOLIX
+
+#if SEND_DAIKIN
+void IRac::daikin(IRDaikinESP *ac,
+ const bool on, const stdAc::opmode_t mode,
+ const float degrees, const stdAc::fanspeed_t fan,
+ const stdAc::swingv_t swingv, const stdAc::swingh_t swingh,
+ const bool quiet, const bool turbo, const bool econo,
+ const bool clean) {
+ ac->setPower(on);
+ ac->setMode(ac->convertMode(mode));
+ ac->setTemp(degrees);
+ ac->setFan(ac->convertFan(fan));
+ ac->setSwingVertical((int8_t)swingv >= 0);
+ ac->setSwingHorizontal((int8_t)swingh >= 0);
+ ac->setQuiet(quiet);
+ // No Light setting available.
+ // No Filter setting available.
+ ac->setPowerful(turbo);
+ ac->setEcono(econo);
+ ac->setMold(clean);
+ // No Beep setting available.
+ // No Sleep setting available.
+ // No Clock setting available.
+ ac->send();
+}
+#endif // SEND_DAIKIN
+
+#if SEND_DAIKIN2
+void IRac::daikin2(IRDaikin2 *ac,
+ const bool on, const stdAc::opmode_t mode,
+ const float degrees, const stdAc::fanspeed_t fan,
+ const stdAc::swingv_t swingv, const stdAc::swingh_t swingh,
+ const bool quiet, const bool turbo, const bool light,
+ const bool econo, const bool filter, const bool clean,
+ const bool beep, const int16_t sleep, const int16_t clock) {
+ ac->setPower(on);
+ ac->setMode(ac->convertMode(mode));
+ ac->setTemp(degrees);
+ ac->setFan(ac->convertFan(fan));
+ ac->setSwingVertical(ac->convertSwingV(swingv));
+ ac->setSwingHorizontal((int8_t)swingh >= 0);
+ ac->setQuiet(quiet);
+ ac->setLight(light);
+ ac->setPowerful(turbo);
+ ac->setEcono(econo);
+ ac->setPurify(filter);
+ ac->setMold(clean);
+ ac->setBeep(beep);
+ if (sleep > 0) ac->enableSleepTimer(sleep);
+ if (clock >= 0) ac->setCurrentTime(clock);
+ ac->send();
+}
+#endif // SEND_DAIKIN2
+
+#if SEND_DAIKIN216
+void IRac::daikin216(IRDaikin216 *ac,
+ const bool on, const stdAc::opmode_t mode,
+ const float degrees, const stdAc::fanspeed_t fan,
+ const stdAc::swingv_t swingv, const stdAc::swingh_t swingh,
+ const bool quiet) {
+ ac->setPower(on);
+ ac->setMode(ac->convertMode(mode));
+ ac->setTemp(degrees);
+ ac->setFan(ac->convertFan(fan));
+ ac->setSwingVertical((int8_t)swingv >= 0);
+ ac->setSwingHorizontal((int8_t)swingh >= 0);
+ ac->setQuiet(quiet);
+ ac->send();
+}
+#endif // SEND_DAIKIN216
+
+#if SEND_FUJITSU_AC
+void IRac::fujitsu(IRFujitsuAC *ac, const fujitsu_ac_remote_model_t model,
+ const bool on, const stdAc::opmode_t mode,
+ const float degrees, const stdAc::fanspeed_t fan,
+ const stdAc::swingv_t swingv, const stdAc::swingh_t swingh,
+ const bool quiet) {
+ ac->setModel(model);
+ ac->setMode(ac->convertMode(mode));
+ ac->setTemp(degrees);
+ ac->setFanSpeed(ac->convertFan(fan));
+ uint8_t swing = kFujitsuAcSwingOff;
+ if (swingv > stdAc::swingv_t::kOff) swing |= kFujitsuAcSwingVert;
+ if (swingh > stdAc::swingh_t::kOff) swing |= kFujitsuAcSwingHoriz;
+ ac->setSwing(swing);
+ if (quiet) ac->setFanSpeed(kFujitsuAcFanQuiet);
+ // No Turbo setting available.
+ // No Light setting available.
+ // No Econo setting available.
+ // No Filter setting available.
+ // No Clean setting available.
+ // No Beep setting available.
+ // No Sleep setting available.
+ // No Clock setting available.
+ if (!on) ac->off();
+ ac->send();
+}
+#endif // SEND_FUJITSU_AC
+
+#if SEND_GREE
+void IRac::gree(IRGreeAC *ac,
+ const bool on, const stdAc::opmode_t mode, const float degrees,
+ const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv,
+ const bool turbo, const bool light, const bool clean,
+ const int16_t sleep) {
+ ac->setPower(on);
+ ac->setMode(ac->convertMode(mode));
+ ac->setTemp(degrees);
+ ac->setFan(ac->convertFan(fan));
+ ac->setSwingVertical(swingv == stdAc::swingv_t::kAuto, // Set auto flag.
+ ac->convertSwingV(swingv));
+ ac->setLight(light);
+ ac->setTurbo(turbo);
+ ac->setXFan(clean);
+ ac->setSleep(sleep >= 0); // Sleep on this A/C is either on or off.
+ // No Horizontal Swing setting available.
+ // No Filter setting available.
+ // No Beep setting available.
+ // No Quiet setting available.
+ // No Clock setting available.
+ ac->send();
+}
+#endif // SEND_GREE
+
+#if SEND_HAIER_AC
+void IRac::haier(IRHaierAC *ac,
+ const bool on, const stdAc::opmode_t mode, const float degrees,
+ const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv,
+ const bool filter, const int16_t sleep, const int16_t clock) {
+ ac->setMode(ac->convertMode(mode));
+ ac->setTemp(degrees);
+ ac->setFan(ac->convertFan(fan));
+ ac->setSwing(ac->convertSwingV(swingv));
+ // No Horizontal Swing setting available.
+ // No Quiet setting available.
+ // No Turbo setting available.
+ // No Light setting available.
+ ac->setHealth(filter);
+ // No Clean setting available.
+ // No Beep setting available.
+ ac->setSleep(sleep >= 0); // Sleep on this A/C is either on or off.
+ if (clock >=0) ac->setCurrTime(clock);
+ if (on)
+ ac->setCommand(kHaierAcCmdOn);
+ else
+ ac->setCommand(kHaierAcCmdOff);
+ ac->send();
+}
+#endif // SEND_HAIER_AC
+
+#if SEND_HAIER_AC_YRW02
+void IRac::haierYrwo2(IRHaierACYRW02 *ac,
+ const bool on, const stdAc::opmode_t mode,
+ const float degrees, const stdAc::fanspeed_t fan,
+ const stdAc::swingv_t swingv, const bool turbo,
+ const bool filter, const int16_t sleep) {
+ ac->setMode(ac->convertMode(mode));
+ ac->setTemp(degrees);
+ ac->setFan(ac->convertFan(fan));
+ ac->setSwing(ac->convertSwingV(swingv));
+ // No Horizontal Swing setting available.
+ // No Quiet setting available.
+ ac->setTurbo(turbo);
+ // No Light setting available.
+ ac->setHealth(filter);
+ // No Clean setting available.
+ // No Beep setting available.
+ ac->setSleep(sleep >= 0); // Sleep on this A/C is either on or off.
+ ac->setPower(on);
+ ac->send();
+}
+#endif // SEND_HAIER_AC_YRW02
+
+#if SEND_HITACHI_AC
+void IRac::hitachi(IRHitachiAc *ac,
+ const bool on, const stdAc::opmode_t mode,
+ const float degrees, const stdAc::fanspeed_t fan,
+ const stdAc::swingv_t swingv, const stdAc::swingh_t swingh) {
+ ac->setPower(on);
+ ac->setMode(ac->convertMode(mode));
+ ac->setTemp(degrees);
+ ac->setFan(ac->convertFan(fan));
+ ac->setSwingVertical(swingv != stdAc::swingv_t::kOff);
+ ac->setSwingHorizontal(swingh != stdAc::swingh_t::kOff);
+ // No Quiet setting available.
+ // No Turbo setting available.
+ // No Light setting available.
+ // No Filter setting available.
+ // No Clean setting available.
+ // No Beep setting available.
+ // No Sleep setting available.
+ // No Clock setting available.
+ ac->send();
+}
+#endif // SEND_HITACHI_AC
+
+#if SEND_KELVINATOR
+void IRac::kelvinator(IRKelvinatorAC *ac,
+ const bool on, const stdAc::opmode_t mode,
+ const float degrees, const stdAc::fanspeed_t fan,
+ const stdAc::swingv_t swingv,
+ const stdAc::swingh_t swingh,
+ const bool quiet, const bool turbo, const bool light,
+ const bool filter, const bool clean) {
+ ac->setPower(on);
+ ac->setMode(ac->convertMode(mode));
+ ac->setTemp(degrees);
+ ac->setFan((uint8_t)fan); // No conversion needed.
+ ac->setSwingVertical((int8_t)swingv >= 0);
+ ac->setSwingHorizontal((int8_t)swingh >= 0);
+ ac->setQuiet(quiet);
+ ac->setTurbo(turbo);
+ ac->setLight(light);
+ ac->setIonFilter(filter);
+ ac->setXFan(clean);
+ // No Beep setting available.
+ // No Sleep setting available.
+ // No Clock setting available.
+ ac->send();
+}
+#endif // SEND_KELVINATOR
+
+#if SEND_MIDEA
+void IRac::midea(IRMideaAC *ac,
+ const bool on, const stdAc::opmode_t mode, const float degrees,
+ const stdAc::fanspeed_t fan, const int16_t sleep) {
+ ac->setPower(on);
+ ac->setMode(ac->convertMode(mode));
+ ac->setTemp(degrees, true); // true means use Celsius.
+ ac->setFan(ac->convertFan(fan));
+ // No Vertical swing setting available.
+ // No Horizontal swing setting available.
+ // No Quiet setting available.
+ // No Turbo setting available.
+ // No Light setting available.
+ // No Filter setting available.
+ // No Clean setting available.
+ // No Beep setting available.
+ ac->setSleep(sleep >= 0); // Sleep on this A/C is either on or off.
+ // No Clock setting available.
+ ac->send();
+}
+#endif // SEND_MIDEA
+
+#if SEND_MITSUBISHI_AC
+void IRac::mitsubishi(IRMitsubishiAC *ac,
+ const bool on, const stdAc::opmode_t mode,
+ const float degrees,
+ const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv,
+ const bool quiet, const int16_t clock) {
+ ac->setPower(on);
+ ac->setMode(ac->convertMode(mode));
+ ac->setTemp(degrees);
+ ac->setFan(ac->convertFan(fan));
+ ac->setVane(ac->convertSwingV(swingv));
+ // No Horizontal swing setting available.
+ if (quiet) ac->setFan(kMitsubishiAcFanSilent);
+ // No Turbo setting available.
+ // No Light setting available.
+ // No Filter setting available.
+ // No Clean setting available.
+ // No Beep setting available.
+ // No Sleep setting available.
+ if (clock >= 0) ac->setClock(clock / 10); // Clock is in 10 min increments.
+ ac->send();
+}
+#endif // SEND_MITSUBISHI_AC
+
+#if SEND_MITSUBISHIHEAVY
+void IRac::mitsubishiHeavy88(IRMitsubishiHeavy88Ac *ac,
+ const bool on, const stdAc::opmode_t mode,
+ const float degrees,
+ const stdAc::fanspeed_t fan,
+ const stdAc::swingv_t swingv,
+ const stdAc::swingh_t swingh,
+ const bool turbo, const bool econo,
+ const bool clean) {
+ ac->setPower(on);
+ ac->setMode(ac->convertMode(mode));
+ ac->setTemp(degrees);
+ ac->setFan(ac->convertFan(fan));
+ ac->setSwingVertical(ac->convertSwingV(swingv));
+ ac->setSwingHorizontal(ac->convertSwingH(swingh));
+ // No Quiet setting available.
+ ac->setTurbo(turbo);
+ // No Light setting available.
+ ac->setEcono(econo);
+ // No Filter setting available.
+ ac->setClean(clean);
+ // No Beep setting available.
+ // No Sleep setting available.
+ // No Clock setting available.
+ ac->send();
+}
+
+void IRac::mitsubishiHeavy152(IRMitsubishiHeavy152Ac *ac,
+ const bool on, const stdAc::opmode_t mode,
+ const float degrees,
+ const stdAc::fanspeed_t fan,
+ const stdAc::swingv_t swingv,
+ const stdAc::swingh_t swingh,
+ const bool quiet, const bool turbo,
+ const bool econo, const bool filter,
+ const bool clean, const int16_t sleep) {
+ ac->setPower(on);
+ ac->setMode(ac->convertMode(mode));
+ ac->setTemp(degrees);
+ ac->setFan(ac->convertFan(fan));
+ ac->setSwingVertical(ac->convertSwingV(swingv));
+ ac->setSwingHorizontal(ac->convertSwingH(swingh));
+ ac->setSilent(quiet);
+ ac->setTurbo(turbo);
+ // No Light setting available.
+ ac->setEcono(econo);
+ ac->setClean(clean);
+ ac->setFilter(filter);
+ // No Beep setting available.
+ ac->setNight(sleep >= 0); // Sleep is either on/off, so convert to boolean.
+ // No Clock setting available.
+ ac->send();
+}
+#endif // SEND_MITSUBISHIHEAVY
+
+#if SEND_PANASONIC_AC
+void IRac::panasonic(IRPanasonicAc *ac, const panasonic_ac_remote_model_t model,
+ const bool on, const stdAc::opmode_t mode,
+ const float degrees, const stdAc::fanspeed_t fan,
+ const stdAc::swingv_t swingv, const stdAc::swingh_t swingh,
+ const bool quiet, const bool turbo, const int16_t clock) {
+ ac->setModel(model);
+ ac->setPower(on);
+ ac->setMode(ac->convertMode(mode));
+ ac->setTemp(degrees);
+ ac->setFan(ac->convertFan(fan));
+ ac->setSwingVertical(ac->convertSwingV(swingv));
+ ac->setSwingHorizontal(ac->convertSwingH(swingh));
+ ac->setQuiet(quiet);
+ ac->setPowerful(turbo);
+ // No Light setting available.
+ // No Econo setting available.
+ // No Filter setting available.
+ // No Clean setting available.
+ // No Beep setting available.
+ // No Sleep setting available.
+ if (clock >= 0) ac->setClock(clock);
+ ac->send();
+}
+#endif // SEND_PANASONIC_AC
+
+#if SEND_SAMSUNG_AC
+void IRac::samsung(IRSamsungAc *ac,
+ const bool on, const stdAc::opmode_t mode,
+ const float degrees,
+ const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv,
+ const bool quiet, const bool turbo, const bool clean,
+ const bool beep, const bool sendOnOffHack) {
+ if (sendOnOffHack) {
+ // Use a hack to for the unit on or off.
+ // See: https://github.com/markszabo/IRremoteESP8266/issues/604#issuecomment-475020036
+ if (on)
+ ac->sendOn();
+ else
+ ac->sendOff();
+ }
+ ac->setPower(on);
+ ac->setMode(ac->convertMode(mode));
+ ac->setTemp(degrees);
+ ac->setFan(ac->convertFan(fan));
+ ac->setSwing(swingv != stdAc::swingv_t::kOff);
+ // No Horizontal swing setting available.
+ ac->setQuiet(quiet);
+ if (turbo) ac->setFan(kSamsungAcFanTurbo);
+ // No Light setting available.
+ // No Econo setting available.
+ // No Filter setting available.
+ ac->setClean(clean);
+ ac->setBeep(beep);
+ // No Sleep setting available.
+ // No Clock setting available.
+ // Do setMode() again as it can affect fan speed.
+ ac->setMode(ac->convertMode(mode));
+ ac->send();
+}
+#endif // SEND_SAMSUNG_AC
+
+#if SEND_TCL112AC
+void IRac::tcl112(IRTcl112Ac *ac,
+ const bool on, const stdAc::opmode_t mode,
+ const float degrees, const stdAc::fanspeed_t fan,
+ const stdAc::swingv_t swingv, const stdAc::swingh_t swingh,
+ const bool turbo, const bool light, const bool econo,
+ const bool filter) {
+ ac->setPower(on);
+ ac->setMode(ac->convertMode(mode));
+ ac->setTemp(degrees);
+ ac->setFan(ac->convertFan(fan));
+ ac->setSwingVertical(swingv != stdAc::swingv_t::kOff);
+ ac->setSwingHorizontal(swingh != stdAc::swingh_t::kOff);
+ // No Quiet setting available.
+ ac->setTurbo(turbo);
+ ac->setLight(light);
+ ac->setEcono(econo);
+ ac->setHealth(filter);
+ // No Clean setting available.
+ // No Beep setting available.
+ // No Sleep setting available.
+ // No Clock setting available.
+ ac->send();
+}
+#endif // SEND_TCL112AC
+
+#if SEND_TECO
+void IRac::teco(IRTecoAc *ac,
+ const bool on, const stdAc::opmode_t mode, const float degrees,
+ const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv,
+ const int16_t sleep) {
+ ac->setPower(on);
+ ac->setMode(ac->convertMode(mode));
+ ac->setTemp(degrees);
+ ac->setFan(ac->convertFan(fan));
+ ac->setSwing(swingv != stdAc::swingv_t::kOff);
+ // No Horizontal swing setting available.
+ // No Quiet setting available.
+ // No Turbo setting available.
+ // No Light setting available.
+ // No Filter setting available.
+ // No Clean setting available.
+ // No Beep setting available.
+ ac->setSleep(sleep >= 0); // Sleep is either on/off, so convert to boolean.
+ // No Clock setting available.
+ ac->send();
+}
+#endif // SEND_TECO
+
+#if SEND_TOSHIBA_AC
+void IRac::toshiba(IRToshibaAC *ac,
+ const bool on, const stdAc::opmode_t mode,
+ const float degrees, const stdAc::fanspeed_t fan) {
+ ac->setPower(on);
+ ac->setMode(ac->convertMode(mode));
+ ac->setTemp(degrees);
+ ac->setFan(ac->convertFan(fan));
+ // No Vertical swing setting available.
+ // No Horizontal swing setting available.
+ // No Quiet setting available.
+ // No Turbo setting available.
+ // No Light setting available.
+ // No Filter setting available.
+ // No Clean setting available.
+ // No Beep setting available.
+ // No Sleep setting available.
+ // No Clock setting available.
+ ac->send();
+}
+#endif // SEND_TOSHIBA_AC
+
+#if SEND_TROTEC
+void IRac::trotec(IRTrotecESP *ac,
+ const bool on, const stdAc::opmode_t mode,
+ const float degrees, const stdAc::fanspeed_t fan,
+ const int16_t sleep) {
+ ac->setPower(on);
+ ac->setMode(ac->convertMode(mode));
+ ac->setTemp(degrees);
+ ac->setSpeed(ac->convertFan(fan));
+ // No Vertical swing setting available.
+ // No Horizontal swing setting available.
+ // No Quiet setting available.
+ // No Turbo setting available.
+ // No Light setting available.
+ // No Filter setting available.
+ // No Clean setting available.
+ // No Beep setting available.
+ ac->setSleep(sleep >= 0); // Sleep is either on/off, so convert to boolean.
+ // No Clock setting available.
+ ac->send();
+}
+#endif // SEND_TROTEC
+
+#if SEND_VESTEL_AC
+void IRac::vestel(IRVestelAc *ac,
+ const bool on, const stdAc::opmode_t mode,
+ const float degrees,
+ const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv,
+ const bool turbo, const bool filter, const int16_t sleep,
+ const int16_t clock, const bool sendNormal) {
+ ac->setPower(on);
+ ac->setMode(ac->convertMode(mode));
+ ac->setTemp(degrees);
+ ac->setFan(ac->convertFan(fan));
+ ac->setSwing(swingv != stdAc::swingv_t::kOff);
+ // No Horizontal swing setting available.
+ // No Quiet setting available.
+ ac->setTurbo(turbo);
+ // No Light setting available.
+ ac->setIon(filter);
+ // No Clean setting available.
+ // No Beep setting available.
+ ac->setSleep(sleep >= 0); // Sleep is either on/off, so convert to boolean.
+ if (sendNormal) ac->send(); // Send the normal message.
+ if (clock >= 0) {
+ ac->setTime(clock);
+ ac->send(); // Setting the clock requires a different "timer" message.
+ }
+}
+#endif // SEND_VESTEL_AC
+
+#if SEND_WHIRLPOOL_AC
+void IRac::whirlpool(IRWhirlpoolAc *ac, const whirlpool_ac_remote_model_t model,
+ const bool on, const stdAc::opmode_t mode,
+ const float degrees,
+ const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv,
+ const bool turbo, const bool light,
+ const int16_t sleep, const int16_t clock) {
+ ac->setModel(model);
+ ac->setMode(ac->convertMode(mode));
+ ac->setTemp(degrees);
+ ac->setFan(ac->convertFan(fan));
+ ac->setSwing(swingv != stdAc::swingv_t::kOff);
+ // No Horizontal swing setting available.
+ // No Quiet setting available.
+ ac->setSuper(turbo);
+ ac->setLight(light);
+ // No Filter setting available
+ // No Clean setting available.
+ // No Beep setting available.
+ ac->setSleep(sleep >= 0); // Sleep is either on/off, so convert to boolean.
+ if (clock >= 0) ac->setClock(clock);
+ ac->setPowerToggle(on);
+ ac->send();
+}
+#endif // SEND_WHIRLPOOL_AC
+
+// Send A/C message for a given device using common A/C settings.
+// Args:
+// vendor: The type of A/C protocol to use.
+// model: The specific model of A/C if supported/applicable.
+// on: Should the unit be powered on? (or in some cases, toggled)
+// mode: What operating mode should the unit perform? e.g. Cool, Heat etc.
+// degrees: What temperature should the unit be set to?
+// celsius: Use degreees Celsius, otherwise Fahrenheit.
+// fan: Fan speed.
+// The following args are all "if supported" by the underlying A/C classes.
+// swingv: Control the vertical swing of the vanes.
+// swingh: Control the horizontal swing of the vanes.
+// quiet: Set the unit to quiet (fan) operation mode.
+// turbo: Set the unit to turbo operating mode. e.g. Max fan & cooling etc.
+// econo: Set the unit to economical operating mode.
+// light: Turn on the display/LEDs etc.
+// filter: Turn on any particle/ion/allergy filter etc.
+// clean: Turn on any settings to reduce mold etc. (Not self-clean mode.)
+// beep: Control if the unit beeps upon receiving commands.
+// sleep: Nr. of mins of sleep mode, or use sleep mode. (< 0 means off.)
+// clock: Nr. of mins past midnight to set the clock to. (< 0 means off.)
+// Returns:
+// boolean: True, if accepted/converted/attempted. False, if unsupported.
+bool IRac::sendAc(const decode_type_t vendor, const int16_t model,
+ const bool power, const stdAc::opmode_t mode,
+ const float degrees, const bool celsius,
+ const stdAc::fanspeed_t fan,
+ const stdAc::swingv_t swingv, const stdAc::swingh_t swingh,
+ const bool quiet, const bool turbo, const bool econo,
+ const bool light, const bool filter, const bool clean,
+ const bool beep, const int16_t sleep, const int16_t clock) {
+ // Convert the temperature to Celsius.
+ float degC;
+ bool on = power;
+ if (celsius)
+ degC = degrees;
+ else
+ degC = (degrees - 32.0) * (5.0 / 9.0);
+ // A hack for Home Assistant, it appears to need/want an Off opmode.
+ if (mode == stdAc::opmode_t::kOff) on = false;
+ // Per vendor settings & setup.
+ switch (vendor) {
+#if SEND_ARGO
+ case ARGO:
+ {
+ IRArgoAC ac(_pin);
+ argo(&ac, on, mode, degC, fan, swingv, turbo, sleep);
+ break;
+ }
+#endif // SEND_DAIKIN
+#if SEND_COOLIX
+ case COOLIX:
+ {
+ IRCoolixAC ac(_pin);
+ coolix(&ac, on, mode, degC, fan, swingv, swingh,
+ quiet, turbo, econo, clean);
+ break;
+ }
+#endif // SEND_DAIKIN
+#if SEND_DAIKIN
+ case DAIKIN:
+ {
+ IRDaikinESP ac(_pin);
+ daikin(&ac, on, mode, degC, fan, swingv, swingh,
+ quiet, turbo, econo, clean);
+ break;
+ }
+#endif // SEND_DAIKIN
+#if SEND_DAIKIN2
+ case DAIKIN2:
+ {
+ IRDaikin2 ac(_pin);
+ daikin2(&ac, on, mode, degC, fan, swingv, swingh, quiet, turbo,
+ light, econo, filter, clean, beep, sleep, clock);
+ break;
+ }
+#endif // SEND_DAIKIN216
+#if SEND_DAIKIN216
+ case DAIKIN216:
+ {
+ IRDaikin216 ac(_pin);
+ daikin216(&ac, on, mode, degC, fan, swingv, swingh, quiet);
+ break;
+ }
+#endif // SEND_DAIKIN216
+#if SEND_FUJITSU_AC
+ case FUJITSU_AC:
+ {
+ IRFujitsuAC ac(_pin);
+ ac.begin();
+ fujitsu(&ac, (fujitsu_ac_remote_model_t)model, on, mode, degC, fan,
+ swingv, swingh, quiet);
+ break;
+ }
+#endif // SEND_FUJITSU_AC
+#if SEND_GREE
+ case GREE:
+ {
+ IRGreeAC ac(_pin);
+ ac.begin();
+ gree(&ac, on, mode, degC, fan, swingv, light, turbo, clean, sleep);
+ break;
+ }
+#endif // SEND_GREE
+#if SEND_HAIER_AC
+ case HAIER_AC:
+ {
+ IRHaierAC ac(_pin);
+ ac.begin();
+ haier(&ac, on, mode, degC, fan, swingv, filter, sleep, clock);
+ break;
+ }
+#endif // SEND_HAIER_AC
+#if SEND_HAIER_AC_YRW02
+ case HAIER_AC_YRW02:
+ {
+ IRHaierACYRW02 ac(_pin);
+ ac.begin();
+ haierYrwo2(&ac, on, mode, degC, fan, swingv, turbo, filter, sleep);
+ break;
+ }
+#endif // SEND_HAIER_AC_YRW02
+#if SEND_HITACHI_AC
+ case HITACHI_AC:
+ {
+ IRHitachiAc ac(_pin);
+ ac.begin();
+ hitachi(&ac, on, mode, degC, fan, swingv, swingh);
+ break;
+ }
+#endif // SEND_HITACHI_AC
+#if SEND_KELVINATOR
+ case KELVINATOR:
+ {
+ IRKelvinatorAC ac(_pin);
+ ac.begin();
+ kelvinator(&ac, on, mode, degC, fan, swingv, swingh, quiet, turbo,
+ light, filter, clean);
+ break;
+ }
+#endif // SEND_KELVINATOR
+#if SEND_MIDEA
+ case MIDEA:
+ {
+ IRMideaAC ac(_pin);
+ ac.begin();
+ midea(&ac, on, mode, degC, fan, sleep);
+ break;
+ }
+#endif // SEND_MIDEA
+#if SEND_MITSUBISHI_AC
+ case MITSUBISHI_AC:
+ {
+ IRMitsubishiAC ac(_pin);
+ ac.begin();
+ mitsubishi(&ac, on, mode, degC, fan, swingv, quiet, clock);
+ break;
+ }
+#endif // SEND_MITSUBISHI_AC
+#if SEND_MITSUBISHIHEAVY
+ case MITSUBISHI_HEAVY_88:
+ {
+ IRMitsubishiHeavy88Ac ac(_pin);
+ ac.begin();
+ mitsubishiHeavy88(&ac, on, mode, degC, fan, swingv, swingh,
+ turbo, econo, clean);
+ break;
+ }
+ case MITSUBISHI_HEAVY_152:
+ {
+ IRMitsubishiHeavy152Ac ac(_pin);
+ ac.begin();
+ mitsubishiHeavy152(&ac, on, mode, degC, fan, swingv, swingh,
+ quiet, turbo, econo, filter, clean, sleep);
+ break;
+ }
+#endif // SEND_MITSUBISHIHEAVY
+#if SEND_PANASONIC_AC
+ case PANASONIC_AC:
+ {
+ IRPanasonicAc ac(_pin);
+ ac.begin();
+ panasonic(&ac, (panasonic_ac_remote_model_t)model, on, mode, degC, fan,
+ swingv, swingh, quiet, turbo, clock);
+ break;
+ }
+#endif // SEND_PANASONIC_AC
+#if SEND_SAMSUNG_AC
+ case SAMSUNG_AC:
+ {
+ IRSamsungAc ac(_pin);
+ ac.begin();
+ samsung(&ac, on, mode, degC, fan, swingv, quiet, turbo, clean, beep);
+ break;
+ }
+#endif // SEND_SAMSUNG_AC
+#if SEND_TCL112AC
+ case TCL112AC:
+ {
+ IRTcl112Ac ac(_pin);
+ ac.begin();
+ tcl112(&ac, on, mode, degC, fan, swingv, swingh, turbo, light, econo,
+ filter);
+ break;
+ }
+#endif // SEND_TCL112AC
+#if SEND_TECO
+ case TECO:
+ {
+ IRTecoAc ac(_pin);
+ ac.begin();
+ teco(&ac, on, mode, degC, fan, swingv, sleep);
+ break;
+ }
+#endif // SEND_TECO
+#if SEND_TOSHIBA_AC
+ case TOSHIBA_AC:
+ {
+ IRToshibaAC ac(_pin);
+ ac.begin();
+ toshiba(&ac, on, mode, degC, fan);
+ break;
+ }
+#endif // SEND_TOSHIBA_AC
+#if SEND_TROTEC
+ case TROTEC:
+ {
+ IRTrotecESP ac(_pin);
+ ac.begin();
+ trotec(&ac, on, mode, degC, fan, sleep);
+ break;
+ }
+#endif // SEND_TROTEC
+#if SEND_VESTEL_AC
+ case VESTEL_AC:
+ {
+ IRVestelAc ac(_pin);
+ ac.begin();
+ vestel(&ac, on, mode, degC, fan, swingv, turbo, filter, sleep, clock);
+ break;
+ }
+#endif // SEND_VESTEL_AC
+#if SEND_WHIRLPOOL_AC
+ case WHIRLPOOL_AC:
+ {
+ IRWhirlpoolAc ac(_pin);
+ ac.begin();
+ whirlpool(&ac, (whirlpool_ac_remote_model_t)model, on, mode, degC, fan,
+ swingv, turbo, light, sleep, clock);
+ break;
+ }
+#endif // SEND_WHIRLPOOL_AC
+ default:
+ return false; // Fail, didn't match anything.
+ }
+ return true; // Success.
+}
+
+stdAc::opmode_t IRac::strToOpmode(const char *str,
+ const stdAc::opmode_t def) {
+ if (!strcmp(str, "AUTO") || !strcmp(str, "AUTOMATIC"))
+ return stdAc::opmode_t::kAuto;
+ else if (!strcmp(str, "OFF") || !strcmp(str, "STOP"))
+ return stdAc::opmode_t::kOff;
+ else if (!strcmp(str, "COOL") || !strcmp(str, "COOLING"))
+ return stdAc::opmode_t::kCool;
+ else if (!strcmp(str, "HEAT") || !strcmp(str, "HEATING"))
+ return stdAc::opmode_t::kHeat;
+ else if (!strcmp(str, "DRY") || !strcmp(str, "DRYING") ||
+ !strcmp(str, "DEHUMIDIFY"))
+ return stdAc::opmode_t::kDry;
+ else if (!strcmp(str, "FAN") || !strcmp(str, "FANONLY") ||
+ !strcmp(str, "FAN_ONLY"))
+ return stdAc::opmode_t::kFan;
+ else
+ return def;
+}
+
+stdAc::fanspeed_t IRac::strToFanspeed(const char *str,
+ const stdAc::fanspeed_t def) {
+ if (!strcmp(str, "AUTO") || !strcmp(str, "AUTOMATIC"))
+ return stdAc::fanspeed_t::kAuto;
+ else if (!strcmp(str, "MIN") || !strcmp(str, "MINIMUM") ||
+ !strcmp(str, "LOWEST"))
+ return stdAc::fanspeed_t::kMin;
+ else if (!strcmp(str, "LOW"))
+ return stdAc::fanspeed_t::kLow;
+ else if (!strcmp(str, "MED") || !strcmp(str, "MEDIUM") ||
+ !strcmp(str, "MID"))
+ return stdAc::fanspeed_t::kMedium;
+ else if (!strcmp(str, "HIGH") || !strcmp(str, "HI"))
+ return stdAc::fanspeed_t::kHigh;
+ else if (!strcmp(str, "MAX") || !strcmp(str, "MAXIMUM") ||
+ !strcmp(str, "HIGHEST"))
+ return stdAc::fanspeed_t::kMax;
+ else
+ return def;
+}
+
+stdAc::swingv_t IRac::strToSwingV(const char *str,
+ const stdAc::swingv_t def) {
+ if (!strcmp(str, "AUTO") || !strcmp(str, "AUTOMATIC") ||
+ !strcmp(str, "ON") || !strcmp(str, "SWING"))
+ return stdAc::swingv_t::kAuto;
+ else if (!strcmp(str, "OFF") || !strcmp(str, "STOP"))
+ return stdAc::swingv_t::kOff;
+ else if (!strcmp(str, "MIN") || !strcmp(str, "MINIMUM") ||
+ !strcmp(str, "LOWEST") || !strcmp(str, "BOTTOM") ||
+ !strcmp(str, "DOWN"))
+ return stdAc::swingv_t::kLowest;
+ else if (!strcmp(str, "LOW"))
+ return stdAc::swingv_t::kLow;
+ else if (!strcmp(str, "MID") || !strcmp(str, "MIDDLE") ||
+ !strcmp(str, "MED") || !strcmp(str, "MEDIUM") ||
+ !strcmp(str, "CENTRE") || !strcmp(str, "CENTER"))
+ return stdAc::swingv_t::kMiddle;
+ else if (!strcmp(str, "HIGH") || !strcmp(str, "HI"))
+ return stdAc::swingv_t::kHigh;
+ else if (!strcmp(str, "HIGHEST") || !strcmp(str, "MAX") ||
+ !strcmp(str, "MAXIMUM") || !strcmp(str, "TOP") ||
+ !strcmp(str, "UP"))
+ return stdAc::swingv_t::kHighest;
+ else
+ return def;
+}
+
+stdAc::swingh_t IRac::strToSwingH(const char *str,
+ const stdAc::swingh_t def) {
+ if (!strcmp(str, "AUTO") || !strcmp(str, "AUTOMATIC") ||
+ !strcmp(str, "ON") || !strcmp(str, "SWING"))
+ return stdAc::swingh_t::kAuto;
+ else if (!strcmp(str, "OFF") || !strcmp(str, "STOP"))
+ return stdAc::swingh_t::kOff;
+ else if (!strcmp(str, "LEFTMAX") || !strcmp(str, "LEFT MAX") ||
+ !strcmp(str, "MAXLEFT") || !strcmp(str, "MAX LEFT") ||
+ !strcmp(str, "FARLEFT") || !strcmp(str, "FAR LEFT"))
+ return stdAc::swingh_t::kLeftMax;
+ else if (!strcmp(str, "LEFT"))
+ return stdAc::swingh_t::kLeft;
+ else if (!strcmp(str, "MID") || !strcmp(str, "MIDDLE") ||
+ !strcmp(str, "MED") || !strcmp(str, "MEDIUM") ||
+ !strcmp(str, "CENTRE") || !strcmp(str, "CENTER"))
+ return stdAc::swingh_t::kMiddle;
+ else if (!strcmp(str, "RIGHT"))
+ return stdAc::swingh_t::kRight;
+ else if (!strcmp(str, "RIGHTMAX") || !strcmp(str, "RIGHT MAX") ||
+ !strcmp(str, "MAXRIGHT") || !strcmp(str, "MAX RIGHT") ||
+ !strcmp(str, "FARRIGHT") || !strcmp(str, "FAR RIGHT"))
+ return stdAc::swingh_t::kRightMax;
+ else
+ return def;
+}
+
+// Assumes str is upper case or an integer >= 1.
+int16_t IRac::strToModel(const char *str, const int16_t def) {
+ // Fujitsu A/C models
+ if (!strcmp(str, "ARRAH2E")) {
+ return fujitsu_ac_remote_model_t::ARRAH2E;
+ } else if (!strcmp(str, "ARDB1")) {
+ return fujitsu_ac_remote_model_t::ARDB1;
+ // Panasonic A/C families
+ } else if (!strcmp(str, "LKE") || !strcmp(str, "PANASONICLKE")) {
+ return panasonic_ac_remote_model_t::kPanasonicLke;
+ } else if (!strcmp(str, "NKE") || !strcmp(str, "PANASONICNKE")) {
+ return panasonic_ac_remote_model_t::kPanasonicNke;
+ } else if (!strcmp(str, "DKE") || !strcmp(str, "PANASONICDKE")) {
+ return panasonic_ac_remote_model_t::kPanasonicDke;
+ } else if (!strcmp(str, "JKE") || !strcmp(str, "PANASONICJKE")) {
+ return panasonic_ac_remote_model_t::kPanasonicJke;
+ } else if (!strcmp(str, "CKP") || !strcmp(str, "PANASONICCKP")) {
+ return panasonic_ac_remote_model_t::kPanasonicCkp;
+ } else if (!strcmp(str, "RKR") || !strcmp(str, "PANASONICRKR")) {
+ return panasonic_ac_remote_model_t::kPanasonicRkr;
+ // Whirlpool A/C models
+ } else if (!strcmp(str, "DG11J13A") || !strcmp(str, "DG11J104") ||
+ !strcmp(str, "DG11J1-04")) {
+ return whirlpool_ac_remote_model_t::DG11J13A;
+ } else if (!strcmp(str, "DG11J191")) {
+ return whirlpool_ac_remote_model_t::DG11J191;
+ } else {
+ int16_t number = atoi(str);
+ if (number > 0)
+ return number;
+ else
+ return def;
+ }
+}
+
+// Assumes str is upper case.
+bool IRac::strToBool(const char *str, const bool def) {
+ if (!strcmp(str, "ON") || !strcmp(str, "1") || !strcmp(str, "YES") ||
+ !strcmp(str, "TRUE"))
+ return true;
+ else if (!strcmp(str, "OFF") || !strcmp(str, "0") ||
+ !strcmp(str, "NO") || !strcmp(str, "FALSE"))
+ return false;
+ else
+ return def;
+}
diff --git a/lib/IRremoteESP8266-2.6.0/src/IRac.h b/lib/IRremoteESP8266-2.6.0/src/IRac.h
new file mode 100644
index 000000000..ce8d50507
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/src/IRac.h
@@ -0,0 +1,248 @@
+#ifndef IRAC_H_
+#define IRAC_H_
+
+// Copyright 2019 David Conran
+
+#ifndef UNIT_TEST
+#include
+#endif
+#ifndef ARDUINO
+#include
+#endif
+#include "IRremoteESP8266.h"
+#include "ir_Argo.h"
+#include "ir_Coolix.h"
+#include "ir_Daikin.h"
+#include "ir_Fujitsu.h"
+#include "ir_Gree.h"
+#include "ir_Haier.h"
+#include "ir_Hitachi.h"
+#include "ir_Kelvinator.h"
+#include "ir_Midea.h"
+#include "ir_Mitsubishi.h"
+#include "ir_MitsubishiHeavy.h"
+#include "ir_Panasonic.h"
+#include "ir_Samsung.h"
+#include "ir_Tcl.h"
+#include "ir_Teco.h"
+#include "ir_Toshiba.h"
+#include "ir_Trotec.h"
+#include "ir_Vestel.h"
+#include "ir_Whirlpool.h"
+
+class IRac {
+ public:
+ explicit IRac(uint8_t pin);
+ static bool isProtocolSupported(const decode_type_t protocol);
+ bool sendAc(const decode_type_t vendor, const int16_t model,
+ const bool power, const stdAc::opmode_t mode, const float degrees,
+ const bool celsius, const stdAc::fanspeed_t fan,
+ const stdAc::swingv_t swingv, const stdAc::swingh_t swingh,
+ const bool quiet, const bool turbo, const bool econo,
+ const bool light, const bool filter, const bool clean,
+ const bool beep, const int16_t sleep = -1,
+ const int16_t clock = -1);
+
+ static bool strToBool(const char *str, const bool def = false);
+ static int16_t strToModel(const char *str, const int16_t def = -1);
+ static stdAc::opmode_t strToOpmode(
+ const char *str, const stdAc::opmode_t def = stdAc::opmode_t::kAuto);
+ static stdAc::fanspeed_t strToFanspeed(
+ const char *str,
+ const stdAc::fanspeed_t def = stdAc::fanspeed_t::kAuto);
+ static stdAc::swingv_t strToSwingV(
+ const char *str, const stdAc::swingv_t def = stdAc::swingv_t::kOff);
+ static stdAc::swingh_t strToSwingH(
+ const char *str, const stdAc::swingh_t def = stdAc::swingh_t::kOff);
+#ifndef UNIT_TEST
+
+ private:
+#endif
+ uint8_t _pin;
+#if SEND_ARGO
+ void argo(IRArgoAC *ac,
+ const bool on, const stdAc::opmode_t mode, const float degrees,
+ const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv,
+ const bool turbo, const int16_t sleep = -1);
+#endif // SEND_ARGO
+#if SEND_COOLIX
+ void coolix(IRCoolixAC *ac,
+ const bool on, const stdAc::opmode_t mode, const float degrees,
+ const stdAc::fanspeed_t fan,
+ const stdAc::swingv_t swingv, const stdAc::swingh_t swingh,
+ const bool turbo, const bool light, const bool clean,
+ const int16_t sleep = -1);
+#endif // SEND_COOLIX
+#if SEND_DAIKIN
+ void daikin(IRDaikinESP *ac,
+ const bool on, const stdAc::opmode_t mode, const float degrees,
+ const stdAc::fanspeed_t fan,
+ const stdAc::swingv_t swingv, const stdAc::swingh_t swingh,
+ const bool quiet, const bool turbo, const bool econo,
+ const bool clean);
+#endif // SEND_DAIKIN
+#if SEND_DAIKIN2
+ void daikin2(IRDaikin2 *ac,
+ const bool on, const stdAc::opmode_t mode,
+ const float degrees, const stdAc::fanspeed_t fan,
+ const stdAc::swingv_t swingv, const stdAc::swingh_t swingh,
+ const bool quiet, const bool turbo, const bool light,
+ const bool econo, const bool filter, const bool clean,
+ const bool beep, const int16_t sleep = -1,
+ const int16_t clock = -1);
+#endif // SEND_DAIKIN2
+#if SEND_DAIKIN216
+void daikin216(IRDaikin216 *ac,
+ const bool on, const stdAc::opmode_t mode,
+ const float degrees, const stdAc::fanspeed_t fan,
+ const stdAc::swingv_t swingv, const stdAc::swingh_t swingh,
+ const bool quiet);
+#endif // SEND_DAIKIN216
+#if SEND_FUJITSU_AC
+ void fujitsu(IRFujitsuAC *ac, const fujitsu_ac_remote_model_t model,
+ const bool on, const stdAc::opmode_t mode, const float degrees,
+ const stdAc::fanspeed_t fan,
+ const stdAc::swingv_t swingv, const stdAc::swingh_t swingh,
+ const bool quiet);
+#endif // SEND_FUJITSU_AC
+#if SEND_GREE
+ void gree(IRGreeAC *ac,
+ const bool on, const stdAc::opmode_t mode, const float degrees,
+ const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv,
+ const bool turbo, const bool light, const bool clean,
+ const int16_t sleep = -1);
+#endif // SEND_GREE
+#if SEND_HAIER_AC
+ void haier(IRHaierAC *ac,
+ const bool on, const stdAc::opmode_t mode, const float degrees,
+ const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv,
+ const bool filter, const int16_t sleep = -1,
+ const int16_t clock = -1);
+#endif // SEND_HAIER_AC
+#if SEND_HAIER_AC_YRW02
+ void haierYrwo2(IRHaierACYRW02 *ac,
+ const bool on, const stdAc::opmode_t mode,
+ const float degrees, const stdAc::fanspeed_t fan,
+ const stdAc::swingv_t swingv,
+ const bool turbo, const bool filter,
+ const int16_t sleep = -1);
+#endif // SEND_HAIER_AC_YRW02
+#if SEND_HITACHI_AC
+ void hitachi(IRHitachiAc *ac,
+ const bool on, const stdAc::opmode_t mode,
+ const float degrees, const stdAc::fanspeed_t fan,
+ const stdAc::swingv_t swingv, const stdAc::swingh_t swingh);
+#endif // SEND_HITACHI_AC
+#if SEND_KELVINATOR
+ void kelvinator(IRKelvinatorAC *ac,
+ const bool on, const stdAc::opmode_t mode,
+ const float degrees, const stdAc::fanspeed_t fan,
+ const stdAc::swingv_t swingv, const stdAc::swingh_t swingh,
+ const bool quiet, const bool turbo, const bool light,
+ const bool filter, const bool clean);
+#endif // SEND_KELVINATOR
+#if SEND_MIDEA
+ void midea(IRMideaAC *ac,
+ const bool on, const stdAc::opmode_t mode, const float degrees,
+ const stdAc::fanspeed_t fan, const int16_t sleep = -1);
+#endif // SEND_MIDEA
+#if SEND_MITSUBISHI_AC
+ void mitsubishi(IRMitsubishiAC *ac,
+ const bool on, const stdAc::opmode_t mode,
+ const float degrees,
+ const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv,
+ const bool quiet, const int16_t clock = -1);
+#endif // SEND_MITSUBISHI_AC
+#if SEND_MITSUBISHIHEAVY
+ void mitsubishiHeavy88(IRMitsubishiHeavy88Ac *ac,
+ const bool on, const stdAc::opmode_t mode,
+ const float degrees, const stdAc::fanspeed_t fan,
+ const stdAc::swingv_t swingv,
+ const stdAc::swingh_t swingh,
+ const bool turbo, const bool econo, const bool clean);
+ void mitsubishiHeavy152(IRMitsubishiHeavy152Ac *ac,
+ const bool on, const stdAc::opmode_t mode,
+ const float degrees, const stdAc::fanspeed_t fan,
+ const stdAc::swingv_t swingv,
+ const stdAc::swingh_t swingh,
+ const bool quiet, const bool turbo, const bool econo,
+ const bool filter, const bool clean,
+ const int16_t sleep = -1);
+#endif // SEND_MITSUBISHIHEAVY
+#if SEND_PANASONIC_AC
+ void panasonic(IRPanasonicAc *ac, const panasonic_ac_remote_model_t model,
+ const bool on, const stdAc::opmode_t mode, const float degrees,
+ const stdAc::fanspeed_t fan,
+ const stdAc::swingv_t swingv, const stdAc::swingh_t swingh,
+ const bool quiet, const bool turbo, const int16_t clock = -1);
+#endif // SEND_PANASONIC_AC
+#if SEND_SAMSUNG_AC
+ void samsung(IRSamsungAc *ac,
+ const bool on, const stdAc::opmode_t mode, const float degrees,
+ const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv,
+ const bool quiet, const bool turbo, const bool clean,
+ const bool beep, const bool sendOnOffHack = true);
+#endif // SEND_SAMSUNG_AC
+#if SEND_TCL112AC
+ void tcl112(IRTcl112Ac *ac,
+ const bool on, const stdAc::opmode_t mode, const float degrees,
+ const stdAc::fanspeed_t fan,
+ const stdAc::swingv_t swingv, const stdAc::swingh_t swingh,
+ const bool turbo, const bool light, const bool econo,
+ const bool filter);
+#endif // SEND_TCL112AC
+#if SEND_TECO
+ void teco(IRTecoAc *ac,
+ const bool on, const stdAc::opmode_t mode, const float degrees,
+ const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv,
+ const int16_t sleep = -1);
+#endif // SEND_TECO
+#if SEND_TOSHIBA_AC
+ void toshiba(IRToshibaAC *ac,
+ const bool on, const stdAc::opmode_t mode, const float degrees,
+ const stdAc::fanspeed_t fan);
+#endif // SEND_TOSHIBA_AC
+#if SEND_TROTEC
+ void trotec(IRTrotecESP *ac,
+ const bool on, const stdAc::opmode_t mode, const float degrees,
+ const stdAc::fanspeed_t fan, const int16_t sleep = -1);
+#endif // SEND_TROTEC
+#if SEND_VESTEL_AC
+ void vestel(IRVestelAc *ac,
+ const bool on, const stdAc::opmode_t mode, const float degrees,
+ const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv,
+ const bool turbo, const bool filter,
+ const int16_t sleep = -1, const int16_t clock = -1,
+ const bool sendNormal = true);
+#endif // SEND_VESTEL_AC
+#if SEND_WHIRLPOOL_AC
+ void whirlpool(IRWhirlpoolAc *ac, const whirlpool_ac_remote_model_t model,
+ const bool on, const stdAc::opmode_t mode, const float degrees,
+ const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv,
+ const bool turbo, const bool light,
+ const int16_t sleep = -1, const int16_t clock = -1);
+#endif // SEND_WHIRLPOOL_AC
+}; // IRac class
+
+// Structure to hold a common A/C state.
+typedef struct {
+ decode_type_t protocol;
+ int16_t model;
+ bool power;
+ stdAc::opmode_t mode;
+ float degrees;
+ bool celsius;
+ stdAc::fanspeed_t fanspeed;
+ stdAc::swingv_t swingv;
+ stdAc::swingh_t swingh;
+ bool quiet;
+ bool turbo;
+ bool econo;
+ bool light;
+ bool filter;
+ bool clean;
+ bool beep;
+ int16_t sleep;
+ int16_t clock;
+} commonAcState_t;
+#endif // IRAC_H_
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/IRrecv.cpp b/lib/IRremoteESP8266-2.6.0/src/IRrecv.cpp
similarity index 95%
rename from lib/IRremoteESP8266-2.5.2.03/src/IRrecv.cpp
rename to lib/IRremoteESP8266-2.6.0/src/IRrecv.cpp
index b2c984396..eac868084 100644
--- a/lib/IRremoteESP8266-2.5.2.03/src/IRrecv.cpp
+++ b/lib/IRremoteESP8266-2.6.0/src/IRrecv.cpp
@@ -364,6 +364,10 @@ bool IRrecv::decode(decode_results *results, irparams_t *save) {
DPRINTLN("Attempting SAMSUNG decode");
if (decodeSAMSUNG(results)) return true;
#endif
+#if DECODE_SAMSUNG36
+ DPRINTLN("Attempting Samsung36 decode");
+ if (decodeSamsung36(results)) return true;
+#endif
#if DECODE_WHYNTER
DPRINTLN("Attempting Whynter decode");
if (decodeWhynter(results)) return true;
@@ -394,6 +398,14 @@ bool IRrecv::decode(decode_results *results, irparams_t *save) {
DPRINTLN("Attempting Daikin decode");
if (decodeDaikin(results)) return true;
#endif
+#if DECODE_DAIKIN2
+ DPRINTLN("Attempting Daikin2 decode");
+ if (decodeDaikin2(results)) return true;
+#endif
+#if DECODE_DAIKIN216
+ DPRINTLN("Attempting Daikin216 decode");
+ if (decodeDaikin216(results)) return true;
+#endif
#if DECODE_TOSHIBA_AC
DPRINTLN("Attempting Toshiba AC decode");
if (decodeToshibaAC(results)) return true;
@@ -489,6 +501,28 @@ bool IRrecv::decode(decode_results *results, irparams_t *save) {
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_TCL112AC
+ DPRINTLN("Attempting TCL112AC decode");
+ if (decodeTcl112Ac(results)) return true;
+#endif
+#if DECODE_TECO
+ DPRINTLN("Attempting Teco decode");
+ if (decodeTeco(results)) return true;
+#endif
+#if DECODE_LEGOPF
+ DPRINTLN("Attempting LEGOPF decode");
+ if (decodeLegoPf(results)) return true;
+#endif
+#if DECODE_MITSUBISHIHEAVY
+ DPRINTLN("Attempting MITSUBISHIHEAVY (152 bit) decode");
+ if (decodeMitsubishiHeavy(results, kMitsubishiHeavy152Bits)) return true;
+ DPRINTLN("Attempting MITSUBISHIHEAVY (88 bit) decode");
+ if (decodeMitsubishiHeavy(results, kMitsubishiHeavy88Bits)) return true;
+#endif
#if DECODE_HASH
// decodeHash returns a hash on any input.
// Thus, it needs to be last in the list.
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/IRrecv.h b/lib/IRremoteESP8266-2.6.0/src/IRrecv.h
similarity index 90%
rename from lib/IRremoteESP8266-2.5.2.03/src/IRrecv.h
rename to lib/IRremoteESP8266-2.6.0/src/IRrecv.h
index c0f5e781a..0659f093e 100644
--- a/lib/IRremoteESP8266-2.5.2.03/src/IRrecv.h
+++ b/lib/IRremoteESP8266-2.6.0/src/IRrecv.h
@@ -181,6 +181,10 @@ class IRrecv {
uint16_t nbits = kMitsubishiACBits,
bool strict = false);
#endif
+#if DECODE_MITSUBISHIHEAVY
+ bool decodeMitsubishiHeavy(decode_results *results, const uint16_t nbits,
+ const bool strict = true);
+#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 = kTolerance,
@@ -216,6 +220,11 @@ class IRrecv {
bool decodeSAMSUNG(decode_results *results, uint16_t nbits = kSamsungBits,
bool strict = true);
#endif
+#if DECODE_SAMSUNG
+ bool decodeSamsung36(decode_results *results,
+ const uint16_t nbits = kSamsung36Bits,
+ const bool strict = true);
+#endif
#if DECODE_SAMSUNG_AC
bool decodeSamsungAC(decode_results *results, uint16_t nbits = kSamsungAcBits,
bool strict = true);
@@ -257,8 +266,17 @@ class IRrecv {
uint16_t nbits = kKelvinatorBits, bool strict = true);
#endif
#if DECODE_DAIKIN
- bool decodeDaikin(decode_results *results, uint16_t nbits = kDaikinRawBits,
- bool strict = true);
+ bool decodeDaikin(decode_results *results, const uint16_t nbits = kDaikinBits,
+ const bool strict = true);
+#endif
+#if DECODE_DAIKIN2
+ bool decodeDaikin2(decode_results *results, uint16_t nbits = kDaikin2Bits,
+ bool strict = true);
+#endif
+#if DECODE_DAIKIN216
+ bool decodeDaikin216(decode_results *results,
+ const uint16_t nbits = kDaikin216Bits,
+ const bool strict = true);
#endif
#if DECODE_TOSHIBA_AC
bool decodeToshibaAC(decode_results *results,
@@ -330,6 +348,22 @@ class IRrecv {
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
+#if DECODE_TCL112AC
+ bool decodeTcl112Ac(decode_results *results, uint16_t nbits = kTcl112AcBits,
+ bool strict = true);
+#endif
+#if DECODE_TECO
+ bool decodeTeco(decode_results *results, uint16_t nbits = kTecoBits,
+ bool strict = false);
+#endif
+#if DECODE_LEGOPF
+ bool decodeLegoPf(decode_results *results, const uint16_t nbits = kLegoPfBits,
+ const bool strict = true);
+#endif
};
#endif // IRRECV_H_
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/IRremoteESP8266.h b/lib/IRremoteESP8266-2.6.0/src/IRremoteESP8266.h
similarity index 82%
rename from lib/IRremoteESP8266-2.5.2.03/src/IRremoteESP8266.h
rename to lib/IRremoteESP8266-2.6.0/src/IRremoteESP8266.h
index e228cbcb0..b532cb1c0 100644
--- a/lib/IRremoteESP8266-2.5.2.03/src/IRremoteESP8266.h
+++ b/lib/IRremoteESP8266-2.6.0/src/IRremoteESP8266.h
@@ -34,6 +34,8 @@
* Fujitsu A/C code added by jonnygraham
* Trotec AC code by stufisher
* Carrier & Haier AC code by crankyoldgit
+ * Vestel AC code by Erdem U. Altınyurt
+ * Teco AC code by Fabien Valthier (hcoohb)
*
* GPL license, all text above must be included in any redistribution
****************************************************/
@@ -48,7 +50,7 @@
#endif
// Library Version
-#define _IRREMOTEESP8266_VERSION_ "2.5.2"
+#define _IRREMOTEESP8266_VERSION_ "2.6.0"
// 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!
@@ -86,6 +88,9 @@
#define DECODE_SAMSUNG true
#define SEND_SAMSUNG true
+#define DECODE_SAMSUNG36 true
+#define SEND_SAMSUNG36 true
+
#define DECODE_SAMSUNG_AC true
#define SEND_SAMSUNG_AC true
@@ -199,6 +204,27 @@
#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
+
+#define DECODE_TECO true
+#define SEND_TECO true
+
+#define DECODE_TCL112AC true
+#define SEND_TCL112AC true
+
+#define DECODE_LEGOPF true
+#define SEND_LEGOPF true
+
+#define DECODE_MITSUBISHIHEAVY true
+#define SEND_MITSUBISHIHEAVY true
+
+#define DECODE_DAIKIN216 true
+#define SEND_DAIKIN216 true
*/
// Tasmota supported protocols (less protocols is less code size)
@@ -233,6 +259,9 @@
#define DECODE_SAMSUNG true
#define SEND_SAMSUNG true
+#define DECODE_SAMSUNG36 false
+#define SEND_SAMSUNG36 false
+
#define DECODE_SAMSUNG_AC false
#define SEND_SAMSUNG_AC false
@@ -347,12 +376,35 @@
#define DECODE_PIONEER false
#define SEND_PIONEER false
+#define DECODE_DAIKIN2 false
+#define SEND_DAIKIN2 false
+
+#define DECODE_VESTEL_AC false
+#define SEND_VESTEL_AC false
+
+#define DECODE_TECO false
+#define SEND_TECO false
+
+#define DECODE_TCL112AC false
+#define SEND_TCL112AC false
+
+#define DECODE_LEGOPF false
+#define SEND_LEGOPF false
+
+#define DECODE_MITSUBISHIHEAVY false
+#define SEND_MITSUBISHIHEAVY false
+
+#define DECODE_DAIKIN216 false
+#define SEND_DAIKIN216 false
+
#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_HAIER_AC_YRW02 || \
DECODE_WHIRLPOOL_AC || DECODE_SAMSUNG_AC || DECODE_ELECTRA_AC || \
- DECODE_PANASONIC_AC || DECODE_MWM)
+ DECODE_PANASONIC_AC || DECODE_MWM || DECODE_DAIKIN2 || \
+ DECODE_VESTEL_AC || DECODE_TCL112AC || DECODE_MITSUBISHIHEAVY || \
+ DECODE_DAIKIN216)
#define DECODE_AC true // We need some common infrastructure for decoding A/Cs.
#else
#define DECODE_AC false // We don't need that infrastructure.
@@ -376,54 +428,65 @@ 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,
HAIER_AC_YRW02,
- WHIRLPOOL_AC,
+ WHIRLPOOL_AC, // (45)
SAMSUNG_AC,
LUTRON,
ELECTRA_AC,
PANASONIC_AC,
- PIONEER,
+ PIONEER, // (50)
LG2,
MWM,
+ DAIKIN2,
+ VESTEL_AC,
+ TECO, // (55)
+ SAMSUNG36,
+ TCL112AC,
+ LEGOPF,
+ MITSUBISHI_HEAVY_88,
+ MITSUBISHI_HEAVY_152, // 60
+ DAIKIN216,
+ // Add new entries before this one, and update it to point to the last entry.
+ kLastDecodeType = DAIKIN216,
};
// Message lengths & required repeat values
@@ -433,13 +496,22 @@ 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 = 1;
const uint16_t kCarrierAcBits = 32;
const uint16_t kCarrierAcMinRepeat = kNoRepeat;
-// Daikin has a lot of static stuff that is discarded
-const uint16_t kDaikinRawBits = 583;
-const uint16_t kDaikinStateLength = 27;
+const uint16_t kDaikinStateLength = 35;
const uint16_t kDaikinBits = kDaikinStateLength * 8;
+const uint16_t kDaikinStateLengthShort = kDaikinStateLength - 8;
+const uint16_t kDaikinBitsShort = kDaikinStateLengthShort * 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 kDaikin216StateLength = 27;
+const uint16_t kDaikin216Bits = kDaikin216StateLength * 8;
+const uint16_t kDaikin216DefaultRepeat = kNoRepeat;
const uint16_t kDenonBits = 15;
const uint16_t kDenonLegacyBits = 14;
const uint16_t kDishBits = 16;
@@ -455,12 +527,16 @@ 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;
@@ -468,8 +544,11 @@ 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 kLegoPfBits = 16;
+const uint16_t kLegoPfMinRepeat = kNoRepeat;
const uint16_t kLgBits = 28;
const uint16_t kLg32Bits = 32;
const uint16_t kLutronBits = 35;
@@ -483,6 +562,12 @@ const uint16_t kMitsubishiMinRepeat = kSingleRepeat;
const uint16_t kMitsubishiACStateLength = 18;
const uint16_t kMitsubishiACBits = kMitsubishiACStateLength * 8;
const uint16_t kMitsubishiACMinRepeat = kSingleRepeat;
+const uint16_t kMitsubishiHeavy88StateLength = 11;
+const uint16_t kMitsubishiHeavy88Bits = kMitsubishiHeavy88StateLength * 8;
+const uint16_t kMitsubishiHeavy88MinRepeat = kNoRepeat;
+const uint16_t kMitsubishiHeavy152StateLength = 19;
+const uint16_t kMitsubishiHeavy152Bits = kMitsubishiHeavy152StateLength * 8;
+const uint16_t kMitsubishiHeavy152MinRepeat = kNoRepeat;
const uint16_t kNikaiBits = 24;
const uint16_t kNECBits = 32;
const uint16_t kPanasonicBits = 48;
@@ -491,6 +576,7 @@ 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;
@@ -500,10 +586,12 @@ 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 kSamsung36Bits = 36;
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;
@@ -519,13 +607,22 @@ const uint16_t kSony15Bits = 15;
const uint16_t kSony20Bits = 20;
const uint16_t kSonyMinBits = 12;
const uint16_t kSonyMinRepeat = 2;
+const uint16_t kTcl112AcStateLength = 14;
+const uint16_t kTcl112AcBits = kTcl112AcStateLength * 8;
+const uint16_t kTcl112AcDefaultRepeat = kNoRepeat;
+const uint16_t kTecoBits = 35;
+const uint16_t kTecoDefaultRepeat = kNoRepeat;
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
@@ -598,4 +695,14 @@ const uint16_t kWhynterBits = 32;
#define DPRINTLN(x)
#endif // DEBUG
+#ifdef UNIT_TEST
+#ifndef F
+// Create a no-op F() macro so the code base still compiles outside of the
+// Arduino framework. Thus we can safely use the Arduino 'F()' macro through-out
+// the code base. That macro stores constants in Flash (PROGMEM) memory.
+// See: https://github.com/markszabo/IRremoteESP8266/issues/667
+#define F(x) x
+#endif // F
+#endif // UNIT_TEST
+
#endif // IRREMOTEESP8266_H_
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/IRsend.cpp b/lib/IRremoteESP8266-2.6.0/src/IRsend.cpp
similarity index 92%
rename from lib/IRremoteESP8266-2.5.2.03/src/IRsend.cpp
rename to lib/IRremoteESP8266-2.6.0/src/IRsend.cpp
index 96f95172d..22c0c874b 100644
--- a/lib/IRremoteESP8266-2.5.2.03/src/IRsend.cpp
+++ b/lib/IRremoteESP8266-2.6.0/src/IRsend.cpp
@@ -1,6 +1,6 @@
// Copyright 2009 Ken Shirriff
// Copyright 2015 Mark Szabo
-// Copyright 2017 David Conran
+// Copyright 2017,2019 David Conran
#include "IRsend.h"
#ifndef UNIT_TEST
@@ -110,6 +110,9 @@ void IRsend::enableIROut(uint32_t freq, uint8_t duty) {
}
if (freq < 1000) // Were we given kHz? Supports the old call usage.
freq *= 1000;
+#ifdef UNIT_TEST
+ _freq_unittest = freq;
+#endif // UNIT_TEST
uint32_t period = calcUSecPeriod(freq);
// Nr. of uSeconds the LED will be on per pulse.
onTimePeriod = (period * _dutycycle) / kDutyMax;
@@ -488,57 +491,24 @@ void IRsend::sendRaw(uint16_t buf[], uint16_t len, uint16_t hz) {
}
#endif // SEND_RAW
-#ifndef UNIT_TEST
-void IRsend::send(uint16_t type, uint64_t data, uint16_t nbits) {
+// Send a simple (up to 64 bits) IR message of a given type.
+// An unknown/unsupported type will do nothing.
+// Args:
+// type: Protocol number/type of the message you want to send.
+// data: The data you want to send (up to 64 bits).
+// nbits: How many bits long the message is to be.
+// Returns:
+// bool: True if it is a type we can attempt to send, false if not.
+bool IRsend::send(decode_type_t type, uint64_t data, uint16_t nbits) {
switch (type) {
-#if SEND_NEC
- case NEC:
- sendNEC(data, nbits);
+#if SEND_AIWA_RC_T501
+ case AIWA_RC_T501:
+ sendAiwaRCT501(data, nbits);
break;
#endif
-#if SEND_SONY
- case SONY:
- sendSony(data, nbits);
- break;
-#endif
-#if SEND_RC5
- case RC5:
- sendRC5(data, nbits);
- break;
-#endif
-#if SEND_RC6
- case RC6:
- sendRC6(data, nbits);
- break;
-#endif
-#if SEND_DISH
- case DISH:
- sendDISH(data, nbits);
- break;
-#endif
-#if SEND_JVC
- case JVC:
- sendJVC(data, nbits);
- break;
-#endif
-#if SEND_SAMSUNG
- case SAMSUNG:
- sendSAMSUNG(data, nbits);
- break;
-#endif
-#if SEND_LG
- 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);
+#if SEND_CARRIER_AC
+ case CARRIER_AC:
+ sendCarrierAC(data, nbits);
break;
#endif
#if SEND_COOLIX
@@ -551,14 +521,57 @@ void IRsend::send(uint16_t type, uint64_t data, uint16_t nbits) {
sendDenon(data, nbits);
break;
#endif
-#if SEND_SHERWOOD
- case SHERWOOD:
- sendSherwood(data, nbits);
+#if SEND_DISH
+ case DISH:
+ sendDISH(data, nbits);
break;
#endif
-#if SEND_RCMM
- case RCMM:
- sendRCMM(data, nbits);
+#if SEND_GICABLE
+ case GICABLE:
+ sendGICable(data, nbits);
+ break;
+#endif
+#if SEND_GREE
+ case GREE:
+ sendGree(data, nbits);
+ break;
+#endif
+#if SEND_JVC
+ case JVC:
+ sendJVC(data, nbits);
+ break;
+#endif
+#if SEND_LASERTAG
+ case LASERTAG:
+ sendLasertag(data, nbits);
+ break;
+#endif
+#if SEND_LEGOPF
+ case LEGOPF:
+ sendLegoPf(data, nbits);
+ break;
+#endif
+#if SEND_LG
+ case LG:
+ sendLG(data, nbits);
+ break;
+ case LG2:
+ sendLG2(data, nbits);
+ break;
+#endif
+#if SEND_LUTRON
+ case LUTRON:
+ sendLutron(data, nbits);
+ break;
+#endif
+#if SEND_MAGIQUEST
+ case MAGIQUEST:
+ sendMagiQuest(data, nbits);
+ break;
+#endif
+#if SEND_MIDEA
+ case MIDEA:
+ sendMidea(data, nbits);
break;
#endif
#if SEND_MITSUBISHI
@@ -571,24 +584,20 @@ void IRsend::send(uint16_t type, uint64_t data, uint16_t nbits) {
sendMitsubishi2(data, nbits);
break;
#endif
-#if SEND_SHARP
- case SHARP:
- sendSharpRaw(data, nbits);
+#if SEND_NIKAI
+ case NIKAI:
+ sendNikai(data, nbits);
break;
#endif
-#if SEND_AIWA_RC_T501
- case AIWA_RC_T501:
- sendAiwaRCT501(data, nbits);
+#if SEND_NEC
+ case NEC:
+ case NEC_LIKE:
+ sendNEC(data, nbits);
break;
#endif
-#if SEND_MIDEA
- case MIDEA:
- sendMidea(data, nbits);
- break;
-#endif
-#if SEND_GICABLE
- case GICABLE:
- sendGICable(data, nbits);
+#if SEND_PANASONIC
+ case PANASONIC:
+ sendPanasonic64(data, nbits);
break;
#endif
#if SEND_PIONEER
@@ -596,6 +605,68 @@ void IRsend::send(uint16_t type, uint64_t data, uint16_t nbits) {
sendPioneer(data, nbits);
break;
#endif
- }
-}
+#if SEND_RC5
+ case RC5:
+ sendRC5(data, nbits);
+ break;
#endif
+#if SEND_RC6
+ case RC6:
+ sendRC6(data, nbits);
+ break;
+#endif
+#if SEND_RCMM
+ case RCMM:
+ sendRCMM(data, nbits);
+ break;
+#endif
+#if SEND_SAMSUNG
+ case SAMSUNG:
+ sendSAMSUNG(data, nbits);
+ break;
+#endif
+#if SEND_SAMSUNG36
+ case SAMSUNG36:
+ sendSamsung36(data, nbits);
+ break;
+#endif
+#if SEND_SANYO
+ case SANYO_LC7461:
+ sendSanyoLC7461(data, nbits);
+ break;
+#endif
+#if SEND_SHARP
+ case SHARP:
+ sendSharpRaw(data, nbits);
+ break;
+#endif
+#if SEND_SHERWOOD
+ case SHERWOOD:
+ sendSherwood(data, nbits);
+ break;
+#endif
+#if SEND_SONY
+ case SONY:
+ sendSony(data, nbits);
+ break;
+#endif
+#if SEND_TECO
+ case TECO:
+ sendTeco(data, nbits);
+ break;
+#endif
+#if SEND_VESTEL_AC
+ case VESTEL_AC:
+ sendVestelAc(data, nbits);
+ break;
+#endif
+#if SEND_WHYNTER
+ case WHYNTER:
+ sendWhynter(data, nbits);
+ break;
+#endif
+ default:
+ return false;
+ }
+ return true;
+}
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/IRsend.h b/lib/IRremoteESP8266-2.6.0/src/IRsend.h
similarity index 77%
rename from lib/IRremoteESP8266-2.5.2.03/src/IRsend.h
rename to lib/IRremoteESP8266-2.6.0/src/IRsend.h
index 8e2dc248e..b065f6582 100644
--- a/lib/IRremoteESP8266-2.5.2.03/src/IRsend.h
+++ b/lib/IRremoteESP8266-2.6.0/src/IRsend.h
@@ -28,6 +28,49 @@ const uint8_t kDutyMax = 100; // Percentage
// delayMicroseconds() is only accurate to 16383us.
// Ref: https://www.arduino.cc/en/Reference/delayMicroseconds
const uint16_t kMaxAccurateUsecDelay = 16383;
+// Usecs to wait between messages we don't know the proper gap time.
+const uint32_t kDefaultMessageGap = 100000;
+
+
+namespace stdAc {
+ enum class opmode_t {
+ kOff = -1,
+ kAuto = 0,
+ kCool = 1,
+ kHeat = 2,
+ kDry = 3,
+ kFan = 4,
+ };
+
+ enum class fanspeed_t {
+ kAuto = 0,
+ kMin = 1,
+ kLow = 2,
+ kMedium = 3,
+ kHigh = 4,
+ kMax = 5,
+ };
+
+ enum class swingv_t {
+ kOff = -1,
+ kAuto = 0,
+ kHighest = 1,
+ kHigh = 2,
+ kMiddle = 3,
+ kLow = 4,
+ kLowest = 5,
+ };
+
+ enum class swingh_t {
+ kOff = -1,
+ kAuto = 0, // a.k.a. On.
+ kLeftMax = 1,
+ kLeft = 2,
+ kMiddle = 3,
+ kRight = 4,
+ kRightMax = 5,
+ };
+}; // namespace stdAc
// Classes
class IRsend {
@@ -66,7 +109,7 @@ 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);
+ bool send(decode_type_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 = kNECBits,
uint16_t repeat = kNoRepeat);
@@ -92,10 +135,14 @@ class IRsend {
uint16_t repeat = kNoRepeat);
uint32_t encodeSAMSUNG(uint8_t customer, uint8_t command);
#endif
+#if SEND_SAMSUNG36
+ void sendSamsung36(const uint64_t data, const uint16_t nbits = kSamsung36Bits,
+ const uint16_t repeat = kNoRepeat);
+#endif
#if SEND_SAMSUNG_AC
- void sendSamsungAC(unsigned char data[],
- uint16_t nbytes = kSamsungAcStateLength,
- uint16_t repeat = kNoRepeat);
+ void sendSamsungAC(const unsigned char data[],
+ const uint16_t nbytes = kSamsungAcStateLength,
+ const uint16_t repeat = kSamsungAcDefaultRepeat);
#endif
#if SEND_LG
void sendLG(uint64_t data, uint16_t nbits = kLgBits,
@@ -166,7 +213,7 @@ class IRsend {
#endif
#if SEND_COOLIX
void sendCOOLIX(uint64_t data, uint16_t nbits = kCoolixBits,
- uint16_t repeat = kNoRepeat);
+ uint16_t repeat = kCoolixDefaultRepeat);
#endif
#if SEND_WHYNTER
void sendWhynter(uint64_t data, uint16_t nbits = kWhynterBits,
@@ -185,6 +232,16 @@ class IRsend {
uint16_t nbytes = kMitsubishiACStateLength,
uint16_t repeat = kMitsubishiACMinRepeat);
#endif
+#if SEND_MITSUBISHIHEAVY
+ void sendMitsubishiHeavy88(
+ const unsigned char data[],
+ const uint16_t nbytes = kMitsubishiHeavy88StateLength,
+ const uint16_t repeat = kMitsubishiHeavy88MinRepeat);
+ void sendMitsubishiHeavy152(
+ const unsigned char data[],
+ const uint16_t nbytes = kMitsubishiHeavy152StateLength,
+ const uint16_t repeat = kMitsubishiHeavy152MinRepeat);
+#endif
#if SEND_FUJITSU_AC
void sendFujitsuAC(unsigned char data[], uint16_t nbytes,
uint16_t repeat = kFujitsuAcMinRepeat);
@@ -195,12 +252,21 @@ class IRsend {
#if SEND_KELVINATOR
void sendKelvinator(unsigned char data[],
uint16_t nbytes = kKelvinatorStateLength,
- uint16_t repeat = kNoRepeat);
+ uint16_t repeat = kKelvinatorDefaultRepeat);
#endif
#if SEND_DAIKIN
- void sendDaikin(unsigned char data[], uint16_t nbytes = kDaikinStateLength,
- uint16_t repeat = kNoRepeat);
- void sendDaikinGapHeader();
+ void sendDaikin(const unsigned char data[],
+ const uint16_t nbytes = kDaikinStateLength,
+ const uint16_t repeat = kDaikinDefaultRepeat);
+#endif
+#if SEND_DAIKIN2
+ void sendDaikin2(unsigned char data[], uint16_t nbytes = kDaikin2StateLength,
+ uint16_t repeat = kDaikin2DefaultRepeat);
+#endif
+#if SEND_DAIKIN216
+ void sendDaikin216(const unsigned char data[],
+ const uint16_t nbytes = kDaikin216StateLength,
+ const uint16_t repeat = kDaikin216DefaultRepeat);
#endif
#if SEND_AIWA_RC_T501
void sendAiwaRCT501(uint64_t data, uint16_t nbits = kAiwaRcT501Bits,
@@ -208,20 +274,20 @@ class IRsend {
#endif
#if SEND_GREE
void sendGree(uint64_t data, uint16_t nbits = kGreeBits,
- uint16_t repeat = kNoRepeat);
+ uint16_t repeat = kGreeDefaultRepeat);
void sendGree(uint8_t data[], uint16_t nbytes = kGreeStateLength,
- uint16_t repeat = kNoRepeat);
+ uint16_t repeat = kGreeDefaultRepeat);
#endif
#if SEND_PRONTO
void sendPronto(uint16_t data[], uint16_t len, uint16_t repeat = kNoRepeat);
#endif
#if SEND_ARGO
void sendArgo(unsigned char data[], uint16_t nbytes = kArgoStateLength,
- uint16_t repeat = kNoRepeat);
+ uint16_t repeat = kArgoDefaultRepeat);
#endif
#if SEND_TROTEC
void sendTrotec(unsigned char data[], uint16_t nbytes = kTrotecStateLength,
- uint16_t repeat = kNoRepeat);
+ uint16_t repeat = kTrotecDefaultRepeat);
#endif
#if SEND_NIKAI
void sendNikai(uint64_t data, uint16_t nbits = kNikaiBits,
@@ -251,17 +317,17 @@ class IRsend {
#endif
#if (SEND_HAIER_AC || SEND_HAIER_AC_YRW02)
void sendHaierAC(unsigned char data[], uint16_t nbytes = kHaierACStateLength,
- uint16_t repeat = kNoRepeat);
+ uint16_t repeat = kHaierAcDefaultRepeat);
#endif
#if SEND_HAIER_AC_YRW02
void sendHaierACYRW02(unsigned char data[],
uint16_t nbytes = kHaierACYRW02StateLength,
- uint16_t repeat = kNoRepeat);
+ uint16_t repeat = kHaierAcYrw02DefaultRepeat);
#endif
#if SEND_HITACHI_AC
void sendHitachiAC(unsigned char data[],
uint16_t nbytes = kHitachiAcStateLength,
- uint16_t repeat = kNoRepeat);
+ uint16_t repeat = kHitachiAcDefaultRepeat);
#endif
#if SEND_HITACHI_AC1
void sendHitachiAC1(unsigned char data[],
@@ -280,7 +346,7 @@ class IRsend {
#if SEND_WHIRLPOOL_AC
void sendWhirlpoolAC(unsigned char data[],
uint16_t nbytes = kWhirlpoolAcStateLength,
- uint16_t repeat = kNoRepeat);
+ uint16_t repeat = kWhirlpoolAcDefaultRepeat);
#endif
#if SEND_LUTRON
void sendLutron(uint64_t data, uint16_t nbits = kLutronBits,
@@ -294,7 +360,7 @@ class IRsend {
#if SEND_PANASONIC_AC
void sendPanasonicAC(unsigned char data[],
uint16_t nbytes = kPanasonicAcStateLength,
- uint16_t repeat = kNoRepeat);
+ uint16_t repeat = kPanasonicAcDefaultRepeat);
#endif
#if SEND_PIONEER
void sendPioneer(const uint64_t data, const uint16_t nbits = kPioneerBits,
@@ -305,6 +371,24 @@ class IRsend {
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
+#if SEND_TCL112AC
+ void sendTcl112Ac(const unsigned char data[],
+ const uint16_t nbytes = kTcl112AcStateLength,
+ const uint16_t repeat = kTcl112AcDefaultRepeat);
+#endif
+#if SEND_TECO
+ void sendTeco(uint64_t data, uint16_t nbits = kTecoBits,
+ uint16_t repeat = kNoRepeat);
+#endif
+#if SEND_LEGOPF
+ void sendLegoPf(const uint64_t data, const uint16_t nbits = kLegoPfBits,
+ const uint16_t repeat = kLegoPfMinRepeat);
+#endif
+
protected:
#ifdef UNIT_TEST
@@ -319,8 +403,12 @@ class IRsend {
uint8_t outputOff;
VIRTUAL void ledOff();
VIRTUAL void ledOn();
+#ifndef UNIT_TEST
private:
+#else
+ uint32_t _freq_unittest;
+#endif // UNIT_TEST
uint16_t onTimePeriod;
uint16_t offTimePeriod;
uint16_t IRpin;
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/IRtimer.cpp b/lib/IRremoteESP8266-2.6.0/src/IRtimer.cpp
similarity index 53%
rename from lib/IRremoteESP8266-2.5.2.03/src/IRtimer.cpp
rename to lib/IRremoteESP8266-2.6.0/src/IRtimer.cpp
index 029637cbb..4173d763b 100644
--- a/lib/IRremoteESP8266-2.5.2.03/src/IRtimer.cpp
+++ b/lib/IRremoteESP8266-2.6.0/src/IRtimer.cpp
@@ -7,12 +7,12 @@
#ifdef UNIT_TEST
// Used to help simulate elapsed time in unit tests.
-extern uint32_t _IRtimer_unittest_now;
+uint32_t _IRtimer_unittest_now = 0;
+uint32_t _TimerMs_unittest_now = 0;
#endif // UNIT_TEST
// This class performs a simple time in useconds since instantiated.
// Handles when the system timer wraps around (once).
-
IRtimer::IRtimer() { reset(); }
void IRtimer::reset() {
@@ -39,3 +39,32 @@ uint32_t IRtimer::elapsed() {
#ifdef UNIT_TEST
void IRtimer::add(uint32_t usecs) { _IRtimer_unittest_now += usecs; }
#endif // UNIT_TEST
+
+// This class performs a simple time in milli-seoncds since instantiated.
+// Handles when the system timer wraps around (once).
+TimerMs::TimerMs() { reset(); }
+
+void TimerMs::reset() {
+#ifndef UNIT_TEST
+ start = millis();
+#else
+ start = _TimerMs_unittest_now;
+#endif
+}
+
+uint32_t TimerMs::elapsed() {
+#ifndef UNIT_TEST
+ uint32_t now = millis();
+#else
+ uint32_t now = _TimerMs_unittest_now;
+#endif
+ if (start <= now) // Check if the system timer has wrapped.
+ return now - start; // No wrap.
+ else
+ return UINT32_MAX - start + now; // Has wrapped.
+}
+
+// Only used in unit testing.
+#ifdef UNIT_TEST
+void TimerMs::add(uint32_t msecs) { _IRtimer_unittest_now += msecs; }
+#endif // UNIT_TEST
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/IRtimer.h b/lib/IRremoteESP8266-2.6.0/src/IRtimer.h
similarity index 64%
rename from lib/IRremoteESP8266-2.5.2.03/src/IRtimer.h
rename to lib/IRremoteESP8266-2.6.0/src/IRtimer.h
index baca1cf74..d00e1d0fa 100644
--- a/lib/IRremoteESP8266-2.5.2.03/src/IRtimer.h
+++ b/lib/IRremoteESP8266-2.6.0/src/IRtimer.h
@@ -20,4 +20,16 @@ class IRtimer {
uint32_t start;
};
+class TimerMs {
+ public:
+ TimerMs();
+ void reset();
+ uint32_t elapsed();
+#ifdef UNIT_TEST
+ static void add(uint32_t msecs);
+#endif // UNIT_TEST
+
+ private:
+ uint32_t start;
+};
#endif // IRTIMER_H_
diff --git a/lib/IRremoteESP8266-2.6.0/src/IRutils.cpp b/lib/IRremoteESP8266-2.6.0/src/IRutils.cpp
new file mode 100644
index 000000000..d90925241
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/src/IRutils.cpp
@@ -0,0 +1,768 @@
+// Copyright 2017 David Conran
+
+#include "IRutils.h"
+#ifndef UNIT_TEST
+#include
+#endif
+
+#define __STDC_LIMIT_MACROS
+#include
+#include
+#include
+#ifndef ARDUINO
+#include
+#endif
+#include "IRrecv.h"
+#include "IRremoteESP8266.h"
+
+// Reverse the order of the requested least significant nr. of bits.
+// Args:
+// input: Bit pattern/integer to reverse.
+// nbits: Nr. of bits to reverse.
+// 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.
+ // 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));
+ uint64_t output = 0;
+ for (uint16_t i = 0; i < nbits; i++) {
+ output <<= 1;
+ output |= (input & 1);
+ input >>= 1;
+ }
+ // Merge any remaining unreversed bits back to the top of the reversed bits.
+ return (input << nbits) | output;
+}
+
+// Convert a uint64_t (unsigned long long) to a string.
+// Arduino String/toInt/Serial.print() can't handle printing 64 bit values.
+//
+// Args:
+// input: The value to print
+// base: The output base.
+// Returns:
+// A string representation of the integer.
+// Note: Based on Arduino's Print::printNumber()
+#ifdef ARDUINO // Arduino's & C++'s string implementations can't co-exist.
+String uint64ToString(uint64_t input, uint8_t base) {
+ String result = "";
+#else
+std::string uint64ToString(uint64_t input, uint8_t base) {
+ std::string result = "";
+#endif
+ // prevent issues if called with base <= 1
+ if (base < 2) base = 10;
+ // Check we have a base that we can actually print.
+ // i.e. [0-9A-Z] == 36
+ if (base > 36) base = 10;
+
+ do {
+ char c = input % base;
+ input /= base;
+
+ if (c < 10)
+ c += '0';
+ else
+ c += 'A' - 10;
+ result = c + result;
+ } while (input);
+ return result;
+}
+
+#ifdef ARDUINO
+// Print a uint64_t/unsigned long long to the Serial port
+// Serial.print() can't handle printing long longs. (uint64_t)
+//
+// Args:
+// input: The value to print
+// base: The output base.
+void serialPrintUint64(uint64_t input, uint8_t base) {
+ Serial.print(uint64ToString(input, base));
+}
+#endif
+
+// Convert a c-style str to a decode_type_t
+// Note: Assumes str is upper case.
+//
+// Args:
+// str: An upper-case C-style string.
+// Returns:
+// A decode_type_t enum.
+decode_type_t strToDecodeType(const char *str) {
+ if (!strcmp(str, "UNKNOWN"))
+ return decode_type_t::UNKNOWN;
+ else if (!strcmp(str, "UNUSED"))
+ return decode_type_t::UNUSED;
+ else if (!strcmp(str, "AIWA_RC_T501"))
+ return decode_type_t::AIWA_RC_T501;
+ else if (!strcmp(str, "ARGO"))
+ return decode_type_t::ARGO;
+ else if (!strcmp(str, "CARRIER_AC"))
+ return decode_type_t::CARRIER_AC;
+ else if (!strcmp(str, "COOLIX"))
+ return decode_type_t::COOLIX;
+ else if (!strcmp(str, "DAIKIN"))
+ return decode_type_t::DAIKIN;
+ else if (!strcmp(str, "DAIKIN2"))
+ return decode_type_t::DAIKIN2;
+ else if (!strcmp(str, "DAIKIN216"))
+ return decode_type_t::DAIKIN216;
+ else if (!strcmp(str, "DENON"))
+ return decode_type_t::DENON;
+ else if (!strcmp(str, "DISH"))
+ return decode_type_t::DISH;
+ else if (!strcmp(str, "ELECTRA_AC"))
+ return decode_type_t::ELECTRA_AC;
+ else if (!strcmp(str, "FUJITSU_AC"))
+ return decode_type_t::FUJITSU_AC;
+ else if (!strcmp(str, "GICABLE"))
+ return decode_type_t::GICABLE;
+ else if (!strcmp(str, "GLOBALCACHE"))
+ return decode_type_t::GLOBALCACHE;
+ else if (!strcmp(str, "GREE"))
+ return decode_type_t::GREE;
+ else if (!strcmp(str, "HAIER_AC"))
+ return decode_type_t::HAIER_AC;
+ else if (!strcmp(str, "HAIER_AC_YRW02"))
+ return decode_type_t::HAIER_AC_YRW02;
+ else if (!strcmp(str, "HITACHI_AC"))
+ return decode_type_t::HITACHI_AC;
+ else if (!strcmp(str, "HITACHI_AC1"))
+ return decode_type_t::HITACHI_AC1;
+ else if (!strcmp(str, "HITACHI_AC2"))
+ return decode_type_t::HITACHI_AC2;
+ else if (!strcmp(str, "JVC"))
+ return decode_type_t::JVC;
+ else if (!strcmp(str, "KELVINATOR"))
+ return decode_type_t::KELVINATOR;
+ else if (!strcmp(str, "LEGOPF"))
+ return decode_type_t::LEGOPF;
+ else if (!strcmp(str, "LG"))
+ return decode_type_t::LG;
+ else if (!strcmp(str, "LG2"))
+ return decode_type_t::LG2;
+ else if (!strcmp(str, "LASERTAG"))
+ return decode_type_t::LASERTAG;
+ else if (!strcmp(str, "LUTRON"))
+ return decode_type_t::LUTRON;
+ else if (!strcmp(str, "MAGIQUEST"))
+ return decode_type_t::MAGIQUEST;
+ else if (!strcmp(str, "MIDEA"))
+ return decode_type_t::MIDEA;
+ else if (!strcmp(str, "MITSUBISHI"))
+ return decode_type_t::MITSUBISHI;
+ else if (!strcmp(str, "MITSUBISHI2"))
+ return decode_type_t::MITSUBISHI2;
+ else if (!strcmp(str, "MITSUBISHI_AC"))
+ return decode_type_t::MITSUBISHI_AC;
+ else if (!strcmp(str, "MWM"))
+ return decode_type_t::MWM;
+ else if (!strcmp(str, "NEC") || !strcmp(str, "NEC (NON-STRICT"))
+ return decode_type_t::NEC;
+ else if (!strcmp(str, "NIKAI"))
+ return decode_type_t::NIKAI;
+ else if (!strcmp(str, "PANASONIC"))
+ return decode_type_t::PANASONIC;
+ else if (!strcmp(str, "PANASONIC_AC"))
+ return decode_type_t::PANASONIC_AC;
+ else if (!strcmp(str, "PIONEER"))
+ return decode_type_t::PIONEER;
+ else if (!strcmp(str, "PRONTO"))
+ return decode_type_t::PRONTO;
+ else if (!strcmp(str, "RAW"))
+ return decode_type_t::RAW;
+ else if (!strcmp(str, "RC5"))
+ return decode_type_t::RC5;
+ else if (!strcmp(str, "RC5X"))
+ return decode_type_t::RC5X;
+ else if (!strcmp(str, "RC6"))
+ return decode_type_t::RC6;
+ else if (!strcmp(str, "RCMM"))
+ return decode_type_t::RCMM;
+ else if (!strcmp(str, "SAMSUNG"))
+ return decode_type_t::SAMSUNG;
+ else if (!strcmp(str, "SAMSUNG36"))
+ return decode_type_t::SAMSUNG36;
+ else if (!strcmp(str, "SAMSUNG_AC"))
+ return decode_type_t::SAMSUNG_AC;
+ else if (!strcmp(str, "SANYO"))
+ return decode_type_t::SANYO;
+ else if (!strcmp(str, "SANYO_LC7461"))
+ return decode_type_t::SANYO_LC7461;
+ else if (!strcmp(str, "SHARP"))
+ return decode_type_t::SHARP;
+ else if (!strcmp(str, "SHERWOOD"))
+ return decode_type_t::SHERWOOD;
+ else if (!strcmp(str, "SONY"))
+ return decode_type_t::SONY;
+ else if (!strcmp(str, "TCL112AC"))
+ return decode_type_t::TCL112AC;
+ else if (!strcmp(str, "TECO"))
+ return decode_type_t::TECO;
+ else if (!strcmp(str, "TOSHIBA_AC"))
+ return decode_type_t::TOSHIBA_AC;
+ else if (!strcmp(str, "TROTEC"))
+ return decode_type_t::TROTEC;
+ else if (!strcmp(str, "VESTEL_AC"))
+ return decode_type_t::VESTEL_AC;
+ else if (!strcmp(str, "WHIRLPOOL_AC"))
+ return decode_type_t::WHIRLPOOL_AC;
+ else if (!strcmp(str, "WHYNTER"))
+ return decode_type_t::WHYNTER;
+ // Handle integer values of the type by converting to a string and back again.
+ decode_type_t result = strToDecodeType(
+ typeToString((decode_type_t)atoi(str)).c_str());
+ if (result > 0)
+ return result;
+ else
+ return decode_type_t::UNKNOWN;
+}
+
+// Escape any special HTML (unsafe) characters in a string. e.g. anti-XSS.
+// Args:
+// unescaped: A string containing text to make HTML safe.
+// Returns:
+// A string that is HTML safe.
+#ifdef ARDUINO // Arduino's & C++'s string implementations can't co-exist.
+String htmlEscape(const String unescaped) {
+ String result = "";
+#else
+std::string htmlEscape(const std::string unescaped) {
+ std::string result = "";
+#endif
+ uint16_t ulen = unescaped.length();
+ result.reserve(ulen); // The result will be at least the size of input.
+ for (size_t i = 0; i < ulen; i++) {
+ char c = unescaped[i];
+ switch (c) {
+ // ';!-"<>={}() are all unsafe.
+ case '\'':
+ result += F("'");
+ break;
+ case ';':
+ result += F(";");
+ break;
+ case '!':
+ result += F("!");
+ break;
+ case '-':
+ result += F("‐");
+ break;
+ case '\"':
+ result += F(""");
+ break;
+ case '<':
+ result += F("<");
+ break;
+ case '>':
+ result += F(">");
+ break;
+ case '=':
+ result += F("equals;");
+ break;
+ case '&':
+ result += F("&");
+ break;
+ case '#':
+ result += F("#");
+ break;
+ case '{':
+ result += F("{");
+ break;
+ case '}':
+ result += F("}");
+ break;
+ case '(':
+ result += F("(");
+ break;
+ case ')':
+ result += F(")");
+ break;
+ default:
+ result += c;
+ }
+ }
+ return result;
+}
+
+// Convert a protocol type (enum etc) to a human readable string.
+// Args:
+// protocol: Nr. (enum) of the protocol.
+// isRepeat: A flag indicating if it is a repeat message of the protocol.
+// Returns:
+// A string containing the protocol name.
+#ifdef ARDUINO // Arduino's & C++'s string implementations can't co-exist.
+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 result = "";
+#endif
+ switch (protocol) {
+ case UNUSED:
+ result = F("UNUSED");
+ break;
+ case AIWA_RC_T501:
+ result = F("AIWA_RC_T501");
+ break;
+ case ARGO:
+ result = F("ARGO");
+ break;
+ case CARRIER_AC:
+ result = F("CARRIER_AC");
+ break;
+ case COOLIX:
+ result = F("COOLIX");
+ break;
+ case DAIKIN:
+ result = F("DAIKIN");
+ break;
+ case DAIKIN2:
+ result = F("DAIKIN2");
+ break;
+ case DAIKIN216:
+ result = F("DAIKIN216");
+ break;
+ case DENON:
+ result = F("DENON");
+ break;
+ case DISH:
+ result = F("DISH");
+ break;
+ case ELECTRA_AC:
+ result = F("ELECTRA_AC");
+ break;
+ case FUJITSU_AC:
+ result = F("FUJITSU_AC");
+ break;
+ case GICABLE:
+ result = F("GICABLE");
+ break;
+ case GLOBALCACHE:
+ result = F("GLOBALCACHE");
+ break;
+ case GREE:
+ result = F("GREE");
+ break;
+ case HAIER_AC:
+ result = F("HAIER_AC");
+ break;
+ case HAIER_AC_YRW02:
+ result = F("HAIER_AC_YRW02");
+ break;
+ case HITACHI_AC:
+ result = F("HITACHI_AC");
+ break;
+ case HITACHI_AC1:
+ result = F("HITACHI_AC1");
+ break;
+ case HITACHI_AC2:
+ result = F("HITACHI_AC2");
+ break;
+ case JVC:
+ result = F("JVC");
+ break;
+ case KELVINATOR:
+ result = F("KELVINATOR");
+ break;
+ case LEGOPF:
+ result = F("LEGOPF");
+ break;
+ case LG:
+ result = F("LG");
+ break;
+ case LG2:
+ result = F("LG2");
+ break;
+ case LASERTAG:
+ result = F("LASERTAG");
+ break;
+ case LUTRON:
+ result = F("LUTRON");
+ break;
+ case MAGIQUEST:
+ result = F("MAGIQUEST");
+ break;
+ case MIDEA:
+ result = F("MIDEA");
+ break;
+ case MITSUBISHI:
+ result = F("MITSUBISHI");
+ break;
+ case MITSUBISHI2:
+ result = F("MITSUBISHI2");
+ break;
+ case MITSUBISHI_AC:
+ result = F("MITSUBISHI_AC");
+ break;
+ case MITSUBISHI_HEAVY_88:
+ result = F("MITSUBISHI_HEAVY_88");
+ break;
+ case MITSUBISHI_HEAVY_152:
+ result = F("MITSUBISHI_HEAVY_152");
+ break;
+ case MWM:
+ result = F("MWM");
+ break;
+ case NEC:
+ result = F("NEC");
+ break;
+ case NEC_LIKE:
+ result = F("NEC (non-strict)");
+ break;
+ case NIKAI:
+ result = F("NIKAI");
+ break;
+ case PANASONIC:
+ result = F("PANASONIC");
+ break;
+ case PANASONIC_AC:
+ result = F("PANASONIC_AC");
+ break;
+ case PIONEER:
+ result = F("PIONEER");
+ break;
+ case PRONTO:
+ result = F("PRONTO");
+ break;
+ case RAW:
+ result = F("RAW");
+ break;
+ case RC5:
+ result = F("RC5");
+ break;
+ case RC5X:
+ result = F("RC5X");
+ break;
+ case RC6:
+ result = F("RC6");
+ break;
+ case RCMM:
+ result = F("RCMM");
+ break;
+ case SAMSUNG:
+ result = F("SAMSUNG");
+ break;
+ case SAMSUNG36:
+ result = F("SAMSUNG36");
+ break;
+ case SAMSUNG_AC:
+ result = F("SAMSUNG_AC");
+ break;
+ case SANYO:
+ result = F("SANYO");
+ break;
+ case SANYO_LC7461:
+ result = F("SANYO_LC7461");
+ break;
+ case SHARP:
+ result = F("SHARP");
+ break;
+ case SHERWOOD:
+ result = F("SHERWOOD");
+ break;
+ case SONY:
+ result = F("SONY");
+ break;
+ case TCL112AC:
+ result = F("TCL112AC");
+ break;
+ case TECO:
+ result = F("TECO");
+ break;
+ case TOSHIBA_AC:
+ result = F("TOSHIBA_AC");
+ break;
+ case TROTEC:
+ result = F("TROTEC");
+ break;
+ case VESTEL_AC:
+ result = F("VESTEL_AC");
+ break;
+ case WHIRLPOOL_AC:
+ result = F("WHIRLPOOL_AC");
+ break;
+ case WHYNTER:
+ result = F("WHYNTER");
+ break;
+ case UNKNOWN:
+ default:
+ result = F("UNKNOWN");
+ break;
+ }
+ if (isRepeat) result += F(" (Repeat)");
+ return result;
+}
+
+// Does the given protocol use a complex state as part of the decode?
+bool hasACState(const decode_type_t protocol) {
+ switch (protocol) {
+ case DAIKIN:
+ case DAIKIN2:
+ case DAIKIN216:
+ 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 MITSUBISHI_HEAVY_88:
+ case MITSUBISHI_HEAVY_152:
+ case MWM:
+ case PANASONIC_AC:
+ case SAMSUNG_AC:
+ case TCL112AC:
+ case TOSHIBA_AC:
+ case WHIRLPOOL_AC:
+ return true;
+ default:
+ return false;
+ }
+}
+
+// Return the corrected length of a 'raw' format array structure
+// after over-large values are converted into multiple entries.
+// Args:
+// results: A ptr to a decode result.
+// Returns:
+// A uint16_t containing the length.
+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] * kRawTick;
+ // Add two extra entries for multiple larger than UINT16_MAX it is.
+ extended_length += (usecs / (UINT16_MAX + 1)) * 2;
+ }
+ return extended_length;
+}
+
+// Return a string containing the key values of a decode_results structure
+// in a C/C++ code style format.
+#ifdef ARDUINO
+String resultToSourceCode(const decode_results *results) {
+ String output = "";
+#else
+std::string resultToSourceCode(const decode_results *results) {
+ std::string output = "";
+#endif
+ // Start declaration
+ output += F("uint16_t "); // variable type
+ output += F("rawData["); // array name
+ output += uint64ToString(getCorrectedRawLength(results), 10);
+ // array size
+ output += F("] = {"); // Start declaration
+
+ // Dump data
+ for (uint16_t i = 1; i < results->rawlen; i++) {
+ uint32_t usecs;
+ for (usecs = results->rawbuf[i] * kRawTick; usecs > UINT16_MAX;
+ usecs -= UINT16_MAX) {
+ output += uint64ToString(UINT16_MAX);
+ if (i % 2)
+ output += F(", 0, ");
+ else
+ output += F(", 0, ");
+ }
+ output += uint64ToString(usecs, 10);
+ if (i < results->rawlen - 1)
+ output += F(", "); // ',' not needed on the last one
+ if (i % 2 == 0) output += ' '; // Extra if it was even.
+ }
+
+ // End declaration
+ output += F("};");
+
+ // Comment
+ output += F(" // ");
+ output += typeToString(results->decode_type, results->repeat);
+ // Only display the value if the decode type doesn't have an A/C state.
+ if (!hasACState(results->decode_type))
+ output += ' ' + uint64ToString(results->value, 16);
+ output += F("\n");
+
+ // Now dump "known" codes
+ if (results->decode_type != UNKNOWN) {
+ if (hasACState(results->decode_type)) {
+#if DECODE_AC
+ uint16_t nbytes = results->bits / 8;
+ output += F("uint8_t state[");
+ output += uint64ToString(nbytes);
+ output += F("] = {");
+ for (uint16_t i = 0; i < nbytes; i++) {
+ output += F("0x");
+ if (results->state[i] < 0x10) output += '0';
+ output += uint64ToString(results->state[i], 16);
+ if (i < nbytes - 1) output += F(", ");
+ }
+ output += F("};\n");
+#endif // DECODE_AC
+ } else {
+ // Simple protocols
+ // Some protocols have an address &/or command.
+ // NOTE: It will ignore the atypical case when a message has been
+ // decoded but the address & the command are both 0.
+ if (results->address > 0 || results->command > 0) {
+ output += F("uint32_t address = 0x");
+ output += uint64ToString(results->address, 16);
+ output += F(";\n");
+ output += F("uint32_t command = 0x");
+ output += uint64ToString(results->command, 16);
+ output += F(";\n");
+ }
+ // Most protocols have data
+ output += F("uint64_t data = 0x");
+ output += uint64ToString(results->value, 16);
+ output += F(";\n");
+ }
+ }
+ return output;
+}
+
+// Dump out the decode_results structure.
+//
+#ifdef ARDUINO
+String resultToTimingInfo(const decode_results *results) {
+ String output = "";
+ String value = "";
+#else
+std::string resultToTimingInfo(const decode_results *results) {
+ std::string output = "";
+ std::string value = "";
+#endif
+ output += F("Raw Timing[");
+ output += uint64ToString(results->rawlen - 1, 10);
+ output += F("]:\n");
+
+ for (uint16_t i = 1; i < results->rawlen; i++) {
+ if (i % 2 == 0)
+ output += '-'; // even
+ else
+ output += F(" +"); // odd
+ value = uint64ToString(results->rawbuf[i] * kRawTick);
+ // Space pad the value till it is at least 6 chars long.
+ while (value.length() < 6) value = ' ' + value;
+ output += value;
+ if (i < results->rawlen - 1)
+ output += F(", "); // ',' 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
+String resultToHumanReadableBasic(const decode_results *results) {
+ String output = "";
+#else
+std::string resultToHumanReadableBasic(const decode_results *results) {
+ std::string output = "";
+#endif
+ // Show Encoding standard
+ output += F("Encoding : ");
+ output += typeToString(results->decode_type, results->repeat);
+ output += '\n';
+
+ // Show Code & length
+ output += F("Code : ");
+ output += resultToHexidecimal(results);
+ output += F(" (");
+ output += uint64ToString(results->bits);
+ output += F(" bits)\n");
+ return output;
+}
+
+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;
+ 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;
+ 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;
+ // Mask off any unwanted bits and return the result.
+ return (result & ((1ULL << nbits) - 1));
+}
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/IRutils.h b/lib/IRremoteESP8266-2.6.0/src/IRutils.h
similarity index 74%
rename from lib/IRremoteESP8266-2.5.2.03/src/IRutils.h
rename to lib/IRremoteESP8266-2.6.0/src/IRutils.h
index c17375d98..0d0b677b5 100644
--- a/lib/IRremoteESP8266-2.5.2.03/src/IRutils.h
+++ b/lib/IRremoteESP8266-2.6.0/src/IRutils.h
@@ -24,7 +24,8 @@ 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
+String htmlEscape(const String unescaped);
+#else // ARDUINO
std::string uint64ToString(uint64_t input, uint8_t base = 10);
std::string typeToString(const decode_type_t protocol,
const bool isRepeat = false);
@@ -32,10 +33,16 @@ 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
+std::string htmlEscape(const std::string unescaped);
+#endif // ARDUINO
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);
-
+decode_type_t strToDecodeType(const char *str);
#endif // IRUTILS_H_
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_Aiwa.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_Aiwa.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_Aiwa.cpp
rename to lib/IRremoteESP8266-2.6.0/src/ir_Aiwa.cpp
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_Argo.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_Argo.cpp
similarity index 84%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_Argo.cpp
rename to lib/IRremoteESP8266-2.6.0/src/ir_Argo.cpp
index 8a3e69f72..d6711acd3 100644
--- a/lib/IRremoteESP8266-2.5.2.03/src/ir_Argo.cpp
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_Argo.cpp
@@ -40,9 +40,9 @@ IRArgoAC::IRArgoAC(uint16_t pin) : _irsend(pin) { stateReset(); }
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
@@ -228,3 +228,37 @@ void IRArgoAC::setRoomTemp(uint8_t temp) {
argo[3] += temp << 5; // Append to bit 5,6,7
argo[4] += temp >> 3; // Remove lowest 3 bits and append in 0,1
}
+
+// Convert a standard A/C Fan speed into its native fan speed.
+uint8_t IRArgoAC::convertFan(const stdAc::fanspeed_t speed) {
+ switch (speed) {
+ case stdAc::fanspeed_t::kMin:
+ case stdAc::fanspeed_t::kLow:
+ return kArgoFan1;
+ case stdAc::fanspeed_t::kMedium:
+ return kArgoFan2;
+ case stdAc::fanspeed_t::kHigh:
+ case stdAc::fanspeed_t::kMax:
+ return kArgoFan3;
+ default:
+ return kArgoFanAuto;
+ }
+}
+
+// Convert a standard A/C Fan speed into its native fan speed.
+uint8_t IRArgoAC::convertSwingV(const stdAc::swingv_t position) {
+ switch (position) {
+ case stdAc::swingv_t::kHighest:
+ return kArgoFlapFull;
+ case stdAc::swingv_t::kHigh:
+ return kArgoFlap5;
+ case stdAc::swingv_t::kMiddle:
+ return kArgoFlap4;
+ case stdAc::swingv_t::kLow:
+ return kArgoFlap3;
+ case stdAc::swingv_t::kLowest:
+ return kArgoFlap1;
+ default:
+ return kArgoFlapAuto;
+ }
+}
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_Argo.h b/lib/IRremoteESP8266-2.6.0/src/ir_Argo.h
similarity index 91%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_Argo.h
rename to lib/IRremoteESP8266-2.6.0/src/ir_Argo.h
index b49fc3517..883c2ddfd 100644
--- a/lib/IRremoteESP8266-2.5.2.03/src/ir_Argo.h
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_Argo.h
@@ -6,6 +6,10 @@
#include "IRremoteESP8266.h"
#include "IRsend.h"
+#ifdef UNIT_TEST
+#include "IRsend_test.h"
+#endif
+
// ARGO Ulisse DCI
@@ -55,7 +59,7 @@ const uint8_t kArgoFlapFull = 7; // 0b111
#define ARGO_COOL_ON kArgoCoolOn
#define ARGO_COOL_OFF kArgoCoolOff
#define ARGO_COOL_AUTO kArgoCoolAuto
-#define ARGO_COOl_HUM kArgoCoolHum
+#define ARGO_COOL_HUM kArgoCoolHum
#define ARGO_HEAT_ON kArgoHeatOn
#define ARGO_HEAT_AUTO kArgoHeatAuto
#define ARGO_HEAT_BLINK kArgoHeatBlink
@@ -80,7 +84,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();
@@ -118,13 +122,19 @@ class IRArgoAC {
void setRoomTemp(uint8_t temp);
uint8_t* getRaw();
+ uint8_t convertFan(const stdAc::fanspeed_t speed);
+ uint8_t convertSwingV(const stdAc::swingv_t position);
+#ifndef UNIT_TEST
private:
+ IRsend _irsend; // instance of the IR send class
+#else
+ IRsendTest _irsend; // instance of the testing IR send class
+#endif
// # of bytes per command
uint8_t argo[kArgoStateLength]; // Defined in IRremoteESP8266.h
void stateReset();
void checksum();
- IRsend _irsend; // instance of the IR send class
// Attributes
uint8_t set_temp;
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_Carrier.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_Carrier.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_Carrier.cpp
rename to lib/IRremoteESP8266-2.6.0/src/ir_Carrier.cpp
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_Coolix.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_Coolix.cpp
similarity index 72%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_Coolix.cpp
rename to lib/IRremoteESP8266-2.6.0/src/ir_Coolix.cpp
index ee539af25..2659a1d88 100644
--- a/lib/IRremoteESP8266-2.5.2.03/src/ir_Coolix.cpp
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_Coolix.cpp
@@ -93,25 +93,62 @@ void IRsend::sendCOOLIX(uint64_t data, uint16_t nbits, uint16_t repeat) {
// https://github.com/markszabo/IRremoteESP8266/issues/484
IRCoolixAC::IRCoolixAC(uint16_t pin) : _irsend(pin) { stateReset(); }
-void IRCoolixAC::stateReset() { remote_state = kCoolixDefaultState; }
+void IRCoolixAC::stateReset() { setRaw(kCoolixDefaultState); }
void IRCoolixAC::begin() { _irsend.begin(); }
#if SEND_COOLIX
-void IRCoolixAC::send() { _irsend.sendCOOLIX(remote_state); }
+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::setRaw(const uint32_t new_code) {
+ remote_state = new_code;
+ saved_state = new_code;
+}
+
+// Return true if the current state is a special state.
+bool IRCoolixAC::isSpecialState(void) {
+ switch (remote_state) {
+ case kCoolixClean:
+ case kCoolixLed:
+ case kCoolixOff:
+ case kCoolixSwing:
+ case kCoolixSleep:
+ case kCoolixTurbo:
+ return true;
+ default:
+ return false;
+ }
+}
+
+void IRCoolixAC::updateSavedState(void) {
+ if (!isSpecialState()) saved_state = remote_state;
+}
+
+void IRCoolixAC::recoverSavedState(void) {
+ // If the current state is a special one, last known normal one.
+ if (isSpecialState()) remote_state = saved_state;
+ // If the saved_state was also a special state, reset as we expect a normal
+ // state out of all this.
+ if (isSpecialState()) stateReset();
+}
+
+uint32_t IRCoolixAC::getNormalState(void) {
+ return isSpecialState() ? saved_state : remote_state;
+}
void IRCoolixAC::setTempRaw(const uint8_t code) {
+ recoverSavedState();
remote_state &= ~kCoolixTempMask; // Clear the old temp.
remote_state |= (code << 4);
}
uint8_t IRCoolixAC::getTempRaw() {
- return (remote_state & kCoolixTempMask) >> 4;
+ return (getNormalState() & kCoolixTempMask) >> 4;
}
void IRCoolixAC::setTemp(const uint8_t desired) {
@@ -130,6 +167,7 @@ uint8_t IRCoolixAC::getTemp() {
}
void IRCoolixAC::setSensorTempRaw(const uint8_t code) {
+ recoverSavedState();
remote_state &= ~kCoolixSensorTempMask; // Clear previous sensor temp.
remote_state |= ((code & 0xF) << 8);
}
@@ -143,7 +181,8 @@ void IRCoolixAC::setSensorTemp(const uint8_t desired) {
}
uint8_t IRCoolixAC::getSensorTemp() {
- return ((remote_state & kCoolixSensorTempMask) >> 8) + kCoolixSensorTempMin;
+ return ((getNormalState() & kCoolixSensorTempMask) >> 8) +
+ kCoolixSensorTempMin;
}
bool IRCoolixAC::getPower() {
@@ -152,25 +191,35 @@ bool IRCoolixAC::getPower() {
}
void IRCoolixAC::setPower(const bool power) {
- if (!power) remote_state = kCoolixOff;
- // There really is no distinct "on" setting, so do nothing.
+ if (power) {
+ // There really is no distinct "on" setting, just ensure it a normal state.
+ recoverSavedState();
+ } else {
+ updateSavedState();
+ remote_state = kCoolixOff;
+ }
}
bool IRCoolixAC::getSwing() { return remote_state == kCoolixSwing; }
void IRCoolixAC::setSwing() {
// Assumes that repeated sending "swing" toggles the action on the device.
+ updateSavedState();
remote_state = kCoolixSwing;
}
bool IRCoolixAC::getSleep() { return remote_state == kCoolixSleep; }
-void IRCoolixAC::setSleep() { remote_state = kCoolixSleep; }
+void IRCoolixAC::setSleep() {
+ updateSavedState();
+ remote_state = kCoolixSleep;
+}
bool IRCoolixAC::getTurbo() { return remote_state == kCoolixTurbo; }
void IRCoolixAC::setTurbo() {
// Assumes that repeated sending "turbo" toggles the action on the device.
+ updateSavedState();
remote_state = kCoolixTurbo;
}
@@ -178,19 +227,24 @@ bool IRCoolixAC::getLed() { return remote_state == kCoolixLed; }
void IRCoolixAC::setLed() {
// Assumes that repeated sending "Led" toggles the action on the device.
+ updateSavedState();
remote_state = kCoolixLed;
}
bool IRCoolixAC::getClean() { return remote_state == kCoolixClean; }
-void IRCoolixAC::setClean() { remote_state = kCoolixClean; }
+void IRCoolixAC::setClean() {
+ updateSavedState();
+ remote_state = kCoolixClean;
+}
bool IRCoolixAC::getZoneFollow() {
- return remote_state & kCoolixZoneFollowMask;
+ return getNormalState() & kCoolixZoneFollowMask;
}
// Internal use only.
void IRCoolixAC::setZoneFollow(bool state) {
+ recoverSavedState();
if (state) {
remote_state |= kCoolixZoneFollowMask;
} else {
@@ -199,6 +253,7 @@ void IRCoolixAC::setZoneFollow(bool state) {
}
void IRCoolixAC::clearSensorTemp() {
+ recoverSavedState();
setZoneFollow(false);
setSensorTempRaw(kCoolixSensorTempIgnoreCode);
}
@@ -212,6 +267,7 @@ void IRCoolixAC::setMode(const uint8_t mode) {
case kCoolixAuto:
case kCoolixHeat:
case kCoolixDry:
+ recoverSavedState();
remote_state = (remote_state & ~kCoolixModeMask) | (actualmode << 2);
// Force the temp into a known-good state.
setTemp(getTemp());
@@ -220,21 +276,25 @@ void IRCoolixAC::setMode(const uint8_t mode) {
}
uint8_t IRCoolixAC::getMode() {
- uint8_t mode = (remote_state & kCoolixModeMask) >> 2;
+ uint8_t mode = (getNormalState() & kCoolixModeMask) >> 2;
if (mode == kCoolixDry)
if (getTempRaw() == kCoolixFanTempCode) return kCoolixFan;
return mode;
}
-uint8_t IRCoolixAC::getFan() { return (remote_state & kCoolixFanMask) >> 13; }
+uint8_t IRCoolixAC::getFan() {
+ return (getNormalState() & kCoolixFanMask) >> 13;
+}
void IRCoolixAC::setFan(const uint8_t speed) {
+ recoverSavedState();
uint8_t newspeed = speed;
switch (speed) {
case kCoolixFanMin:
case kCoolixFanMed:
case kCoolixFanMax:
case kCoolixFanAuto:
+ case kCoolixFanAuto0:
case kCoolixFanZoneFollow:
case kCoolixFanFixed:
break;
@@ -245,6 +305,38 @@ void IRCoolixAC::setFan(const uint8_t speed) {
remote_state |= ((newspeed << 13) & kCoolixFanMask);
}
+// Convert a standard A/C mode into its native mode.
+uint8_t IRCoolixAC::convertMode(const stdAc::opmode_t mode) {
+ switch (mode) {
+ case stdAc::opmode_t::kCool:
+ return kCoolixCool;
+ case stdAc::opmode_t::kHeat:
+ return kCoolixHeat;
+ case stdAc::opmode_t::kDry:
+ return kCoolixDry;
+ case stdAc::opmode_t::kFan:
+ return kCoolixFan;
+ default:
+ return kCoolixAuto;
+ }
+}
+
+// Convert a standard A/C Fan speed into its native fan speed.
+uint8_t IRCoolixAC::convertFan(const stdAc::fanspeed_t speed) {
+ switch (speed) {
+ case stdAc::fanspeed_t::kMin:
+ case stdAc::fanspeed_t::kLow:
+ return kCoolixFanMin;
+ case stdAc::fanspeed_t::kMedium:
+ return kCoolixFanMed;
+ case stdAc::fanspeed_t::kHigh:
+ case stdAc::fanspeed_t::kMax:
+ return kCoolixFanMax;
+ default:
+ return kCoolixFanAuto;
+ }
+}
+
// Convert the internal state into a human readable string.
#ifdef ARDUINO
String IRCoolixAC::toString() {
@@ -253,89 +345,97 @@ String IRCoolixAC::toString() {
std::string IRCoolixAC::toString() {
std::string result = "";
#endif // ARDUINO
- result += "Power: ";
+ result += F("Power: ");
if (getPower()) {
- result += "On";
+ result += F("On");
} else {
- result += "Off";
+ result += F("Off");
return result; // If it's off, there is no other info.
}
- result += ", Fan: " + uint64ToString(getFan());
- switch (getFan()) {
- case kCoolixFanAuto:
- result += " (AUTO)";
- 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";
+ result += F(", Swing: Toggle");
return result;
}
if (getSleep()) {
- result += ", Sleep: Toggle";
+ result += F(", Sleep: Toggle");
return result;
}
if (getTurbo()) {
- result += ", Turbo: Toggle";
+ result += F(", Turbo: Toggle");
return result;
}
if (getLed()) {
- result += ", Led: Toggle";
+ result += F(", Led: Toggle");
return result;
}
if (getClean()) {
- result += ", Mode: Self clean";
+ result += F(", Clean: Toggle");
return result;
}
- result += ", Mode: " + uint64ToString(getMode());
+ result += F(", Mode: ");
+ result += uint64ToString(getMode());
switch (getMode()) {
case kCoolixAuto:
- result += " (AUTO)";
+ result += F(" (AUTO)");
break;
case kCoolixCool:
- result += " (COOL)";
+ result += F(" (COOL)");
break;
case kCoolixHeat:
- result += " (HEAT)";
+ result += F(" (HEAT)");
break;
case kCoolixDry:
- result += " (DRY)";
+ result += F(" (DRY)");
break;
case kCoolixFan:
- result += " (FAN)";
+ result += F(" (FAN)");
break;
default:
- result += " (UNKNOWN)";
+ result += F(" (UNKNOWN)");
}
- if (getMode() != kCoolixFan) // Fan mode doesn't have a temperature.
- result += ", Temp: " + uint64ToString(getTemp()) + "C";
- result += ", Zone Follow: ";
+ result += F(", Fan: ");
+ result += uint64ToString(getFan());
+ switch (getFan()) {
+ case kCoolixFanAuto:
+ result += F(" (AUTO)");
+ break;
+ case kCoolixFanAuto0:
+ result += F(" (AUTO0)");
+ break;
+ case kCoolixFanMax:
+ result += F(" (MAX)");
+ break;
+ case kCoolixFanMin:
+ result += F(" (MIN)");
+ break;
+ case kCoolixFanMed:
+ result += F(" (MED)");
+ break;
+ case kCoolixFanZoneFollow:
+ result += F(" (ZONEFOLLOW)");
+ break;
+ case kCoolixFanFixed:
+ result += F(" (FIXED)");
+ break;
+ default:
+ result += F(" (UNKNOWN)");
+ }
+ if (getMode() != kCoolixFan) { // Fan mode doesn't have a temperature.
+ result += F(", Temp: ");
+ result += uint64ToString(getTemp());
+ result += 'C';
+ }
+ result += F(", Zone Follow: ");
if (getZoneFollow())
- result += "On";
+ result += F("On");
else
- result += "Off";
- result += ", Sensor Temp: ";
+ result += F("Off");
+ result += F(", Sensor Temp: ");
if (getSensorTemp() > kCoolixSensorTempMax)
- result += "Ignored";
+ result += F("Ignored");
else
- result += uint64ToString(getSensorTemp()) + "C";
+ result += uint64ToString(getSensorTemp()) + F("C");
return result;
}
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_Coolix.h b/lib/IRremoteESP8266-2.6.0/src/ir_Coolix.h
similarity index 82%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_Coolix.h
rename to lib/IRremoteESP8266-2.6.0/src/ir_Coolix.h
index ee4552074..d85db98d7 100644
--- a/lib/IRremoteESP8266-2.5.2.03/src/ir_Coolix.h
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_Coolix.h
@@ -14,6 +14,9 @@
#endif
#include "IRremoteESP8266.h"
#include "IRsend.h"
+#ifdef UNIT_TEST
+#include "IRsend_test.h"
+#endif
// CCCCC OOOOO OOOOO LL IIIII XX XX
// CC C OO OO OO OO LL III XX XX
@@ -30,11 +33,11 @@
// 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 uint8_t kCoolixCool = 0b000;
+const uint8_t kCoolixDry = 0b001;
+const uint8_t kCoolixAuto = 0b010;
+const uint8_t kCoolixHeat = 0b011;
+const uint8_t kCoolixFan = 0b100; // Synthetic.
const uint32_t kCoolixModeMask = 0b000000000000000000001100; // 0xC
const uint32_t kCoolixZoneFollowMask = 0b000010000000000000000000; // 0x80000
// Fan Control
@@ -42,6 +45,7 @@ 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
@@ -90,7 +94,7 @@ class IRCoolixAC {
void stateReset();
#if SEND_COOLIX
- void send();
+ void send(const uint16_t repeat = kCoolixDefaultRepeat);
#endif // SEND_COOLIX
void begin();
void on();
@@ -119,21 +123,30 @@ class IRCoolixAC {
bool getZoneFollow();
uint32_t getRaw();
void setRaw(const uint32_t new_code);
-
+ uint8_t convertMode(const stdAc::opmode_t mode);
+ uint8_t convertFan(const stdAc::fanspeed_t speed);
#ifdef ARDUINO
String toString();
#else
std::string toString();
#endif
+#ifndef UNIT_TEST
private:
- // The state of the IR remote in IR code form.
- uint32_t remote_state;
IRsend _irsend;
+#else
+ IRsendTest _irsend;
+#endif
+ uint32_t remote_state; // The state of the IR remote in IR code form.
+ uint32_t saved_state; // Copy of the state if we required a special mode.
void setTempRaw(const uint8_t code);
uint8_t getTempRaw();
void setSensorTempRaw(const uint8_t code);
void setZoneFollow(const bool state);
+ bool isSpecialState(void);
+ void updateSavedState(void);
+ void recoverSavedState(void);
+ uint32_t getNormalState(void);
};
#endif // IR_COOLIX_H_
diff --git a/lib/IRremoteESP8266-2.6.0/src/ir_Daikin.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_Daikin.cpp
new file mode 100644
index 000000000..358dbd603
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_Daikin.cpp
@@ -0,0 +1,1712 @@
+/*
+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"
+#include
+#ifndef ARDUINO
+#include
+#endif
+#include "IRrecv.h"
+#include "IRremoteESP8266.h"
+#include "IRsend.h"
+#ifdef UNIT_TEST
+#include "IRsend_test.h"
+#endif
+#include "IRutils.h"
+
+// DDDDD AAA IIIII KK KK IIIII NN NN
+// DD DD AAAAA III KK KK III NNN NN
+// DD DD AA AA III KKKK III NN N NN
+// DD DD AAAAAAA III KK KK III NN NNN
+// DDDDDD AA AA IIIII KK KK IIIII NN NN
+
+// Constants
+// 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
+// Send a Daikin A/C message.
+//
+// Args:
+// data: An array of kDaikinStateLength bytes containing the IR command.
+//
+// Status: STABLE
+//
+// Ref:
+// IRDaikinESP.cpp
+// https://github.com/mharizanov/Daikin-AC-remote-control-over-the-Internet/tree/master/IRremote
+// https://github.com/blafois/Daikin-IR-Reverse
+void IRsend::sendDaikin(const unsigned char data[], const uint16_t nbytes,
+ const uint16_t repeat) {
+ if (nbytes < kDaikinStateLengthShort)
+ return; // Not enough bytes to send a proper message.
+
+ for (uint16_t r = 0; r <= repeat; r++) {
+ uint16_t offset = 0;
+ // Send the header, 0b00000
+ sendGeneric(0, 0, // No header for the header
+ kDaikinBitMark, kDaikinOneSpace, kDaikinBitMark,
+ kDaikinZeroSpace, kDaikinBitMark, kDaikinZeroSpace + kDaikinGap,
+ (uint64_t)0b00000, kDaikinHeaderLength, 38, false, 0, 50);
+ // Data #1
+ if (nbytes < kDaikinStateLength) { // Are we using the legacy size?
+ // Do this as a constant to save RAM and keep in flash memory
+ sendGeneric(kDaikinHdrMark, kDaikinHdrSpace, kDaikinBitMark,
+ kDaikinOneSpace, kDaikinBitMark, kDaikinZeroSpace,
+ kDaikinBitMark, kDaikinZeroSpace + kDaikinGap,
+ kDaikinFirstHeader64, 64, 38, false, 0, 50);
+ } else { // We are using the newer/more correct size.
+ sendGeneric(kDaikinHdrMark, kDaikinHdrSpace, kDaikinBitMark,
+ kDaikinOneSpace, kDaikinBitMark, kDaikinZeroSpace,
+ kDaikinBitMark, kDaikinZeroSpace + kDaikinGap,
+ data, kDaikinSection1Length, 38, false, 0, 50);
+ offset += kDaikinSection1Length;
+ }
+ // Data #2
+ sendGeneric(kDaikinHdrMark, kDaikinHdrSpace, kDaikinBitMark,
+ kDaikinOneSpace, kDaikinBitMark, kDaikinZeroSpace,
+ kDaikinBitMark, kDaikinZeroSpace + kDaikinGap,
+ data + offset, kDaikinSection2Length, 38, false, 0, 50);
+ offset += kDaikinSection2Length;
+ // Data #3
+ sendGeneric(kDaikinHdrMark, kDaikinHdrSpace, kDaikinBitMark,
+ kDaikinOneSpace, kDaikinBitMark, kDaikinZeroSpace,
+ kDaikinBitMark, kDaikinZeroSpace + kDaikinGap,
+ data + offset, nbytes - offset, 38, false, 0, 50);
+ }
+}
+#endif // SEND_DAIKIN
+
+IRDaikinESP::IRDaikinESP(uint16_t pin) : _irsend(pin) { stateReset(); }
+
+void IRDaikinESP::begin(void) { _irsend.begin(); }
+
+#if SEND_DAIKIN
+void IRDaikinESP::send(const uint16_t repeat) {
+ this->checksum();
+ _irsend.sendDaikin(remote, kDaikinStateLength, repeat);
+}
+#endif // SEND_DAIKIN
+
+// Verify the checksums are valid for a given state.
+// Args:
+// state: The array to verify the checksums of.
+// length: The size of the state.
+// Returns:
+// A boolean.
+bool IRDaikinESP::validChecksum(uint8_t state[], const uint16_t length) {
+ // Data #1
+ if (length < kDaikinSection1Length ||
+ state[kDaikinByteChecksum1] != sumBytes(state, kDaikinSection1Length - 1))
+ return false;
+ // Data #2
+ if (length < kDaikinSection1Length + kDaikinSection2Length ||
+ state[kDaikinByteChecksum2] != sumBytes(state + kDaikinSection1Length,
+ kDaikinSection2Length - 1))
+ return false;
+ // Data #3
+ if (length < kDaikinSection1Length + kDaikinSection2Length + 2 ||
+ state[length - 1] != sumBytes(state + kDaikinSection1Length +
+ kDaikinSection2Length,
+ length - (kDaikinSection1Length +
+ kDaikinSection2Length) - 1))
+ return false;
+ return true;
+}
+
+// Calculate and set the checksum values for the internal state.
+void IRDaikinESP::checksum(void) {
+ remote[kDaikinByteChecksum1] = sumBytes(remote, kDaikinSection1Length - 1);
+ remote[kDaikinByteChecksum2] = sumBytes(remote + kDaikinSection1Length,
+ kDaikinSection2Length - 1);
+ remote[kDaikinByteChecksum3] = sumBytes(remote + kDaikinSection1Length +
+ kDaikinSection2Length,
+ kDaikinSection3Length - 1);
+}
+
+void IRDaikinESP::stateReset(void) {
+ for (uint8_t i = 0; i < kDaikinStateLength; i++) remote[i] = 0x0;
+
+ remote[0] = 0x11;
+ remote[1] = 0xDA;
+ remote[2] = 0x27;
+ remote[4] = 0xC5;
+ // remote[7] is a checksum byte, it will be set by checksum().
+
+ remote[8] = 0x11;
+ remote[9] = 0xDA;
+ remote[10] = 0x27;
+ remote[12] = 0x42;
+ // remote[15] is a checksum byte, it will be set by checksum().
+ remote[16] = 0x11;
+ remote[17] = 0xDA;
+ remote[18] = 0x27;
+ remote[21] = 0x49;
+ remote[22] = 0x1E;
+ remote[24] = 0xB0;
+ remote[27] = 0x06;
+ remote[28] = 0x60;
+ remote[31] = 0xC0;
+ // remote[34] is a checksum byte, it will be set by checksum().
+ this->checksum();
+}
+
+uint8_t *IRDaikinESP::getRaw(void) {
+ this->checksum(); // Ensure correct settings before sending.
+ return remote;
+}
+
+void IRDaikinESP::setRaw(const uint8_t new_code[], const uint16_t length) {
+ uint8_t offset = 0;
+ if (length == kDaikinStateLengthShort) { // Handle the "short" length case.
+ offset = kDaikinStateLength - kDaikinStateLengthShort;
+ this->stateReset();
+ }
+ for (uint8_t i = 0; i < length && i < kDaikinStateLength; i++)
+ remote[i + offset] = new_code[i];
+}
+
+void IRDaikinESP::on(void) { remote[kDaikinBytePower] |= kDaikinBitPower; }
+
+void IRDaikinESP::off(void) { remote[kDaikinBytePower] &= ~kDaikinBitPower; }
+
+void IRDaikinESP::setPower(const bool on) {
+ if (on)
+ this->on();
+ else
+ this->off();
+}
+
+bool IRDaikinESP::getPower(void) {
+ return remote[kDaikinBytePower] & kDaikinBitPower;
+}
+
+// Set the temp in deg C
+void IRDaikinESP::setTemp(const uint8_t temp) {
+ uint8_t degrees = std::max(temp, kDaikinMinTemp);
+ degrees = std::min(degrees, kDaikinMaxTemp);
+ remote[kDaikinByteTemp] = degrees << 1;
+}
+
+uint8_t IRDaikinESP::getTemp(void) { return remote[kDaikinByteTemp] >> 1; }
+
+// Set the speed of the fan, 1-5 or kDaikinFanAuto or kDaikinFanQuiet
+void IRDaikinESP::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[kDaikinByteFan] &= 0x0F;
+ remote[kDaikinByteFan] |= (fanset << 4);
+}
+
+uint8_t IRDaikinESP::getFan(void) {
+ uint8_t fan = remote[kDaikinByteFan] >> 4;
+ if (fan != kDaikinFanQuiet && fan != kDaikinFanAuto) fan -= 2;
+ return fan;
+}
+
+uint8_t IRDaikinESP::getMode(void) { return remote[kDaikinBytePower] >> 4; }
+
+void IRDaikinESP::setMode(const uint8_t mode) {
+ switch (mode) {
+ case kDaikinAuto:
+ case kDaikinCool:
+ case kDaikinHeat:
+ case kDaikinFan:
+ case kDaikinDry:
+ remote[kDaikinBytePower] &= 0b10001111;
+ remote[kDaikinBytePower] |= (mode << 4);
+ break;
+ default:
+ this->setMode(kDaikinAuto);
+ }
+}
+
+void IRDaikinESP::setSwingVertical(const bool on) {
+ if (on)
+ remote[kDaikinByteFan] |= 0x0F;
+ else
+ remote[kDaikinByteFan] &= 0xF0;
+}
+
+bool IRDaikinESP::getSwingVertical(void) {
+ return remote[kDaikinByteFan] & 0x0F;
+}
+
+void IRDaikinESP::setSwingHorizontal(const bool on) {
+ if (on)
+ remote[kDaikinByteSwingH] |= 0x0F;
+ else
+ remote[kDaikinByteSwingH] &= 0xF0;
+}
+
+bool IRDaikinESP::getSwingHorizontal(void) {
+ return remote[kDaikinByteSwingH] & 0x0F;
+}
+
+void IRDaikinESP::setQuiet(const bool on) {
+ if (on) {
+ remote[kDaikinByteSilent] |= kDaikinBitSilent;
+ // Powerful & Quiet mode being on are mutually exclusive.
+ this->setPowerful(false);
+ } else {
+ remote[kDaikinByteSilent] &= ~kDaikinBitSilent;
+ }
+}
+
+bool IRDaikinESP::getQuiet(void) {
+ return remote[kDaikinByteSilent] & kDaikinBitSilent;
+}
+
+void IRDaikinESP::setPowerful(const bool on) {
+ if (on) {
+ remote[kDaikinBytePowerful] |= kDaikinBitPowerful;
+ // Powerful, Quiet, & Econo mode being on are mutually exclusive.
+ this->setQuiet(false);
+ this->setEcono(false);
+ } else {
+ remote[kDaikinBytePowerful] &= ~kDaikinBitPowerful;
+ }
+}
+
+bool IRDaikinESP::getPowerful(void) {
+ return remote[kDaikinBytePowerful] & kDaikinBitPowerful;
+}
+
+void IRDaikinESP::setSensor(const bool on) {
+ if (on)
+ remote[kDaikinByteSensor] |= kDaikinBitSensor;
+ else
+ remote[kDaikinByteSensor] &= ~kDaikinBitSensor;
+}
+
+bool IRDaikinESP::getSensor(void) {
+ return remote[kDaikinByteSensor] & kDaikinBitSensor;
+}
+
+void IRDaikinESP::setEcono(const bool on) {
+ if (on) {
+ remote[kDaikinByteEcono] |= kDaikinBitEcono;
+ // Powerful & Econo mode being on are mutually exclusive.
+ this->setPowerful(false);
+ } else {
+ remote[kDaikinByteEcono] &= ~kDaikinBitEcono;
+ }
+}
+
+bool IRDaikinESP::getEcono(void) {
+ return remote[kDaikinByteEcono] & kDaikinBitEcono;
+}
+
+void IRDaikinESP::setEye(const bool on) {
+ if (on)
+ remote[kDaikinByteEye] |= kDaikinBitEye;
+ else
+ remote[kDaikinByteEye] &= ~kDaikinBitEye;
+}
+
+bool IRDaikinESP::getEye(void) {
+ return remote[kDaikinByteEye] & kDaikinBitEye;
+}
+
+void IRDaikinESP::setMold(const bool on) {
+ if (on)
+ remote[kDaikinByteMold] |= kDaikinBitMold;
+ else
+ remote[kDaikinByteMold] &= ~kDaikinBitMold;
+}
+
+bool IRDaikinESP::getMold(void) {
+ return remote[kDaikinByteMold] & kDaikinBitMold;
+}
+
+void IRDaikinESP::setComfort(const bool on) {
+ if (on)
+ remote[kDaikinByteComfort] |= kDaikinBitComfort;
+ else
+ remote[kDaikinByteComfort] &= ~kDaikinBitComfort;
+}
+
+bool IRDaikinESP::getComfort(void) {
+ return remote[kDaikinByteComfort] & kDaikinBitComfort;
+}
+
+// starttime: Number of minutes after midnight.
+void IRDaikinESP::enableOnTimer(const uint16_t starttime) {
+ remote[kDaikinByteOnTimer] |= kDaikinBitOnTimer;
+ remote[kDaikinByteOnTimerMinsLow] = starttime;
+ // only keep 4 bits
+ remote[kDaikinByteOnTimerMinsHigh] &= 0xF0;
+ remote[kDaikinByteOnTimerMinsHigh] |= ((starttime >> 8) & 0x0F);
+}
+
+void IRDaikinESP::disableOnTimer(void) {
+ this->enableOnTimer(kDaikinUnusedTime);
+ remote[kDaikinByteOnTimer] &= ~kDaikinBitOnTimer;
+}
+
+uint16_t IRDaikinESP::getOnTime(void) {
+ return ((remote[kDaikinByteOnTimerMinsHigh] & 0x0F) << 8) +
+ remote[kDaikinByteOnTimerMinsLow];
+}
+
+bool IRDaikinESP::getOnTimerEnabled(void) {
+ return remote[kDaikinByteOnTimer] & kDaikinBitOnTimer;
+}
+
+// endtime: Number of minutes after midnight.
+void IRDaikinESP::enableOffTimer(const uint16_t endtime) {
+ remote[kDaikinByteOffTimer] |= kDaikinBitOffTimer;
+ remote[kDaikinByteOffTimerMinsHigh] = endtime >> 4;
+ remote[kDaikinByteOffTimerMinsLow] &= 0x0F;
+ remote[kDaikinByteOffTimerMinsLow] |= ((endtime & 0x0F) << 4);
+}
+
+void IRDaikinESP::disableOffTimer(void) {
+ this->enableOffTimer(kDaikinUnusedTime);
+ remote[kDaikinByteOffTimer] &= ~kDaikinBitOffTimer;
+}
+
+uint16_t IRDaikinESP::getOffTime(void) {
+ return (remote[kDaikinByteOffTimerMinsHigh] << 4) +
+ ((remote[kDaikinByteOffTimerMinsLow] & 0xF0) >> 4);
+}
+
+bool IRDaikinESP::getOffTimerEnabled(void) {
+ return remote[kDaikinByteOffTimer] & kDaikinBitOffTimer;
+}
+
+void IRDaikinESP::setCurrentTime(const uint16_t mins_since_midnight) {
+ uint16_t mins = mins_since_midnight;
+ if (mins > 24 * 60) mins = 0; // If > 23:59, set to 00:00
+ remote[kDaikinByteClockMinsLow] = mins;
+ // only keep 4 bits
+ remote[kDaikinByteClockMinsHigh] &= 0xF0;
+ remote[kDaikinByteClockMinsHigh] |= ((mins >> 8) & 0x0F);
+}
+
+uint16_t IRDaikinESP::getCurrentTime(void) {
+ return ((remote[kDaikinByteClockMinsHigh] & 0x0F) << 8) +
+ remote[kDaikinByteClockMinsLow];
+}
+
+#ifdef ARDUINO
+String IRDaikinESP::renderTime(const uint16_t timemins) {
+ String ret;
+#else // ARDUINO
+std::string IRDaikinESP::renderTime(const uint16_t timemins) {
+ std::string ret;
+#endif // ARDUINO
+ ret = uint64ToString(timemins / 60) + ':';
+ uint8_t mins = timemins % 60;
+ if (mins < 10) ret += '0';
+ ret += uint64ToString(mins);
+ return ret;
+}
+
+// Convert the internal state into a human readable string.
+#ifdef ARDUINO
+String IRDaikinESP::toString(void) {
+ String result = "";
+#else // ARDUINO
+std::string IRDaikinESP::toString(void) {
+ std::string result = "";
+#endif // ARDUINO
+ result += F("Power: ");
+ result += this->getPower() ? F("On") : F("Off");
+ result += F(", Mode: ");
+ result += uint64ToString(this->getMode());
+ switch (this->getMode()) {
+ case kDaikinAuto:
+ result += F(" (AUTO)");
+ break;
+ case kDaikinCool:
+ result += F(" (COOL)");
+ break;
+ case kDaikinHeat:
+ result += F(" (HEAT)");
+ break;
+ case kDaikinDry:
+ result += F(" (DRY)");
+ break;
+ case kDaikinFan:
+ result += F(" (FAN)");
+ break;
+ default:
+ result += F(" (UNKNOWN)");
+ }
+ result += F(", Temp: ");
+ result += uint64ToString(this->getTemp());
+ result += F("C, Fan: ");
+ result += uint64ToString(this->getFan());
+ switch (this->getFan()) {
+ case kDaikinFanAuto:
+ result += F(" (AUTO)");
+ break;
+ case kDaikinFanQuiet:
+ result += F(" (QUIET)");
+ break;
+ case kDaikinFanMin:
+ result += F(" (MIN)");
+ break;
+ case kDaikinFanMax:
+ result += F(" (MAX)");
+ break;
+ }
+ result += F(", Powerful: ");
+ result += this->getPowerful() ? F("On") : F("Off");
+ result += F(", Quiet: ");
+ result += this->getQuiet() ? F("On") : F("Off");
+ result += F(", Sensor: ");
+ result += this->getSensor() ? F("On") : F("Off");
+ result += F(", Eye: ");
+ result += this->getEye() ? F("On") : F("Off");
+ result += F(", Mold: ");
+ result += this->getMold() ? F("On") : F("Off");
+ result += F(", Comfort: ");
+ result += this->getComfort() ? F("On") : F("Off");
+ result += F(", Swing (Horizontal): ");
+ result += this->getSwingHorizontal() ? F("On") : F("Off");
+ result += F(", Swing (Vertical): ");
+ result += this->getSwingVertical() ? F("On") : F("Off");
+ result += F(", Current Time: ");
+ result += this->renderTime(this->getCurrentTime());
+ result += F(", On Time: ");
+ if (this->getOnTimerEnabled())
+ result += this->renderTime(this->getOnTime());
+ else
+ result += F("Off");
+ result += F(", Off Time: ");
+ if (this->getOffTimerEnabled())
+ result += this->renderTime(this->getOffTime());
+ else
+ result += F("Off");
+ return result;
+}
+
+// Convert a standard A/C mode into its native mode.
+uint8_t IRDaikinESP::convertMode(const stdAc::opmode_t mode) {
+ switch (mode) {
+ case stdAc::opmode_t::kCool:
+ return kDaikinCool;
+ case stdAc::opmode_t::kHeat:
+ return kDaikinHeat;
+ case stdAc::opmode_t::kDry:
+ return kDaikinDry;
+ case stdAc::opmode_t::kFan:
+ return kDaikinFan;
+ default:
+ return kDaikinAuto;
+ }
+}
+
+// Convert a standard A/C Fan speed into its native fan speed.
+uint8_t IRDaikinESP::convertFan(const stdAc::fanspeed_t speed) {
+ switch (speed) {
+ case stdAc::fanspeed_t::kMin:
+ return kDaikinFanQuiet;
+ case stdAc::fanspeed_t::kLow:
+ return kDaikinFanMin;
+ case stdAc::fanspeed_t::kMedium:
+ return kDaikinFanMin + 1;
+ case stdAc::fanspeed_t::kHigh:
+ return kDaikinFanMax - 1;
+ case stdAc::fanspeed_t::kMax:
+ return kDaikinFanMax;
+ default:
+ return kDaikinFanAuto;
+ }
+}
+
+#if DECODE_DAIKIN
+// 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. (kDaikinBits)
+// strict: Flag to indicate if we strictly adhere to the specification.
+// Returns:
+// boolean: True if it can decode it, false if it can't.
+//
+// Status: BETA / Should be working.
+//
+// Ref:
+// https://github.com/mharizanov/Daikin-AC-remote-control-over-the-Internet/tree/master/IRremote
+bool IRrecv::decodeDaikin(decode_results *results, const uint16_t nbits,
+ const bool strict) {
+ // Is there enough data to match successfully?
+ if (results->rawlen < (2 * (nbits + kDaikinHeaderLength) +
+ kDaikinSections * (kHeader + kFooter) + kFooter - 1))
+ return false;
+
+ // Compliance
+ if (strict && nbits != kDaikinBits) return false;
+
+ uint16_t offset = kStartOffset;
+ match_result_t data_result;
+ uint16_t dataBitsSoFar = 0;
+ uint16_t i = 0;
+
+ // Header #1 - Doesn't count as data.
+ data_result = matchData(&(results->rawbuf[offset]), kDaikinHeaderLength,
+ kDaikinBitMark, kDaikinOneSpace,
+ kDaikinBitMark, kDaikinZeroSpace,
+ kDaikinTolerance, kDaikinMarkExcess, false);
+ offset += data_result.used;
+ if (data_result.success == false) return false; // Fail
+ if (data_result.data) return false; // The header bits should be zero.
+
+ // Read the Data sections.
+ // Keep reading bytes until we either run out of section or state to fill.
+ const uint8_t kSectionSize[kDaikinSections] = {
+ kDaikinSection1Length, kDaikinSection2Length, kDaikinSection3Length};
+ for (uint8_t section = 0, pos = 0; section < kDaikinSections;
+ section++) {
+ pos += kSectionSize[section];
+ // Section Footer
+ if (!matchMark(results->rawbuf[offset++], kDaikinBitMark,
+ kDaikinTolerance, kDaikinMarkExcess)) return false;
+ if (!matchSpace(results->rawbuf[offset++], kDaikinZeroSpace + kDaikinGap,
+ kDaikinTolerance, kDaikinMarkExcess)) return false;
+ // Section Header
+ if (!matchMark(results->rawbuf[offset++], kDaikinHdrMark,
+ kDaikinTolerance, kDaikinMarkExcess)) return false;
+ if (!matchSpace(results->rawbuf[offset++], kDaikinHdrSpace,
+ kDaikinTolerance, kDaikinMarkExcess)) 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,
+ kDaikinBitMark, kDaikinOneSpace,
+ kDaikinBitMark, kDaikinZeroSpace,
+ kDaikinTolerance, kDaikinMarkExcess, false);
+ if (data_result.success == false) break; // Fail
+ results->state[i] = (uint8_t)data_result.data;
+ }
+ }
+
+ // Footer
+ if (!matchMark(results->rawbuf[offset++], kDaikinBitMark)) return false;
+ if (offset < results->rawlen &&
+ !matchAtLeast(results->rawbuf[offset], kDaikinGap))
+ return false;
+
+ // Compliance
+ if (strict) {
+ // Re-check we got the correct size/length due to the way we read the data.
+ if (dataBitsSoFar != kDaikinBits) return false;
+ // Validate the checksum.
+ if (!IRDaikinESP::validChecksum(results->state)) return false;
+ }
+
+ // Success
+ results->decode_type = DAIKIN;
+ 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_DAIKIN
+
+#if SEND_DAIKIN2
+// Send a Daikin2 A/C message.
+//
+// Args:
+// data: An array of kDaikin2StateLength bytes containing the IR command.
+//
+// Status: BETA/Appears to work.
+//
+// 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, kDaikin2Freq, false, 0, 50);
+ // Section #1
+ sendGeneric(kDaikin2HdrMark, kDaikin2HdrSpace, kDaikin2BitMark,
+ kDaikin2OneSpace, kDaikin2BitMark, kDaikin2ZeroSpace,
+ kDaikin2BitMark, kDaikin2Gap, data, kDaikin2Section1Length,
+ kDaikin2Freq, false, 0, 50);
+ // Section #2
+ sendGeneric(kDaikin2HdrMark, kDaikin2HdrSpace, kDaikin2BitMark,
+ kDaikin2OneSpace, kDaikin2BitMark, kDaikin2ZeroSpace,
+ kDaikin2BitMark, kDaikin2Gap, data + kDaikin2Section1Length,
+ nbytes - kDaikin2Section1Length,
+ kDaikin2Freq, 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;
+ remote_state[6] &= ~kDaikin2BitPower;
+}
+
+void IRDaikin2::off() {
+ remote_state[25] &= ~kDaikinBitPower;
+ remote_state[6] |= kDaikin2BitPower;
+}
+
+void IRDaikin2::setPower(const bool state) {
+ if (state)
+ on();
+ else
+ off();
+}
+
+bool IRDaikin2::getPower() {
+ return (remote_state[25] & kDaikinBitPower) &&
+ !(remote_state[6] & kDaikin2BitPower);
+}
+
+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);
+ // Redo the temp setting as Cool mode has a different min temp.
+ if (mode == kDaikinCool) this->setTemp(this->getTemp());
+}
+
+// Set the temp in deg C
+void IRDaikin2::setTemp(const uint8_t desired) {
+ // The A/C has a different min temp if in cool mode.
+ uint8_t temp = std::max(
+ (this->getMode() == kDaikinCool) ? kDaikin2MinCoolTemp : 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 a standard A/C mode into its native mode.
+uint8_t IRDaikin2::convertMode(const stdAc::opmode_t mode) {
+ return IRDaikinESP::convertMode(mode);
+}
+
+// Convert a standard A/C Fan speed into its native fan speed.
+uint8_t IRDaikin2::convertFan(const stdAc::fanspeed_t speed) {
+ return IRDaikinESP::convertFan(speed);
+}
+
+// Convert a standard A/C vertical swing into its native version.
+uint8_t IRDaikin2::convertSwingV(const stdAc::swingv_t position) {
+ switch (position) {
+ case stdAc::swingv_t::kHighest:
+ case stdAc::swingv_t::kHigh:
+ case stdAc::swingv_t::kMiddle:
+ case stdAc::swingv_t::kLow:
+ case stdAc::swingv_t::kLowest:
+ return (uint8_t)position + kDaikin2SwingVHigh;
+ default:
+ return kDaikin2SwingVAuto;
+ }
+}
+
+// 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 += F("Power: ");
+ if (getPower())
+ result += F("On");
+ else
+ result += F("Off");
+ result += F(", Mode: ");
+ result += uint64ToString(getMode());
+ switch (getMode()) {
+ case kDaikinAuto:
+ result += F(" (AUTO)");
+ break;
+ case kDaikinCool:
+ result += F(" (COOL)");
+ break;
+ case kDaikinHeat:
+ result += F(" (HEAT)");
+ break;
+ case kDaikinDry:
+ result += F(" (DRY)");
+ break;
+ case kDaikinFan:
+ result += F(" (FAN)");
+ break;
+ default:
+ result += F(" (UNKNOWN)");
+ }
+ result += F(", Temp: ");
+ result += uint64ToString(getTemp());
+ result += F("C, Fan: ");
+ result += uint64ToString(getFan());
+ switch (getFan()) {
+ case kDaikinFanAuto:
+ result += F(" (Auto)");
+ break;
+ case kDaikinFanQuiet:
+ result += F(" (Quiet)");
+ break;
+ case kDaikinFanMin:
+ result += F(" (Min)");
+ break;
+ case kDaikinFanMax:
+ result += F(" (Max)");
+ break;
+ }
+ result += F(", Swing (V): ");
+ result += uint64ToString(getSwingVertical());
+ switch (getSwingVertical()) {
+ case kDaikin2SwingVHigh:
+ result += F(" (Highest)");
+ break;
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ break;
+ case kDaikin2SwingVLow:
+ result += F(" (Lowest)");
+ break;
+ case kDaikin2SwingVBreeze:
+ result += F(" (Breeze)");
+ break;
+ case kDaikin2SwingVCirculate:
+ result += F(" (Circulate)");
+ break;
+ case kDaikin2SwingVAuto:
+ result += F(" (Auto)");
+ break;
+ default:
+ result += F(" (Unknown)");
+ }
+ result += F(", Swing (H): ");
+ result += uint64ToString(getSwingHorizontal());
+ switch (getSwingHorizontal()) {
+ case kDaikin2SwingHAuto:
+ result += F(" (Auto)");
+ break;
+ case kDaikin2SwingHSwing:
+ result += F(" (Swing)");
+ break;
+ }
+ result += F(", Clock: ");
+ result += IRDaikinESP::renderTime(getCurrentTime());
+ result += F(", On Time: ");
+ if (getOnTimerEnabled())
+ result += IRDaikinESP::renderTime(getOnTime());
+ else
+ result += F("Off");
+ result += F(", Off Time: ");
+ if (getOffTimerEnabled())
+ result += IRDaikinESP::renderTime(getOffTime());
+ else
+ result += F("Off");
+ result += F(", Sleep Time: ");
+ if (getSleepTimerEnabled())
+ result += IRDaikinESP::renderTime(getSleepTime());
+ else
+ result += F("Off");
+ result += F(", Beep: ");
+ result += uint64ToString(getBeep());
+ switch (getBeep()) {
+ case kDaikinBeepLoud:
+ result += F(" (Loud)");
+ break;
+ case kDaikinBeepQuiet:
+ result += F(" (Quiet)");
+ break;
+ case kDaikinBeepOff:
+ result += F(" (Off)");
+ break;
+ default:
+ result += F(" (UNKNOWN)");
+ }
+ result += F(", Light: ");
+ result += uint64ToString(getLight());
+ switch (getLight()) {
+ case kDaikinLightBright:
+ result += F(" (Bright)");
+ break;
+ case kDaikinLightDim:
+ result += F(" (Dim)");
+ break;
+ case kDaikinLightOff:
+ result += F(" (Off)");
+ break;
+ default:
+ result += F(" (UNKNOWN)");
+ }
+ result += F(", Mold: ");
+ result += (getMold() ? F("On") : F("Off"));
+ result += F(", Clean: ");
+ result += (getClean() ? F("On") : F("Off"));
+ result += F(", Fresh Air: ");
+ if (getFreshAir())
+ result += (getFreshAirHigh() ? "High" : "On");
+ else
+ result += F("Off");
+ result += F(", Eye: ");
+ result += (getEye() ? F("On") : F("Off"));
+ result += F(", Eye Auto: ");
+ result += (getEyeAuto() ? F("On") : F("Off"));
+ result += F(", Quiet: ");
+ result += (getQuiet() ? F("On") : F("Off"));
+ result += F(", Powerful: ");
+ result += (getPowerful() ? F("On") : F("Off"));
+ result += ", Purify: ";
+ result += (getPurify() ? F("On") : F("Off"));
+ result += F(", Econo: ");
+ result += (getEcono() ? F("On") : F("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,
+ kDaikin2Tolerance)) return false;
+ if (!matchSpace(results->rawbuf[offset++], kDaikin2LeaderSpace,
+ kDaikin2Tolerance)) 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,
+ kDaikin2Tolerance)) return false;
+ if (!matchSpace(results->rawbuf[offset++], kDaikin2HdrSpace,
+ kDaikin2Tolerance)) 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, kDaikin2Tolerance, 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,
+ kDaikin2Tolerance)) return false;
+ if (section < kDaikin2Sections - 1) { // Inter-section gaps.
+ if (!matchSpace(results->rawbuf[offset++], kDaikin2Gap,
+ kDaikin2Tolerance)) return false;
+ } else { // Last section / End of message gap.
+ if (offset <= results->rawlen &&
+ !matchAtLeast(results->rawbuf[offset++], kDaikin2Gap,
+ kDaikin2Tolerance)) 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
+
+#if SEND_DAIKIN216
+// Send a Daikin 216 bit A/C message.
+//
+// Args:
+// data: An array of kDaikin216StateLength bytes containing the IR command.
+//
+// Status: Alpha/Untested on a real device.
+//
+// Supported devices:
+// - Daikin ARC433B69 remote.
+//
+// Ref:
+// https://github.com/markszabo/IRremoteESP8266/issues/689
+// https://github.com/danny-source/Arduino_DY_IRDaikin
+void IRsend::sendDaikin216(const unsigned char data[], const uint16_t nbytes,
+ const uint16_t repeat) {
+ if (nbytes < kDaikin216Section1Length)
+ return; // Not enough bytes to send a partial message.
+
+ for (uint16_t r = 0; r <= repeat; r++) {
+ // Section #1
+ sendGeneric(kDaikin216HdrMark, kDaikin216HdrSpace, kDaikin216BitMark,
+ kDaikin216OneSpace, kDaikin216BitMark, kDaikin216ZeroSpace,
+ kDaikin216BitMark, kDaikin216Gap, data,
+ kDaikin216Section1Length,
+ kDaikin216Freq, false, 0, kDutyDefault);
+ // Section #2
+ sendGeneric(kDaikin216HdrMark, kDaikin216HdrSpace, kDaikin216BitMark,
+ kDaikin216OneSpace, kDaikin216BitMark, kDaikin216ZeroSpace,
+ kDaikin216BitMark, kDaikin216Gap,
+ data + kDaikin216Section1Length,
+ nbytes - kDaikin216Section1Length,
+ kDaikin216Freq, false, 0, kDutyDefault);
+ }
+}
+#endif // SEND_DAIKIN216
+
+// Class for handling Daikin 216 bit / 27 byte A/C messages.
+//
+// Code by crankyoldgit.
+//
+// Supported Remotes: Daikin ARC433B69 remote
+//
+// Ref:
+// https://github.com/markszabo/IRremoteESP8266/issues/689
+// https://github.com/danny-source/Arduino_DY_IRDaikin
+IRDaikin216::IRDaikin216(uint16_t pin) : _irsend(pin) { stateReset(); }
+
+void IRDaikin216::begin() { _irsend.begin(); }
+
+#if SEND_DAIKIN216
+void IRDaikin216::send(const uint16_t repeat) {
+ checksum();
+ _irsend.sendDaikin216(remote_state, kDaikin216StateLength, repeat);
+}
+#endif // SEND_DAIKIN216
+
+// 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 IRDaikin216::validChecksum(uint8_t state[], const uint16_t length) {
+ // Validate the checksum of section #1.
+ if (length <= kDaikin216Section1Length - 1 ||
+ state[kDaikin216Section1Length - 1] != sumBytes(
+ state, kDaikin216Section1Length - 1))
+ return false;
+ // Validate the checksum of section #2 (a.k.a. the rest)
+ if (length <= kDaikin216Section1Length + 1 ||
+ state[length - 1] != sumBytes(state + kDaikin216Section1Length,
+ length - kDaikin216Section1Length - 1))
+ return false;
+ return true;
+}
+
+// Calculate and set the checksum values for the internal state.
+void IRDaikin216::checksum() {
+ remote_state[kDaikin216Section1Length - 1] = sumBytes(
+ remote_state, kDaikin216Section1Length - 1);
+ remote_state[kDaikin216StateLength - 1] = sumBytes(
+ remote_state + kDaikin216Section1Length, kDaikin216Section2Length - 1);
+}
+
+void IRDaikin216::stateReset() {
+ for (uint8_t i = 0; i < kDaikin216StateLength; i++) remote_state[i] = 0x00;
+ remote_state[0] = 0x11;
+ remote_state[1] = 0xDA;
+ remote_state[2] = 0x27;
+ remote_state[3] = 0xF0;
+ // remote_state[7] is a checksum byte, it will be set by checksum().
+ remote_state[8] = 0x11;
+ remote_state[9] = 0xDA;
+ remote_state[10] = 0x27;
+ remote_state[23] = 0xC0;
+ // remote_state[26] is a checksum byte, it will be set by checksum().
+}
+
+uint8_t *IRDaikin216::getRaw() {
+ checksum(); // Ensure correct settings before sending.
+ return remote_state;
+}
+
+void IRDaikin216::setRaw(const uint8_t new_code[]) {
+ for (uint8_t i = 0; i < kDaikin216StateLength; i++)
+ remote_state[i] = new_code[i];
+}
+
+
+void IRDaikin216::on() {
+ remote_state[kDaikin216BytePower] |= kDaikinBitPower;
+}
+
+void IRDaikin216::off() {
+ remote_state[kDaikin216BytePower] &= ~kDaikinBitPower;
+}
+
+void IRDaikin216::setPower(const bool state) {
+ if (state)
+ on();
+ else
+ off();
+}
+
+bool IRDaikin216::getPower() {
+ return remote_state[kDaikin216BytePower] & kDaikinBitPower;
+}
+
+uint8_t IRDaikin216::getMode() {
+ return (remote_state[kDaikin216ByteMode] & kDaikin216MaskMode) >> 4;
+}
+
+void IRDaikin216::setMode(const uint8_t mode) {
+ switch (mode) {
+ case kDaikinAuto:
+ case kDaikinCool:
+ case kDaikinHeat:
+ case kDaikinFan:
+ case kDaikinDry:
+ remote_state[kDaikin216ByteMode] &= ~kDaikin216MaskMode;
+ remote_state[kDaikin216ByteMode] |= (mode << 4);
+ break;
+ default:
+ this->setMode(kDaikinAuto);
+ }
+}
+
+// Convert a standard A/C mode into its native mode.
+uint8_t IRDaikin216::convertMode(const stdAc::opmode_t mode) {
+ return IRDaikinESP::convertMode(mode);
+}
+
+// Set the temp in deg C
+void IRDaikin216::setTemp(const uint8_t temp) {
+ uint8_t degrees = std::max(temp, kDaikinMinTemp);
+ degrees = std::min(degrees, kDaikinMaxTemp);
+ remote_state[kDaikin216ByteTemp] &= ~kDaikin216MaskTemp;
+ remote_state[kDaikin216ByteTemp] |= (degrees << 1);
+}
+
+uint8_t IRDaikin216::getTemp(void) {
+ return (remote_state[kDaikin216ByteTemp] & kDaikin216MaskTemp) >> 1;
+}
+
+// Set the speed of the fan, 1-5 or kDaikinFanAuto or kDaikinFanQuiet
+void IRDaikin216::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[kDaikin216ByteFan] &= ~kDaikin216MaskFan;
+ remote_state[kDaikin216ByteFan] |= (fanset << 4);
+}
+
+uint8_t IRDaikin216::getFan() {
+ uint8_t fan = remote_state[kDaikin216ByteFan] >> 4;
+ if (fan != kDaikinFanQuiet && fan != kDaikinFanAuto) fan -= 2;
+ return fan;
+}
+
+// Convert a standard A/C Fan speed into its native fan speed.
+uint8_t IRDaikin216::convertFan(const stdAc::fanspeed_t speed) {
+ return IRDaikinESP::convertFan(speed);
+}
+
+void IRDaikin216::setSwingVertical(const bool on) {
+ if (on)
+ remote_state[kDaikin216ByteSwingV] |= kDaikin216MaskSwingV;
+ else
+ remote_state[kDaikin216ByteSwingV] &= ~kDaikin216MaskSwingV;
+}
+
+bool IRDaikin216::getSwingVertical(void) {
+ return remote_state[kDaikin216ByteSwingV] & kDaikin216MaskSwingV;
+}
+
+void IRDaikin216::setSwingHorizontal(const bool on) {
+ if (on)
+ remote_state[kDaikin216ByteSwingH] |= kDaikin216MaskSwingH;
+ else
+ remote_state[kDaikin216ByteSwingH] &= ~kDaikin216MaskSwingH;
+}
+
+bool IRDaikin216::getSwingHorizontal(void) {
+ return remote_state[kDaikin216ByteSwingH] & kDaikin216MaskSwingH;
+}
+
+// This is a horrible hack till someone works out the quiet mode bit.
+void IRDaikin216::setQuiet(const bool on) {
+ if (on)
+ this->setFan(kDaikinFanQuiet);
+ else if (this->getFan() == kDaikinFanQuiet)
+ this->setFan(kDaikinFanAuto);
+}
+
+// This is a horrible hack till someone works out the quiet mode bit.
+bool IRDaikin216::getQuiet(void) {
+ return this->getFan() == kDaikinFanQuiet;
+}
+
+// Convert the internal state into a human readable string.
+#ifdef ARDUINO
+String IRDaikin216::toString() {
+ String result = "";
+#else // ARDUINO
+std::string IRDaikin216::toString() {
+ std::string result = "";
+#endif // ARDUINO
+ result += F("Power: ");
+ if (this->getPower())
+ result += F("On");
+ else
+ result += F("Off");
+ result += F(", Mode: ");
+ result += uint64ToString(this->getMode());
+ switch (getMode()) {
+ case kDaikinAuto:
+ result += F(" (AUTO)");
+ break;
+ case kDaikinCool:
+ result += F(" (COOL)");
+ break;
+ case kDaikinHeat:
+ result += F(" (HEAT)");
+ break;
+ case kDaikinDry:
+ result += F(" (DRY)");
+ break;
+ case kDaikinFan:
+ result += F(" (FAN)");
+ break;
+ default:
+ result += F(" (UNKNOWN)");
+ }
+ result += F(", Temp: ");
+ result += uint64ToString(this->getTemp());
+ result += F("C, Fan: ");
+ result += uint64ToString(this->getFan());
+ switch (this->getFan()) {
+ case kDaikinFanAuto:
+ result += F(" (AUTO)");
+ break;
+ case kDaikinFanQuiet:
+ result += F(" (QUIET)");
+ break;
+ case kDaikinFanMin:
+ result += F(" (MIN)");
+ break;
+ case kDaikinFanMax:
+ result += F(" (MAX)");
+ break;
+ }
+ result += F(", Swing (Horizontal): ");
+ result += this->getSwingHorizontal() ? F("On") : F("Off");
+ result += F(", Swing (Vertical): ");
+ result += this->getSwingVertical() ? F("On") : F("Off");
+ result += F(", Quiet: ");
+ result += (getQuiet() ? F("On") : F("Off"));
+ return result;
+}
+
+#if DECODE_DAIKIN216
+// Decode the supplied Daikin 216 bit 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. (kDaikin216Bits)
+// 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 ARC433B69 remote.
+//
+// Status: BETA / Should be working.
+//
+// Ref:
+// https://github.com/markszabo/IRremoteESP8266/issues/689
+// https://github.com/danny-source/Arduino_DY_IRDaikin
+bool IRrecv::decodeDaikin216(decode_results *results, const uint16_t nbits,
+ const bool strict) {
+ if (results->rawlen < 2 * (nbits + kHeader + kFooter) - 1)
+ return false;
+
+ // Compliance
+ if (strict && nbits != kDaikin216Bits) return false;
+
+ uint16_t offset = kStartOffset;
+ uint16_t dataBitsSoFar = 0;
+ uint16_t i = 0;
+ match_result_t data_result;
+ uint8_t sectionSize[kDaikin216Sections] = {kDaikin216Section1Length,
+ kDaikin216Section2Length};
+
+ // Sections
+ // Keep reading bytes until we either run out of section or state to fill.
+ for (uint8_t section = 0, pos = 0; section < kDaikin216Sections;
+ section++) {
+ pos += sectionSize[section];
+
+ // Section Header
+ if (!matchMark(results->rawbuf[offset++], kDaikin216HdrMark)) 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, kDaikin216BitMark,
+ kDaikin216OneSpace, kDaikin216BitMark,
+ kDaikin216ZeroSpace, 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++], kDaikin216BitMark)) return false;
+ if (section < kDaikin216Sections - 1) { // Inter-section gaps.
+ if (!matchSpace(results->rawbuf[offset++], kDaikin216Gap)) return false;
+ } else { // Last section / End of message gap.
+ if (offset <= results->rawlen &&
+ !matchAtLeast(results->rawbuf[offset++], kDaikin216Gap)) return false;
+ }
+ }
+
+ // Compliance
+ if (strict) {
+ // Re-check we got the correct size/length due to the way we read the data.
+ if (dataBitsSoFar != kDaikin216Bits) return false;
+ // Validate the checksum.
+ if (!IRDaikin216::validChecksum(results->state)) return false;
+ }
+
+ // Success
+ results->decode_type = decode_type_t::DAIKIN216;
+ 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_DAIKIN216
diff --git a/lib/IRremoteESP8266-2.6.0/src/ir_Daikin.h b/lib/IRremoteESP8266-2.6.0/src/ir_Daikin.h
new file mode 100644
index 000000000..038e8edd9
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_Daikin.h
@@ -0,0 +1,444 @@
+// Copyright 2016 sillyfrog
+// Copyright 2017 sillyfrog, crankyoldgit
+// Copyright 2018-2019 crankyoldgit
+#ifndef IR_DAIKIN_H_
+#define IR_DAIKIN_H_
+
+#ifndef UNIT_TEST
+#include
+#else
+#include
+#endif
+#include "IRrecv.h"
+#include "IRremoteESP8266.h"
+#include "IRsend.h"
+#ifdef UNIT_TEST
+#include "IRsend_test.h"
+#endif
+
+// DDDDD AAA IIIII KK KK IIIII NN NN
+// DD DD AAAAA III KK KK III NNN NN
+// DD DD AA AA III KKKK III NN N NN
+// DD DD AAAAAAA III KK KK III NN NNN
+// DDDDDD AA AA IIIII KK KK IIIII NN NN
+
+/*
+ Daikin AC map
+ byte 6=
+ b4:Comfort
+ byte 7= checksum of the first part (and last byte before a 29ms pause)
+ byte 13=Current time, mins past midnight, low bits
+ byte 14
+ b0-b3=Current time, mins past midnight, high bits
+ byte 15= checksum of the second part (and last byte before a 29ms pause)
+ byte 21=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 22=temp*2 (Temp should be between 10 - 32)
+ byte 24=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 25
+ Swing control left/right:
+ 0000 = Swing left/right off
+ 1111 = Swing left/right on
+ byte 26=On timer mins past midnight, low bits
+ byte 27
+ b0-b3=On timer mins past midnight, high bits
+ b4-b7=Off timer mins past midnight, low bits
+ byte 28=Off timer mins past midnight, high bits
+ byte 29=Aux -> Powerful (bit 1), Silent (bit 5)
+ byte 32=Aux2
+ b1: Sensor
+ b2: Econo mode
+ b7: Intelligent eye on
+ byte 33=Aux3
+ b1: Mold Proof
+ byte 34= checksum of the third part
+*/
+
+// Constants
+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 uint16_t kDaikinHeaderLength = 5;
+const uint8_t kDaikinSections = 3;
+const uint8_t kDaikinSection1Length = 8;
+const uint8_t kDaikinSection2Length = 8;
+const uint8_t kDaikinSection3Length =
+ kDaikinStateLength - kDaikinSection1Length - kDaikinSection2Length;
+const uint8_t kDaikinByteComfort = 6;
+const uint8_t kDaikinByteChecksum1 = 7;
+const uint8_t kDaikinBitComfort = 0b00010000;
+const uint8_t kDaikinByteClockMinsLow = 13;
+const uint8_t kDaikinByteClockMinsHigh = 14;
+const uint8_t kDaikinByteChecksum2 = 15;
+const uint8_t kDaikinBytePower = 21;
+const uint8_t kDaikinBitPower = 0b00000001;
+const uint8_t kDaikinByteTemp = 22;
+const uint8_t kDaikinByteFan = 24;
+const uint8_t kDaikinByteSwingH = 25;
+const uint8_t kDaikinByteOnTimerMinsLow = 26;
+const uint8_t kDaikinByteOnTimerMinsHigh = 27;
+const uint8_t kDaikinByteOffTimerMinsLow = kDaikinByteOnTimerMinsHigh;
+const uint8_t kDaikinByteOffTimerMinsHigh = 28;
+const uint8_t kDaikinBytePowerful = 29;
+const uint8_t kDaikinBitPowerful = 0b00000001;
+const uint8_t kDaikinByteSilent = kDaikinBytePowerful;
+const uint8_t kDaikinBitSilent = 0b00100000;
+const uint8_t kDaikinByteSensor = 32;
+const uint8_t kDaikinBitSensor = 0b00000010;
+const uint8_t kDaikinByteEcono = kDaikinByteSensor;
+const uint8_t kDaikinBitEcono = 0b00000100;
+const uint8_t kDaikinByteEye = kDaikinByteSensor;
+const uint8_t kDaikinBitEye = 0b10000000;
+const uint8_t kDaikinByteMold = 33;
+const uint8_t kDaikinBitMold = 0b00000010;
+const uint8_t kDaikinByteOffTimer = kDaikinBytePower;
+const uint8_t kDaikinBitOffTimer = 0b00000100;
+const uint8_t kDaikinByteOnTimer = kDaikinByteOffTimer;
+const uint8_t kDaikinBitOnTimer = 0b00000010;
+const uint8_t kDaikinByteChecksum3 = kDaikinStateLength - 1;
+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
+const uint64_t kDaikinFirstHeader64 =
+ 0b1101011100000000000000001100010100000000001001111101101000010001;
+
+// Another variant of the protocol for the Daikin ARC477A1 remote.
+const uint16_t kDaikin2Freq = 36700; // Modulation Frequency in Hz.
+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 = 460;
+const uint16_t kDaikin2OneSpace = 1270;
+const uint16_t kDaikin2ZeroSpace = 420;
+const uint16_t kDaikin2Sections = 2;
+const uint16_t kDaikin2Section1Length = 20;
+const uint16_t kDaikin2Section2Length = 19;
+const uint8_t kDaikin2Tolerance = kTolerance + 5;
+
+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 kDaikin2BitPower = 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;
+const uint8_t kDaikin2MinCoolTemp = 18; // Min temp (in C) when in Cool mode.
+
+// Another variant of the protocol for the Daikin ARC433B69 remote.
+const uint16_t kDaikin216Freq = 38000; // Modulation Frequency in Hz.
+const uint16_t kDaikin216HdrMark = 3400;
+const uint16_t kDaikin216HdrSpace = 1800;
+const uint16_t kDaikin216BitMark = 380;
+const uint16_t kDaikin216OneSpace = 1350;
+const uint16_t kDaikin216ZeroSpace = 480;
+const uint16_t kDaikin216Gap = 29650;
+const uint16_t kDaikin216Sections = 2;
+const uint16_t kDaikin216Section1Length = 8;
+const uint16_t kDaikin216Section2Length = kDaikin216StateLength -
+ kDaikin216Section1Length;
+const uint8_t kDaikin216BytePower = 13;
+const uint8_t kDaikin216ByteMode = kDaikin216BytePower;
+const uint8_t kDaikin216MaskMode = 0b01110000;
+const uint8_t kDaikin216ByteTemp = 14;
+const uint8_t kDaikin216MaskTemp = 0b01111110;
+const uint8_t kDaikin216ByteFan = 16;
+const uint8_t kDaikin216MaskFan = 0b11110000;
+const uint8_t kDaikin216ByteSwingV = 16;
+const uint8_t kDaikin216MaskSwingV = 0b00001111;
+const uint8_t kDaikin216ByteSwingH = 17;
+const uint8_t kDaikin216MaskSwingH = kDaikin216MaskSwingV;
+
+
+// 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(const uint16_t repeat = kDaikinDefaultRepeat);
+#endif
+ void begin(void);
+ void on(void);
+ void off(void);
+ void setPower(const bool on);
+ bool getPower(void);
+ void setTemp(const uint8_t temp);
+ uint8_t getTemp();
+ void setFan(const uint8_t fan);
+ uint8_t getFan(void);
+ void setMode(const uint8_t mode);
+ uint8_t getMode(void);
+ void setSwingVertical(const bool on);
+ bool getSwingVertical(void);
+ void setSwingHorizontal(const bool on);
+ bool getSwingHorizontal(void);
+ bool getQuiet(void);
+ void setQuiet(const bool on);
+ bool getPowerful(void);
+ void setPowerful(const bool on);
+ void setSensor(const bool on);
+ bool getSensor(void);
+ void setEcono(const bool on);
+ bool getEcono(void);
+ void setEye(const bool on);
+ bool getEye(void);
+ void setMold(const bool on);
+ bool getMold(void);
+ void setComfort(const bool on);
+ bool getComfort(void);
+ void enableOnTimer(const uint16_t starttime);
+ void disableOnTimer(void);
+ uint16_t getOnTime(void);
+ bool getOnTimerEnabled();
+ void enableOffTimer(const uint16_t endtime);
+ void disableOffTimer(void);
+ uint16_t getOffTime(void);
+ bool getOffTimerEnabled(void);
+ void setCurrentTime(const uint16_t mins_since_midnight);
+ uint16_t getCurrentTime(void);
+ uint8_t* getRaw(void);
+ void setRaw(const uint8_t new_code[],
+ const uint16_t length = kDaikinStateLength);
+ static bool validChecksum(uint8_t state[],
+ const uint16_t length = kDaikinStateLength);
+ static uint8_t convertMode(const stdAc::opmode_t mode);
+ static uint8_t convertFan(const stdAc::fanspeed_t speed);
+#ifdef ARDUINO
+ String toString(void);
+ static String renderTime(const uint16_t timemins);
+#else
+ std::string toString(void);
+ static std::string renderTime(const uint16_t timemins);
+#endif
+#ifndef UNIT_TEST
+
+ private:
+ IRsend _irsend;
+#else
+ IRsendTest _irsend;
+#endif
+ // # of bytes per command
+ uint8_t remote[kDaikinStateLength];
+ void stateReset(void);
+ void checksum(void);
+};
+
+// 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);
+ static uint8_t convertMode(const stdAc::opmode_t mode);
+ static uint8_t convertFan(const stdAc::fanspeed_t speed);
+ uint8_t convertSwingV(const stdAc::swingv_t position);
+#ifdef ARDUINO
+ String toString();
+ static String renderTime(uint16_t timemins);
+#else
+ std::string toString();
+ static std::string renderTime(uint16_t timemins);
+#endif
+#ifndef UNIT_TEST
+
+ private:
+ IRsend _irsend;
+#else
+ IRsendTest _irsend;
+#endif
+ // # of bytes per command
+ uint8_t remote_state[kDaikin2StateLength];
+ void stateReset();
+ void checksum();
+ void clearOnTimerFlag();
+ void clearSleepTimerFlag();
+};
+
+// Class to emulate a Daikin ARC433B69 remote.
+class IRDaikin216 {
+ public:
+ explicit IRDaikin216(uint16_t pin);
+
+#if SEND_DAIKIN216
+ void send(const uint16_t repeat = kDaikin216DefaultRepeat);
+#endif
+ void begin();
+ uint8_t* getRaw();
+ void setRaw(const uint8_t new_code[]);
+ static bool validChecksum(uint8_t state[],
+ const uint16_t length = kDaikin216StateLength);
+ void on(void);
+ void off(void);
+ void setPower(const bool on);
+ bool getPower(void);
+ void setTemp(const uint8_t temp);
+ uint8_t getTemp();
+ void setMode(const uint8_t mode);
+ uint8_t getMode(void);
+ static uint8_t convertMode(const stdAc::opmode_t mode);
+ void setFan(const uint8_t fan);
+ uint8_t getFan(void);
+ static uint8_t convertFan(const stdAc::fanspeed_t speed);
+ void setSwingVertical(const bool on);
+ bool getSwingVertical(void);
+ void setSwingHorizontal(const bool on);
+ bool getSwingHorizontal(void);
+ void setQuiet(const bool on);
+ bool getQuiet(void);
+#ifdef ARDUINO
+ String toString(void);
+ static String renderTime(const uint16_t timemins);
+#else
+ std::string toString(void);
+ static std::string renderTime(const uint16_t timemins);
+#endif
+#ifndef UNIT_TEST
+
+ private:
+ IRsend _irsend;
+#else
+ IRsendTest _irsend;
+#endif
+ // # of bytes per command
+ uint8_t remote_state[kDaikin216StateLength];
+ void stateReset();
+ void checksum();
+};
+
+#endif // IR_DAIKIN_H_
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_Denon.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_Denon.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_Denon.cpp
rename to lib/IRremoteESP8266-2.6.0/src/ir_Denon.cpp
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_Dish.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_Dish.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_Dish.cpp
rename to lib/IRremoteESP8266-2.6.0/src/ir_Dish.cpp
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_Electra.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_Electra.cpp
similarity index 87%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_Electra.cpp
rename to lib/IRremoteESP8266-2.6.0/src/ir_Electra.cpp
index df69be748..0700ab698 100644
--- a/lib/IRremoteESP8266-2.5.2.03/src/ir_Electra.cpp
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_Electra.cpp
@@ -1,4 +1,4 @@
-// Copyright 2018 David Conran
+// Copyright 2018, 2019 David Conran
#include "IRrecv.h"
#include "IRsend.h"
@@ -17,6 +17,7 @@
// Ref:
// https://github.com/markszabo/IRremoteESP8266/issues/527
+// https://github.com/markszabo/IRremoteESP8266/issues/642
// Constants
const uint16_t kElectraAcHdrMark = 9166;
@@ -24,7 +25,7 @@ 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.
+const uint32_t kElectraAcMessageGap = kDefaultMessageGap; // Just a guess.
#if SEND_ELECTRA_AC
// Send a Electra message
@@ -42,7 +43,8 @@ void IRsend::sendElectraAC(uint8_t data[], uint16_t nbytes, uint16_t repeat) {
kElectraAcOneSpace, kElectraAcBitMark, kElectraAcZeroSpace,
kElectraAcBitMark, kElectraAcMessageGap, data, nbytes,
38000, // Complete guess of the modulation frequency.
- true, 0, 50);
+ false, // Send data in LSB order per byte
+ 0, 50);
}
#endif
@@ -56,7 +58,7 @@ void IRsend::sendElectraAC(uint8_t data[], uint16_t nbytes, uint16_t repeat) {
// Returns:
// boolean: True if it can decode it, false if it can't.
//
-// Status: Alpha / Needs testing against a real device.
+// Status: Beta / Probably works.
//
bool IRrecv::decodeElectraAC(decode_results *results, uint16_t nbits,
bool strict) {
@@ -68,8 +70,6 @@ bool IRrecv::decodeElectraAC(decode_results *results, uint16_t nbits,
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.
@@ -87,7 +87,7 @@ bool IRrecv::decodeElectraAC(decode_results *results, uint16_t nbits,
i++, dataBitsSoFar += 8, offset += data_result.used) {
data_result = matchData(&(results->rawbuf[offset]), 8, kElectraAcBitMark,
kElectraAcOneSpace, kElectraAcBitMark,
- kElectraAcZeroSpace, kTolerance, 0, true);
+ kElectraAcZeroSpace, kTolerance, 0, false);
if (data_result.success == false) return false; // Fail
results->state[i] = data_result.data;
}
@@ -99,7 +99,12 @@ bool IRrecv::decodeElectraAC(decode_results *results, uint16_t nbits,
return false;
// Compliance
- if (strict && dataBitsSoFar != nbits) return false;
+ if (strict) {
+ if (dataBitsSoFar != nbits) return false;
+ // Verify the checksum.
+ if (sumBytes(results->state, (dataBitsSoFar / 8) - 1) !=
+ results->state[(dataBitsSoFar / 8) - 1]) return false;
+ }
// Success
results->decode_type = ELECTRA_AC;
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_Fujitsu.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_Fujitsu.cpp
similarity index 88%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_Fujitsu.cpp
rename to lib/IRremoteESP8266-2.6.0/src/ir_Fujitsu.cpp
index 7c1b99834..de1b97e87 100644
--- a/lib/IRremoteESP8266-2.5.2.03/src/ir_Fujitsu.cpp
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_Fujitsu.cpp
@@ -84,9 +84,9 @@ 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
@@ -281,6 +281,7 @@ void IRFujitsuAC::setMode(uint8_t 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) {
@@ -319,6 +320,39 @@ bool IRFujitsuAC::validChecksum(uint8_t state[], uint16_t length) {
return checksum == (uint8_t)(sum_complement - sum); // Does it match?
}
+// Convert a standard A/C mode into its native mode.
+uint8_t IRFujitsuAC::convertMode(const stdAc::opmode_t mode) {
+ switch (mode) {
+ case stdAc::opmode_t::kCool:
+ return kFujitsuAcModeCool;
+ case stdAc::opmode_t::kHeat:
+ return kFujitsuAcModeHeat;
+ case stdAc::opmode_t::kDry:
+ return kFujitsuAcModeDry;
+ case stdAc::opmode_t::kFan:
+ return kFujitsuAcModeFan;
+ default:
+ return kFujitsuAcModeAuto;
+ }
+}
+
+// Convert a standard A/C Fan speed into its native fan speed.
+uint8_t IRFujitsuAC::convertFan(stdAc::fanspeed_t speed) {
+ switch (speed) {
+ case stdAc::fanspeed_t::kMin:
+ return kFujitsuAcFanQuiet;
+ case stdAc::fanspeed_t::kLow:
+ return kFujitsuAcFanLow;
+ case stdAc::fanspeed_t::kMedium:
+ return kFujitsuAcFanMed;
+ case stdAc::fanspeed_t::kHigh:
+ case stdAc::fanspeed_t::kMax:
+ return kFujitsuAcFanHigh;
+ default:
+ return kFujitsuAcFanAuto;
+ }
+}
+
// Convert the internal state into a human readable string.
#ifdef ARDUINO
String IRFujitsuAC::toString() {
@@ -327,77 +361,80 @@ String IRFujitsuAC::toString() {
std::string IRFujitsuAC::toString() {
std::string result = "";
#endif // ARDUINO
- result += "Power: ";
+ result += F("Power: ");
if (getPower())
- result += "On";
+ result += F("On");
else
- result += "Off";
- result += ", Mode: " + uint64ToString(getMode());
+ result += F("Off");
+ result += F(", Mode: ");
+ result += uint64ToString(getMode());
switch (getMode()) {
case kFujitsuAcModeAuto:
- result += " (AUTO)";
+ result += F(" (AUTO)");
break;
case kFujitsuAcModeCool:
- result += " (COOL)";
+ result += F(" (COOL)");
break;
case kFujitsuAcModeHeat:
- result += " (HEAT)";
+ result += F(" (HEAT)");
break;
case kFujitsuAcModeDry:
- result += " (DRY)";
+ result += F(" (DRY)");
break;
case kFujitsuAcModeFan:
- result += " (FAN)";
+ result += F(" (FAN)");
break;
default:
- result += " (UNKNOWN)";
+ result += F(" (UNKNOWN)");
}
- result += ", Temp: " + uint64ToString(getTemp()) + "C";
- result += ", Fan: " + uint64ToString(getFanSpeed());
+ result += F(", Temp: ");
+ result += uint64ToString(getTemp());
+ result += F("C, Fan: ");
+ result += uint64ToString(getFanSpeed());
switch (getFanSpeed()) {
case kFujitsuAcFanAuto:
- result += " (AUTO)";
+ result += F(" (AUTO)");
break;
case kFujitsuAcFanHigh:
- result += " (HIGH)";
+ result += F(" (HIGH)");
break;
case kFujitsuAcFanMed:
- result += " (MED)";
+ result += F(" (MED)");
break;
case kFujitsuAcFanLow:
- result += " (LOW)";
+ result += F(" (LOW)");
break;
case kFujitsuAcFanQuiet:
- result += " (QUIET)";
+ result += F(" (QUIET)");
break;
}
- result += ", Swing: ";
+ result += F(", Swing: ");
switch (getSwing()) {
case kFujitsuAcSwingOff:
- result += "Off";
+ result += F("Off");
break;
case kFujitsuAcSwingVert:
- result += "Vert";
+ result += F("Vert");
break;
case kFujitsuAcSwingHoriz:
- result += "Horiz";
+ result += F("Horiz");
break;
case kFujitsuAcSwingBoth:
- result += "Vert + Horiz";
+ result += F("Vert + Horiz");
break;
default:
- result += "UNKNOWN";
+ result += F("UNKNOWN");
}
- result += ", Command: ";
+ result += F(", Command: ");
switch (getCmd()) {
case kFujitsuAcCmdStepHoriz:
- result += "Step vane horizontally";
+ result += F("Step vane horizontally");
break;
case kFujitsuAcCmdStepVert:
- result += "Step vane vertically";
+ result += F("Step vane vertically");
break;
default:
- result += "N/A";
+ result += F("N/A");
}
return result;
}
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_Fujitsu.h b/lib/IRremoteESP8266-2.6.0/src/ir_Fujitsu.h
similarity index 93%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_Fujitsu.h
rename to lib/IRremoteESP8266-2.6.0/src/ir_Fujitsu.h
index bba634be6..78a4f8951 100644
--- a/lib/IRremoteESP8266-2.5.2.03/src/ir_Fujitsu.h
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_Fujitsu.h
@@ -13,6 +13,9 @@
#include "IRrecv.h"
#include "IRremoteESP8266.h"
#include "IRsend.h"
+#ifdef UNIT_TEST
+#include "IRsend_test.h"
+#endif
// FUJITSU A/C support added by Jonny Graham
@@ -78,7 +81,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();
@@ -99,15 +102,21 @@ class IRFujitsuAC {
uint8_t getStateLength();
static bool validChecksum(uint8_t* state, uint16_t length);
bool getPower();
+ uint8_t convertMode(const stdAc::opmode_t mode);
+ uint8_t convertFan(stdAc::fanspeed_t speed);
#ifdef ARDUINO
String toString();
#else
std::string toString();
#endif
+#ifndef UNIT_TEST
private:
- uint8_t remote_state[kFujitsuAcStateLength];
IRsend _irsend;
+#else
+ IRsendTest _irsend;
+#endif
+ uint8_t remote_state[kFujitsuAcStateLength];
uint8_t _temp;
uint8_t _fanSpeed;
uint8_t _mode;
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_GICable.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_GICable.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_GICable.cpp
rename to lib/IRremoteESP8266-2.6.0/src/ir_GICable.cpp
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_GlobalCache.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_GlobalCache.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_GlobalCache.cpp
rename to lib/IRremoteESP8266-2.6.0/src/ir_GlobalCache.cpp
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_Gree.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_Gree.cpp
similarity index 82%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_Gree.cpp
rename to lib/IRremoteESP8266-2.6.0/src/ir_Gree.cpp
index df8afada6..756f008d4 100644
--- a/lib/IRremoteESP8266-2.5.2.03/src/ir_Gree.cpp
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_Gree.cpp
@@ -27,7 +27,7 @@
// Constants
// Ref: https://github.com/ToniA/arduino-heatpumpir/blob/master/GreeHeatpumpIR.h
const uint16_t kGreeHdrMark = 9000;
-const uint16_t kGreeHdrSpace = 4000;
+const uint16_t kGreeHdrSpace = 4500; // See #684 and real example in unit tests
const uint16_t kGreeBitMark = 620;
const uint16_t kGreeOneSpace = 1600;
const uint16_t kGreeZeroSpace = 540;
@@ -59,7 +59,7 @@ void IRsend::sendGree(unsigned char data[], uint16_t nbytes, uint16_t repeat) {
// Footer #1
sendGeneric(0, 0, // No Header
kGreeBitMark, kGreeOneSpace, kGreeBitMark, kGreeZeroSpace,
- kGreeBitMark, kGreeMsgSpace, 0b010, 3, 38, true, 0, false);
+ kGreeBitMark, kGreeMsgSpace, 0b010, 3, 38, false, 0, 50);
// Block #2
sendGeneric(0, 0, // No Header for Block #2
@@ -129,9 +129,9 @@ void IRGreeAC::fixup() {
void IRGreeAC::begin() { _irsend.begin(); }
#if SEND_GREE
-void IRGreeAC::send() {
+void IRGreeAC::send(const uint16_t repeat) {
fixup(); // Ensure correct settings before sending.
- _irsend.sendGree(remote_state);
+ _irsend.sendGree(remote_state, kGreeStateLength, repeat);
}
#endif // SEND_GREE
@@ -305,6 +305,57 @@ uint8_t IRGreeAC::getSwingVerticalPosition() {
return remote_state[4] & kGreeSwingPosMask;
}
+
+// Convert a standard A/C mode into its native mode.
+uint8_t IRGreeAC::convertMode(const stdAc::opmode_t mode) {
+ switch (mode) {
+ case stdAc::opmode_t::kCool:
+ return kGreeCool;
+ case stdAc::opmode_t::kHeat:
+ return kGreeHeat;
+ case stdAc::opmode_t::kDry:
+ return kGreeDry;
+ case stdAc::opmode_t::kFan:
+ return kGreeFan;
+ default:
+ return kGreeAuto;
+ }
+}
+
+// Convert a standard A/C Fan speed into its native fan speed.
+uint8_t IRGreeAC::convertFan(const stdAc::fanspeed_t speed) {
+ switch (speed) {
+ case stdAc::fanspeed_t::kMin:
+ return kGreeFanMin;
+ case stdAc::fanspeed_t::kLow:
+ case stdAc::fanspeed_t::kMedium:
+ return kGreeFanMax - 1;
+ case stdAc::fanspeed_t::kHigh:
+ case stdAc::fanspeed_t::kMax:
+ return kGreeFanMax;
+ default:
+ return kGreeFanAuto;
+ }
+}
+
+// Convert a standard A/C Vertical Swing into its native version.
+uint8_t IRGreeAC::convertSwingV(const stdAc::swingv_t swingv) {
+ switch (swingv) {
+ case stdAc::swingv_t::kHighest:
+ return kGreeSwingUp;
+ case stdAc::swingv_t::kHigh:
+ return kGreeSwingMiddleUp;
+ case stdAc::swingv_t::kMiddle:
+ return kGreeSwingMiddle;
+ case stdAc::swingv_t::kLow:
+ return kGreeSwingMiddleDown;
+ case stdAc::swingv_t::kLowest:
+ return kGreeSwingDown;
+ default:
+ return kGreeSwingAuto;
+ }
+}
+
// Convert the internal state into a human readable string.
#ifdef ARDUINO
String IRGreeAC::toString() {
@@ -313,74 +364,77 @@ String IRGreeAC::toString() {
std::string IRGreeAC::toString() {
std::string result = "";
#endif // ARDUINO
- result += "Power: ";
+ result += F("Power: ");
if (getPower())
- result += "On";
+ result += F("On");
else
- result += "Off";
- result += ", Mode: " + uint64ToString(getMode());
+ result += F("Off");
+ result += F(", Mode: ");
+ result += uint64ToString(getMode());
switch (getMode()) {
case kGreeAuto:
- result += " (AUTO)";
+ result += F(" (AUTO)");
break;
case kGreeCool:
- result += " (COOL)";
+ result += F(" (COOL)");
break;
case kGreeHeat:
- result += " (HEAT)";
+ result += F(" (HEAT)");
break;
case kGreeDry:
- result += " (DRY)";
+ result += F(" (DRY)");
break;
case kGreeFan:
- result += " (FAN)";
+ result += F(" (FAN)");
break;
default:
- result += " (UNKNOWN)";
+ result += F(" (UNKNOWN)");
}
- result += ", Temp: " + uint64ToString(getTemp()) + "C";
- result += ", Fan: " + uint64ToString(getFan());
+ result += F(", Temp: ");
+ result += uint64ToString(getTemp());
+ result += F("C, Fan: ");
+ result += uint64ToString(getFan());
switch (getFan()) {
case 0:
- result += " (AUTO)";
+ result += F(" (AUTO)");
break;
case kGreeFanMax:
- result += " (MAX)";
+ result += F(" (MAX)");
break;
}
- result += ", Turbo: ";
+ result += F(", Turbo: ");
if (getTurbo())
- result += "On";
+ result += F("On");
else
- result += "Off";
- result += ", XFan: ";
+ result += F("Off");
+ result += F(", XFan: ");
if (getXFan())
- result += "On";
+ result += F("On");
else
- result += "Off";
- result += ", Light: ";
+ result += F("Off");
+ result += F(", Light: ");
if (getLight())
- result += "On";
+ result += F("On");
else
- result += "Off";
- result += ", Sleep: ";
+ result += F("Off");
+ result += F(", Sleep: ");
if (getSleep())
- result += "On";
+ result += F("On");
else
- result += "Off";
- result += ", Swing Vertical Mode: ";
+ result += F("Off");
+ result += F(", Swing Vertical Mode: ");
if (getSwingVerticalAuto())
- result += "Auto";
+ result += F("Auto");
else
- result += "Manual";
- result +=
- ", Swing Vertical Pos: " + uint64ToString(getSwingVerticalPosition());
+ result += F("Manual");
+ result += F(", Swing Vertical Pos: ");
+ result += uint64ToString(getSwingVerticalPosition());
switch (getSwingVerticalPosition()) {
case kGreeSwingLastPos:
- result += " (Last Pos)";
+ result += F(" (Last Pos)");
break;
case kGreeSwingAuto:
- result += " (Auto)";
+ result += F(" (Auto)");
break;
}
return result;
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_Gree.h b/lib/IRremoteESP8266-2.6.0/src/ir_Gree.h
similarity index 89%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_Gree.h
rename to lib/IRremoteESP8266-2.6.0/src/ir_Gree.h
index 73f69eb31..c3c5916dc 100644
--- a/lib/IRremoteESP8266-2.5.2.03/src/ir_Gree.h
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_Gree.h
@@ -14,6 +14,9 @@
#endif
#include "IRremoteESP8266.h"
#include "IRsend.h"
+#ifdef UNIT_TEST
+#include "IRsend_test.h"
+#endif
// GGGG RRRRRR EEEEEEE EEEEEEE
// GG GG RR RR EE EE
@@ -44,6 +47,8 @@ const uint8_t kGreeSwingPosMask = 0b00001111;
const uint8_t kGreeMinTemp = 16; // Celsius
const uint8_t kGreeMaxTemp = 30; // Celsius
+const uint8_t kGreeFanAuto = 0;
+const uint8_t kGreeFanMin = 1;
const uint8_t kGreeFanMax = 3;
const uint8_t kGreeSwingLastPos = 0b00000000;
@@ -84,7 +89,7 @@ class IRGreeAC {
void stateReset();
#if SEND_GREE
- void send();
+ void send(const uint16_t repeat = kGreeDefaultRepeat);
#endif // SEND_GREE
void begin();
void on();
@@ -108,7 +113,9 @@ class IRGreeAC {
void setSwingVertical(const bool automatic, const uint8_t position);
bool getSwingVerticalAuto();
uint8_t getSwingVerticalPosition();
-
+ uint8_t convertMode(const stdAc::opmode_t mode);
+ uint8_t convertFan(const stdAc::fanspeed_t speed);
+ uint8_t convertSwingV(const stdAc::swingv_t swingv);
uint8_t* getRaw();
void setRaw(uint8_t new_code[]);
static bool validChecksum(const uint8_t state[],
@@ -118,13 +125,17 @@ class IRGreeAC {
#else
std::string toString();
#endif
+#ifndef UNIT_TEST
private:
+ IRsend _irsend;
+#else // UNIT_TEST
+ IRsendTest _irsend;
+#endif // UNIT_TEST
// The state of the IR remote in IR code form.
uint8_t remote_state[kGreeStateLength];
void checksum(const uint16_t length = kGreeStateLength);
void fixup();
- IRsend _irsend;
};
#endif // IR_GREE_H_
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_Haier.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_Haier.cpp
similarity index 75%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_Haier.cpp
rename to lib/IRremoteESP8266-2.6.0/src/ir_Haier.cpp
index 2c47e4eac..f76bb3447 100644
--- a/lib/IRremoteESP8266-2.5.2.03/src/ir_Haier.cpp
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_Haier.cpp
@@ -45,7 +45,7 @@ const uint32_t kHaierAcMinGap = 150000; // Completely made up value.
// 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.
+// Status: STABLE / Known to be working.
//
void IRsend::sendHaierAC(unsigned char data[], uint16_t nbytes,
uint16_t repeat) {
@@ -86,9 +86,9 @@ 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
@@ -104,7 +104,10 @@ bool IRHaierAC::validChecksum(uint8_t state[], const uint16_t length) {
void IRHaierAC::stateReset() {
for (uint8_t i = 1; i < kHaierACStateLength; i++) remote_state[i] = 0x0;
remote_state[0] = kHaierAcPrefix;
- remote_state[2] = 0b00100000;
+ remote_state[2] = 0x20;
+ remote_state[4] = 0x0C;
+ remote_state[5] = 0xC0;
+ remote_state[6] = 0x20;
setTemp(kHaierAcDefTemp);
setFan(kHaierAcFanAuto);
@@ -304,14 +307,63 @@ 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.
+ result += ':';
+ if (nr_mins % 60 < 10) result += '0'; // Zero pad.
result += uint64ToString(nr_mins % 60);
return result;
}
+// Convert a standard A/C mode into its native mode.
+uint8_t IRHaierAC::convertMode(const stdAc::opmode_t mode) {
+ switch (mode) {
+ case stdAc::opmode_t::kCool:
+ return kHaierAcCool;
+ case stdAc::opmode_t::kHeat:
+ return kHaierAcHeat;
+ case stdAc::opmode_t::kDry:
+ return kHaierAcDry;
+ case stdAc::opmode_t::kFan:
+ return kHaierAcFan;
+ default:
+ return kHaierAcAuto;
+ }
+}
+
+// Convert a standard A/C Fan speed into its native fan speed.
+uint8_t IRHaierAC::convertFan(const stdAc::fanspeed_t speed) {
+ switch (speed) {
+ case stdAc::fanspeed_t::kMin:
+ case stdAc::fanspeed_t::kLow:
+ return kHaierAcFanLow;
+ case stdAc::fanspeed_t::kMedium:
+ return kHaierAcFanMed;
+ case stdAc::fanspeed_t::kHigh:
+ case stdAc::fanspeed_t::kMax:
+ return kHaierAcFanHigh;
+ default:
+ return kHaierAcFanAuto;
+ }
+}
+
+// Convert a standard A/C vertical swing into its native setting.
+uint8_t IRHaierAC::convertSwingV(const stdAc::swingv_t position) {
+ switch (position) {
+ case stdAc::swingv_t::kHighest:
+ case stdAc::swingv_t::kHigh:
+ case stdAc::swingv_t::kMiddle:
+ return kHaierAcSwingUp;
+ case stdAc::swingv_t::kLow:
+ case stdAc::swingv_t::kLowest:
+ return kHaierAcSwingDown;
+ case stdAc::swingv_t::kOff:
+ return kHaierAcSwingOff;
+ default:
+ return kHaierAcSwingChg;
+ }
+}
+
// Convert the internal state into a human readable string.
#ifdef ARDUINO
String IRHaierAC::toString() {
@@ -321,114 +373,122 @@ std::string IRHaierAC::toString() {
std::string result = "";
#endif // ARDUINO
uint8_t cmd = getCommand();
- result += "Command: " + uint64ToString(cmd) + " (";
+ result += F("Command: ");
+ result += uint64ToString(cmd);
+ result += F(" (");
switch (cmd) {
case kHaierAcCmdOff:
- result += "Off";
+ result += F("Off");
break;
case kHaierAcCmdOn:
- result += "On";
+ result += F("On");
break;
case kHaierAcCmdMode:
- result += "Mode";
+ result += F("Mode");
break;
case kHaierAcCmdFan:
- result += "Fan";
+ result += F("Fan");
break;
case kHaierAcCmdTempUp:
- result += "Temp Up";
+ result += F("Temp Up");
break;
case kHaierAcCmdTempDown:
- result += "Temp Down";
+ result += F("Temp Down");
break;
case kHaierAcCmdSleep:
- result += "Sleep";
+ result += F("Sleep");
break;
case kHaierAcCmdTimerSet:
- result += "Timer Set";
+ result += F("Timer Set");
break;
case kHaierAcCmdTimerCancel:
- result += "Timer Cancel";
+ result += F("Timer Cancel");
break;
case kHaierAcCmdHealth:
- result += "Health";
+ result += F("Health");
break;
case kHaierAcCmdSwing:
- result += "Swing";
+ result += F("Swing");
break;
default:
- result += "Unknown";
+ result += F("Unknown");
}
- result += ")";
- result += ", Mode: " + uint64ToString(getMode());
+ result += ')';
+ result += F(", Mode: ");
+ result += uint64ToString(getMode());
switch (getMode()) {
case kHaierAcAuto:
- result += " (AUTO)";
+ result += F(" (AUTO)");
break;
case kHaierAcCool:
- result += " (COOL)";
+ result += F(" (COOL)");
break;
case kHaierAcHeat:
- result += " (HEAT)";
+ result += F(" (HEAT)");
break;
case kHaierAcDry:
- result += " (DRY)";
+ result += F(" (DRY)");
break;
case kHaierAcFan:
- result += " (FAN)";
+ result += F(" (FAN)");
break;
default:
- result += " (UNKNOWN)";
+ result += F(" (UNKNOWN)");
}
- result += ", Temp: " + uint64ToString(getTemp()) + "C";
- result += ", Fan: " + uint64ToString(getFan());
+ result += F(", Temp: ");
+ result += uint64ToString(getTemp());
+ result += F("C, Fan: ");
+ result += uint64ToString(getFan());
switch (getFan()) {
case kHaierAcFanAuto:
- result += " (AUTO)";
+ result += F(" (AUTO)");
break;
case kHaierAcFanHigh:
- result += " (MAX)";
+ result += F(" (MAX)");
break;
}
- result += ", Swing: " + uint64ToString(getSwing()) + " (";
+ result += F(", Swing: ");
+ result += uint64ToString(getSwing());
+ result += F(" (");
switch (getSwing()) {
case kHaierAcSwingOff:
- result += "Off";
+ result += F("Off");
break;
case kHaierAcSwingUp:
- result += "Up";
+ result += F("Up");
break;
case kHaierAcSwingDown:
- result += "Down";
+ result += F("Down");
break;
case kHaierAcSwingChg:
- result += "Chg";
+ result += F("Chg");
break;
default:
- result += "Unknown";
+ result += F("Unknown");
}
- result += ")";
- result += ", Sleep: ";
+ result += ')';
+ result += F(", Sleep: ");
if (getSleep())
- result += "On";
+ result += F("On");
else
- result += "Off";
- result += ", Health: ";
+ result += F("Off");
+ result += F(", Health: ");
if (getHealth())
- result += "On";
+ result += F("On");
else
- result += "Off";
- result += ", Current Time: " + timeToString(getCurrTime());
- result += ", On Timer: ";
+ result += F("Off");
+ result += F(", Current Time: ");
+ result += timeToString(getCurrTime());
+ result += F(", On Timer: ");
if (getOnTimer() >= 0)
result += timeToString(getOnTimer());
else
- result += "Off";
- result += ", Off Timer: ";
+ result += F("Off");
+ result += F(", Off Timer: ");
if (getOffTimer() >= 0)
result += timeToString(getOffTimer());
else
- result += "Off";
+ result += F("Off");
return result;
}
@@ -440,9 +500,9 @@ IRHaierACYRW02::IRHaierACYRW02(uint16_t pin) : _irsend(pin) { stateReset(); }
void IRHaierACYRW02::begin() { _irsend.begin(); }
#if SEND_HAIER_AC_YRW02
-void IRHaierACYRW02::send() {
+void IRHaierACYRW02::send(const uint16_t repeat) {
checksum();
- _irsend.sendHaierACYRW02(remote_state);
+ _irsend.sendHaierACYRW02(remote_state, kHaierACYRW02StateLength, repeat);
}
#endif // SEND_HAIER_AC_YRW02
@@ -628,6 +688,57 @@ void IRHaierACYRW02::setSwing(uint8_t state) {
remote_state[1] |= newstate;
}
+// Convert a standard A/C mode into its native mode.
+uint8_t IRHaierACYRW02::convertMode(const stdAc::opmode_t mode) {
+ switch (mode) {
+ case stdAc::opmode_t::kCool:
+ return kHaierAcYrw02Cool;
+ case stdAc::opmode_t::kHeat:
+ return kHaierAcYrw02Heat;
+ case stdAc::opmode_t::kDry:
+ return kHaierAcYrw02Dry;
+ case stdAc::opmode_t::kFan:
+ return kHaierAcYrw02Fan;
+ default:
+ return kHaierAcYrw02Auto;
+ }
+}
+
+// Convert a standard A/C Fan speed into its native fan speed.
+uint8_t IRHaierACYRW02::convertFan(const stdAc::fanspeed_t speed) {
+ switch (speed) {
+ case stdAc::fanspeed_t::kMin:
+ case stdAc::fanspeed_t::kLow:
+ return kHaierAcYrw02FanLow;
+ case stdAc::fanspeed_t::kMedium:
+ return kHaierAcYrw02FanMed;
+ case stdAc::fanspeed_t::kHigh:
+ case stdAc::fanspeed_t::kMax:
+ return kHaierAcYrw02FanHigh;
+ default:
+ return kHaierAcYrw02FanAuto;
+ }
+}
+
+// Convert a standard A/C vertical swing into its native setting.
+uint8_t IRHaierACYRW02::convertSwingV(const stdAc::swingv_t position) {
+ switch (position) {
+ case stdAc::swingv_t::kHighest:
+ case stdAc::swingv_t::kHigh:
+ return kHaierAcYrw02SwingTop;
+ case stdAc::swingv_t::kMiddle:
+ return kHaierAcYrw02SwingMiddle;
+ case stdAc::swingv_t::kLow:
+ return kHaierAcYrw02SwingDown;
+ case stdAc::swingv_t::kLowest:
+ return kHaierAcYrw02SwingBottom;
+ case stdAc::swingv_t::kOff:
+ return kHaierAcYrw02SwingOff;
+ default:
+ return kHaierAcYrw02SwingAuto;
+ }
+}
+
// Convert the internal state into a human readable string.
#ifdef ARDUINO
String IRHaierACYRW02::toString() {
@@ -636,132 +747,141 @@ String IRHaierACYRW02::toString() {
std::string IRHaierACYRW02::toString() {
std::string result = "";
#endif // ARDUINO
- result += "Power: ";
+ result += F("Power: ");
if (getPower())
- result += "On";
+ result += F("On");
else
- result += "Off";
+ result += F("Off");
uint8_t cmd = getButton();
- result += ", Button: " + uint64ToString(cmd) + " (";
+ result += F(", Button: ");
+ result += uint64ToString(cmd);
+ result += F(" (");
switch (cmd) {
case kHaierAcYrw02ButtonPower:
- result += "Power";
+ result += F("Power");
break;
case kHaierAcYrw02ButtonMode:
- result += "Mode";
+ result += F("Mode");
break;
case kHaierAcYrw02ButtonFan:
- result += "Fan";
+ result += F("Fan");
break;
case kHaierAcYrw02ButtonTempUp:
- result += "Temp Up";
+ result += F("Temp Up");
break;
case kHaierAcYrw02ButtonTempDown:
- result += "Temp Down";
+ result += F("Temp Down");
break;
case kHaierAcYrw02ButtonSleep:
- result += "Sleep";
+ result += F("Sleep");
break;
case kHaierAcYrw02ButtonHealth:
result += "Health";
break;
case kHaierAcYrw02ButtonSwing:
- result += "Swing";
+ result += F("Swing");
break;
case kHaierAcYrw02ButtonTurbo:
- result += "Turbo";
+ result += F("Turbo");
break;
default:
- result += "Unknown";
+ result += F("Unknown");
}
- result += ")";
- result += ", Mode: " + uint64ToString(getMode());
+ result += ')';
+ result += F(", Mode: ");
+ result += uint64ToString(getMode());
switch (getMode()) {
case kHaierAcYrw02Auto:
- result += " (Auto)";
+ result += F(" (Auto)");
break;
case kHaierAcYrw02Cool:
- result += " (Cool)";
+ result += F(" (Cool)");
break;
case kHaierAcYrw02Heat:
- result += " (Heat)";
+ result += F(" (Heat)");
break;
case kHaierAcYrw02Dry:
- result += " (Dry)";
+ result += F(" (Dry)");
break;
case kHaierAcYrw02Fan:
- result += " (Fan)";
+ result += F(" (Fan)");
break;
default:
- result += " (UNKNOWN)";
+ result += F(" (UNKNOWN)");
}
- result += ", Temp: " + uint64ToString(getTemp()) + "C";
- result += ", Fan: " + uint64ToString(getFan());
+ result += F(", Temp: ");
+ result += uint64ToString(getTemp());
+ result += F("C, Fan: ");
+ result += uint64ToString(getFan());
switch (getFan()) {
case kHaierAcYrw02FanAuto:
- result += " (Auto)";
+ result += F(" (Auto)");
break;
case kHaierAcYrw02FanHigh:
- result += " (High)";
+ result += F(" (High)");
break;
case kHaierAcYrw02FanLow:
- result += " (Low)";
+ result += F(" (Low)");
break;
case kHaierAcYrw02FanMed:
- result += " (Med)";
+ result += F(" (Med)");
break;
default:
- result += " (Unknown)";
+ result += F(" (Unknown)");
}
- result += ", Turbo: " + uint64ToString(getTurbo()) + " (";
+ result += F(", Turbo: ");
+ result += uint64ToString(getTurbo());
+ result += F(" (");
switch (getTurbo()) {
case kHaierAcYrw02TurboOff:
- result += "Off";
+ result += F("Off");
break;
case kHaierAcYrw02TurboLow:
- result += "Low";
+ result += F("Low");
break;
case kHaierAcYrw02TurboHigh:
- result += "High";
+ result += F("High");
break;
default:
- result += "Unknown";
+ result += F("Unknown");
}
- result += ")";
- result += ", Swing: " + uint64ToString(getSwing()) + " (";
+ result += ')';
+ result += F(", Swing: ");
+ result += uint64ToString(getSwing());
+ result += F(" (");
switch (getSwing()) {
case kHaierAcYrw02SwingOff:
- result += "Off";
+ result += F("Off");
break;
case kHaierAcYrw02SwingAuto:
- result += "Auto";
+ result += F("Auto");
break;
case kHaierAcYrw02SwingBottom:
- result += "Bottom";
+ result += F("Bottom");
break;
case kHaierAcYrw02SwingDown:
- result += "Down";
+ result += F("Down");
break;
case kHaierAcYrw02SwingTop:
- result += "Top";
+ result += F("Top");
break;
case kHaierAcYrw02SwingMiddle:
- result += "Middle";
+ result += F("Middle");
break;
default:
- result += "Unknown";
+ result += F("Unknown");
}
- result += ")";
- result += ", Sleep: ";
+ result += ')';
+ result += F(", Sleep: ");
if (getSleep())
- result += "On";
+ result += F("On");
else
- result += "Off";
- result += ", Health: ";
+ result += F("Off");
+ result += F(", Health: ");
if (getHealth())
- result += "On";
+ result += F("On");
else
- result += "Off";
+ result += F("Off");
return result;
}
@@ -777,7 +897,7 @@ std::string IRHaierACYRW02::toString() {
// Returns:
// boolean: True if it can decode it, false if it can't.
//
-// Status: BETA / Appears to be working.
+// Status: STABLE / Known to be working.
//
bool IRrecv::decodeHaierAC(decode_results* results, uint16_t nbits,
bool strict) {
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_Haier.h b/lib/IRremoteESP8266-2.6.0/src/ir_Haier.h
similarity index 93%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_Haier.h
rename to lib/IRremoteESP8266-2.6.0/src/ir_Haier.h
index fdc15a3a8..8f7b35196 100644
--- a/lib/IRremoteESP8266-2.5.2.03/src/ir_Haier.h
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_Haier.h
@@ -11,6 +11,9 @@
#endif
#include "IRremoteESP8266.h"
#include "IRsend.h"
+#ifdef UNIT_TEST
+#include "IRsend_test.h"
+#endif
// HH HH AAA IIIII EEEEEEE RRRRRR
// HH HH AAAAA III EE RR RR
@@ -186,7 +189,7 @@ class IRHaierAC {
explicit IRHaierAC(uint16_t pin);
#if SEND_HAIER_AC
- void send();
+ void send(const uint16_t repeat = kHaierAcDefaultRepeat);
#endif // SEND_HAIER_AC
void begin();
@@ -223,6 +226,10 @@ class IRHaierAC {
void setRaw(uint8_t new_code[]);
static bool validChecksum(uint8_t state[],
const uint16_t length = kHaierACStateLength);
+ uint8_t convertMode(const stdAc::opmode_t mode);
+ uint8_t convertFan(const stdAc::fanspeed_t speed);
+ uint8_t convertSwingV(const stdAc::swingv_t position);
+
#ifdef ARDUINO
String toString();
static String timeToString(const uint16_t nr_mins);
@@ -230,14 +237,18 @@ class IRHaierAC {
std::string toString();
static std::string timeToString(const uint16_t nr_mins);
#endif
+#ifndef UNIT_TEST
private:
+ IRsend _irsend;
+#else
+ IRsendTest _irsend;
+#endif
uint8_t remote_state[kHaierACStateLength];
void stateReset();
void checksum();
static uint16_t getTime(const uint8_t ptr[]);
static void setTime(uint8_t ptr[], const uint16_t nr_mins);
- IRsend _irsend;
};
class IRHaierACYRW02 {
@@ -245,7 +256,7 @@ class IRHaierACYRW02 {
explicit IRHaierACYRW02(uint16_t pin);
#if SEND_HAIER_AC_YRW02
- void send();
+ void send(const uint16_t repeat = kHaierAcYrw02DefaultRepeat);
#endif // SEND_HAIER_AC_YRW02
void begin();
@@ -281,17 +292,24 @@ class IRHaierACYRW02 {
void setRaw(uint8_t new_code[]);
static bool validChecksum(uint8_t state[],
const uint16_t length = kHaierACYRW02StateLength);
+ uint8_t convertMode(const stdAc::opmode_t mode);
+ uint8_t convertFan(const stdAc::fanspeed_t speed);
+ uint8_t convertSwingV(const stdAc::swingv_t position);
#ifdef ARDUINO
String toString();
#else
std::string toString();
#endif
+#ifndef UNIT_TEST
private:
+ IRsend _irsend;
+#else
+ IRsendTest _irsend;
+#endif
uint8_t remote_state[kHaierACYRW02StateLength];
void stateReset();
void checksum();
- IRsend _irsend;
};
#endif // IR_HAIER_H_
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_Hitachi.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_Hitachi.cpp
similarity index 86%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_Hitachi.cpp
rename to lib/IRremoteESP8266-2.6.0/src/ir_Hitachi.cpp
index 111051974..b88189f4a 100644
--- a/lib/IRremoteESP8266-2.5.2.03/src/ir_Hitachi.cpp
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_Hitachi.cpp
@@ -30,7 +30,7 @@ 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.
+const uint32_t kHitachiAcMinGap = kDefaultMessageGap; // Just a guess.
#if (SEND_HITACHI_AC || SEND_HITACHI_AC2)
// Send a Hitachi A/C message.
@@ -106,7 +106,7 @@ void IRsend::sendHitachiAC2(unsigned char data[], uint16_t nbytes,
}
#endif // SEND_HITACHI_AC2
-// Class for handling the remote control oh a Hitachi 28 byte A/C message.
+// Class for handling the remote control on a Hitachi 28 byte A/C message.
// Inspired by:
// https://github.com/ToniA/arduino-heatpumpir/blob/master/HitachiHeatpumpIR.cpp
@@ -159,9 +159,9 @@ void IRHitachiAc::setRaw(const uint8_t new_code[], const uint16_t length) {
}
#if SEND_HITACHI_AC
-void IRHitachiAc::send() {
+void IRHitachiAc::send(const uint16_t repeat) {
checksum();
- _irsend.sendHitachiAC(remote_state);
+ _irsend.sendHitachiAC(remote_state, kHitachiAcStateLength, repeat);
}
#endif // SEND_HITACHI_AC
@@ -257,6 +257,40 @@ void IRHitachiAc::setSwingHorizontal(const bool on) {
remote_state[15] &= 0x7F;
}
+
+// Convert a standard A/C mode into its native mode.
+uint8_t IRHitachiAc::convertMode(const stdAc::opmode_t mode) {
+ switch (mode) {
+ case stdAc::opmode_t::kCool:
+ return kHitachiAcCool;
+ case stdAc::opmode_t::kHeat:
+ return kHitachiAcHeat;
+ case stdAc::opmode_t::kDry:
+ return kHitachiAcDry;
+ case stdAc::opmode_t::kFan:
+ return kHitachiAcFan;
+ default:
+ return kHitachiAcAuto;
+ }
+}
+
+// Convert a standard A/C Fan speed into its native fan speed.
+uint8_t IRHitachiAc::convertFan(const stdAc::fanspeed_t speed) {
+ switch (speed) {
+ case stdAc::fanspeed_t::kMin:
+ case stdAc::fanspeed_t::kLow:
+ return kHitachiAcFanLow;
+ case stdAc::fanspeed_t::kMedium:
+ return kHitachiAcFanLow + 1;
+ case stdAc::fanspeed_t::kHigh:
+ return kHitachiAcFanHigh - 1;
+ case stdAc::fanspeed_t::kMax:
+ return kHitachiAcFanHigh;
+ default:
+ return kHitachiAcFanAuto;
+ }
+}
+
// Convert the internal state into a human readable string.
#ifdef ARDUINO
String IRHitachiAc::toString() {
@@ -265,57 +299,60 @@ String IRHitachiAc::toString() {
std::string IRHitachiAc::toString() {
std::string result = "";
#endif // ARDUINO
- result += "Power: ";
+ result += F("Power: ");
if (getPower())
- result += "On";
+ result += F("On");
else
- result += "Off";
- result += ", Mode: " + uint64ToString(getMode());
+ result += F("Off");
+ result += F(", Mode: ");
+ result += uint64ToString(getMode());
switch (getMode()) {
case kHitachiAcAuto:
- result += " (AUTO)";
+ result += F(" (AUTO)");
break;
case kHitachiAcCool:
- result += " (COOL)";
+ result += F(" (COOL)");
break;
case kHitachiAcHeat:
- result += " (HEAT)";
+ result += F(" (HEAT)");
break;
case kHitachiAcDry:
- result += " (DRY)";
+ result += F(" (DRY)");
break;
case kHitachiAcFan:
- result += " (FAN)";
+ result += F(" (FAN)");
break;
default:
- result += " (UNKNOWN)";
+ result += F(" (UNKNOWN)");
}
- result += ", Temp: " + uint64ToString(getTemp()) + "C";
- result += ", Fan: " + uint64ToString(getFan());
+ result += F(", Temp: ");
+ result += uint64ToString(getTemp());
+ result += F("C, Fan: ");
+ result += uint64ToString(getFan());
switch (getFan()) {
case kHitachiAcFanAuto:
- result += " (AUTO)";
+ result += F(" (AUTO)");
break;
case kHitachiAcFanLow:
- result += " (LOW)";
+ result += F(" (LOW)");
break;
case kHitachiAcFanHigh:
- result += " (HIGH)";
+ result += F(" (HIGH)");
break;
default:
- result += " (UNKNOWN)";
+ result += F(" (UNKNOWN)");
break;
}
- result += ", Swing (Vertical): ";
+ result += F(", Swing (Vertical): ");
if (getSwingVertical())
- result += "On";
+ result += F("On");
else
- result += "Off";
- result += ", Swing (Horizontal): ";
+ result += F("Off");
+ result += F(", Swing (Horizontal): ");
if (getSwingHorizontal())
- result += "On";
+ result += F("On");
else
- result += "Off";
+ result += F("Off");
return result;
}
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_Hitachi.h b/lib/IRremoteESP8266-2.6.0/src/ir_Hitachi.h
similarity index 87%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_Hitachi.h
rename to lib/IRremoteESP8266-2.6.0/src/ir_Hitachi.h
index eddab59e4..532717447 100644
--- a/lib/IRremoteESP8266-2.5.2.03/src/ir_Hitachi.h
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_Hitachi.h
@@ -14,6 +14,9 @@
#endif
#include "IRremoteESP8266.h"
#include "IRsend.h"
+#ifdef UNIT_TEST
+#include "IRsend_test.h"
+#endif
// Constants
const uint8_t kHitachiAcAuto = 2;
@@ -35,7 +38,7 @@ class IRHitachiAc {
void stateReset();
#if SEND_HITACHI_AC
- void send();
+ void send(const uint16_t repeat = kHitachiAcDefaultRepeat);
#endif // SEND_HITACHI_AC
void begin();
void on();
@@ -59,17 +62,23 @@ class IRHitachiAc {
const uint16_t length = kHitachiAcStateLength);
static uint8_t calcChecksum(const uint8_t state[],
const uint16_t length = kHitachiAcStateLength);
+ uint8_t convertMode(const stdAc::opmode_t mode);
+ uint8_t convertFan(const stdAc::fanspeed_t speed);
#ifdef ARDUINO
String toString();
#else
std::string toString();
#endif
+#ifndef UNIT_TEST
private:
+ IRsend _irsend;
+#else
+ IRsendTest _irsend;
+#endif
// 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;
};
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_JVC.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_JVC.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_JVC.cpp
rename to lib/IRremoteESP8266-2.6.0/src/ir_JVC.cpp
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_Kelvinator.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_Kelvinator.cpp
similarity index 91%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_Kelvinator.cpp
rename to lib/IRremoteESP8266-2.6.0/src/ir_Kelvinator.cpp
index ddf61b097..c69f4cb8a 100644
--- a/lib/IRremoteESP8266-2.5.2.03/src/ir_Kelvinator.cpp
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_Kelvinator.cpp
@@ -19,6 +19,7 @@
#ifndef ARDUINO
#include
#endif
+#include "IRac.h"
#include "IRrecv.h"
#include "IRsend.h"
#include "IRutils.h"
@@ -141,9 +142,9 @@ void IRKelvinatorAC::fixup() {
}
#if SEND_KELVINATOR
-void IRKelvinatorAC::send() {
+void IRKelvinatorAC::send(const uint16_t repeat) {
fixup(); // Ensure correct settings before sending.
- _irsend.sendKelvinator(remote_state);
+ _irsend.sendKelvinator(remote_state, kKelvinatorStateLength, repeat);
}
#endif // SEND_KELVINATOR
@@ -347,6 +348,22 @@ bool IRKelvinatorAC::getTurbo() {
return ((remote_state[2] & kKelvinatorTurbo) != 0);
}
+// Convert a standard A/C mode into its native mode.
+uint8_t IRKelvinatorAC::convertMode(const stdAc::opmode_t mode) {
+ switch (mode) {
+ case stdAc::opmode_t::kCool:
+ return kKelvinatorCool;
+ case stdAc::opmode_t::kHeat:
+ return kKelvinatorHeat;
+ case stdAc::opmode_t::kDry:
+ return kKelvinatorDry;
+ case stdAc::opmode_t::kFan:
+ return kKelvinatorFan;
+ default:
+ return kKelvinatorAuto;
+ }
+}
+
// Convert the internal state into a human readable string.
#ifdef ARDUINO
String IRKelvinatorAC::toString() {
@@ -355,76 +372,79 @@ String IRKelvinatorAC::toString() {
std::string IRKelvinatorAC::toString() {
std::string result = "";
#endif // ARDUINO
- result += "Power: ";
+ result += F("Power: ");
if (getPower())
- result += "On";
+ result += F("On");
else
- result += "Off";
- result += ", Mode: " + uint64ToString(getMode());
+ result += F("Off");
+ result += F(", Mode: ");
+ result += uint64ToString(getMode());
switch (getMode()) {
case kKelvinatorAuto:
- result += " (AUTO)";
+ result += F(" (AUTO)");
break;
case kKelvinatorCool:
- result += " (COOL)";
+ result += F(" (COOL)");
break;
case kKelvinatorHeat:
- result += " (HEAT)";
+ result += F(" (HEAT)");
break;
case kKelvinatorDry:
- result += " (DRY)";
+ result += F(" (DRY)");
break;
case kKelvinatorFan:
- result += " (FAN)";
+ result += F(" (FAN)");
break;
default:
- result += " (UNKNOWN)";
+ result += F(" (UNKNOWN)");
}
- result += ", Temp: " + uint64ToString(getTemp()) + "C";
- result += ", Fan: " + uint64ToString(getFan());
+ result += F(", Temp: ");
+ result += uint64ToString(getTemp());
+ result += F("C, Fan: ");
+ result += uint64ToString(getFan());
switch (getFan()) {
case kKelvinatorFanAuto:
- result += " (AUTO)";
+ result += F(" (AUTO)");
break;
case kKelvinatorFanMax:
- result += " (MAX)";
+ result += F(" (MAX)");
break;
}
- result += ", Turbo: ";
+ result += F(", Turbo: ");
if (getTurbo())
- result += "On";
+ result += F("On");
else
- result += "Off";
- result += ", Quiet: ";
+ result += F("Off");
+ result += F(", Quiet: ");
if (getQuiet())
- result += "On";
+ result += F("On");
else
- result += "Off";
- result += ", XFan: ";
+ result += F("Off");
+ result += F(", XFan: ");
if (getXFan())
- result += "On";
+ result += F("On");
else
- result += "Off";
- result += ", IonFilter: ";
+ result += F("Off");
+ result += F(", IonFilter: ");
if (getIonFilter())
- result += "On";
+ result += F("On");
else
- result += "Off";
- result += ", Light: ";
+ result += F("Off");
+ result += F(", Light: ");
if (getLight())
- result += "On";
+ result += F("On");
else
- result += "Off";
- result += ", Swing (Horizontal): ";
+ result += F("Off");
+ result += F(", Swing (Horizontal): ");
if (getSwingHorizontal())
- result += "On";
+ result += F("On");
else
- result += "Off";
- result += ", Swing (Vertical): ";
+ result += F("Off");
+ result += F(", Swing (Vertical): ");
if (getSwingVertical())
- result += "On";
+ result += F("On");
else
- result += "Off";
+ result += F("Off");
return result;
}
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_Kelvinator.h b/lib/IRremoteESP8266-2.6.0/src/ir_Kelvinator.h
similarity index 96%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_Kelvinator.h
rename to lib/IRremoteESP8266-2.6.0/src/ir_Kelvinator.h
index 1508d6cdc..ce830c70a 100644
--- a/lib/IRremoteESP8266-2.5.2.03/src/ir_Kelvinator.h
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_Kelvinator.h
@@ -14,6 +14,9 @@
#endif
#include "IRremoteESP8266.h"
#include "IRsend.h"
+#ifdef UNIT_TEST
+#include "IRsend_test.h"
+#endif
// KK KK EEEEEEE LL VV VV IIIII NN NN AAA TTTTTTT OOOOO RRRRRR
// KK KK EE LL VV VV III NNN NN AAAAA TTT OO OO RR RR
@@ -130,7 +133,7 @@ class IRKelvinatorAC {
void stateReset();
#if SEND_KELVINATOR
- void send();
+ void send(const uint16_t repeat = kKelvinatorDefaultRepeat);
#endif // SEND_KELVINATOR
void begin();
void on();
@@ -163,18 +166,23 @@ class IRKelvinatorAC {
const uint8_t* block, const uint16_t length = kKelvinatorStateLength / 2);
static bool validChecksum(const uint8_t state[],
const uint16_t length = kKelvinatorStateLength);
+ uint8_t convertMode(const stdAc::opmode_t mode);
#ifdef ARDUINO
String toString();
#else
std::string toString();
#endif
+#ifndef UNIT_TEST
private:
+ IRsend _irsend;
+#else
+ IRsendTest _irsend;
+#endif
// The state of the IR remote in IR code form.
uint8_t remote_state[kKelvinatorStateLength];
void checksum(const uint16_t length = kKelvinatorStateLength);
void fixup();
- IRsend _irsend;
};
#endif // IR_KELVINATOR_H_
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_LG.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_LG.cpp
similarity index 98%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_LG.cpp
rename to lib/IRremoteESP8266-2.6.0/src/ir_LG.cpp
index f9d922fc7..36c85ff15 100644
--- a/lib/IRremoteESP8266-2.5.2.03/src/ir_LG.cpp
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_LG.cpp
@@ -85,11 +85,13 @@ uint8_t calcLGChecksum(uint16_t data) {
// IR Remote models: 6711A20083V
void IRsend::sendLG(uint64_t data, uint16_t nbits, uint16_t repeat) {
uint16_t repeatHeaderMark = 0;
+ uint8_t duty = kDutyDefault;
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 = kLg32RptHdrMark;
+ duty = 33;
repeat++;
} else {
// LG (28-bit) protocol.
@@ -97,7 +99,7 @@ void IRsend::sendLG(uint64_t data, uint16_t nbits, uint16_t repeat) {
sendGeneric(kLgHdrMark, kLgHdrSpace, kLgBitMark, kLgOneSpace, kLgBitMark,
kLgZeroSpace, kLgBitMark, kLgMinGap, kLgMinMessageLength, data,
nbits, 38, true, 0, // Repeats are handled later.
- 50);
+ duty);
}
// Repeat
@@ -105,7 +107,7 @@ void IRsend::sendLG(uint64_t data, uint16_t nbits, uint16_t repeat) {
if (repeat)
sendGeneric(repeatHeaderMark, kLgRptSpace, 0, 0, 0, 0, // No data is sent.
kLgBitMark, kLgMinGap, kLgMinMessageLength, 0, 0, // No data.
- 38, true, repeat - 1, 50);
+ 38, true, repeat - 1, duty);
}
// Send an LG Variant-2 formatted message.
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_LG.h b/lib/IRremoteESP8266-2.6.0/src/ir_LG.h
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_LG.h
rename to lib/IRremoteESP8266-2.6.0/src/ir_LG.h
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_Lasertag.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_Lasertag.cpp
similarity index 98%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_Lasertag.cpp
rename to lib/IRremoteESP8266-2.6.0/src/ir_Lasertag.cpp
index 7f0b89ae9..b1cbdc9b1 100644
--- a/lib/IRremoteESP8266-2.5.2.03/src/ir_Lasertag.cpp
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_Lasertag.cpp
@@ -14,7 +14,7 @@
// Constants
const uint16_t kLasertagMinSamples = 13;
const uint16_t kLasertagTick = 333;
-const uint32_t kLasertagMinGap = 100000; // Completely made up amount.
+const uint32_t kLasertagMinGap = kDefaultMessageGap; // Just a guess.
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.
diff --git a/lib/IRremoteESP8266-2.6.0/src/ir_Lego.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_Lego.cpp
new file mode 100644
index 000000000..b051aba51
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_Lego.cpp
@@ -0,0 +1,128 @@
+// Copyright 2019 David Conran
+
+#include
+#include "IRrecv.h"
+#include "IRsend.h"
+#include "IRutils.h"
+
+// LEGO
+// (LEGO is a Registrated Trademark of the Lego Group.)
+//
+// Supported Devices:
+// - LEGO Power Functions IR Receiver
+//
+// Ref:
+// - https://github.com/markszabo/IRremoteESP8266/issues/641
+// - https://github.com/markszabo/IRremoteESP8266/files/2974525/LEGO_Power_Functions_RC_v120.pdf
+
+// Constants
+const uint16_t kLegoPfBitMark = 158;
+const uint16_t kLegoPfHdrSpace = 1026;
+const uint16_t kLegoPfZeroSpace = 263;
+const uint16_t kLegoPfOneSpace = 553;
+const uint32_t kLegoPfMinCommandLength = 16000; // 16ms
+
+
+#if SEND_LEGOPF
+// Send a LEGO Power Functions message.
+//
+// Args:
+// data: Contents of the message to be sent.
+// nbits: Nr. of bits of data to be sent. Typically kLegoPfBits.
+// repeat: Nr. of additional times the message is to be sent.
+// Note: Non-zero repeats results in at least 5 messages per spec.
+//
+// Status: Beta / Should work.
+void IRsend::sendLegoPf(const uint64_t data, const uint16_t nbits,
+ const uint16_t repeat) {
+ uint8_t channelid = ((data >> (nbits - 4)) & 0b11) + 1;
+ if (repeat) {
+ // We are in repeat mode.
+ // Spec says a pause before transmittion.
+ if (channelid < 4) space((4 - channelid) * kLegoPfMinCommandLength);
+ // Spec says there are a minimum of 5 message repeats.
+ for (uint16_t r = 0; r < std::max(repeat, (uint16_t)5); r++) {
+ // Lego has a special repeat mode which repeats a message with varying
+ // start to start times.
+ sendGeneric(kLegoPfBitMark, kLegoPfHdrSpace,
+ kLegoPfBitMark, kLegoPfOneSpace,
+ kLegoPfBitMark, kLegoPfZeroSpace,
+ kLegoPfBitMark, kLegoPfHdrSpace,
+ ((r < 2) ? 5 : (6 + 2 * channelid)) * kLegoPfMinCommandLength,
+ data, nbits, 38000, true, 0, kDutyDefault);
+ }
+ } else { // No repeat, just a simple message.
+ sendGeneric(kLegoPfBitMark, kLegoPfHdrSpace,
+ kLegoPfBitMark, kLegoPfOneSpace,
+ kLegoPfBitMark, kLegoPfZeroSpace,
+ kLegoPfBitMark, kLegoPfHdrSpace,
+ kLegoPfMinCommandLength * 5,
+ data, nbits, 38000, true, 0, kDutyDefault);
+ }
+}
+#endif // SEND_LEGO
+
+#if DECODE_LEGOPF
+// Decode the supplied LEGO Power Functions 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 kLegoPfBits.
+// 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::decodeLegoPf(decode_results* results,
+ const uint16_t nbits, const bool strict) {
+ // Check if can possibly be a valid LEGO message.
+ if (results->rawlen < 2 * nbits + kHeader + kFooter - 1) return false;
+ if (strict && nbits != kLegoPfBits) return false; // Not what is expected
+
+ uint64_t data = 0;
+ uint16_t offset = kStartOffset;
+ match_result_t data_result;
+
+ // Header
+ if (!matchMark(results->rawbuf[offset++], kLegoPfBitMark)) return false;
+ if (!matchSpace(results->rawbuf[offset++], kLegoPfHdrSpace)) return false;
+ // Data (Typically 16 bits)
+ data_result =
+ matchData(&(results->rawbuf[offset]), nbits,
+ kLegoPfBitMark, kLegoPfOneSpace,
+ kLegoPfBitMark, kLegoPfZeroSpace,
+ kTolerance, kMarkExcess, true);
+ 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++], kLegoPfBitMark)) return false;
+ if (offset < results->rawlen &&
+ !matchAtLeast(results->rawbuf[offset], kLegoPfMinCommandLength))
+ return false;
+
+ // Compliance
+ if (actualBits < nbits) return false;
+ if (strict) {
+ if (actualBits != nbits) return false; // Not as we expected.
+ // Verify the Longitudinal Redundancy Check (LRC)
+ uint16_t lrc_data = data;
+ uint8_t lrc = 0xF;
+ for (uint8_t i = 0; i < 4; i++) {
+ lrc ^= (lrc_data & 0xF);
+ lrc_data >>= 4;
+ }
+ if (lrc) return false;
+ }
+
+ // Success
+ results->decode_type = LEGOPF;
+ results->bits = actualBits;
+ results->value = data;
+ results->address = ((data >> (nbits - 4)) & 0b11) + 1; // Channel Id
+ results->command = (data >> 4) & 0xFF; // Stuff between Channel Id and LRC.
+ return true;
+}
+#endif // DECODE_LEGOPF
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_Lutron.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_Lutron.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_Lutron.cpp
rename to lib/IRremoteESP8266-2.6.0/src/ir_Lutron.cpp
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_MWM.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_MWM.cpp
similarity index 98%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_MWM.cpp
rename to lib/IRremoteESP8266-2.6.0/src/ir_MWM.cpp
index a75e99e3a..61eac49e2 100644
--- a/lib/IRremoteESP8266-2.5.2.03/src/ir_MWM.cpp
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_MWM.cpp
@@ -105,7 +105,7 @@ bool IRrecv::decodeMWM(decode_results *results, uint16_t nbits, bool strict) {
for (; offset < results->rawlen && results->bits < 8 * kStateSizeMax;
frame_bits++) {
DPRINT("DEBUG: decodeMWM: offset = ");
- DPRINTLN(uint64ToString(offset));
+ DPRINTLN(offset);
int16_t level = getRClevel(results, &offset, &used, kMWMTick, kMWMTolerance,
kMWMExcess, kMWMDelta, kMWMMaxWidth);
if (level < 0) {
@@ -129,7 +129,7 @@ bool IRrecv::decodeMWM(decode_results *results, uint16_t nbits, bool strict) {
DPRINT("DEBUG: decodeMWM: data_bits = ");
DPRINTLN(data_bits);
DPRINT("DEBUG: decodeMWM: Finished byte: ");
- DPRINTLN(data);
+ DPRINTLN(uint64ToString(data));
results->state[data_bits / 8 - 1] = data & 0xFF;
results->bits = data_bits;
data = 0;
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_Magiquest.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_Magiquest.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_Magiquest.cpp
rename to lib/IRremoteESP8266-2.6.0/src/ir_Magiquest.cpp
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_Magiquest.h b/lib/IRremoteESP8266-2.6.0/src/ir_Magiquest.h
similarity index 86%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_Magiquest.h
rename to lib/IRremoteESP8266-2.6.0/src/ir_Magiquest.h
index d2d82d152..81fff53ad 100644
--- a/lib/IRremoteESP8266-2.5.2.03/src/ir_Magiquest.h
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_Magiquest.h
@@ -31,5 +31,5 @@ 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_
+const uint32_t kMagiQuestGap = kDefaultMessageGap; // Just a guess.
+#endif // IR_MAGIQUEST_H_
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_Midea.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_Midea.cpp
similarity index 87%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_Midea.cpp
rename to lib/IRremoteESP8266-2.6.0/src/ir_Midea.cpp
index 8e55c7d22..8d5d9494f 100644
--- a/lib/IRremoteESP8266-2.5.2.03/src/ir_Midea.cpp
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_Midea.cpp
@@ -104,9 +104,9 @@ void IRMideaAC::begin() { _irsend.begin(); }
#if SEND_MIDEA
// Send the current desired state to the IR LED.
-void IRMideaAC::send() {
+void IRMideaAC::send(const uint16_t repeat) {
checksum(); // Ensure correct checksum before sending.
- _irsend.sendMidea(remote_state);
+ _irsend.sendMidea(remote_state, kMideaBits, repeat);
}
#endif // SEND_MIDEA
@@ -257,6 +257,39 @@ void IRMideaAC::checksum() {
remote_state |= calcChecksum(remote_state);
}
+
+// Convert a standard A/C mode into its native mode.
+uint8_t IRMideaAC::convertMode(const stdAc::opmode_t mode) {
+ switch (mode) {
+ case stdAc::opmode_t::kCool:
+ return kMideaACCool;
+ case stdAc::opmode_t::kHeat:
+ return kMideaACHeat;
+ case stdAc::opmode_t::kDry:
+ return kMideaACDry;
+ case stdAc::opmode_t::kFan:
+ return kMideaACFan;
+ default:
+ return kMideaACAuto;
+ }
+}
+
+// Convert a standard A/C Fan speed into its native fan speed.
+uint8_t IRMideaAC::convertFan(const stdAc::fanspeed_t speed) {
+ switch (speed) {
+ case stdAc::fanspeed_t::kMin:
+ case stdAc::fanspeed_t::kLow:
+ return kMideaACFanLow;
+ case stdAc::fanspeed_t::kMedium:
+ return kMideaACFanMed;
+ case stdAc::fanspeed_t::kHigh:
+ case stdAc::fanspeed_t::kMax:
+ return kMideaACFanHigh;
+ default:
+ return kMideaACFanAuto;
+ }
+}
+
// Convert the internal state into a human readable string.
#ifdef ARDUINO
String IRMideaAC::toString() {
@@ -265,53 +298,57 @@ String IRMideaAC::toString() {
std::string IRMideaAC::toString() {
std::string result = "";
#endif // ARDUINO
- result += "Power: ";
+ result += F("Power: ");
if (getPower())
- result += "On";
+ result += F("On");
else
- result += "Off";
- result += ", Mode: " + uint64ToString(getMode());
+ result += F("Off");
+ result += F(", Mode: ");
+ result += uint64ToString(getMode());
switch (getMode()) {
case kMideaACAuto:
- result += " (AUTO)";
+ result += F(" (AUTO)");
break;
case kMideaACCool:
- result += " (COOL)";
+ result += F(" (COOL)");
break;
case kMideaACHeat:
- result += " (HEAT)";
+ result += F(" (HEAT)");
break;
case kMideaACDry:
- result += " (DRY)";
+ result += F(" (DRY)");
break;
case kMideaACFan:
- result += " (FAN)";
+ result += F(" (FAN)");
break;
default:
- result += " (UNKNOWN)";
+ result += F(" (UNKNOWN)");
}
- result += ", Temp: " + uint64ToString(getTemp(true)) + "C/" +
- uint64ToString(getTemp(false)) + "F";
- result += ", Fan: " + uint64ToString(getFan());
+ result += F(", Temp: ");
+ result += uint64ToString(getTemp(true));
+ result += F("C/");
+ result += uint64ToString(getTemp(false));
+ result += F("F, Fan: ");
+ result += uint64ToString(getFan());
switch (getFan()) {
case kMideaACFanAuto:
- result += " (AUTO)";
+ result += F(" (AUTO)");
break;
case kMideaACFanLow:
- result += " (LOW)";
+ result += F(" (LOW)");
break;
case kMideaACFanMed:
- result += " (MED)";
+ result += F(" (MED)");
break;
case kMideaACFanHigh:
- result += " (HI)";
+ result += F(" (HI)");
break;
}
- result += ", Sleep: ";
+ result += F(", Sleep: ");
if (getSleep())
- result += "On";
+ result += F("On");
else
- result += "Off";
+ result += F("Off");
return result;
}
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_Midea.h b/lib/IRremoteESP8266-2.6.0/src/ir_Midea.h
similarity index 93%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_Midea.h
rename to lib/IRremoteESP8266-2.6.0/src/ir_Midea.h
index aa9f94a92..ab14eb252 100644
--- a/lib/IRremoteESP8266-2.5.2.03/src/ir_Midea.h
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_Midea.h
@@ -11,6 +11,9 @@
#endif
#include "IRremoteESP8266.h"
#include "IRsend.h"
+#ifdef UNIT_TEST
+#include "IRsend_test.h"
+#endif
// MM MM IIIII DDDDD EEEEEEE AAA
// MMM MMM III DD DD EE AAAAA
@@ -67,7 +70,7 @@ class IRMideaAC {
void stateReset();
#if SEND_MIDEA
- void send();
+ void send(const uint16_t repeat = kMideaMinRepeat);
#endif // SEND_MIDEA
void begin();
void on();
@@ -85,6 +88,8 @@ class IRMideaAC {
static bool validChecksum(const uint64_t state);
void setSleep(const bool state);
bool getSleep();
+ uint8_t convertMode(const stdAc::opmode_t mode);
+ uint8_t convertFan(const stdAc::fanspeed_t speed);
#ifdef ARDUINO
String toString();
#else
@@ -93,11 +98,13 @@ class IRMideaAC {
#ifndef UNIT_TEST
private:
+ IRsend _irsend;
+#else
+ IRsendTest _irsend;
#endif
uint64_t remote_state;
void checksum();
static uint8_t calcChecksum(const uint64_t state);
- IRsend _irsend;
};
#endif // IR_MIDEA_H_
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_Mitsubishi.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_Mitsubishi.cpp
similarity index 90%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_Mitsubishi.cpp
rename to lib/IRremoteESP8266-2.6.0/src/ir_Mitsubishi.cpp
index b092c27b9..ca9bef5d9 100644
--- a/lib/IRremoteESP8266-2.5.2.03/src/ir_Mitsubishi.cpp
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_Mitsubishi.cpp
@@ -165,7 +165,7 @@ bool IRrecv::decodeMitsubishi(decode_results *results, uint16_t nbits,
// This protocol appears to have a manditory in-protocol repeat.
// That is in *addition* to the entire message needing to be sent twice
// for the device to accept the command. That is separate from the repeat.
-// i.e. Allegedly, the real remote requires the "OFF" button pressed twice.
+// i.e. Allegedly, the real remote requires the "Off" button pressed twice.
// You will need to add a suitable gap yourself.
// Ref:
// https://github.com/markszabo/IRremoteESP8266/issues/441
@@ -453,9 +453,9 @@ void IRMitsubishiAC::begin() { _irsend.begin(); }
#if SEND_MITSUBISHI_AC
// Send the current desired state to the IR LED.
-void IRMitsubishiAC::send() {
+void IRMitsubishiAC::send(const uint16_t repeat) {
checksum(); // Ensure correct checksum before sending.
- _irsend.sendMitsubishiAC(remote_state);
+ _irsend.sendMitsubishiAC(remote_state, kMitsubishiACStateLength, repeat);
}
#endif // SEND_MITSUBISHI_AC
@@ -615,6 +615,52 @@ void IRMitsubishiAC::setTimer(uint8_t timer) {
remote_state[13] = timer & 0b111;
}
+// Convert a standard A/C mode into its native mode.
+uint8_t IRMitsubishiAC::convertMode(const stdAc::opmode_t mode) {
+ switch (mode) {
+ case stdAc::opmode_t::kCool:
+ return kMitsubishiAcCool;
+ case stdAc::opmode_t::kHeat:
+ return kMitsubishiAcHeat;
+ case stdAc::opmode_t::kDry:
+ return kMitsubishiAcDry;
+ default:
+ return kMitsubishiAcAuto;
+ }
+}
+
+// Convert a standard A/C Fan speed into its native fan speed.
+uint8_t IRMitsubishiAC::convertFan(const stdAc::fanspeed_t speed) {
+ switch (speed) {
+ case stdAc::fanspeed_t::kMin:
+ return kMitsubishiAcFanSilent;
+ case stdAc::fanspeed_t::kLow:
+ return kMitsubishiAcFanRealMax - 3;
+ case stdAc::fanspeed_t::kMedium:
+ return kMitsubishiAcFanRealMax - 2;
+ case stdAc::fanspeed_t::kHigh:
+ return kMitsubishiAcFanRealMax - 1;
+ case stdAc::fanspeed_t::kMax:
+ return kMitsubishiAcFanRealMax;
+ default:
+ return kMitsubishiAcFanAuto;
+ }
+}
+
+// Convert a standard A/C vertical swing into its native setting.
+uint8_t IRMitsubishiAC::convertSwingV(const stdAc::swingv_t position) {
+ switch (position) {
+ case stdAc::swingv_t::kHighest:
+ case stdAc::swingv_t::kHigh:
+ case stdAc::swingv_t::kMiddle:
+ case stdAc::swingv_t::kLow:
+ case stdAc::swingv_t::kLowest:
+ return kMitsubishiAcVaneAutoMove;
+ default:
+ return kMitsubishiAcVaneAuto;
+ }
+}
+
#ifdef ARDUINO
String IRMitsubishiAC::timeToString(uint64_t time) {
String result = "";
@@ -622,10 +668,10 @@ String IRMitsubishiAC::timeToString(uint64_t time) {
std::string IRMitsubishiAC::timeToString(uint64_t time) {
std::string result = "";
#endif // ARDUINO
- if (time / 6 < 10) result += "0";
+ if (time / 6 < 10) result += '0';
result += uint64ToString(time / 6);
- result += ":";
- if (time * 10 % 60 < 10) result += "0";
+ result += ':';
+ if (time * 10 % 60 < 10) result += '0';
result += uint64ToString(time * 10 % 60);
return result;
}
@@ -638,77 +684,78 @@ String IRMitsubishiAC::toString() {
std::string IRMitsubishiAC::toString() {
std::string result = "";
#endif // ARDUINO
- result += "Power: ";
+ result += F("Power: ");
if (getPower())
- result += "On";
+ result += F("On");
else
- result += "Off";
+ result += F("Off");
switch (getMode()) {
case MITSUBISHI_AC_AUTO:
- result += " (AUTO)";
+ result += F(" (AUTO)");
break;
case MITSUBISHI_AC_COOL:
- result += " (COOL)";
+ result += F(" (COOL)");
break;
case MITSUBISHI_AC_DRY:
- result += " (DRY)";
+ result += F(" (DRY)");
break;
case MITSUBISHI_AC_HEAT:
- result += " (HEAT)";
+ result += F(" (HEAT)");
break;
default:
- result += " (UNKNOWN)";
+ result += F(" (UNKNOWN)");
}
- result += ", Temp: " + uint64ToString(getTemp()) + "C";
- result += ", FAN: ";
+ result += F(", Temp: ");
+ result += uint64ToString(getTemp());
+ result += F("C, FAN: ");
switch (getFan()) {
case MITSUBISHI_AC_FAN_AUTO:
- result += "AUTO";
+ result += F("AUTO");
break;
case MITSUBISHI_AC_FAN_MAX:
- result += "MAX";
+ result += F("MAX");
break;
case MITSUBISHI_AC_FAN_SILENT:
- result += "SILENT";
+ result += F("SILENT");
break;
default:
result += uint64ToString(getFan());
}
- result += ", VANE: ";
+ result += F(", VANE: ");
switch (getVane()) {
case MITSUBISHI_AC_VANE_AUTO:
- result += "AUTO";
+ result += F("AUTO");
break;
case MITSUBISHI_AC_VANE_AUTO_MOVE:
- result += "AUTO MOVE";
+ result += F("AUTO MOVE");
break;
default:
result += uint64ToString(getVane());
}
- result += ", Time: ";
+ result += F(", Time: ");
result += timeToString(getClock());
- result += ", On timer: ";
+ result += F(", On timer: ");
result += timeToString(getStartClock());
- result += ", Off timer: ";
+ result += F(", Off timer: ");
result += timeToString(getStopClock());
- result += ", Timer: ";
+ result += F(", Timer: ");
switch (getTimer()) {
case kMitsubishiAcNoTimer:
- result += "-";
+ result += '-';
break;
case kMitsubishiAcStartTimer:
- result += "Start";
+ result += F("Start");
break;
case kMitsubishiAcStopTimer:
- result += "Stop";
+ result += F("Stop");
break;
case kMitsubishiAcStartStopTimer:
- result += "Start+Stop";
+ result += F("Start+Stop");
break;
default:
- result += "? (";
+ result += F("? (");
result += getTimer();
- result += ")\n";
+ result += F(")\n");
}
return result;
}
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_Mitsubishi.h b/lib/IRremoteESP8266-2.6.0/src/ir_Mitsubishi.h
similarity index 91%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_Mitsubishi.h
rename to lib/IRremoteESP8266-2.6.0/src/ir_Mitsubishi.h
index 7b03efce6..c8dca5dbc 100644
--- a/lib/IRremoteESP8266-2.5.2.03/src/ir_Mitsubishi.h
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_Mitsubishi.h
@@ -12,6 +12,9 @@
#endif
#include "IRremoteESP8266.h"
#include "IRsend.h"
+#ifdef UNIT_TEST
+#include "IRsend_test.h"
+#endif
// MMMMM IIIII TTTTT SSSS U U BBBB IIIII SSSS H H IIIII
// M M M I T S U U B B I S H H I
@@ -64,7 +67,7 @@ class IRMitsubishiAC {
void stateReset();
#if SEND_MITSUBISHI_AC
- void send();
+ void send(const uint16_t repeat = kMitsubishiACMinRepeat);
#endif // SEND_MITSUBISHI_AC
void begin();
void on();
@@ -89,13 +92,21 @@ class IRMitsubishiAC {
void setStopClock(uint8_t clock);
uint8_t getTimer();
void setTimer(uint8_t timer);
+ uint8_t convertMode(const stdAc::opmode_t mode);
+ uint8_t convertFan(const stdAc::fanspeed_t speed);
+ uint8_t convertSwingV(const stdAc::swingv_t position);
#ifdef ARDUINO
String toString();
#else
std::string toString();
#endif
+#ifndef UNIT_TEST
private:
+ IRsend _irsend;
+#else
+ IRsendTest _irsend;
+#endif
#ifdef ARDUINO
String timeToString(uint64_t time);
#else
@@ -103,7 +114,6 @@ class IRMitsubishiAC {
#endif
uint8_t remote_state[kMitsubishiACStateLength];
void checksum();
- IRsend _irsend;
};
#endif // IR_MITSUBISHI_H_
diff --git a/lib/IRremoteESP8266-2.6.0/src/ir_MitsubishiHeavy.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_MitsubishiHeavy.cpp
new file mode 100644
index 000000000..9048124d4
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_MitsubishiHeavy.cpp
@@ -0,0 +1,1014 @@
+// Copyright 2019 David Conran
+// Mitsubishi Heavy Industries A/C remote emulation.
+
+// Code to emulate Mitsubishi Heavy Industries A/C IR remote control units,
+// which should control at least the following A/C units:
+// Remote Control RLA502A700B:
+// Model SRKxxZM-S
+// Model SRKxxZMXA-S
+// Remote Control RKX502A001C:
+// Model SRKxxZJ-S
+
+// Note: This code was *heavily* influenced by @ToniA's great work & code,
+// but it has been written from scratch.
+// Nothing was copied other than constants and message analysis.
+
+#include "ir_MitsubishiHeavy.h"
+#include
+#include "IRremoteESP8266.h"
+#include "IRutils.h"
+#ifndef ARDUINO
+#include
+#endif
+
+// Ref:
+// https://github.com/markszabo/IRremoteESP8266/issues/660
+// https://github.com/ToniA/Raw-IR-decoder-for-Arduino/blob/master/MitsubishiHeavy.cpp
+// https://github.com/ToniA/arduino-heatpumpir/blob/master/MitsubishiHeavyHeatpumpIR.cpp
+
+// Constants
+const uint16_t kMitsubishiHeavyHdrMark = 3140;
+const uint16_t kMitsubishiHeavyHdrSpace = 1630;
+const uint16_t kMitsubishiHeavyBitMark = 370;
+const uint16_t kMitsubishiHeavyOneSpace = 420;
+const uint16_t kMitsubishiHeavyZeroSpace = 1220;
+const uint32_t kMitsubishiHeavyGap = kDefaultMessageGap; // Just a guess.
+
+#if SEND_MITSUBISHIHEAVY
+// Send a MitsubishiHeavy 88 bit A/C message.
+//
+// Args:
+// data: Contents of the message to be sent.
+// nbits: Nr. of bits of data to be sent. Typically kMitsubishiHeavy88Bits.
+// repeat: Nr. of additional times the message is to be sent.
+//
+// Status: BETA / Appears to be working. Needs testing against a real device.
+void IRsend::sendMitsubishiHeavy88(const unsigned char data[],
+ const uint16_t nbytes,
+ const uint16_t repeat) {
+ if (nbytes < kMitsubishiHeavy88StateLength)
+ return; // Not enough bytes to send a proper message.
+ sendGeneric(kMitsubishiHeavyHdrMark, kMitsubishiHeavyHdrSpace,
+ kMitsubishiHeavyBitMark, kMitsubishiHeavyOneSpace,
+ kMitsubishiHeavyBitMark, kMitsubishiHeavyZeroSpace,
+ kMitsubishiHeavyBitMark, kMitsubishiHeavyGap,
+ data, nbytes, 38000, false, repeat, kDutyDefault);
+}
+
+// Send a MitsubishiHeavy 152 bit A/C message.
+//
+// Args:
+// data: Contents of the message to be sent.
+// nbits: Nr. of bits of data to be sent. Typically kMitsubishiHeavy152Bits.
+// repeat: Nr. of additional times the message is to be sent.
+//
+// Status: BETA / Appears to be working. Needs testing against a real device.
+void IRsend::sendMitsubishiHeavy152(const unsigned char data[],
+ const uint16_t nbytes,
+ const uint16_t repeat) {
+ if (nbytes < kMitsubishiHeavy152StateLength)
+ return; // Not enough bytes to send a proper message.
+ sendMitsubishiHeavy88(data, nbytes, repeat);
+}
+#endif // SEND_MITSUBISHIHEAVY
+
+// Class for decoding and constructing MitsubishiHeavy152 AC messages.
+IRMitsubishiHeavy152Ac::IRMitsubishiHeavy152Ac(
+ const uint16_t pin) : _irsend(pin) { stateReset(); }
+
+void IRMitsubishiHeavy152Ac::begin() { _irsend.begin(); }
+
+#if SEND_MITSUBISHIHEAVY
+void IRMitsubishiHeavy152Ac::send(const uint16_t repeat) {
+ _irsend.sendMitsubishiHeavy152(this->getRaw(), kMitsubishiHeavy152StateLength,
+ repeat);
+}
+#endif // SEND_MITSUBISHIHEAVY
+
+void IRMitsubishiHeavy152Ac::stateReset(void) {
+ uint8_t i = 0;
+ for (; i < kMitsubishiHeavySigLength; i++)
+ remote_state[i] = kMitsubishiHeavyZmsSig[i];
+ for (; i < kMitsubishiHeavy152StateLength - 3; i += 2) remote_state[i] = 0;
+ remote_state[17] = 0x80;
+}
+
+uint8_t *IRMitsubishiHeavy152Ac::getRaw(void) {
+ checksum();
+ return remote_state;
+}
+
+void IRMitsubishiHeavy152Ac::setRaw(const uint8_t *data) {
+ for (uint8_t i = 0; i < kMitsubishiHeavy152StateLength; i++)
+ remote_state[i] = data[i];
+}
+
+void IRMitsubishiHeavy152Ac::on(void) {
+ remote_state[5] |= kMitsubishiHeavyPowerBit;
+}
+
+void IRMitsubishiHeavy152Ac::off(void) {
+ remote_state[5] &= ~kMitsubishiHeavyPowerBit;
+}
+
+void IRMitsubishiHeavy152Ac::setPower(const bool on) {
+ if (on)
+ this->on();
+ else
+ this->off();
+}
+
+bool IRMitsubishiHeavy152Ac::getPower(void) {
+ return remote_state[5] & kMitsubishiHeavyPowerBit;
+}
+
+void IRMitsubishiHeavy152Ac::setTemp(const uint8_t temp) {
+ uint8_t newtemp = temp;
+ newtemp = std::min(newtemp, kMitsubishiHeavyMaxTemp);
+ newtemp = std::max(newtemp, kMitsubishiHeavyMinTemp);
+
+ remote_state[7] &= ~kMitsubishiHeavyTempMask;
+ remote_state[7] |= newtemp - kMitsubishiHeavyMinTemp;
+}
+
+uint8_t IRMitsubishiHeavy152Ac::getTemp(void) {
+ return (remote_state[7] & kMitsubishiHeavyTempMask) + kMitsubishiHeavyMinTemp;
+}
+
+// Set the speed of the fan
+void IRMitsubishiHeavy152Ac::setFan(const uint8_t speed) {
+ uint8_t newspeed = speed;
+ switch (speed) {
+ case kMitsubishiHeavy152FanLow:
+ case kMitsubishiHeavy152FanMed:
+ case kMitsubishiHeavy152FanHigh:
+ case kMitsubishiHeavy152FanMax:
+ case kMitsubishiHeavy152FanEcono:
+ case kMitsubishiHeavy152FanTurbo:
+ break;
+ default:
+ newspeed = kMitsubishiHeavy152FanAuto;
+ }
+ remote_state[9] &= ~kMitsubishiHeavyFanMask;
+ remote_state[9] |= newspeed;
+}
+
+uint8_t IRMitsubishiHeavy152Ac::getFan(void) {
+ return remote_state[9] & kMitsubishiHeavyFanMask;
+}
+
+void IRMitsubishiHeavy152Ac::setMode(const uint8_t mode) {
+ uint8_t newmode = mode;
+ switch (mode) {
+ case kMitsubishiHeavyCool:
+ case kMitsubishiHeavyDry:
+ case kMitsubishiHeavyFan:
+ case kMitsubishiHeavyHeat:
+ break;
+ default:
+ newmode = kMitsubishiHeavyAuto;
+ }
+ remote_state[5] &= ~kMitsubishiHeavyModeMask;
+ remote_state[5] |= newmode;
+}
+
+uint8_t IRMitsubishiHeavy152Ac::getMode(void) {
+ return remote_state[5] & kMitsubishiHeavyModeMask;
+}
+
+void IRMitsubishiHeavy152Ac::setSwingVertical(const uint8_t pos) {
+ uint8_t newpos = std::min(pos, kMitsubishiHeavy152SwingVOff);
+ remote_state[11] &= ~kMitsubishiHeavy152SwingVMask;
+ remote_state[11] |= (newpos << 5);
+}
+
+uint8_t IRMitsubishiHeavy152Ac::getSwingVertical(void) {
+ return remote_state[11] >> 5;
+}
+
+void IRMitsubishiHeavy152Ac::setSwingHorizontal(const uint8_t pos) {
+ uint8_t newpos = std::min(pos, kMitsubishiHeavy152SwingHOff);
+ remote_state[13] &= ~kMitsubishiHeavy152SwingHMask;
+ remote_state[13] |= (newpos & kMitsubishiHeavy152SwingHMask);
+}
+
+uint8_t IRMitsubishiHeavy152Ac::getSwingHorizontal(void) {
+ return remote_state[13] & kMitsubishiHeavy152SwingHMask;
+}
+
+void IRMitsubishiHeavy152Ac::setNight(const bool on) {
+ if (on)
+ remote_state[15] |= kMitsubishiHeavyNightBit;
+ else
+ remote_state[15] &= ~kMitsubishiHeavyNightBit;
+}
+
+bool IRMitsubishiHeavy152Ac::getNight(void) {
+ return remote_state[15] & kMitsubishiHeavyNightBit;
+}
+
+void IRMitsubishiHeavy152Ac::set3D(const bool on) {
+ if (on)
+ remote_state[11] |= kMitsubishiHeavy3DMask;
+ else
+ remote_state[11] &= ~kMitsubishiHeavy3DMask;
+}
+
+bool IRMitsubishiHeavy152Ac::get3D(void) {
+ return (remote_state[11] & kMitsubishiHeavy3DMask) == kMitsubishiHeavy3DMask;
+}
+
+void IRMitsubishiHeavy152Ac::setSilent(const bool on) {
+ if (on)
+ remote_state[15] |= kMitsubishiHeavySilentBit;
+ else
+ remote_state[15] &= ~kMitsubishiHeavySilentBit;
+}
+
+bool IRMitsubishiHeavy152Ac::getSilent(void) {
+ return remote_state[15] & kMitsubishiHeavySilentBit;
+}
+
+void IRMitsubishiHeavy152Ac::setFilter(const bool on) {
+ if (on)
+ remote_state[5] |= kMitsubishiHeavyFilterBit;
+ else
+ remote_state[5] &= ~kMitsubishiHeavyFilterBit;
+}
+
+bool IRMitsubishiHeavy152Ac::getFilter(void) {
+ return remote_state[5] & kMitsubishiHeavyFilterBit;
+}
+
+void IRMitsubishiHeavy152Ac::setClean(const bool on) {
+ this->setFilter(on);
+ if (on)
+ remote_state[5] |= kMitsubishiHeavyCleanBit;
+ else
+ remote_state[5] &= ~kMitsubishiHeavyCleanBit;
+}
+
+bool IRMitsubishiHeavy152Ac::getClean(void) {
+ return remote_state[5] & kMitsubishiHeavyCleanBit && this->getFilter();
+}
+
+void IRMitsubishiHeavy152Ac::setTurbo(const bool on) {
+ if (on)
+ this->setFan(kMitsubishiHeavy152FanTurbo);
+ else if (this->getTurbo()) this->setFan(kMitsubishiHeavy152FanAuto);
+}
+
+bool IRMitsubishiHeavy152Ac::getTurbo(void) {
+ return this->getFan() == kMitsubishiHeavy152FanTurbo;
+}
+
+void IRMitsubishiHeavy152Ac::setEcono(const bool on) {
+ if (on)
+ this->setFan(kMitsubishiHeavy152FanEcono);
+ else if (this->getEcono()) this->setFan(kMitsubishiHeavy152FanAuto);
+}
+
+bool IRMitsubishiHeavy152Ac::getEcono(void) {
+ return this->getFan() == kMitsubishiHeavy152FanEcono;
+}
+
+// Verify the given state has a ZM-S signature.
+bool IRMitsubishiHeavy152Ac::checkZmsSig(const uint8_t *state) {
+ for (uint8_t i = 0; i < kMitsubishiHeavySigLength; i++)
+ if (state[i] != kMitsubishiHeavyZmsSig[i]) return false;
+ return true;
+}
+
+// Protocol technically has no checksum, but does has inverted byte pairs.
+void IRMitsubishiHeavy152Ac::checksum(void) {
+ for (uint8_t i = kMitsubishiHeavySigLength - 2;
+ i < kMitsubishiHeavy152StateLength;
+ i += 2) {
+ remote_state[i + 1] = ~remote_state[i];
+ }
+}
+
+// Protocol technically has no checksum, but does has inverted byte pairs.
+bool IRMitsubishiHeavy152Ac::validChecksum(const uint8_t *state,
+ const uint16_t length) {
+ // Assume anything too short is fine.
+ if (length < kMitsubishiHeavySigLength) return true;
+ // Check all the byte pairs.
+ for (uint16_t i = kMitsubishiHeavySigLength - 2;
+ i < length;
+ i += 2) {
+ // XOR of a byte and it's self inverted should be 0xFF;
+ if ((state[i] ^ state[i + 1]) != 0xFF) return false;
+ }
+ return true;
+}
+
+
+// Convert a standard A/C mode into its native mode.
+uint8_t IRMitsubishiHeavy152Ac::convertMode(const stdAc::opmode_t mode) {
+ switch (mode) {
+ case stdAc::opmode_t::kCool:
+ return kMitsubishiHeavyCool;
+ case stdAc::opmode_t::kHeat:
+ return kMitsubishiHeavyHeat;
+ case stdAc::opmode_t::kDry:
+ return kMitsubishiHeavyDry;
+ case stdAc::opmode_t::kFan:
+ return kMitsubishiHeavyFan;
+ default:
+ return kMitsubishiHeavyAuto;
+ }
+}
+
+// Convert a standard A/C Fan speed into its native fan speed.
+uint8_t IRMitsubishiHeavy152Ac::convertFan(const stdAc::fanspeed_t speed) {
+ switch (speed) {
+ case stdAc::fanspeed_t::kMin:
+ return kMitsubishiHeavy152FanEcono; // Assumes Econo is slower than Low.
+ case stdAc::fanspeed_t::kLow:
+ return kMitsubishiHeavy152FanLow;
+ case stdAc::fanspeed_t::kMedium:
+ return kMitsubishiHeavy152FanMed;
+ case stdAc::fanspeed_t::kHigh:
+ return kMitsubishiHeavy152FanHigh;
+ case stdAc::fanspeed_t::kMax:
+ return kMitsubishiHeavy152FanMax;
+ default:
+ return kMitsubishiHeavy152FanAuto;
+ }
+}
+
+// Convert a standard A/C vertical swing into its native setting.
+uint8_t IRMitsubishiHeavy152Ac::convertSwingV(const stdAc::swingv_t position) {
+ switch (position) {
+ case stdAc::swingv_t::kAuto:
+ return kMitsubishiHeavy152SwingVAuto;
+ case stdAc::swingv_t::kHighest:
+ return kMitsubishiHeavy152SwingVHighest;
+ case stdAc::swingv_t::kHigh:
+ return kMitsubishiHeavy152SwingVHigh;
+ case stdAc::swingv_t::kMiddle:
+ return kMitsubishiHeavy152SwingVMiddle;
+ case stdAc::swingv_t::kLow:
+ return kMitsubishiHeavy152SwingVLow;
+ case stdAc::swingv_t::kLowest:
+ return kMitsubishiHeavy152SwingVLowest;
+ default:
+ return kMitsubishiHeavy152SwingVOff;
+ }
+}
+
+// Convert a standard A/C horizontal swing into its native setting.
+uint8_t IRMitsubishiHeavy152Ac::convertSwingH(const stdAc::swingh_t position) {
+ switch (position) {
+ case stdAc::swingh_t::kAuto:
+ return kMitsubishiHeavy152SwingHAuto;
+ case stdAc::swingh_t::kLeftMax:
+ return kMitsubishiHeavy152SwingHLeftMax;
+ case stdAc::swingh_t::kLeft:
+ return kMitsubishiHeavy152SwingHLeft;
+ case stdAc::swingh_t::kMiddle:
+ return kMitsubishiHeavy152SwingHMiddle;
+ case stdAc::swingh_t::kRight:
+ return kMitsubishiHeavy152SwingHRight;
+ case stdAc::swingh_t::kRightMax:
+ return kMitsubishiHeavy152SwingHRightMax;
+ default:
+ return kMitsubishiHeavy152SwingHOff;
+ }
+}
+
+// Convert the internal state into a human readable string.
+#ifdef ARDUINO
+String IRMitsubishiHeavy152Ac::toString(void) {
+ String result = "";
+#else
+std::string IRMitsubishiHeavy152Ac::toString(void) {
+ std::string result = "";
+#endif // ARDUINO
+ result += F("Power: ");
+ result += (this->getPower() ? F("On") : F("Off"));
+ result += F(", Mode: ");
+ result += uint64ToString(this->getMode());
+ switch (this->getMode()) {
+ case kMitsubishiHeavyAuto:
+ result += F(" (Auto)");
+ break;
+ case kMitsubishiHeavyCool:
+ result += F(" (Cool)");
+ break;
+ case kMitsubishiHeavyHeat:
+ result += F(" (Heat)");
+ break;
+ case kMitsubishiHeavyDry:
+ result += F(" (Dry)");
+ break;
+ case kMitsubishiHeavyFan:
+ result += F(" (Fan)");
+ break;
+ default:
+ result += F(" (UNKNOWN)");
+ }
+ result += F(", Temp: ");
+ result += uint64ToString(this->getTemp()) + 'C';
+ result += F(", Fan: ");
+ result += uint64ToString(this->getFan());
+ switch (this->getFan()) {
+ case kMitsubishiHeavy152FanAuto:
+ result += F(" (Auto)");
+ break;
+ case kMitsubishiHeavy152FanHigh:
+ result += F(" (High)");
+ break;
+ case kMitsubishiHeavy152FanLow:
+ result += F(" (Low)");
+ break;
+ case kMitsubishiHeavy152FanMed:
+ result += F(" (Med)");
+ break;
+ case kMitsubishiHeavy152FanMax:
+ result += F(" (Max)");
+ break;
+ case kMitsubishiHeavy152FanEcono:
+ result += F(" (Econo)");
+ break;
+ case kMitsubishiHeavy152FanTurbo:
+ result += F(" (Turbo)");
+ break;
+ default:
+ result += F(" (UNKNOWN)");
+ }
+ result += F(", Swing (V): ");
+ result += uint64ToString(this->getSwingVertical());
+ switch (this->getSwingVertical()) {
+ case kMitsubishiHeavy152SwingVAuto:
+ result += F(" (Auto)");
+ break;
+ case kMitsubishiHeavy152SwingVHighest:
+ result += F(" (Highest)");
+ break;
+ case kMitsubishiHeavy152SwingVHigh:
+ result += F(" (High)");
+ break;
+ case kMitsubishiHeavy152SwingVMiddle:
+ result += F(" (Middle)");
+ break;
+ case kMitsubishiHeavy152SwingVLow:
+ result += F(" (Low)");
+ break;
+ case kMitsubishiHeavy152SwingVLowest:
+ result += F(" (Lowest)");
+ break;
+ case kMitsubishiHeavy152SwingVOff:
+ result += F(" (Off)");
+ break;
+ default:
+ result += F(" (UNKNOWN)");
+ }
+ result += F(", Swing (H): ");
+ result += uint64ToString(this->getSwingHorizontal());
+ switch (this->getSwingHorizontal()) {
+ case kMitsubishiHeavy152SwingHAuto:
+ result += F(" (Auto)");
+ break;
+ case kMitsubishiHeavy152SwingHLeftMax:
+ result += F(" (Max Left)");
+ break;
+ case kMitsubishiHeavy152SwingHLeft:
+ result += F(" (Left)");
+ break;
+ case kMitsubishiHeavy152SwingHMiddle:
+ result += F(" (Middle)");
+ break;
+ case kMitsubishiHeavy152SwingHRight:
+ result += F(" (Right)");
+ break;
+ case kMitsubishiHeavy152SwingHRightMax:
+ result += F(" (Max Right)");
+ break;
+ case kMitsubishiHeavy152SwingHLeftRight:
+ result += F(" (Left Right)");
+ break;
+ case kMitsubishiHeavy152SwingHRightLeft:
+ result += F(" (Right Left)");
+ break;
+ case kMitsubishiHeavy152SwingHOff:
+ result += F(" (Off)");
+ break;
+ default:
+ result += F(" (UNKNOWN)");
+ }
+ result += F(", Silent: ");
+ result += (this->getSilent() ? F("On") : F("Off"));
+ result += F(", Turbo: ");
+ result += (this->getTurbo() ? F("On") : F("Off"));
+ result += F(", Econo: ");
+ result += (this->getEcono() ? F("On") : F("Off"));
+ result += F(", Night: ");
+ result += (this->getNight() ? F("On") : F("Off"));
+ result += F(", Filter: ");
+ result += (this->getFilter() ? F("On") : F("Off"));
+ result += F(", 3D: ");
+ result += (this->get3D() ? F("On") : F("Off"));
+ result += F(", Clean: ");
+ result += (this->getClean() ? F("On") : F("Off"));
+ return result;
+}
+
+
+// Class for decoding and constructing MitsubishiHeavy88 AC messages.
+IRMitsubishiHeavy88Ac::IRMitsubishiHeavy88Ac(
+ const uint16_t pin) : _irsend(pin) { stateReset(); }
+
+void IRMitsubishiHeavy88Ac::begin() { _irsend.begin(); }
+
+#if SEND_MITSUBISHIHEAVY
+void IRMitsubishiHeavy88Ac::send(const uint16_t repeat) {
+ _irsend.sendMitsubishiHeavy88(this->getRaw(), kMitsubishiHeavy88StateLength,
+ repeat);
+}
+#endif // SEND_MITSUBISHIHEAVY
+
+void IRMitsubishiHeavy88Ac::stateReset(void) {
+ uint8_t i = 0;
+ for (; i < kMitsubishiHeavySigLength; i++)
+ remote_state[i] = kMitsubishiHeavyZjsSig[i];
+ for (; i < kMitsubishiHeavy88StateLength; i++) remote_state[i] = 0;
+}
+
+uint8_t *IRMitsubishiHeavy88Ac::getRaw(void) {
+ checksum();
+ return remote_state;
+}
+
+void IRMitsubishiHeavy88Ac::setRaw(const uint8_t *data) {
+ for (uint8_t i = 0; i < kMitsubishiHeavy88StateLength; i++)
+ remote_state[i] = data[i];
+}
+
+void IRMitsubishiHeavy88Ac::on(void) {
+ remote_state[9] |= kMitsubishiHeavyPowerBit;
+}
+
+void IRMitsubishiHeavy88Ac::off(void) {
+ remote_state[9] &= ~kMitsubishiHeavyPowerBit;
+}
+
+void IRMitsubishiHeavy88Ac::setPower(const bool on) {
+ if (on)
+ this->on();
+ else
+ this->off();
+}
+
+bool IRMitsubishiHeavy88Ac::getPower(void) {
+ return remote_state[9] & kMitsubishiHeavyPowerBit;
+}
+
+void IRMitsubishiHeavy88Ac::setTemp(const uint8_t temp) {
+ uint8_t newtemp = temp;
+ newtemp = std::min(newtemp, kMitsubishiHeavyMaxTemp);
+ newtemp = std::max(newtemp, kMitsubishiHeavyMinTemp);
+
+ remote_state[9] &= kMitsubishiHeavyTempMask;
+ remote_state[9] |= ((newtemp - kMitsubishiHeavyMinTemp) << 4);
+}
+
+uint8_t IRMitsubishiHeavy88Ac::getTemp(void) {
+ return (remote_state[9] >> 4) + kMitsubishiHeavyMinTemp;
+}
+
+// Set the speed of the fan
+void IRMitsubishiHeavy88Ac::setFan(const uint8_t speed) {
+ uint8_t newspeed = speed;
+ switch (speed) {
+ case kMitsubishiHeavy88FanLow:
+ case kMitsubishiHeavy88FanMed:
+ case kMitsubishiHeavy88FanHigh:
+ case kMitsubishiHeavy88FanTurbo:
+ case kMitsubishiHeavy88FanEcono:
+ break;
+ default:
+ newspeed = kMitsubishiHeavy88FanAuto;
+ }
+ remote_state[7] &= ~kMitsubishiHeavy88FanMask;
+ remote_state[7] |= (newspeed << 5);
+}
+
+uint8_t IRMitsubishiHeavy88Ac::getFan(void) {
+ return remote_state[7] >> 5;
+}
+
+void IRMitsubishiHeavy88Ac::setMode(const uint8_t mode) {
+ uint8_t newmode = mode;
+ switch (mode) {
+ case kMitsubishiHeavyCool:
+ case kMitsubishiHeavyDry:
+ case kMitsubishiHeavyFan:
+ case kMitsubishiHeavyHeat:
+ break;
+ default:
+ newmode = kMitsubishiHeavyAuto;
+ }
+ remote_state[9] &= ~kMitsubishiHeavyModeMask;
+ remote_state[9] |= newmode;
+}
+
+uint8_t IRMitsubishiHeavy88Ac::getMode(void) {
+ return remote_state[9] & kMitsubishiHeavyModeMask;
+}
+
+void IRMitsubishiHeavy88Ac::setSwingVertical(const uint8_t pos) {
+ uint8_t newpos;
+ switch (pos) {
+ case kMitsubishiHeavy88SwingVAuto:
+ case kMitsubishiHeavy88SwingVHighest:
+ case kMitsubishiHeavy88SwingVHigh:
+ case kMitsubishiHeavy88SwingVMiddle:
+ case kMitsubishiHeavy88SwingVLow:
+ case kMitsubishiHeavy88SwingVLowest:
+ newpos = pos;
+ break;
+ default:
+ newpos = kMitsubishiHeavy88SwingVOff;
+ }
+ remote_state[5] &= ~kMitsubishiHeavy88SwingVMaskByte5;
+ remote_state[5] |= (newpos & kMitsubishiHeavy88SwingVMaskByte5);
+ remote_state[7] &= ~kMitsubishiHeavy88SwingVMaskByte7;
+ remote_state[7] |= (newpos & kMitsubishiHeavy88SwingVMaskByte7);
+}
+
+uint8_t IRMitsubishiHeavy88Ac::getSwingVertical(void) {
+ return (remote_state[5] & kMitsubishiHeavy88SwingVMaskByte5) |
+ (remote_state[7] & kMitsubishiHeavy88SwingVMaskByte7);
+}
+
+void IRMitsubishiHeavy88Ac::setSwingHorizontal(const uint8_t pos) {
+ uint8_t newpos;
+ switch (pos) {
+ case kMitsubishiHeavy88SwingHAuto:
+ case kMitsubishiHeavy88SwingHLeftMax:
+ case kMitsubishiHeavy88SwingHLeft:
+ case kMitsubishiHeavy88SwingHMiddle:
+ case kMitsubishiHeavy88SwingHRight:
+ case kMitsubishiHeavy88SwingHRightMax:
+ case kMitsubishiHeavy88SwingHLeftRight:
+ case kMitsubishiHeavy88SwingHRightLeft:
+ case kMitsubishiHeavy88SwingH3D:
+ newpos = pos;
+ break;
+ default:
+ newpos = kMitsubishiHeavy88SwingHOff;
+ }
+ remote_state[5] &= ~kMitsubishiHeavy88SwingHMask;
+ remote_state[5] |= newpos;
+}
+
+uint8_t IRMitsubishiHeavy88Ac::getSwingHorizontal(void) {
+ return remote_state[5] & kMitsubishiHeavy88SwingHMask;
+}
+
+void IRMitsubishiHeavy88Ac::setTurbo(const bool on) {
+ if (on)
+ this->setFan(kMitsubishiHeavy88FanTurbo);
+ else if (this->getTurbo()) this->setFan(kMitsubishiHeavy88FanAuto);
+}
+
+bool IRMitsubishiHeavy88Ac::getTurbo(void) {
+ return this->getFan() == kMitsubishiHeavy88FanTurbo;
+}
+
+void IRMitsubishiHeavy88Ac::setEcono(const bool on) {
+ if (on)
+ this->setFan(kMitsubishiHeavy88FanEcono);
+ else if (this->getEcono()) this->setFan(kMitsubishiHeavy88FanAuto);
+}
+
+bool IRMitsubishiHeavy88Ac::getEcono(void) {
+ return this->getFan() == kMitsubishiHeavy88FanEcono;
+}
+
+void IRMitsubishiHeavy88Ac::set3D(const bool on) {
+ if (on)
+ this->setSwingHorizontal(kMitsubishiHeavy88SwingH3D);
+ else if (this->get3D())
+ this->setSwingHorizontal(kMitsubishiHeavy88SwingHOff);
+}
+
+bool IRMitsubishiHeavy88Ac::get3D(void) {
+ return this->getSwingHorizontal() == kMitsubishiHeavy88SwingH3D;
+}
+
+void IRMitsubishiHeavy88Ac::setClean(const bool on) {
+ if (on)
+ remote_state[5] |= kMitsubishiHeavy88CleanBit;
+ else
+ remote_state[5] &= ~kMitsubishiHeavy88CleanBit;
+}
+
+bool IRMitsubishiHeavy88Ac::getClean(void) {
+ return remote_state[5] & kMitsubishiHeavy88CleanBit;
+}
+
+// Verify the given state has a ZJ-S signature.
+bool IRMitsubishiHeavy88Ac::checkZjsSig(const uint8_t *state) {
+ for (uint8_t i = 0; i < kMitsubishiHeavySigLength; i++)
+ if (state[i] != kMitsubishiHeavyZjsSig[i]) return false;
+ return true;
+}
+
+// Protocol technically has no checksum, but does has inverted byte pairs.
+void IRMitsubishiHeavy88Ac::checksum(void) {
+ for (uint8_t i = kMitsubishiHeavySigLength - 2;
+ i < kMitsubishiHeavy88StateLength;
+ i += 2) {
+ remote_state[i + 1] = ~remote_state[i];
+ }
+}
+
+// Protocol technically has no checksum, but does has inverted byte pairs.
+bool IRMitsubishiHeavy88Ac::validChecksum(const uint8_t *state,
+ const uint16_t length) {
+ return IRMitsubishiHeavy152Ac::validChecksum(state, length);
+}
+
+// Convert a standard A/C mode into its native mode.
+uint8_t IRMitsubishiHeavy88Ac::convertMode(const stdAc::opmode_t mode) {
+ return IRMitsubishiHeavy152Ac::convertMode(mode);
+}
+
+
+// Convert a standard A/C Fan speed into its native fan speed.
+uint8_t IRMitsubishiHeavy88Ac::convertFan(const stdAc::fanspeed_t speed) {
+ switch (speed) {
+ case stdAc::fanspeed_t::kMin:
+ return kMitsubishiHeavy88FanEcono; // Assumes Econo is slower than Low.
+ case stdAc::fanspeed_t::kLow:
+ return kMitsubishiHeavy88FanLow;
+ case stdAc::fanspeed_t::kMedium:
+ return kMitsubishiHeavy88FanMed;
+ case stdAc::fanspeed_t::kHigh:
+ return kMitsubishiHeavy88FanHigh;
+ case stdAc::fanspeed_t::kMax:
+ return kMitsubishiHeavy88FanTurbo;
+ default:
+ return kMitsubishiHeavy88FanAuto;
+ }
+}
+
+// Convert a standard A/C vertical swing into its native setting.
+uint8_t IRMitsubishiHeavy88Ac::convertSwingV(const stdAc::swingv_t position) {
+ switch (position) {
+ case stdAc::swingv_t::kAuto:
+ return kMitsubishiHeavy88SwingVAuto;
+ case stdAc::swingv_t::kHighest:
+ return kMitsubishiHeavy88SwingVHighest;
+ case stdAc::swingv_t::kHigh:
+ return kMitsubishiHeavy88SwingVHigh;
+ case stdAc::swingv_t::kMiddle:
+ return kMitsubishiHeavy88SwingVMiddle;
+ case stdAc::swingv_t::kLow:
+ return kMitsubishiHeavy88SwingVLow;
+ case stdAc::swingv_t::kLowest:
+ return kMitsubishiHeavy88SwingVLowest;
+ default:
+ return kMitsubishiHeavy88SwingVOff;
+ }
+}
+
+// Convert a standard A/C horizontal swing into its native setting.
+uint8_t IRMitsubishiHeavy88Ac::convertSwingH(const stdAc::swingh_t position) {
+ switch (position) {
+ case stdAc::swingh_t::kAuto:
+ return kMitsubishiHeavy88SwingHAuto;
+ case stdAc::swingh_t::kLeftMax:
+ return kMitsubishiHeavy88SwingHLeftMax;
+ case stdAc::swingh_t::kLeft:
+ return kMitsubishiHeavy88SwingHLeft;
+ case stdAc::swingh_t::kMiddle:
+ return kMitsubishiHeavy88SwingHMiddle;
+ case stdAc::swingh_t::kRight:
+ return kMitsubishiHeavy88SwingHRight;
+ case stdAc::swingh_t::kRightMax:
+ return kMitsubishiHeavy88SwingHRightMax;
+ default:
+ return kMitsubishiHeavy88SwingHOff;
+ }
+}
+
+// Convert the internal state into a human readable string.
+#ifdef ARDUINO
+String IRMitsubishiHeavy88Ac::toString(void) {
+ String result = "";
+#else
+std::string IRMitsubishiHeavy88Ac::toString(void) {
+ std::string result = "";
+#endif // ARDUINO
+ result += F("Power: ");
+ result += (this->getPower() ? F("On") : F("Off"));
+ result += F(", Mode: ");
+ result += uint64ToString(this->getMode());
+ switch (this->getMode()) {
+ case kMitsubishiHeavyAuto:
+ result += F(" (Auto)");
+ break;
+ case kMitsubishiHeavyCool:
+ result += F(" (Cool)");
+ break;
+ case kMitsubishiHeavyHeat:
+ result += F(" (Heat)");
+ break;
+ case kMitsubishiHeavyDry:
+ result += F(" (Dry)");
+ break;
+ case kMitsubishiHeavyFan:
+ result += F(" (Fan)");
+ break;
+ default:
+ result += F(" (UNKNOWN)");
+ }
+ result += F(", Temp: ");
+ result += uint64ToString(this->getTemp()) + 'C';
+ result += F(", Fan: ");
+ result += uint64ToString(this->getFan());
+ switch (this->getFan()) {
+ case kMitsubishiHeavy88FanAuto:
+ result += F(" (Auto)");
+ break;
+ case kMitsubishiHeavy88FanHigh:
+ result += F(" (High)");
+ break;
+ case kMitsubishiHeavy88FanLow:
+ result += F(" (Low)");
+ break;
+ case kMitsubishiHeavy88FanMed:
+ result += F(" (Med)");
+ break;
+ case kMitsubishiHeavy88FanEcono:
+ result += F(" (Econo)");
+ break;
+ case kMitsubishiHeavy88FanTurbo:
+ result += F(" (Turbo)");
+ break;
+ default:
+ result += F(" (UNKNOWN)");
+ }
+ result += F(", Swing (V): ");
+ result += uint64ToString(this->getSwingVertical());
+ switch (this->getSwingVertical()) {
+ case kMitsubishiHeavy88SwingVAuto:
+ result += F(" (Auto)");
+ break;
+ case kMitsubishiHeavy88SwingVHighest:
+ result += F(" (Highest)");
+ break;
+ case kMitsubishiHeavy88SwingVHigh:
+ result += F(" (High)");
+ break;
+ case kMitsubishiHeavy88SwingVMiddle:
+ result += F(" (Middle)");
+ break;
+ case kMitsubishiHeavy88SwingVLow:
+ result += F(" (Low)");
+ break;
+ case kMitsubishiHeavy88SwingVLowest:
+ result += F(" (Lowest)");
+ break;
+ case kMitsubishiHeavy88SwingVOff:
+ result += F(" (Off)");
+ break;
+ default:
+ result += F(" (UNKNOWN)");
+ }
+ result += F(", Swing (H): ");
+ result += uint64ToString(this->getSwingHorizontal());
+ switch (this->getSwingHorizontal()) {
+ case kMitsubishiHeavy88SwingHAuto:
+ result += F(" (Auto)");
+ break;
+ case kMitsubishiHeavy88SwingHLeftMax:
+ result += F(" (Max Left)");
+ break;
+ case kMitsubishiHeavy88SwingHLeft:
+ result += F(" (Left)");
+ break;
+ case kMitsubishiHeavy88SwingHMiddle:
+ result += F(" (Middle)");
+ break;
+ case kMitsubishiHeavy88SwingHRight:
+ result += F(" (Right)");
+ break;
+ case kMitsubishiHeavy88SwingHRightMax:
+ result += F(" (Max Right)");
+ break;
+ case kMitsubishiHeavy88SwingHLeftRight:
+ result += F(" (Left Right)");
+ break;
+ case kMitsubishiHeavy88SwingHRightLeft:
+ result += F(" (Right Left)");
+ break;
+ case kMitsubishiHeavy88SwingH3D:
+ result += F(" (3D)");
+ break;
+ case kMitsubishiHeavy88SwingHOff:
+ result += F(" (Off)");
+ break;
+ default:
+ result += F(" (UNKNOWN)");
+ }
+ result += F(", Turbo: ");
+ result += (this->getTurbo() ? F("On") : F("Off"));
+ result += F(", Econo: ");
+ result += (this->getEcono() ? F("On") : F("Off"));
+ result += F(", 3D: ");
+ result += (this->get3D() ? F("On") : F("Off"));
+ result += F(", Clean: ");
+ result += (this->getClean() ? F("On") : F("Off"));
+ return result;
+}
+
+#if DECODE_MITSUBISHIHEAVY
+// Decode the supplied MitsubishiHeavy 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 kMitsubishiHeavy88Bits or kMitsubishiHeavy152Bits.
+// 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. Needs testing against a real device.
+bool IRrecv::decodeMitsubishiHeavy(decode_results* results,
+ const uint16_t nbits, const bool strict) {
+ // Check if can possibly be a valid MitsubishiHeavy message.
+ if (results->rawlen < 2 * nbits + kHeader + kFooter - 1) return false;
+ if (strict) {
+ switch (nbits) {
+ case kMitsubishiHeavy88Bits:
+ case kMitsubishiHeavy152Bits:
+ break;
+ default:
+ return false; // Not what is expected
+ }
+ }
+
+ uint16_t actualBits = 0;
+ uint16_t offset = kStartOffset;
+ match_result_t data_result;
+
+ // Header
+ if (!matchMark(results->rawbuf[offset++], kMitsubishiHeavyHdrMark))
+ return false;
+ if (!matchSpace(results->rawbuf[offset++], kMitsubishiHeavyHdrSpace))
+ return false;
+ // Data
+ // Keep reading bytes until we either run out of section or state to fill.
+ for (uint16_t i = 0;
+ offset <= results->rawlen - 16 && actualBits < nbits;
+ i++, actualBits += 8, offset += data_result.used) {
+ data_result = matchData(&(results->rawbuf[offset]), 8,
+ kMitsubishiHeavyBitMark, kMitsubishiHeavyOneSpace,
+ kMitsubishiHeavyBitMark, kMitsubishiHeavyZeroSpace,
+ 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;
+ }
+ // Footer.
+ if (!matchMark(results->rawbuf[offset++], kMitsubishiHeavyBitMark))
+ return false;
+ if (offset < results->rawlen &&
+ !matchAtLeast(results->rawbuf[offset], kMitsubishiHeavyGap)) return false;
+
+ // Compliance
+ if (actualBits < nbits) return false;
+ if (strict && actualBits != nbits) return false; // Not as we expected.
+ switch (actualBits) {
+ case kMitsubishiHeavy88Bits:
+ if (strict && !(IRMitsubishiHeavy88Ac::checkZjsSig(results->state) &&
+ IRMitsubishiHeavy88Ac::validChecksum(results->state)))
+ return false;
+ results->decode_type = MITSUBISHI_HEAVY_88;
+ break;
+ case kMitsubishiHeavy152Bits:
+ if (strict && !(IRMitsubishiHeavy152Ac::checkZmsSig(results->state) &&
+ IRMitsubishiHeavy152Ac::validChecksum(results->state)))
+ return false;
+ results->decode_type = MITSUBISHI_HEAVY_152;
+ break;
+ default:
+ return false;
+ }
+
+ // Success
+ results->bits = actualBits;
+ // 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_MITSUBISHIHEAVY
diff --git a/lib/IRremoteESP8266-2.6.0/src/ir_MitsubishiHeavy.h b/lib/IRremoteESP8266-2.6.0/src/ir_MitsubishiHeavy.h
new file mode 100644
index 000000000..bcd85c6e0
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_MitsubishiHeavy.h
@@ -0,0 +1,264 @@
+// Copyright 2019 David Conran
+
+#ifndef IR_MITSUBISHIHEAVY_H_
+#define IR_MITSUBISHIHEAVY_H_
+
+#ifndef UNIT_TEST
+#include
+#else
+#include
+#endif
+#include "IRremoteESP8266.h"
+#include "IRsend.h"
+#ifdef UNIT_TEST
+#include "IRsend_test.h"
+#endif
+
+// Ref:
+// https://github.com/markszabo/IRremoteESP8266/issues/660
+// https://github.com/ToniA/Raw-IR-decoder-for-Arduino/blob/master/MitsubishiHeavy.cpp
+// https://github.com/ToniA/arduino-heatpumpir/blob/master/MitsubishiHeavyHeatpumpIR.cpp
+
+// Constants.
+const uint8_t kMitsubishiHeavySigLength = 5;
+
+
+// ZMS (152 bit)
+const uint8_t kMitsubishiHeavyZmsSig[kMitsubishiHeavySigLength] = {
+ 0xAD, 0x51, 0x3C, 0xE5, 0x1A};
+// Byte[5]
+const uint8_t kMitsubishiHeavyFilterBit = 0b01000000;
+const uint8_t kMitsubishiHeavyCleanBit = 0b00100000;
+const uint8_t kMitsubishiHeavyPowerBit = 0b00001000; // Byte 9 on ZJS
+const uint8_t kMitsubishiHeavyModeMask = 0b00000111; // Byte 9 on ZJS
+const uint8_t kMitsubishiHeavyAuto = 0; // 0b000
+const uint8_t kMitsubishiHeavyCool = 1; // 0b001
+const uint8_t kMitsubishiHeavyDry = 2; // 0b010
+const uint8_t kMitsubishiHeavyFan = 3; // 0b011
+const uint8_t kMitsubishiHeavyHeat = 4; // 0b100
+// Byte[7]
+const uint8_t kMitsubishiHeavyTempMask = 0b00001111;
+const uint8_t kMitsubishiHeavyMinTemp = 17; // 17C
+const uint8_t kMitsubishiHeavyMaxTemp = 31; // 31C
+// Byte[9]
+const uint8_t kMitsubishiHeavyFanMask = 0b00001111; // ~Byte 7 on ZJS.
+const uint8_t kMitsubishiHeavy152FanAuto = 0x0; // 0b0000
+const uint8_t kMitsubishiHeavy152FanLow = 0x1; // 0b0001
+const uint8_t kMitsubishiHeavy152FanMed = 0x2; // 0b0010
+const uint8_t kMitsubishiHeavy152FanHigh = 0x3; // 0b0011
+const uint8_t kMitsubishiHeavy152FanMax = 0x4; // 0b0100
+const uint8_t kMitsubishiHeavy152FanEcono = 0x6; // 0b0110
+const uint8_t kMitsubishiHeavy152FanTurbo = 0x8; // 0b1000
+// Byte[11]
+const uint8_t kMitsubishiHeavy3DMask = 0b00010010;
+const uint8_t kMitsubishiHeavy152SwingVMask = 0b11100000;
+const uint8_t kMitsubishiHeavy152SwingVAuto = 0; // 0b000
+const uint8_t kMitsubishiHeavy152SwingVHighest = 1; // 0b001
+const uint8_t kMitsubishiHeavy152SwingVHigh = 2; // 0b010
+const uint8_t kMitsubishiHeavy152SwingVMiddle = 3; // 0b011
+const uint8_t kMitsubishiHeavy152SwingVLow = 4; // 0b100
+const uint8_t kMitsubishiHeavy152SwingVLowest = 5; // 0b101
+const uint8_t kMitsubishiHeavy152SwingVOff = 6; // 0b110
+// Byte[13]
+const uint8_t kMitsubishiHeavy152SwingHMask = 0b00001111;
+const uint8_t kMitsubishiHeavy152SwingHAuto = 0; // 0b0000
+const uint8_t kMitsubishiHeavy152SwingHLeftMax = 1; // 0b0001
+const uint8_t kMitsubishiHeavy152SwingHLeft = 2; // 0b0010
+const uint8_t kMitsubishiHeavy152SwingHMiddle = 3; // 0b0011
+const uint8_t kMitsubishiHeavy152SwingHRight = 4; // 0b0100
+const uint8_t kMitsubishiHeavy152SwingHRightMax = 5; // 0b0101
+const uint8_t kMitsubishiHeavy152SwingHRightLeft = 6; // 0b0110
+const uint8_t kMitsubishiHeavy152SwingHLeftRight = 7; // 0b0111
+const uint8_t kMitsubishiHeavy152SwingHOff = 8; // 0b1000
+// Byte[15]
+const uint8_t kMitsubishiHeavyNightBit = 0b01000000;
+const uint8_t kMitsubishiHeavySilentBit = 0b10000000;
+
+
+// ZJS (88 bit)
+const uint8_t kMitsubishiHeavyZjsSig[kMitsubishiHeavySigLength] = {
+ 0xAD, 0x51, 0x3C, 0xD9, 0x26};
+// Byte [5]
+const uint8_t kMitsubishiHeavy88CleanBit = 0b00100000;
+const uint8_t kMitsubishiHeavy88SwingHMask = 0b11001100;
+const uint8_t kMitsubishiHeavy88SwingHAuto = 0x80; // 0b10000000
+const uint8_t kMitsubishiHeavy88SwingHLeftMax = 0x04; // 0b00000100
+const uint8_t kMitsubishiHeavy88SwingHLeft = 0x44; // 0b01000100
+const uint8_t kMitsubishiHeavy88SwingHMiddle = 0x84; // 0b10000100
+const uint8_t kMitsubishiHeavy88SwingHRight = 0xC4; // 0b11000100
+const uint8_t kMitsubishiHeavy88SwingHRightMax = 0x08; // 0b00001000
+const uint8_t kMitsubishiHeavy88SwingHRightLeft = 0x88; // 0b10001000
+const uint8_t kMitsubishiHeavy88SwingHLeftRight = 0x48; // 0b01001000
+const uint8_t kMitsubishiHeavy88SwingHOff = 0x00; // 0b00000000
+const uint8_t kMitsubishiHeavy88SwingH3D = 0xC8; // 0b11001000
+// Byte[7]
+const uint8_t kMitsubishiHeavy88FanMask = 0b11100000;
+const uint8_t kMitsubishiHeavy88FanAuto = 0; // 0b000
+const uint8_t kMitsubishiHeavy88FanLow = 2; // 0b010
+const uint8_t kMitsubishiHeavy88FanMed = 3; // 0b011
+const uint8_t kMitsubishiHeavy88FanHigh = 4; // 0b100
+const uint8_t kMitsubishiHeavy88FanTurbo = 6; // 0b110
+const uint8_t kMitsubishiHeavy88FanEcono = 7; // 0b111
+const uint8_t kMitsubishiHeavy88SwingVMaskByte5 = 0b00000010;
+const uint8_t kMitsubishiHeavy88SwingVMaskByte7 = 0b00011000;
+const uint8_t kMitsubishiHeavy88SwingVMask =
+ kMitsubishiHeavy88SwingVMaskByte5 | kMitsubishiHeavy88SwingVMaskByte7;
+ // i.e. 0b00011010
+const uint8_t kMitsubishiHeavy88SwingVAuto = 0b00010000; // 0x10
+const uint8_t kMitsubishiHeavy88SwingVHighest = 0b00011000; // 0x18
+const uint8_t kMitsubishiHeavy88SwingVHigh = 0b00000010; // 0x02
+const uint8_t kMitsubishiHeavy88SwingVMiddle = 0b00001010; // 0x0A
+const uint8_t kMitsubishiHeavy88SwingVLow = 0b00010010; // 0x12
+const uint8_t kMitsubishiHeavy88SwingVLowest = 0b00011010; // 0x1A
+const uint8_t kMitsubishiHeavy88SwingVOff = 0b00000000; // 0x00
+// Byte[9] is Power & Mode & Temp.
+
+
+// Classes
+class IRMitsubishiHeavy152Ac {
+ public:
+ explicit IRMitsubishiHeavy152Ac(const uint16_t pin);
+
+ void stateReset(void);
+#if SEND_MITSUBISHIHEAVY
+ void send(const uint16_t repeat = kMitsubishiHeavy152MinRepeat);
+#endif // SEND_MITSUBISHIHEAVY
+ void begin(void);
+ void on(void);
+ void off(void);
+
+ void setPower(const bool on);
+ bool getPower(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 setSwingVertical(const uint8_t pos);
+ uint8_t getSwingVertical(void);
+ void setSwingHorizontal(const uint8_t pos);
+ uint8_t getSwingHorizontal(void);
+
+ void setNight(const bool on);
+ bool getNight(void);
+
+ void set3D(const bool on);
+ bool get3D(void);
+
+ void setSilent(const bool on);
+ bool getSilent(void);
+
+ void setFilter(const bool on);
+ bool getFilter(void);
+
+ void setClean(const bool on);
+ bool getClean(void);
+
+ void setTurbo(const bool on);
+ bool getTurbo(void);
+
+ void setEcono(const bool on);
+ bool getEcono(void);
+
+ uint8_t* getRaw(void);
+ void setRaw(const uint8_t* data);
+
+ static bool checkZmsSig(const uint8_t *state);
+ static bool validChecksum(
+ const uint8_t *state,
+ const uint16_t length = kMitsubishiHeavy152StateLength);
+ static uint8_t convertMode(const stdAc::opmode_t mode);
+ static uint8_t convertFan(const stdAc::fanspeed_t speed);
+ static uint8_t convertSwingV(const stdAc::swingv_t position);
+ static uint8_t convertSwingH(const stdAc::swingh_t position);
+#ifdef ARDUINO
+ String toString(void);
+#else // ARDUINO
+ std::string toString(void);
+#endif // ARDUINO
+#ifndef UNIT_TEST
+
+ private:
+ IRsend _irsend;
+#else // UNIT_TEST
+ IRsendTest _irsend;
+#endif // UNIT_TEST
+ // The state of the IR remote in IR code form.
+ uint8_t remote_state[kMitsubishiHeavy152StateLength];
+ void checksum();
+};
+
+class IRMitsubishiHeavy88Ac {
+ public:
+ explicit IRMitsubishiHeavy88Ac(const uint16_t pin);
+
+ void stateReset(void);
+#if SEND_MITSUBISHIHEAVY
+ void send(const uint16_t repeat = kMitsubishiHeavy88MinRepeat);
+#endif // SEND_MITSUBISHIHEAVY
+ void begin(void);
+ void on(void);
+ void off(void);
+
+ void setPower(const bool on);
+ bool getPower(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 setSwingVertical(const uint8_t pos);
+ uint8_t getSwingVertical(void);
+ void setSwingHorizontal(const uint8_t pos);
+ uint8_t getSwingHorizontal(void);
+
+ void setTurbo(const bool on);
+ bool getTurbo(void);
+
+ void setEcono(const bool on);
+ bool getEcono(void);
+
+ void set3D(const bool on);
+ bool get3D(void);
+
+ void setClean(const bool on);
+ bool getClean(void);
+
+ uint8_t* getRaw(void);
+ void setRaw(const uint8_t* data);
+
+ static bool checkZjsSig(const uint8_t *state);
+ static bool validChecksum(
+ const uint8_t *state,
+ const uint16_t length = kMitsubishiHeavy88StateLength);
+ static uint8_t convertMode(const stdAc::opmode_t mode);
+ static uint8_t convertFan(const stdAc::fanspeed_t speed);
+ static uint8_t convertSwingV(const stdAc::swingv_t position);
+ static uint8_t convertSwingH(const stdAc::swingh_t position);
+#ifdef ARDUINO
+ String toString(void);
+#else // ARDUINO
+ std::string toString(void);
+#endif // ARDUINO
+#ifndef UNIT_TEST
+
+ private:
+ IRsend _irsend;
+#else // UNIT_TEST
+ IRsendTest _irsend;
+#endif // UNIT_TEST
+ // The state of the IR remote in IR code form.
+ uint8_t remote_state[kMitsubishiHeavy152StateLength];
+ void checksum();
+};
+#endif // IR_MITSUBISHIHEAVY_H_
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_NEC.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_NEC.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_NEC.cpp
rename to lib/IRremoteESP8266-2.6.0/src/ir_NEC.cpp
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_NEC.h b/lib/IRremoteESP8266-2.6.0/src/ir_NEC.h
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_NEC.h
rename to lib/IRremoteESP8266-2.6.0/src/ir_NEC.h
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_Nikai.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_Nikai.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_Nikai.cpp
rename to lib/IRremoteESP8266-2.6.0/src/ir_Nikai.cpp
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_Panasonic.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_Panasonic.cpp
similarity index 83%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_Panasonic.cpp
rename to lib/IRremoteESP8266-2.6.0/src/ir_Panasonic.cpp
index e79b136a5..47aa51c96 100644
--- a/lib/IRremoteESP8266-2.5.2.03/src/ir_Panasonic.cpp
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_Panasonic.cpp
@@ -27,8 +27,8 @@
// Code by crankyoldgit
// Panasonic A/C models supported:
// A/C Series/models:
-// JKE, LKE, DKE, CKP, & NKE series. (In theory)
-// CS-YW9MKD (confirmed)
+// JKE, LKE, DKE, CKP, RKR, & NKE series. (In theory)
+// CS-YW9MKD, CS-Z9RKR (confirmed)
// CS-ME14CKPG / CS-ME12CKPG / CS-ME10CKPG
// A/C Remotes:
// A75C3747 (confirmed)
@@ -63,7 +63,7 @@ const uint32_t kPanasonicMinGap = kPanasonicMinGapTicks * kPanasonicTick;
const uint16_t kPanasonicAcSectionGap = 10000;
const uint16_t kPanasonicAcSection1Length = 8;
-const uint32_t kPanasonicAcMessageGap = 100000; // A complete guess.
+const uint32_t kPanasonicAcMessageGap = kDefaultMessageGap; // Just a guess.
#if (SEND_PANASONIC || SEND_DENON)
// Send a Panasonic formatted message.
@@ -211,7 +211,7 @@ bool IRrecv::decodePanasonic(decode_results *results, uint16_t nbits,
//:
// Panasonic A/C models supported:
// A/C Series/models:
-// JKE, LKE, DKE, & NKE series.
+// JKE, LKE, DKE, CKP, RKR, & NKE series.
// CS-YW9MKD
// A/C Remotes:
// A75C3747
@@ -268,9 +268,9 @@ void IRPanasonicAc::fixChecksum(const uint16_t length) {
}
#if SEND_PANASONIC_AC
-void IRPanasonicAc::send() {
+void IRPanasonicAc::send(const uint16_t repeat) {
fixChecksum();
- _irsend.sendPanasonicAC(remote_state);
+ _irsend.sendPanasonicAC(remote_state, kPanasonicAcStateLength, repeat);
}
#endif // SEND_PANASONIC_AC
@@ -281,6 +281,7 @@ void IRPanasonicAc::setModel(const panasonic_ac_remote_model_t model) {
case kPanasonicLke:
case kPanasonicNke:
case kPanasonicCkp:
+ case kPanasonicRkr:
break;
default: // Only proceed if we know what to do.
return;
@@ -311,12 +312,17 @@ void IRPanasonicAc::setModel(const panasonic_ac_remote_model_t model) {
case kPanasonicCkp:
remote_state[21] |= 0x10;
remote_state[23] = 0x01;
+ break;
+ case kPanasonicRkr:
+ remote_state[13] |= 0x08;
+ remote_state[23] = 0x89;
default:
break;
}
}
panasonic_ac_remote_model_t IRPanasonicAc::getModel() {
+ if (remote_state[23] == 0x89) return kPanasonicRkr;
if (remote_state[17] == 0x00) {
if ((remote_state[21] & 0x10) && (remote_state[23] & 0x01))
return kPanasonicCkp;
@@ -438,6 +444,7 @@ void IRPanasonicAc::setSwingHorizontal(const uint8_t desired_direction) {
uint8_t direction = desired_direction;
switch (getModel()) {
case kPanasonicDke:
+ case kPanasonicRkr:
break;
case kPanasonicNke:
case kPanasonicLke:
@@ -460,18 +467,25 @@ uint8_t IRPanasonicAc::getFan() {
}
bool IRPanasonicAc::getQuiet() {
- if (getModel() == kPanasonicCkp)
- return remote_state[21] & kPanasonicAcQuietCkp;
- else
- return remote_state[21] & kPanasonicAcQuiet;
+ switch (getModel()) {
+ case kPanasonicRkr:
+ case kPanasonicCkp:
+ return remote_state[21] & kPanasonicAcQuietCkp;
+ default:
+ return remote_state[21] & kPanasonicAcQuiet;
+ }
}
void IRPanasonicAc::setQuiet(const bool state) {
uint8_t quiet;
- if (getModel() == kPanasonicCkp)
- quiet = kPanasonicAcQuietCkp;
- else
- quiet = kPanasonicAcQuiet;
+ switch (getModel()) {
+ case kPanasonicRkr:
+ case kPanasonicCkp:
+ quiet = kPanasonicAcQuietCkp;
+ break;
+ default:
+ quiet = kPanasonicAcQuiet;
+ }
if (state) {
setPowerful(false); // Powerful is mutually exclusive.
@@ -482,18 +496,25 @@ void IRPanasonicAc::setQuiet(const bool state) {
}
bool IRPanasonicAc::getPowerful() {
- if (getModel() == kPanasonicCkp)
- return remote_state[21] & kPanasonicAcPowerfulCkp;
- else
- return remote_state[21] & kPanasonicAcPowerful;
+ switch (getModel()) {
+ case kPanasonicRkr:
+ case kPanasonicCkp:
+ return remote_state[21] & kPanasonicAcPowerfulCkp;
+ default:
+ return remote_state[21] & kPanasonicAcPowerful;
+ }
}
void IRPanasonicAc::setPowerful(const bool state) {
uint8_t powerful;
- if (getModel() == kPanasonicCkp)
- powerful = kPanasonicAcPowerfulCkp;
- else
- powerful = kPanasonicAcPowerful;
+ switch (getModel()) {
+ case kPanasonicRkr:
+ case kPanasonicCkp:
+ powerful = kPanasonicAcPowerfulCkp;
+ break;
+ default:
+ powerful = kPanasonicAcPowerful;
+ }
if (state) {
setQuiet(false); // Quiet is mutually exclusive.
@@ -591,12 +612,79 @@ String IRPanasonicAc::timeToString(const uint16_t mins_since_midnight) {
std::string IRPanasonicAc::timeToString(const uint16_t mins_since_midnight) {
std::string result = "";
#endif // ARDUINO
- result += uint64ToString(mins_since_midnight / 60) + ":";
+ result += uint64ToString(mins_since_midnight / 60) + ':';
uint8_t mins = mins_since_midnight % 60;
- if (mins < 10) result += "0"; // Zero pad the minutes.
+ if (mins < 10) result += '0'; // Zero pad the minutes.
return result + uint64ToString(mins);
}
+// Convert a standard A/C mode into its native mode.
+uint8_t IRPanasonicAc::convertMode(const stdAc::opmode_t mode) {
+ switch (mode) {
+ case stdAc::opmode_t::kCool:
+ return kPanasonicAcCool;
+ case stdAc::opmode_t::kHeat:
+ return kPanasonicAcHeat;
+ case stdAc::opmode_t::kDry:
+ return kPanasonicAcDry;
+ case stdAc::opmode_t::kFan:
+ return kPanasonicAcFan;
+ default:
+ return kPanasonicAcAuto;
+ }
+}
+
+// Convert a standard A/C Fan speed into its native fan speed.
+uint8_t IRPanasonicAc::convertFan(const stdAc::fanspeed_t speed) {
+ switch (speed) {
+ case stdAc::fanspeed_t::kMin:
+ return kPanasonicAcFanMin;
+ case stdAc::fanspeed_t::kLow:
+ return kPanasonicAcFanMin + 1;
+ case stdAc::fanspeed_t::kMedium:
+ return kPanasonicAcFanMin + 2;
+ case stdAc::fanspeed_t::kHigh:
+ return kPanasonicAcFanMin + 3;
+ case stdAc::fanspeed_t::kMax:
+ return kPanasonicAcFanMax;
+ default:
+ return kPanasonicAcFanAuto;
+ }
+}
+
+// Convert a standard A/C vertical swing into its native setting.
+uint8_t IRPanasonicAc::convertSwingV(const stdAc::swingv_t position) {
+ switch (position) {
+ case stdAc::swingv_t::kHighest:
+ case stdAc::swingv_t::kHigh:
+ case stdAc::swingv_t::kMiddle:
+ return kPanasonicAcSwingVUp;
+ case stdAc::swingv_t::kLow:
+ case stdAc::swingv_t::kLowest:
+ return kPanasonicAcSwingVDown;
+ default:
+ return kPanasonicAcSwingVAuto;
+ }
+}
+
+// Convert a standard A/C horizontal swing into its native setting.
+uint8_t IRPanasonicAc::convertSwingH(const stdAc::swingh_t position) {
+ switch (position) {
+ case stdAc::swingh_t::kLeftMax:
+ return kPanasonicAcSwingHFullLeft;
+ case stdAc::swingh_t::kLeft:
+ return kPanasonicAcSwingHLeft;
+ case stdAc::swingh_t::kMiddle:
+ return kPanasonicAcSwingHMiddle;
+ case stdAc::swingh_t::kRight:
+ return kPanasonicAcSwingHRight;
+ case stdAc::swingh_t::kRightMax:
+ return kPanasonicAcSwingHFullRight;
+ default:
+ return kPanasonicAcSwingHAuto;
+ }
+}
+
// Convert the internal state into a human readable string.
#ifdef ARDUINO
String IRPanasonicAc::toString() {
@@ -605,84 +693,92 @@ String IRPanasonicAc::toString() {
std::string IRPanasonicAc::toString() {
std::string result = "";
#endif // ARDUINO
- result += "Model: " + uint64ToString(getModel());
+ result += F("Model: ");
+ result += uint64ToString(getModel());
switch (getModel()) {
case kPanasonicDke:
- result += " (DKE)";
+ result += F(" (DKE)");
break;
case kPanasonicJke:
- result += " (JKE)";
+ result += F(" (JKE)");
break;
case kPanasonicNke:
- result += " (NKE)";
+ result += F(" (NKE)");
break;
case kPanasonicLke:
- result += " (LKE)";
+ result += F(" (LKE)");
break;
case kPanasonicCkp:
- result += " (CKP)";
+ result += F(" (CKP)");
+ break;
+ case kPanasonicRkr:
+ result += F(" (RKR)");
break;
default:
- result += " (UNKNOWN)";
+ result += F(" (UNKNOWN)");
}
- result += ", Power: ";
+ result += F(", Power: ");
if (getPower())
- result += "On";
+ result += F("On");
else
- result += "Off";
- result += ", Mode: " + uint64ToString(getMode());
+ result += F("Off");
+ result += F(", Mode: ");
+ result += uint64ToString(getMode());
switch (getMode()) {
case kPanasonicAcAuto:
- result += " (AUTO)";
+ result += F(" (AUTO)");
break;
case kPanasonicAcCool:
- result += " (COOL)";
+ result += F(" (COOL)");
break;
case kPanasonicAcHeat:
- result += " (HEAT)";
+ result += F(" (HEAT)");
break;
case kPanasonicAcDry:
- result += " (DRY)";
+ result += F(" (DRY)");
break;
case kPanasonicAcFan:
- result += " (FAN)";
+ result += F(" (FAN)");
break;
default:
- result += " (UNKNOWN)";
+ result += F(" (UNKNOWN)");
}
- result += ", Temp: " + uint64ToString(getTemp()) + "C";
- result += ", Fan: " + uint64ToString(getFan());
+ result += F(", Temp: ");
+ result += uint64ToString(getTemp());
+ result += F("C, Fan: ");
+ result += uint64ToString(getFan());
switch (getFan()) {
case kPanasonicAcFanAuto:
- result += " (AUTO)";
+ result += F(" (AUTO)");
break;
case kPanasonicAcFanMax:
- result += " (MAX)";
+ result += F(" (MAX)");
break;
case kPanasonicAcFanMin:
- result += " (MIN)";
+ result += F(" (MIN)");
break;
default:
- result += " (UNKNOWN)";
+ result += F(" (UNKNOWN)");
break;
}
- result += ", Swing (Vertical): " + uint64ToString(getSwingVertical());
+ result += F(", Swing (Vertical): ");
+ result += uint64ToString(getSwingVertical());
switch (getSwingVertical()) {
case kPanasonicAcSwingVAuto:
- result += " (AUTO)";
+ result += F(" (AUTO)");
break;
case kPanasonicAcSwingVUp:
- result += " (Full Up)";
+ result += F(" (Full Up)");
break;
case kPanasonicAcSwingVDown:
- result += " (Full Down)";
+ result += F(" (Full Down)");
break;
case 2:
case 3:
case 4:
break;
default:
- result += " (UNKNOWN)";
+ result += F(" (UNKNOWN)");
break;
}
switch (getModel()) {
@@ -690,52 +786,54 @@ std::string IRPanasonicAc::toString() {
case kPanasonicCkp:
break; // No Horizontal Swing support.
default:
- result += ", Swing (Horizontal): " + uint64ToString(getSwingHorizontal());
+ result += F(", Swing (Horizontal): ");
+ result += uint64ToString(getSwingHorizontal());
switch (getSwingHorizontal()) {
case kPanasonicAcSwingHAuto:
- result += " (AUTO)";
+ result += F(" (AUTO)");
break;
case kPanasonicAcSwingHFullLeft:
- result += " (Full Left)";
+ result += F(" (Full Left)");
break;
case kPanasonicAcSwingHLeft:
- result += " (Left)";
+ result += F(" (Left)");
break;
case kPanasonicAcSwingHMiddle:
- result += " (Middle)";
+ result += F(" (Middle)");
break;
case kPanasonicAcSwingHFullRight:
- result += " (Full Right)";
+ result += F(" (Full Right)");
break;
case kPanasonicAcSwingHRight:
- result += " (Right)";
+ result += F(" (Right)");
break;
default:
- result += " (UNKNOWN)";
+ result += F(" (UNKNOWN)");
break;
}
}
- result += ", Quiet: ";
+ result += F(", Quiet: ");
if (getQuiet())
- result += "On";
+ result += F("On");
else
- result += "Off";
- result += ", Powerful: ";
+ result += F("Off");
+ result += F(", Powerful: ");
if (getPowerful())
- result += "On";
+ result += F("On");
else
- result += "Off";
- result += ", Clock: " + timeToString(getClock());
- result += ", On Timer: ";
+ result += F("Off");
+ result += F(", Clock: ");
+ result += timeToString(getClock());
+ result += F(", On Timer: ");
if (isOnTimerEnabled())
result += timeToString(getOnTimer());
else
- result += "Off";
- result += ", Off Timer: ";
+ result += F("Off");
+ result += F(", Off Timer: ");
if (isOffTimerEnabled())
result += timeToString(getOffTimer());
else
- result += "Off";
+ result += F("Off");
return result;
}
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_Panasonic.h b/lib/IRremoteESP8266-2.6.0/src/ir_Panasonic.h
similarity index 91%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_Panasonic.h
rename to lib/IRremoteESP8266-2.6.0/src/ir_Panasonic.h
index 762631fe7..1a7b4e114 100644
--- a/lib/IRremoteESP8266-2.5.2.03/src/ir_Panasonic.h
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_Panasonic.h
@@ -12,6 +12,9 @@
#endif
#include "IRremoteESP8266.h"
#include "IRsend.h"
+#ifdef UNIT_TEST
+#include "IRsend_test.h"
+#endif
// 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
@@ -43,7 +46,7 @@ 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.
+// CKP & RKR models have Powerful and Quiet bits swapped.
const uint8_t kPanasonicAcQuietCkp = 0x20; // 0b100000
const uint8_t kPanasonicAcPowerfulCkp = 1; // 0b1
const uint8_t kPanasonicAcSwingVAuto = 0xF;
@@ -73,6 +76,7 @@ enum panasonic_ac_remote_model_t {
kPanasonicDke = 3,
kPanasonicJke = 4,
kPanasonicCkp = 5,
+ kPanasonicRkr = 6,
};
class IRPanasonicAc {
@@ -81,7 +85,7 @@ class IRPanasonicAc {
void stateReset();
#if SEND_PANASONIC
- void send();
+ void send(const uint16_t repeat = kPanasonicAcDefaultRepeat);
#endif // SEND_PANASONIC
void begin();
void on();
@@ -122,6 +126,10 @@ class IRPanasonicAc {
const bool enable = true);
void cancelOffTimer();
bool isOffTimerEnabled();
+ uint8_t convertMode(const stdAc::opmode_t mode);
+ uint8_t convertFan(const stdAc::fanspeed_t speed);
+ uint8_t convertSwingV(const stdAc::swingv_t position);
+ uint8_t convertSwingH(const stdAc::swingh_t position);
#ifdef ARDUINO
String toString();
static String timeToString(const uint16_t mins_since_midnight);
@@ -132,6 +140,9 @@ class IRPanasonicAc {
#ifndef UNIT_TEST
private:
+ IRsend _irsend;
+#else
+ IRsendTest _irsend;
#endif
uint8_t remote_state[kPanasonicAcStateLength];
uint8_t _swingh;
@@ -139,7 +150,6 @@ class IRPanasonicAc {
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-2.5.2.03/src/ir_Pioneer.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_Pioneer.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_Pioneer.cpp
rename to lib/IRremoteESP8266-2.6.0/src/ir_Pioneer.cpp
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_Pronto.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_Pronto.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_Pronto.cpp
rename to lib/IRremoteESP8266-2.6.0/src/ir_Pronto.cpp
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_RC5_RC6.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_RC5_RC6.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_RC5_RC6.cpp
rename to lib/IRremoteESP8266-2.6.0/src/ir_RC5_RC6.cpp
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_RCMM.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_RCMM.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_RCMM.cpp
rename to lib/IRremoteESP8266-2.6.0/src/ir_RCMM.cpp
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_Samsung.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_Samsung.cpp
similarity index 66%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_Samsung.cpp
rename to lib/IRremoteESP8266-2.6.0/src/ir_Samsung.cpp
index d943f8cf9..7e54d17df 100644
--- a/lib/IRremoteESP8266-2.5.2.03/src/ir_Samsung.cpp
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_Samsung.cpp
@@ -1,5 +1,5 @@
// Copyright 2009 Ken Shirriff
-// Copyright 2017 David Conran
+// Copyright 2017, 2018, 2019 David Conran
#include "ir_Samsung.h"
#include
@@ -168,6 +168,127 @@ bool IRrecv::decodeSAMSUNG(decode_results *results, uint16_t nbits,
}
#endif
+#if SEND_SAMSUNG36
+// Send a Samsung 36-bit formatted message.
+//
+// Args:
+// data: The message to be sent.
+// nbits: The bit size of the message being sent. typically kSamsung36Bits.
+// repeat: The number of times the message is to be repeated.
+//
+// Status: Alpha / Experimental.
+//
+// Note:
+// Protocol is used by Samsung Bluray Remote: ak59-00167a
+//
+// Ref:
+// https://github.com/markszabo/IRremoteESP8266/issues/621
+void IRsend::sendSamsung36(const uint64_t data, const uint16_t nbits,
+ const uint16_t repeat) {
+ if (nbits < 16) return; // To small to send.
+ for (uint16_t r = 0; r <= repeat; r++) {
+ // Block #1 (16 bits)
+ sendGeneric(kSamsungHdrMark, kSamsungHdrSpace,
+ kSamsungBitMark, kSamsungOneSpace,
+ kSamsungBitMark, kSamsungZeroSpace,
+ kSamsungBitMark, kSamsungHdrSpace,
+ data >> (nbits - 16), 16, 38, true, 0, kDutyDefault);
+ // Block #2 (The rest, typically 20 bits)
+ sendGeneric(0, 0, // No header
+ kSamsungBitMark, kSamsungOneSpace,
+ kSamsungBitMark, kSamsungZeroSpace,
+ kSamsungBitMark, kSamsungMinGap, // Gap is just a guess.
+ // Mask off the rest of the bits.
+ data & ((1ULL << (nbits - 16)) - 1),
+ nbits - 16, 38, true, 0, kDutyDefault);
+ }
+}
+#endif // SEND_SAMSUNG36
+
+#if DECODE_SAMSUNG36
+// Decode the supplied Samsung36 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.
+// Typically kSamsung36Bits.
+// strict: Flag to indicate if we strictly adhere to the specification.
+// Returns:
+// boolean: True if it can decode it, false if it can't.
+//
+// Status: Alpha / Experimental
+//
+// Note:
+// Protocol is used by Samsung Bluray Remote: ak59-00167a
+//
+// Ref:
+// https://github.com/markszabo/IRremoteESP8266/issues/621
+bool IRrecv::decodeSamsung36(decode_results *results, const uint16_t nbits,
+ const bool strict) {
+ if (results->rawlen < 2 * nbits + kHeader + kFooter * 2 - 1)
+ return false; // Can't possibly be a valid Samsung message.
+ // We need to be looking for > 16 bits to make sense.
+ if (nbits <= 16) return false;
+ if (strict && nbits != kSamsung36Bits)
+ return false; // We expect nbits to be 36 bits of message.
+
+ uint64_t data = 0;
+ uint16_t offset = kStartOffset;
+
+ // Header
+ 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++] * 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++] * kRawTick / kSamsungHdrSpaceTicks;
+ // Data (Block #1)
+ match_result_t data_result =
+ matchData(&(results->rawbuf[offset]), 16,
+ 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;
+ uint16_t bitsSoFar = data_result.used / 2;
+ // Footer (Block #1)
+ if (!matchMark(results->rawbuf[offset++], kSamsungBitMarkTicks * m_tick))
+ return false;
+ if (!matchSpace(results->rawbuf[offset++], kSamsungHdrSpaceTicks * s_tick))
+ return false;
+ // Data (Block #2)
+ data_result = matchData(&(results->rawbuf[offset]),
+ nbits - 16,
+ kSamsungBitMarkTicks * m_tick,
+ kSamsungOneSpaceTicks * s_tick,
+ kSamsungBitMarkTicks * m_tick,
+ kSamsungZeroSpaceTicks * s_tick);
+ if (data_result.success == false) return false;
+ data <<= (nbits - 16);
+ data += data_result.data;
+ offset += data_result.used;
+ bitsSoFar += data_result.used / 2;
+ // Footer (Block #2)
+ if (!matchMark(results->rawbuf[offset++], kSamsungBitMarkTicks * m_tick))
+ return false;
+ if (offset < results->rawlen &&
+ !matchAtLeast(results->rawbuf[offset], kSamsungMinGapTicks * s_tick))
+ return false;
+
+ // Compliance
+ if (nbits != bitsSoFar) return false;
+
+ // Success
+ results->bits = bitsSoFar;
+ results->value = data;
+ results->decode_type = SAMSUNG36;
+ results->command = data & ((1ULL << (nbits - 16)) - 1);
+ results->address = data >> (nbits - 16);
+ return true;
+}
+#endif // DECODE_SAMSUNG36
+
#if SEND_SAMSUNG_AC
// Send a Samsung A/C message.
//
@@ -180,7 +301,8 @@ bool IRrecv::decodeSAMSUNG(decode_results *results, uint16_t nbits,
//
// Ref:
// https://github.com/markszabo/IRremoteESP8266/issues/505
-void IRsend::sendSamsungAC(uint8_t data[], uint16_t nbytes, uint16_t repeat) {
+void IRsend::sendSamsungAC(const uint8_t data[], const uint16_t nbytes,
+ const uint16_t repeat) {
if (nbytes < kSamsungAcStateLength && nbytes % kSamsungACSectionLength)
return; // Not an appropriate number of bytes to send a proper message.
@@ -226,53 +348,85 @@ void IRSamsungAc::begin() { _irsend.begin(); }
uint8_t IRSamsungAc::calcChecksum(const uint8_t state[],
const uint16_t length) {
uint8_t sum = 0;
- uint8_t currentbyte;
// Safety check so we don't go outside the array.
- if (length <= 5) return 255;
+ 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.
- for (uint8_t i = length - 5; i < length - 1; i++) {
- currentbyte = state[i];
- if (i == length - 5) currentbyte = state[length - 5] & 0b11111110;
- for (; currentbyte; currentbyte >>= 1)
- if (currentbyte & 1) sum++;
- }
+ 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 <= 5) return true; // No checksum to compare with. Assume okay.
- return (state[length - 6] >> 4) == calcChecksum(state, 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 < 9) return;
+ 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
-void IRSamsungAc::send(const bool calcchecksum) {
+// 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);
+ _irsend.sendSamsungAC(remote_state, kSamsungAcStateLength, repeat);
}
-#endif // SEND_SAMSUNG_AC
-#if SEND_SAMSUNG_AC
-void IRSamsungAc::sendExtended(const bool calcchecksum) {
+// 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};
+ 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);
+ _irsend.sendSamsungAC(extended_state, kSamsungAcExtendedStateLength, repeat);
+}
+
+// Send the special extended "On" message as the library can't seem to reproduce
+// this message automatically.
+// See: https://github.com/markszabo/IRremoteESP8266/issues/604#issuecomment-475020036
+void IRSamsungAc::sendOn(const uint16_t repeat) {
+ const uint8_t extended_state[21] = {
+ 0x02, 0x92, 0x0F, 0x00, 0x00, 0x00, 0xF0,
+ 0x01, 0xD2, 0x0F, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0xE2, 0xFE, 0x71, 0x80, 0x11, 0xF0};
+ _irsend.sendSamsungAC(extended_state, kSamsungAcExtendedStateLength, repeat);
+}
+
+// Send the special extended "Off" message as the library can't seem to
+// reproduce this message automatically.
+// See: https://github.com/markszabo/IRremoteESP8266/issues/604#issuecomment-475020036
+void IRSamsungAc::sendOff(const uint16_t repeat) {
+ const uint8_t extended_state[21] = {
+ 0x02, 0xB2, 0x0F, 0x00, 0x00, 0x00, 0xC0,
+ 0x01, 0xD2, 0x0F, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x02, 0xFF, 0x71, 0x80, 0x11, 0xC0};
+ _irsend.sendSamsungAC(extended_state, kSamsungAcExtendedStateLength, repeat);
}
#endif // SEND_SAMSUNG_AC
@@ -423,6 +577,39 @@ void IRSamsungAc::setQuiet(const bool state) {
}
}
+// Convert a standard A/C mode into its native mode.
+uint8_t IRSamsungAc::convertMode(const stdAc::opmode_t mode) {
+ switch (mode) {
+ case stdAc::opmode_t::kCool:
+ return kSamsungAcCool;
+ case stdAc::opmode_t::kHeat:
+ return kSamsungAcHeat;
+ case stdAc::opmode_t::kDry:
+ return kSamsungAcDry;
+ case stdAc::opmode_t::kFan:
+ return kSamsungAcFan;
+ default:
+ return kSamsungAcAuto;
+ }
+}
+
+// Convert a standard A/C Fan speed into its native fan speed.
+uint8_t IRSamsungAc::convertFan(const stdAc::fanspeed_t speed) {
+ switch (speed) {
+ case stdAc::fanspeed_t::kMin:
+ case stdAc::fanspeed_t::kLow:
+ return kSamsungAcFanLow;
+ case stdAc::fanspeed_t::kMedium:
+ return kSamsungAcFanMed;
+ case stdAc::fanspeed_t::kHigh:
+ return kSamsungAcFanHigh;
+ case stdAc::fanspeed_t::kMax:
+ return kSamsungAcFanTurbo;
+ default:
+ return kSamsungAcFanAuto;
+ }
+}
+
// Convert the internal state into a human readable string.
#ifdef ARDUINO
String IRSamsungAc::toString() {
@@ -431,74 +618,77 @@ String IRSamsungAc::toString() {
std::string IRSamsungAc::toString() {
std::string result = "";
#endif // ARDUINO
- result += "Power: ";
+ result += F("Power: ");
if (getPower())
- result += "On";
+ result += F("On");
else
- result += "Off";
- result += ", Mode: " + uint64ToString(getMode());
+ result += F("Off");
+ result += F(", Mode: ");
+ result += uint64ToString(getMode());
switch (getMode()) {
case kSamsungAcAuto:
- result += " (AUTO)";
+ result += F(" (AUTO)");
break;
case kSamsungAcCool:
- result += " (COOL)";
+ result += F(" (COOL)");
break;
case kSamsungAcHeat:
- result += " (HEAT)";
+ result += F(" (HEAT)");
break;
case kSamsungAcDry:
- result += " (DRY)";
+ result += F(" (DRY)");
break;
case kSamsungAcFan:
- result += " (FAN)";
+ result += F(" (FAN)");
break;
default:
- result += " (UNKNOWN)";
+ result += F(" (UNKNOWN)");
}
- result += ", Temp: " + uint64ToString(getTemp()) + "C";
- result += ", Fan: " + uint64ToString(getFan());
+ result += F(", Temp: ");
+ result += uint64ToString(getTemp());
+ result += F("C, Fan: ");
+ result += uint64ToString(getFan());
switch (getFan()) {
case kSamsungAcFanAuto:
case kSamsungAcFanAuto2:
- result += " (AUTO)";
+ result += F(" (AUTO)");
break;
case kSamsungAcFanLow:
- result += " (LOW)";
+ result += F(" (LOW)");
break;
case kSamsungAcFanMed:
- result += " (MED)";
+ result += F(" (MED)");
break;
case kSamsungAcFanHigh:
- result += " (HIGH)";
+ result += F(" (HIGH)");
break;
case kSamsungAcFanTurbo:
- result += " (TURBO)";
+ result += F(" (TURBO)");
break;
default:
- result += " (UNKNOWN)";
+ result += F(" (UNKNOWN)");
break;
}
- result += ", Swing: ";
+ result += F(", Swing: ");
if (getSwing())
- result += "On";
+ result += F("On");
else
- result += "Off";
- result += ", Beep: ";
+ result += F("Off");
+ result += F(", Beep: ");
if (getBeep())
- result += "On";
+ result += F("On");
else
- result += "Off";
- result += ", Clean: ";
+ result += F("Off");
+ result += F(", Clean: ");
if (getBeep())
- result += "On";
+ result += F("On");
else
- result += "Off";
- result += ", Quiet: ";
+ result += F("Off");
+ result += F(", Quiet: ");
if (getQuiet())
- result += "On";
+ result += F("On");
else
- result += "Off";
+ result += F("Off");
return result;
}
@@ -571,7 +761,6 @@ bool IRrecv::decodeSamsungAC(decode_results *results, uint16_t nbits,
// Is the signature correct?
DPRINTLN("DEBUG: Checking signature.");
if (results->state[0] != 0x02 || results->state[2] != 0x0F) return false;
- if (results->state[1] != 0x92 && results->state[1] != 0xB2) return false;
if (strict) {
// Is the checksum valid?
if (!IRSamsungAc::validChecksum(results->state, nbits / 8)) {
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_Samsung.h b/lib/IRremoteESP8266-2.6.0/src/ir_Samsung.h
similarity index 84%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_Samsung.h
rename to lib/IRremoteESP8266-2.6.0/src/ir_Samsung.h
index f80b47d20..9df427c6f 100644
--- a/lib/IRremoteESP8266-2.5.2.03/src/ir_Samsung.h
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_Samsung.h
@@ -14,6 +14,9 @@
#endif
#include "IRremoteESP8266.h"
#include "IRsend.h"
+#ifdef UNIT_TEST
+#include "IRsend_test.h"
+#endif
// SSSS AAA MMM SSSS U U N N GGGG
// S A A M M M S U U NN N G
@@ -62,8 +65,12 @@ class IRSamsungAc {
void stateReset();
#if SEND_SAMSUNG_AC
- void send(const bool calcchecksum = true);
- void sendExtended(const bool calcchecksum = true);
+ void send(const uint16_t repeat = kSamsungAcDefaultRepeat,
+ const bool calcchecksum = true);
+ void sendExtended(const uint16_t repeat = kSamsungAcDefaultRepeat,
+ const bool calcchecksum = true);
+ void sendOn(const uint16_t repeat = kSamsungAcDefaultRepeat);
+ void sendOff(const uint16_t repeat = kSamsungAcDefaultRepeat);
#endif // SEND_SAMSUNG_AC
void begin();
void on();
@@ -91,17 +98,23 @@ class IRSamsungAc {
const uint16_t length = kSamsungAcStateLength);
static uint8_t calcChecksum(const uint8_t state[],
const uint16_t length = kSamsungAcStateLength);
+ uint8_t convertMode(const stdAc::opmode_t mode);
+ uint8_t convertFan(const stdAc::fanspeed_t speed);
#ifdef ARDUINO
String toString();
#else
std::string toString();
#endif
+#ifndef UNIT_TEST
private:
+ IRsend _irsend;
+#else
+ IRsendTest _irsend;
+#endif
// 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-2.5.2.03/src/ir_Sanyo.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_Sanyo.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_Sanyo.cpp
rename to lib/IRremoteESP8266-2.6.0/src/ir_Sanyo.cpp
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_Sharp.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_Sharp.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_Sharp.cpp
rename to lib/IRremoteESP8266-2.6.0/src/ir_Sharp.cpp
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_Sherwood.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_Sherwood.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_Sherwood.cpp
rename to lib/IRremoteESP8266-2.6.0/src/ir_Sherwood.cpp
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_Sony.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_Sony.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_Sony.cpp
rename to lib/IRremoteESP8266-2.6.0/src/ir_Sony.cpp
diff --git a/lib/IRremoteESP8266-2.6.0/src/ir_Tcl.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_Tcl.cpp
new file mode 100644
index 000000000..79fb23cf1
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_Tcl.cpp
@@ -0,0 +1,420 @@
+// Copyright 2019 David Conran
+
+#include "ir_Tcl.h"
+#include
+#ifndef ARDUINO
+#include
+#endif
+#include "IRremoteESP8266.h"
+#include "IRutils.h"
+
+// Constants
+
+
+#if SEND_TCL112AC
+void IRsend::sendTcl112Ac(const unsigned char data[], const uint16_t nbytes,
+ const uint16_t repeat) {
+ sendGeneric(kTcl112AcHdrMark, kTcl112AcHdrSpace,
+ kTcl112AcBitMark, kTcl112AcOneSpace,
+ kTcl112AcBitMark, kTcl112AcZeroSpace,
+ kTcl112AcBitMark, kTcl112AcGap,
+ data, nbytes, 38000, false, repeat, 50);
+}
+#endif // SEND_TCL112AC
+
+IRTcl112Ac::IRTcl112Ac(uint16_t pin) : _irsend(pin) { stateReset(); }
+
+void IRTcl112Ac::begin() { this->_irsend.begin(); }
+
+#if SEND_TCL112AC
+void IRTcl112Ac::send(const uint16_t repeat) {
+ this->checksum();
+ this->_irsend.sendTcl112Ac(remote_state, kTcl112AcStateLength, repeat);
+}
+#endif // SEND_TCL112AC
+
+// Calculate the checksum for a given array.
+// Args:
+// state: The array to calculate the checksum over.
+// length: The size of the array.
+// Returns:
+// The 8 bit checksum value.
+uint8_t IRTcl112Ac::calcChecksum(uint8_t state[],
+ const uint16_t length) {
+ if (length)
+ return sumBytes(state, length - 1);
+ else
+ return 0;
+}
+
+// Calculate & set the checksum for the current internal state of the remote.
+void IRTcl112Ac::checksum(const uint16_t length) {
+ // Stored the checksum value in the last byte.
+ if (length > 1)
+ remote_state[length - 1] = calcChecksum(remote_state, length);
+}
+
+// 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 IRTcl112Ac::validChecksum(uint8_t state[], const uint16_t length) {
+ return (length > 1 && state[length - 1] == calcChecksum(state, length));
+}
+
+void IRTcl112Ac::stateReset() {
+ for (uint8_t i = 0; i < kTcl112AcStateLength; i++)
+ remote_state[i] = 0x0;
+ // A known good state. (On, Cool, 24C)
+ remote_state[0] = 0x23;
+ remote_state[1] = 0xCB;
+ remote_state[2] = 0x26;
+ remote_state[3] = 0x01;
+ remote_state[5] = 0x24;
+ remote_state[6] = 0x03;
+ remote_state[7] = 0x07;
+ remote_state[8] = 0x40;
+ remote_state[13] = 0x03;
+}
+
+uint8_t* IRTcl112Ac::getRaw() {
+ this->checksum();
+ return remote_state;
+}
+
+void IRTcl112Ac::setRaw(const uint8_t new_code[], const uint16_t length) {
+ for (uint8_t i = 0; i < length && i < kTcl112AcStateLength; i++) {
+ remote_state[i] = new_code[i];
+ }
+}
+
+// Set the requested power state of the A/C to on.
+void IRTcl112Ac::on(void) { this->setPower(true); }
+
+// Set the requested power state of the A/C to off.
+void IRTcl112Ac::off(void) { this->setPower(false); }
+
+// Set the requested power state of the A/C.
+void IRTcl112Ac::setPower(const bool on) {
+ if (on)
+ remote_state[5] |= kTcl112AcPowerMask;
+ else
+ remote_state[5] &= ~kTcl112AcPowerMask;
+}
+
+// Return the requested power state of the A/C.
+bool IRTcl112Ac::getPower(void) {
+ return remote_state[5] & kTcl112AcPowerMask;
+}
+
+// Get the requested climate operation mode of the a/c unit.
+// Returns:
+// A uint8_t containing the A/C mode.
+uint8_t IRTcl112Ac::getMode() {
+ return remote_state[6] & 0xF;
+}
+
+// Set the requested climate operation mode of the a/c unit.
+// Note: Fan/Ventilation mode sets the fan speed to high.
+// Unknown values default to Auto.
+void IRTcl112Ac::setMode(const uint8_t mode) {
+ // If we get an unexpected mode, default to AUTO.
+ switch (mode) {
+ case kTcl112AcFan:
+ this->setFan(kTcl112AcFanHigh);
+ // FALLTHRU
+ case kTcl112AcAuto:
+ case kTcl112AcCool:
+ case kTcl112AcHeat:
+ case kTcl112AcDry:
+ remote_state[6] &= 0xF0;
+ remote_state[6] |= mode;
+ break;
+ default:
+ setMode(kTcl112AcAuto);
+ }
+}
+
+void IRTcl112Ac::setTemp(const float celsius) {
+ // Make sure we have desired temp in the correct range.
+ float safecelsius = std::max(celsius, kTcl112AcTempMin);
+ safecelsius = std::min(safecelsius, kTcl112AcTempMax);
+ // Convert to integer nr. of half degrees.
+ uint8_t nrHalfDegrees = safecelsius * 2;
+ if (nrHalfDegrees & 1) // Do we have a half degree celsius?
+ remote_state[12] |= kTcl112AcHalfDegree; // Add 0.5 degrees
+ else
+ remote_state[12] &= ~kTcl112AcHalfDegree; // Clear the half degree.
+ remote_state[7] &= 0xF0; // Clear temp bits.
+ remote_state[7] |= ((uint8_t)kTcl112AcTempMax - nrHalfDegrees / 2);
+}
+
+float IRTcl112Ac::getTemp() {
+ float result = kTcl112AcTempMax - (remote_state[7] & 0xF);
+ if (remote_state[12] & kTcl112AcHalfDegree) result += 0.5;
+ return result;
+}
+
+// Set the speed of the fan.
+// Unknown speeds will default to Auto.
+void IRTcl112Ac::setFan(const uint8_t speed) {
+ switch (speed) {
+ case kTcl112AcFanAuto:
+ case kTcl112AcFanLow:
+ case kTcl112AcFanMed:
+ case kTcl112AcFanHigh:
+ remote_state[8] &= ~kTcl112AcFanMask;
+ remote_state[8] |= speed;
+ break;
+ default:
+ this->setFan(kTcl112AcFanAuto);
+ }
+}
+
+// Return the currect fan speed.
+uint8_t IRTcl112Ac::getFan() {
+ return remote_state[8] & kTcl112AcFanMask;
+}
+
+// Control economy mode.
+void IRTcl112Ac::setEcono(const bool on) {
+ if (on)
+ remote_state[5] |= kTcl112AcBitEcono;
+ else
+ remote_state[5] &= ~kTcl112AcBitEcono;
+}
+
+// Return the economy state of the A/C.
+bool IRTcl112Ac::getEcono(void) {
+ return remote_state[5] & kTcl112AcBitEcono;
+}
+
+// Control Health mode.
+void IRTcl112Ac::setHealth(const bool on) {
+ if (on)
+ remote_state[6] |= kTcl112AcBitHealth;
+ else
+ remote_state[6] &= ~kTcl112AcBitHealth;
+}
+
+// Return the Health mode state of the A/C.
+bool IRTcl112Ac::getHealth(void) {
+ return remote_state[6] & kTcl112AcBitHealth;
+}
+
+// Control Light/Display mode.
+void IRTcl112Ac::setLight(const bool on) {
+ if (on)
+ remote_state[5] &= ~kTcl112AcBitLight;
+ else
+ remote_state[5] |= kTcl112AcBitLight;
+}
+
+// Return the Light/Display mode state of the A/C.
+bool IRTcl112Ac::getLight(void) {
+ return !(remote_state[5] & kTcl112AcBitLight);
+}
+
+// Control Horizontal Swing.
+void IRTcl112Ac::setSwingHorizontal(const bool on) {
+ if (on)
+ remote_state[12] |= kTcl112AcBitSwingH;
+ else
+ remote_state[12] &= ~kTcl112AcBitSwingH;
+}
+
+// Return the Horizontal Swing state of the A/C.
+bool IRTcl112Ac::getSwingHorizontal(void) {
+ return remote_state[12] & kTcl112AcBitSwingH;
+}
+
+// Control Vertical Swing.
+void IRTcl112Ac::setSwingVertical(const bool on) {
+ if (on)
+ remote_state[8] |= kTcl112AcBitSwingV;
+ else
+ remote_state[8] &= ~kTcl112AcBitSwingV;
+}
+
+// Return the Vertical Swing state of the A/C.
+bool IRTcl112Ac::getSwingVertical(void) {
+ return remote_state[8] & kTcl112AcBitSwingV;
+}
+
+// Control the Turbo setting.
+void IRTcl112Ac::setTurbo(const bool on) {
+ if (on) {
+ remote_state[6] |= kTcl112AcBitTurbo;
+ this->setFan(kTcl112AcFanHigh);
+ this->setSwingVertical(true);
+ } else {
+ remote_state[6] &= ~kTcl112AcBitTurbo;
+ }
+}
+
+// Return the Turbo setting state of the A/C.
+bool IRTcl112Ac::getTurbo(void) {
+ return remote_state[6] & kTcl112AcBitTurbo;
+}
+
+// Convert a standard A/C mode into its native mode.
+uint8_t IRTcl112Ac::convertMode(const stdAc::opmode_t mode) {
+ switch (mode) {
+ case stdAc::opmode_t::kCool:
+ return kTcl112AcCool;
+ case stdAc::opmode_t::kHeat:
+ return kTcl112AcHeat;
+ case stdAc::opmode_t::kDry:
+ return kTcl112AcDry;
+ case stdAc::opmode_t::kFan:
+ return kTcl112AcFan;
+ default:
+ return kTcl112AcAuto;
+ }
+}
+
+// Convert a standard A/C Fan speed into its native fan speed.
+uint8_t IRTcl112Ac::convertFan(const stdAc::fanspeed_t speed) {
+ switch (speed) {
+ case stdAc::fanspeed_t::kMin:
+ case stdAc::fanspeed_t::kLow:
+ return kTcl112AcFanLow;
+ case stdAc::fanspeed_t::kMedium:
+ return kTcl112AcFanMed;
+ case stdAc::fanspeed_t::kHigh:
+ case stdAc::fanspeed_t::kMax:
+ return kTcl112AcFanHigh;
+ default:
+ return kTcl112AcFanAuto;
+ }
+}
+
+// Convert the internal state into a human readable string.
+#ifdef ARDUINO
+String IRTcl112Ac::toString() {
+ String result = "";
+#else
+std::string IRTcl112Ac::toString() {
+ std::string result = "";
+#endif // ARDUINO
+ result += F("Power: ");
+ result += (this->getPower() ? F("On") : F("Off"));
+ result += F(", Mode: ");
+ result += uint64ToString(getMode());
+ switch (this->getMode()) {
+ case kTcl112AcAuto:
+ result += F(" (AUTO)");
+ break;
+ case kTcl112AcCool:
+ result += F(" (COOL)");
+ break;
+ case kTcl112AcHeat:
+ result += F(" (HEAT)");
+ break;
+ case kTcl112AcDry:
+ result += F(" (DRY)");
+ break;
+ case kTcl112AcFan:
+ result += F(" (FAN)");
+ break;
+ default:
+ result += F(" (UNKNOWN)");
+ }
+ uint16_t nrHalfDegrees = this->getTemp() * 2;
+ result += F(", Temp: ");
+ result += uint64ToString(nrHalfDegrees / 2);
+ if (nrHalfDegrees & 1) result += F(".5");
+ result += F("C, Fan: ");
+ result += uint64ToString(getFan());
+ switch (getFan()) {
+ case kTcl112AcFanAuto:
+ result += F(" (Auto)");
+ break;
+ case kTcl112AcFanLow:
+ result += F(" (Low)");
+ break;
+ case kTcl112AcFanMed:
+ result += F(" (Med)");
+ break;
+ case kTcl112AcFanHigh:
+ result += F(" (High)");
+ break;
+ }
+ result += F(", Econo: ");
+ result += (this->getEcono() ? F("On") : F("Off"));
+ result += ", Health: ";
+ result += (this->getHealth() ? F("On") : F("Off"));
+ result += F(", Light: ");
+ result += (this->getLight() ? F("On") : F("Off"));
+ result += F(", Turbo: ");
+ result += (this->getTurbo() ? F("On") : F("Off"));
+ result += ", Swing (H): ";
+ result += (this->getSwingHorizontal() ? F("On") : F("Off"));
+ result += F(", Swing (V): ");
+ result += (this->getSwingVertical() ? F("On") : F("Off"));
+ return result;
+}
+
+#if DECODE_TCL112AC
+// Decode the supplied TCL112AC 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 kTcl112AcBits.
+// 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/619
+bool IRrecv::decodeTcl112Ac(decode_results *results, uint16_t nbits,
+ bool strict) {
+ if (results->rawlen < 2 * nbits + kHeader + kFooter - 1)
+ return false; // Can't possibly be a valid Samsung A/C message.
+ if (strict && nbits != kTcl112AcBits) return false;
+
+ uint16_t offset = kStartOffset;
+ uint16_t dataBitsSoFar = 0;
+ match_result_t data_result;
+
+ // Message Header
+ if (!matchMark(results->rawbuf[offset++], kTcl112AcHdrMark)) return false;
+ if (!matchSpace(results->rawbuf[offset++], kTcl112AcHdrSpace)) return false;
+
+ // Data
+ // 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, kTcl112AcBitMark,
+ kTcl112AcOneSpace, kTcl112AcBitMark,
+ kTcl112AcZeroSpace, 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;
+ }
+
+ // Footer
+ if (!matchMark(results->rawbuf[offset++], kTcl112AcBitMark)) return false;
+ if (offset <= results->rawlen &&
+ !matchAtLeast(results->rawbuf[offset++], kTcl112AcGap)) return false;
+ // Compliance
+ // Re-check we got the correct size/length due to the way we read the data.
+ if (dataBitsSoFar != nbits) return false;
+ // Verify we got a valid checksum.
+ if (strict && !IRTcl112Ac::validChecksum(results->state)) return false;
+ // Success
+ results->decode_type = TCL112AC;
+ 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_TCL112AC
diff --git a/lib/IRremoteESP8266-2.6.0/src/ir_Tcl.h b/lib/IRremoteESP8266-2.6.0/src/ir_Tcl.h
new file mode 100644
index 000000000..a1595451d
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_Tcl.h
@@ -0,0 +1,105 @@
+// Copyright 2019 David Conran
+
+#ifndef IR_TCL_H_
+#define IR_TCL_H_
+
+#ifndef UNIT_TEST
+#include
+#else
+#include
+#endif
+#include "IRremoteESP8266.h"
+#include "IRsend.h"
+#ifdef UNIT_TEST
+#include "IRsend_test.h"
+#endif
+
+// Constants
+const uint16_t kTcl112AcHdrMark = 3000;
+const uint16_t kTcl112AcHdrSpace = 1650;
+const uint16_t kTcl112AcBitMark = 500;
+const uint16_t kTcl112AcOneSpace = 1050;
+const uint16_t kTcl112AcZeroSpace = 325;
+const uint32_t kTcl112AcGap = kDefaultMessageGap; // Just a guess.
+
+const uint8_t kTcl112AcHeat = 1;
+const uint8_t kTcl112AcDry = 2;
+const uint8_t kTcl112AcCool = 3;
+const uint8_t kTcl112AcFan = 7;
+const uint8_t kTcl112AcAuto = 8;
+const uint8_t kTcl112AcFanMask = 0b00000111;
+const uint8_t kTcl112AcFanAuto = 0b00000000;
+const uint8_t kTcl112AcFanLow = 0b00000010;
+const uint8_t kTcl112AcFanMed = 0b00000011;
+const uint8_t kTcl112AcFanHigh = 0b00000101;
+
+const uint8_t kTcl112AcHalfDegree = 0b00100000;
+const float kTcl112AcTempMax = 31.0;
+const float kTcl112AcTempMin = 16.0;
+
+const uint8_t kTcl112AcPowerMask = 0b00000100;
+const uint8_t kTcl112AcBitEcono = 0b10000000;
+const uint8_t kTcl112AcBitLight = 0b01000000;
+const uint8_t kTcl112AcBitHealth = 0b00010000;
+const uint8_t kTcl112AcBitSwingH = 0b00001000;
+const uint8_t kTcl112AcBitSwingV = 0b00111000;
+const uint8_t kTcl112AcBitTurbo = 0b01000000;
+
+
+class IRTcl112Ac {
+ public:
+ explicit IRTcl112Ac(uint16_t pin);
+
+#if SEND_TCL112AC
+ void send(const uint16_t repeat = kTcl112AcDefaultRepeat);
+#endif // SEND_TCL
+ void begin(void);
+ uint8_t* getRaw(void);
+ void setRaw(const uint8_t new_code[],
+ const uint16_t length = kTcl112AcStateLength);
+ void on(void);
+ void off(void);
+ void setPower(const bool on);
+ bool getPower(void);
+ void setTemp(const float celsius); // Celsius in 0.5 increments
+ float getTemp(void);
+ void setMode(const uint8_t mode);
+ uint8_t getMode(void);
+ static uint8_t calcChecksum(uint8_t state[],
+ const uint16_t length = kTcl112AcStateLength);
+ static bool validChecksum(uint8_t state[],
+ const uint16_t length = kTcl112AcStateLength);
+ void setFan(const uint8_t speed);
+ uint8_t getFan(void);
+ void setEcono(const bool on);
+ bool getEcono(void);
+ void setHealth(const bool on);
+ bool getHealth(void);
+ void setLight(const bool on);
+ bool getLight(void);
+ void setSwingHorizontal(const bool on);
+ bool getSwingHorizontal(void);
+ void setSwingVertical(const bool on);
+ bool getSwingVertical(void);
+ void setTurbo(const bool on);
+ bool getTurbo(void);
+ uint8_t convertMode(const stdAc::opmode_t mode);
+ uint8_t convertFan(const stdAc::fanspeed_t speed);
+#ifdef ARDUINO
+ String toString();
+#else
+ std::string toString();
+#endif
+#ifndef UNIT_TEST
+
+ private:
+ IRsend _irsend;
+#else
+ IRsendTest _irsend;
+#endif
+ uint8_t remote_state[kTcl112AcStateLength];
+ void stateReset();
+ void checksum(const uint16_t length = kTcl112AcStateLength);
+};
+
+#endif // IR_TCL_H_
diff --git a/lib/IRremoteESP8266-2.6.0/src/ir_Teco.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_Teco.cpp
new file mode 100644
index 000000000..779bf8f8f
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_Teco.cpp
@@ -0,0 +1,278 @@
+// Copyright 2019 Fabien Valthier
+/*
+Node MCU/ESP8266 Sketch to emulate Teco
+*/
+
+#include "ir_Teco.h"
+#include
+#include "IRremoteESP8266.h"
+#include "IRutils.h"
+#ifndef ARDUINO
+#include
+#endif
+
+// Constants
+// using SPACE modulation.
+const uint16_t kTecoHdrMark = 9000;
+const uint16_t kTecoHdrSpace = 4440;
+const uint16_t kTecoBitMark = 620;
+const uint16_t kTecoOneSpace = 1650;
+const uint16_t kTecoZeroSpace = 580;
+const uint32_t kTecoGap = kDefaultMessageGap; // Made-up value. Just a guess.
+
+#if SEND_TECO
+// Send a Teco A/C message.
+//
+// Args:
+// data: Contents of the message to be sent.
+// nbits: Nr. of bits of data to be sent. Typically kTecoBits.
+// repeat: Nr. of additional times the message is to be sent.
+void IRsend::sendTeco(uint64_t data, uint16_t nbits, uint16_t repeat) {
+ sendGeneric(kTecoHdrMark, kTecoHdrSpace, kTecoBitMark, kTecoOneSpace,
+ kTecoBitMark, kTecoZeroSpace, kTecoBitMark, kTecoGap,
+ data, nbits, 38000, false, repeat, kDutyDefault);
+}
+#endif // SEND_TECO
+
+// Class for decoding and constructing Teco AC messages.
+IRTecoAc::IRTecoAc(const uint16_t pin) : _irsend(pin) { stateReset(); }
+
+void IRTecoAc::begin() { _irsend.begin(); }
+
+#if SEND_TECO
+void IRTecoAc::send(const uint16_t repeat) {
+ _irsend.sendTeco(remote_state, kTecoBits, repeat);
+}
+#endif // SEND_TECO
+
+void IRTecoAc::stateReset(void) {
+ // Mode:auto, Power:Off, fan:auto, temp:16, swing:off, sleep:off
+ remote_state = kTecoReset;
+}
+
+uint64_t IRTecoAc::getRaw(void) { return remote_state; }
+
+void IRTecoAc::setRaw(const uint64_t new_code) { remote_state = new_code; }
+
+void IRTecoAc::on(void) { remote_state |= kTecoPower; }
+
+void IRTecoAc::off(void) { remote_state &= ~kTecoPower; }
+
+void IRTecoAc::setPower(const bool on) {
+ if (on)
+ this->on();
+ else
+ this->off();
+}
+
+bool IRTecoAc::getPower(void) {
+ return (remote_state & kTecoPower) == kTecoPower; }
+
+void IRTecoAc::setTemp(const uint8_t temp) {
+ uint8_t newtemp = temp;
+ newtemp = std::min(newtemp, kTecoMaxTemp);
+ newtemp = std::max(newtemp, kTecoMinTemp);
+ newtemp -= kTecoMinTemp; // 16=0b000
+
+ remote_state &= ~kTecoTempMask; // reinit temp
+ remote_state |= (newtemp << 8);
+}
+
+uint8_t IRTecoAc::getTemp(void) {
+ return ((remote_state & kTecoTempMask) >> 8) + kTecoMinTemp;
+}
+
+// Set the speed of the fan
+void IRTecoAc::setFan(const uint8_t speed) {
+ uint8_t newspeed = speed;
+ switch (speed) {
+ case kTecoFanAuto:
+ case kTecoFanHigh:
+ case kTecoFanMed:
+ case kTecoFanLow:
+ break;
+ default:
+ newspeed = kTecoFanAuto;
+ }
+ remote_state &= ~kTecoFanMask; // reinit fan
+ remote_state |= (newspeed << 4);
+}
+
+uint8_t IRTecoAc::getFan(void) { return (remote_state & kTecoFanMask) >> 4; }
+
+void IRTecoAc::setMode(const uint8_t mode) {
+ uint8_t newmode = mode;
+ switch (mode) {
+ case kTecoAuto:
+ case kTecoCool:
+ case kTecoDry:
+ case kTecoFan:
+ case kTecoHeat:
+ break;
+ default:
+ newmode = kTecoAuto;
+ }
+ remote_state &= ~kTecoModeMask; // reinit mode
+ remote_state |= newmode;
+}
+
+uint8_t IRTecoAc::getMode(void) { return remote_state & kTecoModeMask; }
+
+void IRTecoAc::setSwing(const bool on) {
+ if (on)
+ remote_state |= kTecoSwing;
+ else
+ remote_state &= ~kTecoSwing;
+}
+
+bool IRTecoAc::getSwing(void) { return remote_state & kTecoSwing; }
+
+void IRTecoAc::setSleep(const bool on) {
+ if (on)
+ remote_state |= kTecoSleep;
+ else
+ remote_state &= ~kTecoSleep;
+}
+
+bool IRTecoAc::getSleep(void) { return remote_state & kTecoSleep; }
+
+// Convert a standard A/C mode into its native mode.
+uint8_t IRTecoAc::convertMode(const stdAc::opmode_t mode) {
+ switch (mode) {
+ case stdAc::opmode_t::kCool:
+ return kTecoCool;
+ case stdAc::opmode_t::kHeat:
+ return kTecoHeat;
+ case stdAc::opmode_t::kDry:
+ return kTecoDry;
+ case stdAc::opmode_t::kFan:
+ return kTecoFan;
+ default:
+ return kTecoAuto;
+ }
+}
+
+// Convert a standard A/C Fan speed into its native fan speed.
+uint8_t IRTecoAc::convertFan(const stdAc::fanspeed_t speed) {
+ switch (speed) {
+ case stdAc::fanspeed_t::kMin:
+ case stdAc::fanspeed_t::kLow:
+ return kTecoFanLow;
+ case stdAc::fanspeed_t::kMedium:
+ return kTecoFanMed;
+ case stdAc::fanspeed_t::kHigh:
+ case stdAc::fanspeed_t::kMax:
+ return kTecoFanHigh;
+ default:
+ return kTecoFanAuto;
+ }
+}
+
+// Convert the internal state into a human readable string.
+#ifdef ARDUINO
+String IRTecoAc::toString(void) {
+ String result = "";
+#else
+std::string IRTecoAc::toString(void) {
+ std::string result = "";
+#endif // ARDUINO
+ result += F("Power: ");
+ result += (this->getPower() ? F("On") : F("Off"));
+ result += F(", Mode: ");
+ result += uint64ToString(this->getMode());
+ switch (this->getMode()) {
+ case kTecoAuto:
+ result += F(" (AUTO)");
+ break;
+ case kTecoCool:
+ result += F(" (COOL)");
+ break;
+ case kTecoHeat:
+ result += F(" (HEAT)");
+ break;
+ case kTecoDry:
+ result += F(" (DRY)");
+ break;
+ case kTecoFan:
+ result += F(" (FAN)");
+ break;
+ default:
+ result += F(" (UNKNOWN)");
+ }
+ result += F(", Temp: ");
+ result += uint64ToString(getTemp());
+ result += F("C, Fan: ");
+ result += uint64ToString(getFan());
+ switch (this->getFan()) {
+ case kTecoFanAuto:
+ result += F(" (Auto)");
+ break;
+ case kTecoFanHigh:
+ result += F(" (High)");
+ break;
+ case kTecoFanLow:
+ result += F(" (Low)");
+ break;
+ case kTecoFanMed:
+ result += F(" (Med)");
+ break;
+ default:
+ result += F(" (UNKNOWN)");
+ }
+ result += F(", Sleep: ");
+ result += (this->getSleep() ? F("On") : F("Off"));
+ result += F(", Swing: ");
+ result += (this->getSwing() ? F("On") : F("Off"));
+ return result;
+}
+
+#if DECODE_TECO
+// Decode the supplied Teco 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 kTecoBits.
+// strict: Flag indicating if we should perform strict matching.
+// Returns:
+// boolean: True if it can decode it, false if it can't.
+//
+// Status: STABLE / Tested.
+bool IRrecv::decodeTeco(decode_results* results, uint16_t nbits, bool strict) {
+ // Check if can possibly be a valid Teco message.
+ if (results->rawlen < 2 * nbits + kHeader + kFooter - 1) return false;
+ if (strict && nbits != kTecoBits) return false; // Not what is expected
+
+ uint64_t data = 0;
+ uint16_t offset = kStartOffset;
+ match_result_t data_result;
+
+ // Header
+ if (!matchMark(results->rawbuf[offset++], kTecoHdrMark)) return false;
+ if (!matchSpace(results->rawbuf[offset++], kTecoHdrSpace)) return false;
+ // Data (35 bits)
+ data_result =
+ matchData(&(results->rawbuf[offset]), 35, kTecoBitMark, kTecoOneSpace,
+ kTecoBitMark, kTecoZeroSpace, kTolerance, kMarkExcess, false);
+ 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++], kTecoBitMark)) return false;
+ if (offset < results->rawlen &&
+ !matchAtLeast(results->rawbuf[offset], kTecoGap)) return false;
+
+ // Compliance
+ if (actualBits < nbits) return false;
+ if (strict && actualBits != nbits) return false; // Not as we expected.
+
+ // Success
+ results->decode_type = TECO;
+ results->bits = actualBits;
+ results->value = data;
+ results->address = 0;
+ results->command = 0;
+ return true;
+}
+#endif // DECODE_TECO
diff --git a/lib/IRremoteESP8266-2.6.0/src/ir_Teco.h b/lib/IRremoteESP8266-2.6.0/src/ir_Teco.h
new file mode 100644
index 000000000..65a0050ae
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_Teco.h
@@ -0,0 +1,144 @@
+// Copyright 2019 Fabien Valthier
+
+#ifndef IR_TECO_H_
+#define IR_TECO_H_
+
+#ifndef UNIT_TEST
+#include
+#else
+#include
+#endif
+#include "IRremoteESP8266.h"
+#include "IRsend.h"
+#ifdef UNIT_TEST
+#include "IRsend_test.h"
+#endif
+
+// Constants. Using LSB to be able to send only 35bits.
+const uint8_t kTecoAuto = 0; // 0b000
+const uint8_t kTecoCool = 1; // 0b001
+const uint8_t kTecoDry = 2; // 0b010
+const uint8_t kTecoFan = 3; // 0b110
+const uint8_t kTecoHeat = 4; // 0b001
+const uint8_t kTecoFanAuto = 0; // 0b00
+const uint8_t kTecoFanHigh = 3; // 0b11
+const uint8_t kTecoFanMed = 2; // 0b10
+const uint8_t kTecoFanLow = 1; // 0b01
+const uint8_t kTecoMinTemp = 16; // 16C
+const uint8_t kTecoMaxTemp = 30; // 30C
+
+const uint64_t kTecoModeMask = 0b00000000000000000000000000000000111;
+const uint64_t kTecoPower = 0b00000000000000000000000000000001000;
+const uint64_t kTecoFanMask = 0b00000000000000000000000000000110000;
+const uint64_t kTecoSwing = 0b00000000000000000000000000001000000;
+const uint64_t kTecoSleep = 0b00000000000000000000000000010000000;
+const uint64_t kTecoTempMask = 0b00000000000000000000000111100000000;
+const uint64_t kTecoTimerHalfH = 0b00000000000000000000001000000000000;
+const uint64_t kTecoTimerTenHr = 0b00000000000000000000110000000000000;
+const uint64_t kTecoTimerOn = 0b00000000000000000001000000000000000;
+const uint64_t kTecoTimerUniHr = 0b00000000000000011110000000000000000;
+const uint64_t kTecoReset = 0b01001010000000000000010000000000000;
+/*
+ (header mark and space)
+ Teco AC map read and to be sent in LSB with number of bits
+
+ byte 0 = Cst 0x02
+ byte 1 = Cst 0x50
+ byte 2:
+ b0-3 = 0b0000
+ b4-7 = Timer hours (unit, not thenth)
+ hours:
+ 0000 (0) = +0 hour
+ 0001 (1) = +1 hour
+ ...
+ 1001 (9) = +9 hours
+ byte 3: = timer and Temperature
+ b0 = Timer (1 = On, 0 = Off)
+ b1-2 = Timer - number of 10hours
+ 10Hours:
+ 00 = 0 * 10hours of timer
+ 01 = 1 * 10 hours of timer
+ 10 = 2 * 10hours of timer
+ b3 = Timer - half hour (1=half hour on, 0 = round hour)
+ b4-7: Degrees C.
+ 0000 (0) = 16C
+ 0001 (1) = 17C
+ 0010 (2) = 18C
+ ...
+ 1101 (13) = 29C
+ 1110 (14) = 30C
+ byte 4: Basics
+ b0 = Sleep Mode (1 = On, 0 = Off)
+ b1 = Vent swing (1 = On, 0 = Off)
+ b2-3 = Fan
+ Fan:
+ 00 = Auto
+ 01 = Fan 1
+ 10 = Fan 2
+ 11 = Fan 3 or higher
+ b4 = Power Status (1 = On, 0 = Off)
+ b5-7 = Modes LSB first
+ Modes:
+ 000 = Auto (temp = 25C)
+ 001 = Cool
+ 010 = Dry (temp = 25C, but not shown)
+ 011 = Fan
+ 100 = Heat
+*/
+
+// Classes
+class IRTecoAc {
+ public:
+ explicit IRTecoAc(const uint16_t pin);
+
+ void stateReset(void);
+#if SEND_TECO
+ void send(const uint16_t repeat = kTecoDefaultRepeat);
+#endif // SEND_TECO
+ void begin(void);
+ void on(void);
+ void off(void);
+
+ void setPower(const bool on);
+ bool getPower(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 setSwing(const bool state);
+ bool getSwing(void);
+
+ void setSleep(const bool state);
+ bool getSleep(void);
+
+ // void setTimer(uint8_t time); // To check unit
+ // uint8_t getTimer(uint8_t);
+
+ uint64_t getRaw(void);
+ void setRaw(const uint64_t new_code);
+
+ uint8_t convertMode(const stdAc::opmode_t mode);
+ uint8_t convertFan(const stdAc::fanspeed_t speed);
+#ifdef ARDUINO
+ String toString(void);
+#else
+ std::string toString(void);
+#endif
+#ifndef UNIT_TEST
+
+ private:
+ IRsend _irsend;
+#else
+ IRsendTest _irsend;
+#endif
+ // The state of the IR remote in IR code form.
+ uint64_t remote_state;
+};
+
+#endif // IR_TECO_H_
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_Toshiba.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_Toshiba.cpp
similarity index 86%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_Toshiba.cpp
rename to lib/IRremoteESP8266-2.6.0/src/ir_Toshiba.cpp
index 817b5fbaa..a82a2fb24 100644
--- a/lib/IRremoteESP8266-2.5.2.03/src/ir_Toshiba.cpp
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_Toshiba.cpp
@@ -89,9 +89,9 @@ void IRToshibaAC::begin() { _irsend.begin(); }
#if SEND_TOSHIBA_AC
// Send the current desired state to the IR LED.
-void IRToshibaAC::send() {
+void IRToshibaAC::send(const uint16_t repeat) {
checksum(); // Ensure correct checksum before sending.
- _irsend.sendToshibaAC(remote_state);
+ _irsend.sendToshibaAC(remote_state, kToshibaACStateLength, repeat);
}
#endif // SEND_TOSHIBA_AC
@@ -233,6 +233,39 @@ void IRToshibaAC::setMode(uint8_t mode) {
}
}
+// Convert a standard A/C mode into its native mode.
+uint8_t IRToshibaAC::convertMode(const stdAc::opmode_t mode) {
+ switch (mode) {
+ case stdAc::opmode_t::kCool:
+ return kToshibaAcCool;
+ case stdAc::opmode_t::kHeat:
+ return kToshibaAcHeat;
+ case stdAc::opmode_t::kDry:
+ return kToshibaAcDry;
+ // No Fan mode.
+ default:
+ return kToshibaAcAuto;
+ }
+}
+
+// Convert a standard A/C Fan speed into its native fan speed.
+uint8_t IRToshibaAC::convertFan(const stdAc::fanspeed_t speed) {
+ switch (speed) {
+ case stdAc::fanspeed_t::kMin:
+ return kToshibaAcFanMax - 4;
+ case stdAc::fanspeed_t::kLow:
+ return kToshibaAcFanMax - 3;
+ case stdAc::fanspeed_t::kMedium:
+ return kToshibaAcFanMax - 2;
+ case stdAc::fanspeed_t::kHigh:
+ return kToshibaAcFanMax - 1;
+ case stdAc::fanspeed_t::kMax:
+ return kToshibaAcFanMax;
+ default:
+ return kToshibaAcFanAuto;
+ }
+}
+
// Convert the internal state into a human readable string.
#ifdef ARDUINO
String IRToshibaAC::toString() {
@@ -241,36 +274,39 @@ String IRToshibaAC::toString() {
std::string IRToshibaAC::toString() {
std::string result = "";
#endif // ARDUINO
- result += "Power: ";
+ result += F("Power: ");
if (getPower())
- result += "On";
+ result += F("On");
else
- result += "Off";
- result += ", Mode: " + uint64ToString(getMode());
+ result += F("Off");
+ result += F(", Mode: ");
+ result += uint64ToString(getMode());
switch (getMode()) {
case kToshibaAcAuto:
- result += " (AUTO)";
+ result += F(" (AUTO)");
break;
case kToshibaAcCool:
- result += " (COOL)";
+ result += F(" (COOL)");
break;
case kToshibaAcHeat:
- result += " (HEAT)";
+ result += F(" (HEAT)");
break;
case kToshibaAcDry:
- result += " (DRY)";
+ result += F(" (DRY)");
break;
default:
- result += " (UNKNOWN)";
+ result += F(" (UNKNOWN)");
}
- result += ", Temp: " + uint64ToString(getTemp()) + "C";
- result += ", Fan: " + uint64ToString(getFan());
+ result += F(", Temp: ");
+ result += uint64ToString(getTemp());
+ result += F("C, Fan: ");
+ result += uint64ToString(getFan());
switch (getFan()) {
case kToshibaAcFanAuto:
- result += " (AUTO)";
+ result += F(" (AUTO)");
break;
case kToshibaAcFanMax:
- result += " (MAX)";
+ result += F(" (MAX)");
break;
}
return result;
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_Toshiba.h b/lib/IRremoteESP8266-2.6.0/src/ir_Toshiba.h
similarity index 90%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_Toshiba.h
rename to lib/IRremoteESP8266-2.6.0/src/ir_Toshiba.h
index 1a1e6cdc8..03b461add 100644
--- a/lib/IRremoteESP8266-2.5.2.03/src/ir_Toshiba.h
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_Toshiba.h
@@ -11,6 +11,9 @@
#endif
#include "IRremoteESP8266.h"
#include "IRsend.h"
+#ifdef UNIT_TEST
+#include "IRsend_test.h"
+#endif
// TTTTTTT OOOOO SSSSS HH HH IIIII BBBBB AAA
// TTT OO OO SS HH HH III BB B AAAAA
@@ -48,7 +51,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();
@@ -65,6 +68,8 @@ class IRToshibaAC {
uint8_t* getRaw();
static bool validChecksum(const uint8_t state[],
const uint16_t length = kToshibaACStateLength);
+ uint8_t convertMode(const stdAc::opmode_t mode);
+ uint8_t convertFan(const stdAc::fanspeed_t speed);
#ifdef ARDUINO
String toString();
#else
@@ -73,13 +78,15 @@ class IRToshibaAC {
#ifndef UNIT_TEST
private:
+ IRsend _irsend;
+#else
+ IRsendTest _irsend;
#endif
uint8_t remote_state[kToshibaACStateLength];
void checksum(const uint16_t length = kToshibaACStateLength);
static uint8_t calcChecksum(const uint8_t state[],
const uint16_t length = kToshibaACStateLength);
uint8_t mode_state;
- IRsend _irsend;
};
#endif // IR_TOSHIBA_H_
diff --git a/lib/IRremoteESP8266-2.6.0/src/ir_Trotec.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_Trotec.cpp
new file mode 100644
index 000000000..b5c15e7fd
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_Trotec.cpp
@@ -0,0 +1,162 @@
+// Copyright 2017 stufisher
+
+#include "ir_Trotec.h"
+#include
+#include "IRremoteESP8266.h"
+#include "IRutils.h"
+
+// Constants
+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 < kTrotecStateLength) return;
+
+ for (uint16_t r = 0; r <= repeat; r++) {
+ sendGeneric(kTrotecHdrMark, kTrotecHdrSpace, kTrotecOneMark,
+ kTrotecOneSpace, kTrotecZeroMark, kTrotecZeroSpace,
+ kTrotecOneMark, kTrotecGap, data, nbytes, 36, false,
+ 0, // Repeats handled elsewhere
+ 50);
+ // More footer
+ enableIROut(36);
+ mark(kTrotecOneMark);
+ space(kTrotecGapEnd);
+ }
+}
+#endif // SEND_TROTEC
+
+IRTrotecESP::IRTrotecESP(uint16_t pin) : _irsend(pin) { stateReset(); }
+
+void IRTrotecESP::begin() { _irsend.begin(); }
+
+#if SEND_TROTEC
+void IRTrotecESP::send(const uint16_t repeat) {
+ checksum();
+ _irsend.sendTrotec(remote_state, kTrotecStateLength, repeat);
+}
+#endif // SEND_TROTEC
+
+void IRTrotecESP::checksum() {
+ uint8_t sum = 0;
+
+ for (uint8_t i = 2; i < 8; i++) sum += remote_state[i];
+ remote_state[8] = sum & 0xFF;
+}
+
+void IRTrotecESP::stateReset() {
+ for (uint8_t i = 2; i < kTrotecStateLength; i++) remote_state[i] = 0x0;
+
+ remote_state[0] = kTrotecIntro1;
+ remote_state[1] = kTrotecIntro2;
+
+ setPower(false);
+ setTemp(kTrotecDefTemp);
+ setSpeed(kTrotecFanMed);
+ setMode(kTrotecAuto);
+}
+
+uint8_t* IRTrotecESP::getRaw() {
+ checksum();
+ return remote_state;
+}
+
+void IRTrotecESP::setPower(const bool on) {
+ if (on)
+ remote_state[2] |= kTrotecPowerBit;
+ else
+ remote_state[2] &= ~kTrotecPowerBit;
+}
+
+bool IRTrotecESP::getPower() { return remote_state[2] & kTrotecPowerBit; }
+
+void IRTrotecESP::setSpeed(const uint8_t fan) {
+ uint8_t speed = std::min(fan, kTrotecFanHigh);
+ remote_state[2] = (remote_state[2] & 0b11001111) | (speed << 4);
+}
+
+uint8_t IRTrotecESP::getSpeed() { return (remote_state[2] & 0b00110000) >> 4; }
+
+void IRTrotecESP::setMode(const uint8_t mode) {
+ switch (mode) {
+ case kTrotecAuto:
+ case kTrotecCool:
+ case kTrotecDry:
+ case kTrotecFan:
+ remote_state[2] = (remote_state[2] & 0b11111100) | mode;
+ return;
+ default:
+ this->setMode(kTrotecAuto);
+ }
+}
+
+uint8_t IRTrotecESP::getMode() { return remote_state[2] & 0b00000011; }
+
+void IRTrotecESP::setTemp(const uint8_t celsius) {
+ uint8_t temp = std::max(celsius, kTrotecMinTemp);
+ temp = std::min(temp, kTrotecMaxTemp);
+ remote_state[3] = (remote_state[3] & 0x80) | (temp - kTrotecMinTemp);
+}
+
+uint8_t IRTrotecESP::getTemp() {
+ return (remote_state[3] & 0b01111111) + kTrotecMinTemp;
+}
+
+void IRTrotecESP::setSleep(bool sleep) {
+ if (sleep)
+ remote_state[3] |= kTrotecSleepBit;
+ else
+ remote_state[3] &= ~kTrotecSleepBit;
+}
+
+bool IRTrotecESP::getSleep(void) { return remote_state[3] & kTrotecSleepBit; }
+
+void IRTrotecESP::setTimer(const uint8_t timer) {
+ if (timer)
+ remote_state[5] |= kTrotecTimerBit;
+ else
+ remote_state[5] &= ~kTrotecTimerBit;
+ remote_state[6] = (timer > kTrotecMaxTimer) ? kTrotecMaxTimer : timer;
+}
+
+uint8_t IRTrotecESP::getTimer() { return remote_state[6]; }
+
+// Convert a standard A/C mode into its native mode.
+uint8_t IRTrotecESP::convertMode(const stdAc::opmode_t mode) {
+ switch (mode) {
+ case stdAc::opmode_t::kCool:
+ return kTrotecCool;
+ case stdAc::opmode_t::kDry:
+ return kTrotecDry;
+ case stdAc::opmode_t::kFan:
+ return kTrotecFan;
+ // Note: No Heat mode.
+ default:
+ return kTrotecAuto;
+ }
+}
+
+// Convert a standard A/C Fan speed into its native fan speed.
+uint8_t IRTrotecESP::convertFan(const stdAc::fanspeed_t speed) {
+ switch (speed) {
+ case stdAc::fanspeed_t::kMin:
+ case stdAc::fanspeed_t::kLow:
+ return kTrotecFanLow;
+ case stdAc::fanspeed_t::kMedium:
+ return kTrotecFanMed;
+ case stdAc::fanspeed_t::kHigh:
+ case stdAc::fanspeed_t::kMax:
+ return kTrotecFanHigh;
+ default:
+ return kTrotecFanMed;
+ }
+}
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_Trotec.h b/lib/IRremoteESP8266-2.6.0/src/ir_Trotec.h
similarity index 68%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_Trotec.h
rename to lib/IRremoteESP8266-2.6.0/src/ir_Trotec.h
index 040d9a722..dfbc26c07 100644
--- a/lib/IRremoteESP8266-2.5.2.03/src/ir_Trotec.h
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_Trotec.h
@@ -5,6 +5,9 @@
#include "IRremoteESP8266.h"
#include "IRsend.h"
+#ifdef UNIT_TEST
+#include "IRsend_test.h"
+#endif
// Constants
// Byte 0
@@ -19,8 +22,7 @@ const uint8_t kTrotecCool = 1;
const uint8_t kTrotecDry = 2;
const uint8_t kTrotecFan = 3;
-const uint8_t kTrotecOn = 1;
-const uint8_t kTrotecOff = 0;
+const uint8_t kTrotecPowerBit = 0b00001000;
const uint8_t kTrotecFanLow = 1;
const uint8_t kTrotecFanMed = 2;
@@ -31,13 +33,12 @@ const uint8_t kTrotecMinTemp = 18;
const uint8_t kTrotecDefTemp = 25;
const uint8_t kTrotecMaxTemp = 32;
-const uint8_t kTrotecSleepOn = 1;
+const uint8_t kTrotecSleepBit = 0b10000000;
// Byte 5
-const uint8_t kTrotecTimerOn = 1;
+const uint8_t kTrotecTimerBit = 0b01000000;
// Byte 6
-const uint8_t kTrotecMinTimer = 0;
const uint8_t kTrotecMaxTimer = 23;
// Legacy defines. (Deperecated)
@@ -50,7 +51,6 @@ const uint8_t kTrotecMaxTimer = 23;
#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 {
@@ -58,35 +58,42 @@ class IRTrotecESP {
explicit IRTrotecESP(uint16_t pin);
#if SEND_TROTEC
- void send();
+ void send(const uint16_t repeat = kTrotecDefaultRepeat);
#endif // SEND_TROTEC
void begin();
- void setPower(bool state);
- uint8_t getPower();
+ void setPower(const bool state);
+ bool getPower();
- void setTemp(uint8_t temp);
+ void setTemp(const uint8_t celsius);
uint8_t getTemp();
- void setSpeed(uint8_t fan);
+ void setSpeed(const uint8_t fan);
uint8_t getSpeed();
uint8_t getMode();
- void setMode(uint8_t mode);
+ void setMode(const uint8_t mode);
bool getSleep();
void setSleep(bool sleep);
uint8_t getTimer();
- void setTimer(uint8_t timer);
+ void setTimer(const uint8_t timer);
uint8_t* getRaw();
+ uint8_t convertMode(const stdAc::opmode_t mode);
+ uint8_t convertFan(const stdAc::fanspeed_t speed);
+#ifndef UNIT_TEST
+
private:
- uint8_t trotec[kTrotecStateLength];
+ IRsend _irsend;
+#else
+ IRsendTest _irsend;
+#endif
+ uint8_t remote_state[kTrotecStateLength];
void stateReset();
void checksum();
- IRsend _irsend;
};
#endif // IR_TROTEC_H_
diff --git a/lib/IRremoteESP8266-2.6.0/src/ir_Vestel.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_Vestel.cpp
new file mode 100644
index 000000000..1fbb822cf
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_Vestel.cpp
@@ -0,0 +1,583 @@
+// Copyright 2018 Erdem U. Altinyurt
+// Copyright 2019 David Conran
+
+#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 = kVestelAcStateDefault;
+ remote_time_state = kVestelAcTimeStateDefault;
+ use_time_state = false;
+}
+
+// Configure the pin for output.
+void IRVestelAc::begin() {
+ _irsend.begin();
+}
+
+#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;
+ else
+ code_to_send = remote_state;
+ _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;
+ return remote_state;
+}
+
+// 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);
+ this->setRaw(upState);
+}
+
+void IRVestelAc::setRaw(const uint64_t newState) {
+ use_time_state = false;
+ remote_state = newState;
+ remote_time_state = newState;
+ if (this->isTimeCommand()) {
+ use_time_state = true;
+ remote_state = kVestelAcStateDefault;
+ } else {
+ remote_time_state = kVestelAcTimeStateDefault;
+ }
+}
+
+// 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) {
+ remote_state &= ~((uint64_t)0xF << kVestelAcPowerOffset);
+ if (state)
+ remote_state |= ((uint64_t)0xF << kVestelAcPowerOffset);
+ else
+ remote_state |= ((uint64_t)0xC << kVestelAcPowerOffset);
+ use_time_state = false;
+}
+
+// Return the requested power state of the A/C.
+bool IRVestelAc::getPower() {
+ return (remote_state >> kVestelAcPowerOffset == 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 &= ~((uint64_t)0xF << kVestelAcTempOffset);
+ remote_state |= (uint64_t)(new_temp - 16) << kVestelAcTempOffset;
+ use_time_state = false;
+}
+
+// Return the set temperature.
+uint8_t IRVestelAc::getTemp(void) {
+ return ((remote_state >> kVestelAcTempOffset) & 0xF) + 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:
+ case kVestelAcFanAuto:
+ remote_state &= ~((uint64_t)0xF << kVestelAcFanOffset);
+ remote_state |= (uint64_t)fan << kVestelAcFanOffset;
+ break;
+ default:
+ setFan(kVestelAcFanAuto);
+ }
+ use_time_state = false;
+}
+
+// Return the requested state of the unit's fan.
+uint8_t IRVestelAc::getFan() {
+ return (remote_state >> kVestelAcFanOffset) & 0xF;
+}
+
+// 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 >> kVestelAcModeOffset) & 0xF;
+}
+
+// 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 &= ~((uint64_t)0xF << kVestelAcModeOffset);
+ remote_state |= (uint64_t)mode << kVestelAcModeOffset;
+ break;
+ default:
+ setMode(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);
+}
+
+void IRVestelAc::setTimerActive(const bool on) {
+ if (on) // activation
+ remote_time_state |= ((uint64_t)1 << kVestelAcTimerFlagOffset);
+ else // deactivate
+ remote_time_state &= ~((uint64_t)1 << kVestelAcTimerFlagOffset);
+ use_time_state = true;
+}
+
+bool IRVestelAc::isTimerActive(void) {
+ return (remote_time_state >> kVestelAcTimerFlagOffset) & 1;
+}
+
+// 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) {
+ // Clear both On & Off timers.
+ remote_time_state &= ~((uint64_t)0xFFFF << kVestelAcOffTimeOffset);
+ // Set the "Off" time with the nr of minutes before we turn off.
+ remote_time_state |= (uint64_t)(((minutes / 60) << 3) + (minutes % 60) / 10)
+ << kVestelAcOffTimeOffset;
+ setOffTimerActive(false);
+ // Yes. On Timer instead of Off timer active.
+ setOnTimerActive(minutes != 0);
+ setTimerActive(minutes != 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 &= ~((uint64_t)0x1F << kVestelAcHourOffset);
+ remote_time_state |= (uint64_t)((minutes / 60) & 0x1F)
+ << kVestelAcHourOffset;
+ remote_time_state &= ~((uint64_t)0xFF << kVestelAcMinuteOffset);
+ remote_time_state |= (uint64_t)((minutes % 60) & 0xFF)
+ << kVestelAcMinuteOffset;
+ use_time_state = true;
+}
+
+uint16_t IRVestelAc::getTime(void) {
+ return ((remote_time_state >> kVestelAcHourOffset) & 0x1F) * 60 +
+ ((remote_time_state >> kVestelAcMinuteOffset) & 0xFF);
+}
+
+void IRVestelAc::setOnTimerActive(const bool on) {
+ if (on) // activation
+ remote_time_state |= ((uint64_t)1 << kVestelAcOnTimerFlagOffset);
+ else // deactivate
+ remote_time_state &= ~((uint64_t)1 << kVestelAcOnTimerFlagOffset);
+ use_time_state = true;
+}
+
+bool IRVestelAc::isOnTimerActive(void) {
+ return (remote_time_state >> kVestelAcOnTimerFlagOffset) & 1;
+}
+
+// Set AC's wake up time. Takes time in minute.
+void IRVestelAc::setOnTimer(const uint16_t minutes) {
+ remote_time_state &= ~((uint64_t)0xFF << kVestelAcOnTimeOffset);
+ remote_time_state |= (uint64_t)(((minutes / 60) << 3) + (minutes % 60) / 10)
+ << kVestelAcOnTimeOffset;
+ setOnTimerActive(minutes != 0);
+ setTimerActive(false);
+ use_time_state = true;
+}
+
+uint16_t IRVestelAc::getOnTimer(void) {
+ uint8_t ontime = (remote_time_state >> kVestelAcOnTimeOffset) & 0xFF;
+ return (ontime >> 3) * 60 + (ontime & 0x7) * 10;
+}
+
+void IRVestelAc::setOffTimerActive(const bool on) {
+ if (on) // activation
+ remote_time_state |= ((uint64_t)1 << kVestelAcOffTimerFlagOffset);
+ else // deactivate
+ remote_time_state &= ~((uint64_t)1 << kVestelAcOffTimerFlagOffset);
+ use_time_state = true;
+}
+
+bool IRVestelAc::isOffTimerActive(void) {
+ return (remote_time_state >> kVestelAcOffTimerFlagOffset) & 1;
+}
+
+// Set AC's turn off time. Takes time in minute.
+void IRVestelAc::setOffTimer(const uint16_t minutes) {
+ remote_time_state &= ~((uint64_t)0xFF << kVestelAcOffTimeOffset);
+ remote_time_state |=
+ (uint64_t)((((minutes / 60) << 3) + (minutes % 60) / 10) & 0xFF)
+ << kVestelAcOffTimeOffset;
+ setOffTimerActive(minutes != 0);
+ setTimerActive(false);
+ use_time_state = true;
+}
+
+uint16_t IRVestelAc::getOffTimer(void) {
+ uint8_t offtime = (remote_time_state >> kVestelAcOffTimeOffset) & 0xFF;
+ return (offtime >> 3) * 60 + (offtime & 0x7) * 10;
+}
+
+// Set the Sleep state of the A/C.
+void IRVestelAc::setSleep(const bool state) {
+ remote_state &= ~((uint64_t)0xF << kVestelAcTurboSleepOffset);
+ remote_state |= (uint64_t)(state ? kVestelAcSleep : kVestelAcNormal)
+ << kVestelAcTurboSleepOffset;
+ use_time_state = false;
+}
+
+// Return the Sleep state of the A/C.
+bool IRVestelAc::getSleep() {
+ return ((remote_state >> kVestelAcTurboSleepOffset) & 0xF) == kVestelAcSleep;
+}
+
+// Set the Turbo state of the A/C.
+void IRVestelAc::setTurbo(const bool state) {
+ remote_state &= ~((uint64_t)0xF << kVestelAcTurboSleepOffset);
+ remote_state |= (uint64_t)(state ? kVestelAcTurbo : kVestelAcNormal)
+ << kVestelAcTurboSleepOffset;
+ use_time_state = false;
+}
+
+// Return the Turbo state of the A/C.
+bool IRVestelAc::getTurbo() {
+ return ((remote_state >> kVestelAcTurboSleepOffset) & 0xF) == kVestelAcTurbo;
+}
+
+// Set the Ion state of the A/C.
+void IRVestelAc::setIon(const bool state) {
+ remote_state &= ~((uint64_t)0x1 << kVestelAcIonOffset);
+
+ remote_state |= (uint64_t)(state ? 1 : 0) << kVestelAcIonOffset;
+ use_time_state = false;
+}
+
+// Return the Ion state of the A/C.
+bool IRVestelAc::getIon() { return (remote_state >> kVestelAcIonOffset) & 1; }
+
+// Set the Swing Roaming state of the A/C.
+void IRVestelAc::setSwing(const bool state) {
+ remote_state &= ~((uint64_t)0xF << kVestelAcSwingOffset);
+
+ remote_state |= (uint64_t)(state ? kVestelAcSwing : 0xF)
+ << kVestelAcSwingOffset;
+ use_time_state = false;
+}
+
+// Return the Swing Roaming state of the A/C.
+bool IRVestelAc::getSwing() {
+ return ((remote_state >> kVestelAcSwingOffset) & 0xF) == 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 >> kVestelAcChecksumOffset) & 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 &= ~((uint64_t)0xFF << kVestelAcChecksumOffset);
+ remote_state |= (uint64_t)calcChecksum(remote_state)
+ << kVestelAcChecksumOffset;
+
+ remote_time_state &= ~((uint64_t)0xFF << kVestelAcChecksumOffset);
+ remote_time_state |= (uint64_t)calcChecksum(remote_time_state)
+ << kVestelAcChecksumOffset;
+}
+
+bool IRVestelAc::isTimeCommand() {
+ return (remote_state >> kVestelAcPowerOffset == 0x00 || use_time_state);
+}
+
+
+// Convert a standard A/C mode into its native mode.
+uint8_t IRVestelAc::convertMode(const stdAc::opmode_t mode) {
+ switch (mode) {
+ case stdAc::opmode_t::kCool:
+ return kVestelAcCool;
+ case stdAc::opmode_t::kHeat:
+ return kVestelAcHeat;
+ case stdAc::opmode_t::kDry:
+ return kVestelAcDry;
+ case stdAc::opmode_t::kFan:
+ return kVestelAcFan;
+ default:
+ return kVestelAcAuto;
+ }
+}
+
+// Convert a standard A/C Fan speed into its native fan speed.
+uint8_t IRVestelAc::convertFan(const stdAc::fanspeed_t speed) {
+ switch (speed) {
+ case stdAc::fanspeed_t::kMin:
+ case stdAc::fanspeed_t::kLow:
+ return kVestelAcFanLow;
+ case stdAc::fanspeed_t::kMedium:
+ return kVestelAcFanMed;
+ case stdAc::fanspeed_t::kHigh:
+ case stdAc::fanspeed_t::kMax:
+ return kVestelAcFanHigh;
+ default:
+ return kVestelAcFanAuto;
+ }
+}
+
+// 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 += F("Time: ");
+ result += IRHaierAC::timeToString(getTime());
+
+ result += F(", Timer: ");
+ result += isTimerActive() ? IRHaierAC::timeToString(getTimer()) : F("Off");
+
+ result += F(", On Timer: ");
+ result += (isOnTimerActive() && !isTimerActive())
+ ? IRHaierAC::timeToString(getOnTimer())
+ : F("Off");
+
+ result += F(", Off Timer: ");
+ result +=
+ isOffTimerActive() ? IRHaierAC::timeToString(getOffTimer()) : F("Off");
+ return result;
+ }
+ // Not a time command, it's a normal command.
+ result += F("Power: ");
+ result += (getPower() ? F("On") : F("Off"));
+ result += F(", Mode: ");
+ result += uint64ToString(getMode());
+ switch (getMode()) {
+ case kVestelAcAuto:
+ result += F(" (AUTO)");
+ break;
+ case kVestelAcCool:
+ result += F(" (COOL)");
+ break;
+ case kVestelAcHeat:
+ result += F(" (HEAT)");
+ break;
+ case kVestelAcDry:
+ result += F(" (DRY)");
+ break;
+ case kVestelAcFan:
+ result += F(" (FAN)");
+ break;
+ default:
+ result += F(" (UNKNOWN)");
+ }
+ result += F(", Temp: ");
+ result += uint64ToString(getTemp());
+ result += F("C, Fan: ");
+ result += uint64ToString(getFan());
+ switch (getFan()) {
+ case kVestelAcFanAuto:
+ result += F(" (AUTO)");
+ break;
+ case kVestelAcFanLow:
+ result += F(" (LOW)");
+ break;
+ case kVestelAcFanMed:
+ result += F(" (MEDIUM)");
+ break;
+ case kVestelAcFanHigh:
+ result += F(" (HIGH)");
+ break;
+ case kVestelAcFanAutoCool:
+ result += F(" (AUTO COOL)");
+ break;
+ case kVestelAcFanAutoHot:
+ result += F(" (AUTO HOT)");
+ break;
+ default:
+ result += F(" (UNKNOWN)");
+ }
+ result += F(", Sleep: ");
+ result += (getSleep() ? F("On") : F("Off"));
+ result += F(", Turbo: ");
+ result += (getTurbo() ? F("On") : F("Off"));
+ result += F(", Ion: ");
+ result += (getIon() ? F("On") : F("Off"));
+ result += F(", Swing: ");
+ result += (getSwing() ? F("On") : F("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-2.6.0/src/ir_Vestel.h b/lib/IRremoteESP8266-2.6.0/src/ir_Vestel.h
new file mode 100644
index 000000000..ab04e8b35
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_Vestel.h
@@ -0,0 +1,177 @@
+// Copyright 2018 Erdem U. Altinyurt
+// Copyright 2019 David Conran
+
+#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"
+#ifdef UNIT_TEST
+#include "IRsend_test.h"
+#endif
+
+// 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
+
+// Structure of a Command message (56 bits)
+// Signature: 12 bits. e.g. 0x201
+// Checksum: 8 bits
+// Swing: 4 bits. (auto 0xA, stop 0xF)
+// turbo_sleep_normal: 4bits. (normal 0x1, sleep 0x3, turbo 0x7)
+// Unused: 8 bits. (0x00)
+// Temperature: 4 bits. (Celcius, but offset by -16 degrees. e.g. 0x0 = 16C)
+// Fan Speed: 4 bits (auto 0x1, low 0x5, mid 0x9, high 0xB, 0xD auto hot,
+// 0xC auto cool)
+// Mode: 3 bits. (auto 0x0, cold 0x1, dry 0x2, fan 0x3, hot 0x4)
+// unknown/unused: 6 bits.
+// Ion flag: 1 bit.
+// unknown/unused: 1 bit.
+// Power/message type: 4 bits. (on 0xF, off 0xC, 0x0 == Timer mesage)
+//
+// Structure of a Time(r) message (56 bits)
+// Signature: 12 bits. e.g. 0x201
+// Checksum: 8 bits
+// Off Minutes: 3 bits. (Stored in 10 min increments. eg. xx:20 is 0x2)
+// Off Hours: 5 bits. (0x17 == 11PM / 23:00)
+// On Minutes: 3 bits. (Stored in 10 min increments. eg. xx:20 is 0x2)
+// On Hours: 5 bits. (0x9 == 9AM / 09:00)
+// Clock Hours: 5 bits.
+// On Timer flag: 1 bit.
+// Off Timer flag: 1 bit.
+// Timer mode flag: 1 bit. (Off after X many hours/mins, not at clock time.)
+// Clock Minutes: 8 bits. (0-59)
+// Power/message type: 4 bits. (0x0 == Timer mesage, else see Comman message)
+
+// 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;
+
+const uint8_t kVestelAcChecksumOffset = 12;
+const uint8_t kVestelAcSwingOffset = 20;
+const uint8_t kVestelAcTurboSleepOffset = 24;
+const uint8_t kVestelAcTempOffset = 36;
+const uint8_t kVestelAcFanOffset = 40;
+const uint8_t kVestelAcModeOffset = 44;
+const uint8_t kVestelAcIonOffset = 50;
+const uint8_t kVestelAcPowerOffset = 52;
+const uint8_t kVestelAcOffTimeOffset = 20;
+const uint8_t kVestelAcOnTimeOffset = 28;
+const uint8_t kVestelAcHourOffset = 36; // 5 bits
+const uint8_t kVestelAcOnTimerFlagOffset = kVestelAcHourOffset + 5;
+const uint8_t kVestelAcOffTimerFlagOffset = kVestelAcHourOffset + 6;
+const uint8_t kVestelAcTimerFlagOffset = kVestelAcHourOffset + 7;
+const uint8_t kVestelAcMinuteOffset = 44;
+
+const uint64_t kVestelAcStateDefault = 0x0F00D9001FEF201ULL;
+const uint64_t kVestelAcTimeStateDefault = 0x201ULL;
+
+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);
+ bool isOnTimerActive(void);
+ void setOnTimerActive(const bool on);
+ bool isOffTimerActive(void);
+ void setOffTimerActive(const bool on);
+ bool isTimerActive(void);
+ void setTimerActive(const bool on);
+ static uint8_t calcChecksum(const uint64_t state);
+ uint8_t convertMode(const stdAc::opmode_t mode);
+ uint8_t convertFan(const stdAc::fanspeed_t speed);
+#ifdef ARDUINO
+ String toString();
+#else
+ std::string toString();
+#endif
+#ifndef UNIT_TEST
+
+ private:
+ IRsend _irsend;
+#else
+ IRsendTest _irsend;
+#endif
+ uint64_t remote_state;
+ uint64_t remote_time_state;
+ bool use_time_state;
+ void checksum();
+};
+
+#endif // IR_VESTEL_H_
diff --git a/lib/IRremoteESP8266-2.6.0/src/ir_Whirlpool.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_Whirlpool.cpp
new file mode 100644
index 000000000..048c1a1eb
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_Whirlpool.cpp
@@ -0,0 +1,671 @@
+// 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 = kDefaultMessageGap; // Just a guess.
+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;
+}
+
+// Convert a standard A/C mode into its native mode.
+uint8_t IRWhirlpoolAc::convertMode(const stdAc::opmode_t mode) {
+ switch (mode) {
+ case stdAc::opmode_t::kCool:
+ return kWhirlpoolAcCool;
+ case stdAc::opmode_t::kHeat:
+ return kWhirlpoolAcHeat;
+ case stdAc::opmode_t::kDry:
+ return kWhirlpoolAcDry;
+ case stdAc::opmode_t::kFan:
+ return kWhirlpoolAcFan;
+ default:
+ return kWhirlpoolAcAuto;
+ }
+}
+
+// Convert a standard A/C Fan speed into its native fan speed.
+uint8_t IRWhirlpoolAc::convertFan(const stdAc::fanspeed_t speed) {
+ switch (speed) {
+ case stdAc::fanspeed_t::kMin:
+ case stdAc::fanspeed_t::kLow:
+ return kWhirlpoolAcFanLow;
+ case stdAc::fanspeed_t::kMedium:
+ return kWhirlpoolAcFanMedium;
+ case stdAc::fanspeed_t::kHigh:
+ case stdAc::fanspeed_t::kMax:
+ return kWhirlpoolAcFanHigh;
+ default:
+ return kWhirlpoolAcFanAuto;
+ }
+}
+
+#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 += F("Model: ");
+ result += uint64ToString(getModel());
+ switch (getModel()) {
+ case DG11J191:
+ result += F(" (DG11J191)");
+ break;
+ case DG11J13A:
+ result += F(" (DG11J13A)");
+ break;
+ default:
+ result += F(" (UNKNOWN)");
+ }
+ result += F(", Power toggle: ");
+ if (getPowerToggle())
+ result += F("On");
+ else
+ result += F("Off");
+ result += F(", Mode: ");
+ result += uint64ToString(getMode());
+ switch (getMode()) {
+ case kWhirlpoolAcHeat:
+ result += F(" (HEAT)");
+ break;
+ case kWhirlpoolAcAuto:
+ result += F(" (AUTO)");
+ break;
+ case kWhirlpoolAcCool:
+ result += F(" (COOL)");
+ break;
+ case kWhirlpoolAcDry:
+ result += F(" (DRY)");
+ break;
+ case kWhirlpoolAcFan:
+ result += F(" (FAN)");
+ break;
+ default:
+ result += F(" (UNKNOWN)");
+ }
+ result += F(", Temp: ");
+ result += uint64ToString(getTemp());
+ result += F("C, Fan: ");
+ result += uint64ToString(getFan());
+ switch (getFan()) {
+ case kWhirlpoolAcFanAuto:
+ result += F(" (AUTO)");
+ break;
+ case kWhirlpoolAcFanHigh:
+ result += F(" (HIGH)");
+ break;
+ case kWhirlpoolAcFanMedium:
+ result += F(" (MEDIUM)");
+ break;
+ case kWhirlpoolAcFanLow:
+ result += F(" (LOW)");
+ break;
+ default:
+ result += F(" (UNKNOWN)");
+ break;
+ }
+ result += F(", Swing: ");
+ if (getSwing())
+ result += F("On");
+ else
+ result += F("Off");
+ result += F(", Light: ");
+ if (getLight())
+ result += F("On");
+ else
+ result += F("Off");
+ result += F(", Clock: ");
+ result += timeToString(getClock());
+ result += F(", On Timer: ");
+ if (isOnTimerEnabled())
+ result += timeToString(getOnTimer());
+ else
+ result += F("Off");
+ result += F(", Off Timer: ");
+ if (isOffTimerEnabled())
+ result += timeToString(getOffTimer());
+ else
+ result += F("Off");
+ result += F(", Sleep: ");
+ if (getSleep())
+ result += F("On");
+ else
+ result += F("Off");
+ result += F(", Super: ");
+ if (getSuper())
+ result += F("On");
+ else
+ result += F("Off");
+ result += F(", Command: ");
+ result += uint64ToString(getCommand());
+ switch (getCommand()) {
+ case kWhirlpoolAcCommandLight:
+ result += F(" (LIGHT)");
+ break;
+ case kWhirlpoolAcCommandPower:
+ result += F(" (POWER)");
+ break;
+ case kWhirlpoolAcCommandTemp:
+ result += F(" (TEMP)");
+ break;
+ case kWhirlpoolAcCommandSleep:
+ result += F(" (SLEEP)");
+ break;
+ case kWhirlpoolAcCommandSuper:
+ result += F(" (SUPER)");
+ break;
+ case kWhirlpoolAcCommandOnTimer:
+ result += F(" (ONTIMER)");
+ break;
+ case kWhirlpoolAcCommandMode:
+ result += F(" (MODE)");
+ break;
+ case kWhirlpoolAcCommandSwing:
+ result += F(" (SWING)");
+ break;
+ case kWhirlpoolAcCommandIFeel:
+ result += F(" (IFEEL)");
+ break;
+ case kWhirlpoolAcCommandFanSpeed:
+ result += F(" (FANSPEED)");
+ break;
+ case kWhirlpoolAcCommand6thSense:
+ result += F(" (6THSENSE)");
+ break;
+ case kWhirlpoolAcCommandOffTimer:
+ result += F(" (OFFTIMER)");
+ break;
+ default:
+ result += F(" (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-2.6.0/src/ir_Whirlpool.h b/lib/IRremoteESP8266-2.6.0/src/ir_Whirlpool.h
new file mode 100644
index 000000000..9604d025c
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_Whirlpool.h
@@ -0,0 +1,167 @@
+// 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"
+#ifdef UNIT_TEST
+#include "IRsend_test.h"
+#endif
+
+// 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);
+ uint8_t convertMode(const stdAc::opmode_t mode);
+ uint8_t convertFan(const stdAc::fanspeed_t speed);
+#ifdef ARDUINO
+ String toString();
+#else
+ std::string toString();
+#endif
+#ifndef UNIT_TEST
+
+ private:
+ IRsend _irsend;
+#else
+ IRsendTest _irsend;
+#endif
+ // The state of the IR remote in IR code form.
+ uint8_t remote_state[kWhirlpoolAcStateLength];
+ 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-2.5.2.03/src/ir_Whynter.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_Whynter.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_Whynter.cpp
rename to lib/IRremoteESP8266-2.6.0/src/ir_Whynter.cpp
diff --git a/lib/IRremoteESP8266-2.6.0/test/IRac_test.cpp b/lib/IRremoteESP8266-2.6.0/test/IRac_test.cpp
new file mode 100644
index 000000000..39c17a84b
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/test/IRac_test.cpp
@@ -0,0 +1,865 @@
+// Copyright 2019 David Conran
+
+#include "ir_Argo.h"
+#include "ir_Daikin.h"
+#include "ir_Fujitsu.h"
+#include "ir_Gree.h"
+#include "ir_Haier.h"
+#include "ir_Hitachi.h"
+#include "ir_Kelvinator.h"
+#include "ir_Midea.h"
+#include "ir_Mitsubishi.h"
+#include "ir_MitsubishiHeavy.h"
+#include "ir_Panasonic.h"
+#include "ir_Samsung.h"
+#include "ir_Tcl.h"
+#include "ir_Teco.h"
+#include "ir_Toshiba.h"
+#include "ir_Trotec.h"
+#include "ir_Vestel.h"
+#include "ir_Whirlpool.h"
+#include "IRac.h"
+#include "IRrecv.h"
+#include "IRrecv_test.h"
+#include "IRremoteESP8266.h"
+#include "IRsend.h"
+#include "IRsend_test.h"
+#include "gtest/gtest.h"
+
+// Tests for IRac class.
+
+TEST(TestIRac, Argo) {
+ IRArgoAC ac(0);
+ IRac irac(0);
+
+ ac.begin();
+ irac.argo(&ac,
+ true, // Power
+ stdAc::opmode_t::kHeat, // Mode
+ 21, // Celsius
+ stdAc::fanspeed_t::kHigh, // Fan speed
+ stdAc::swingv_t::kOff, // Veritcal swing
+ false, // Turbo
+ -1); // Sleep
+ EXPECT_TRUE(ac.getPower());
+ EXPECT_EQ(1, ac.getMode());
+ EXPECT_EQ(21, ac.getTemp());
+ EXPECT_EQ(kArgoFlapAuto, ac.getFlap());
+ EXPECT_FALSE(ac.getMax()); // Turbo
+ EXPECT_FALSE(ac.getNight()); // Sleep
+}
+
+TEST(TestIRac, Coolix) {
+ IRCoolixAC ac(0);
+ IRac irac(0);
+ IRrecv capture(0);
+ char expected[] =
+ "Power: On, Mode: 3 (HEAT), Fan: 1 (MAX), Temp: 21C, Zone Follow: Off, "
+ "Sensor Temp: Ignored";
+
+ ac.begin();
+ irac.coolix(&ac,
+ true, // Power
+ stdAc::opmode_t::kHeat, // Mode
+ 21, // Celsius
+ stdAc::fanspeed_t::kHigh, // Fan speed
+ stdAc::swingv_t::kOff, // Veritcal swing
+ stdAc::swingh_t::kOff, // Horizontal swing
+ false, // Turbo
+ false, // Light
+ false, // Clean
+ -1); // Sleep
+ ASSERT_EQ(expected, ac.toString());
+ ac._irsend.makeDecodeResult();
+ EXPECT_TRUE(capture.decode(&ac._irsend.capture));
+ ASSERT_EQ(COOLIX, ac._irsend.capture.decode_type);
+ ASSERT_EQ(kCoolixBits, ac._irsend.capture.bits);
+ ac.setRaw(ac._irsend.capture.value);
+ ASSERT_EQ(expected, ac.toString());
+}
+
+TEST(TestIRac, Daikin) {
+ IRDaikinESP ac(0);
+ IRac irac(0);
+ char expected[] =
+ "Power: On, Mode: 3 (COOL), Temp: 19C, Fan: 2, Powerful: Off, "
+ "Quiet: Off, Sensor: Off, Eye: Off, Mold: On, Comfort: Off, "
+ "Swing (Horizontal): Off, Swing (Vertical): Off, "
+ "Current Time: 0:00, On Time: Off, Off Time: Off";
+
+ ac.begin();
+ irac.daikin(&ac,
+ true, // Power
+ stdAc::opmode_t::kCool, // Mode
+ 19, // Celsius
+ stdAc::fanspeed_t::kMedium, // Fan speed
+ stdAc::swingv_t::kOff, // Veritcal swing
+ stdAc::swingh_t::kOff, // Horizontal swing
+ false, // Quiet
+ false, // Turbo
+ true, // Filter
+ true); // Clean
+ ASSERT_EQ(expected, ac.toString());
+}
+
+TEST(TestIRac, Daikin2) {
+ IRDaikin2 ac(0);
+ IRac irac(0);
+ IRrecv capture(0);
+ char expected[] =
+ "Power: On, Mode: 3 (COOL), Temp: 19C, Fan: 2, Swing (V): 14 (Auto), "
+ "Swing (H): 0, Clock: 0:00, On Time: Off, Off Time: Off, "
+ "Sleep Time: Off, Beep: 1 (Quiet), Light: 1 (Bright), Mold: On, "
+ "Clean: Off, Fresh Air: Off, Eye: Off, Eye Auto: Off, Quiet: Off, "
+ "Powerful: Off, Purify: On, Econo: Off";
+
+ ac.begin();
+ irac.daikin2(&ac,
+ true, // Power
+ stdAc::opmode_t::kCool, // Mode
+ 19, // Celsius
+ stdAc::fanspeed_t::kMedium, // Fan speed
+ stdAc::swingv_t::kOff, // Veritcal swing
+ stdAc::swingh_t::kOff, // Horizontal swing
+ false, // Quiet
+ false, // Turbo
+ true, // Light
+ false, // Econo
+ true, // Filter
+ true, // Clean (aka Mold)
+ -1, // Sleep time
+ -1); // Current time
+ ASSERT_EQ(expected, ac.toString());
+ ac._irsend.makeDecodeResult();
+ EXPECT_TRUE(capture.decode(&ac._irsend.capture));
+ ASSERT_EQ(DAIKIN2, ac._irsend.capture.decode_type);
+ ASSERT_EQ(kDaikin2Bits, ac._irsend.capture.bits);
+ ac.setRaw(ac._irsend.capture.state);
+ ASSERT_EQ(expected, ac.toString());
+}
+
+TEST(TestIRac, Daikin216) {
+ IRDaikin216 ac(0);
+ IRac irac(0);
+ IRrecv capture(0);
+ char expected[] =
+ "Power: On, Mode: 4 (HEAT), Temp: 31C, Fan: 11 (QUIET), "
+ "Swing (Horizontal): On, Swing (Vertical): On, Quiet: On";
+
+ ac.begin();
+ irac.daikin216(&ac,
+ true, // Power
+ stdAc::opmode_t::kHeat, // Mode
+ 31, // Celsius
+ stdAc::fanspeed_t::kMedium, // Fan speed
+ stdAc::swingv_t::kAuto, // Veritcal swing
+ stdAc::swingh_t::kLeft, // Horizontal swing
+ true); // Quiet
+ ASSERT_EQ(expected, ac.toString());
+ ac._irsend.makeDecodeResult();
+ EXPECT_TRUE(capture.decode(&ac._irsend.capture));
+ ASSERT_EQ(DAIKIN216, ac._irsend.capture.decode_type);
+ ASSERT_EQ(kDaikin216Bits, ac._irsend.capture.bits);
+ ac.setRaw(ac._irsend.capture.state);
+ ASSERT_EQ(expected, ac.toString());
+}
+
+TEST(TestIRac, Fujitsu) {
+ IRFujitsuAC ac(0);
+ IRac irac(0);
+ IRrecv capture(0);
+ char expected[] =
+ "Power: On, Mode: 1 (COOL), Temp: 19C, Fan: 2 (MED), "
+ "Swing: Off, Command: N/A";
+
+ ac.begin();
+ irac.fujitsu(&ac,
+ ARDB1, // Model
+ true, // Power
+ stdAc::opmode_t::kCool, // Mode
+ 19, // Celsius
+ stdAc::fanspeed_t::kMedium, // Fan speed
+ stdAc::swingv_t::kOff, // Veritcal swing
+ stdAc::swingh_t::kOff, // Horizontal swing
+ false); // Quiet
+ ASSERT_EQ(expected, ac.toString());
+ ac._irsend.makeDecodeResult();
+ EXPECT_TRUE(capture.decode(&ac._irsend.capture));
+ ASSERT_EQ(FUJITSU_AC, ac._irsend.capture.decode_type);
+ ASSERT_EQ(kFujitsuAcBits - 8, ac._irsend.capture.bits);
+ ac.setRaw(ac._irsend.capture.state, ac._irsend.capture.bits / 8);
+ ASSERT_EQ(expected, ac.toString());
+
+ ac._irsend.reset();
+ irac.fujitsu(&ac,
+ ARRAH2E, // Model
+ true, // Power
+ stdAc::opmode_t::kCool, // Mode
+ 19, // Celsius
+ stdAc::fanspeed_t::kMedium, // Fan speed
+ stdAc::swingv_t::kOff, // Veritcal swing
+ stdAc::swingh_t::kOff, // Horizontal swing
+ false); // Quiet
+ ASSERT_EQ(expected, ac.toString());
+ ac._irsend.makeDecodeResult();
+ EXPECT_TRUE(capture.decode(&ac._irsend.capture));
+ ASSERT_EQ(FUJITSU_AC, ac._irsend.capture.decode_type);
+ ASSERT_EQ(kFujitsuAcBits, ac._irsend.capture.bits);
+ ac.setRaw(ac._irsend.capture.state, ac._irsend.capture.bits / 8);
+ ASSERT_EQ(expected, ac.toString());
+}
+
+TEST(TestIRac, Gree) {
+ IRGreeAC ac(0);
+ IRac irac(0);
+ IRrecv capture(0);
+ char expected[] =
+ "Power: On, Mode: 1 (COOL), Temp: 22C, Fan: 2, Turbo: Off, XFan: On, "
+ "Light: On, Sleep: On, Swing Vertical Mode: Manual, "
+ "Swing Vertical Pos: 3";
+
+ ac.begin();
+ irac.gree(&ac,
+ true, // Power
+ stdAc::opmode_t::kCool, // Mode
+ 22, // Celsius
+ stdAc::fanspeed_t::kMedium, // Fan speed
+ stdAc::swingv_t::kHigh, // Veritcal swing
+ false, // Turbo
+ true, // Light
+ true, // Clean (aka Mold/XFan)
+ 8 * 60 + 0); // Sleep time
+ ASSERT_EQ(expected, ac.toString());
+ ac._irsend.makeDecodeResult();
+ EXPECT_TRUE(capture.decode(&ac._irsend.capture));
+ ASSERT_EQ(GREE, ac._irsend.capture.decode_type);
+ ASSERT_EQ(kGreeBits, ac._irsend.capture.bits);
+ ac.setRaw(ac._irsend.capture.state);
+ ASSERT_EQ(expected, ac.toString());
+}
+
+TEST(TestIRac, Haier) {
+ IRHaierAC ac(0);
+ IRac irac(0);
+ IRrecv capture(0);
+ char expected[] =
+ "Command: 1 (On), Mode: 3 (HEAT), Temp: 24C, Fan: 2, Swing: 1 (Up), "
+ "Sleep: On, Health: On, Current Time: 13:45, On Timer: Off, "
+ "Off Timer: Off";
+
+ ac.begin();
+ irac.haier(&ac,
+ true, // Power
+ stdAc::opmode_t::kCool, // Mode
+ 24, // Celsius
+ stdAc::fanspeed_t::kMedium, // Fan speed
+ stdAc::swingv_t::kHigh, // Veritcal swing
+ true, // Filter
+ 8 * 60 + 0, // Sleep time
+ 13 * 60 + 45); // Clock
+ ASSERT_EQ(expected, ac.toString());
+ ac._irsend.makeDecodeResult();
+ EXPECT_TRUE(capture.decode(&ac._irsend.capture));
+ ASSERT_EQ(HAIER_AC, ac._irsend.capture.decode_type);
+ ASSERT_EQ(kHaierACBits, ac._irsend.capture.bits);
+ ac.setRaw(ac._irsend.capture.state);
+ ASSERT_EQ(expected, ac.toString());
+}
+
+
+TEST(TestIRac, HaierYrwo2) {
+ IRHaierACYRW02 ac(0);
+ IRac irac(0);
+ IRrecv capture(0);
+ char expected[] =
+ "Power: On, Button: 5 (Power), Mode: 2 (Cool), Temp: 23C, Fan: 4 (Med), "
+ "Turbo: 1 (High), Swing: 1 (Top), Sleep: On, Health: On";
+
+ ac.begin();
+ irac.haierYrwo2(&ac,
+ true, // Power
+ stdAc::opmode_t::kCool, // Mode
+ 23, // Celsius
+ stdAc::fanspeed_t::kMedium, // Fan speed
+ stdAc::swingv_t::kHigh, // Veritcal swing
+ true, // Turbo
+ true, // Filter
+ 8 * 60 + 0); // Sleep time
+ ASSERT_EQ(expected, ac.toString());
+ ac._irsend.makeDecodeResult();
+ EXPECT_TRUE(capture.decode(&ac._irsend.capture));
+ ASSERT_EQ(HAIER_AC_YRW02, ac._irsend.capture.decode_type);
+ ASSERT_EQ(kHaierACYRW02Bits, ac._irsend.capture.bits);
+ ac.setRaw(ac._irsend.capture.state);
+ ASSERT_EQ(expected, ac.toString());
+}
+
+TEST(TestIRac, Hitachi) {
+ IRHitachiAc ac(0);
+ IRac irac(0);
+ IRrecv capture(0);
+ char expected[] =
+ "Power: On, Mode: 2 (AUTO), Temp: 22C, Fan: 3 (UNKNOWN), "
+ "Swing (Vertical): Off, Swing (Horizontal): On";
+
+ ac.begin();
+ irac.hitachi(&ac,
+ true, // Power
+ stdAc::opmode_t::kAuto, // Mode
+ 22, // Celsius
+ stdAc::fanspeed_t::kMedium, // Fan speed
+ stdAc::swingv_t::kOff, // Veritcal swing
+ stdAc::swingh_t::kAuto); // Horizontal swing
+
+ ASSERT_EQ(expected, ac.toString());
+ ac._irsend.makeDecodeResult();
+ EXPECT_TRUE(capture.decode(&ac._irsend.capture));
+ ASSERT_EQ(HITACHI_AC, ac._irsend.capture.decode_type);
+ ASSERT_EQ(kHitachiAcBits, ac._irsend.capture.bits);
+ ac.setRaw(ac._irsend.capture.state);
+ ASSERT_EQ(expected, ac.toString());
+}
+
+TEST(TestIRac, Kelvinator) {
+ IRKelvinatorAC ac(0);
+ IRac irac(0);
+ IRrecv capture(0);
+ char expected[] =
+ "Power: On, Mode: 1 (COOL), Temp: 19C, Fan: 3, Turbo: Off, Quiet: Off, "
+ "XFan: On, IonFilter: On, Light: On, Swing (Horizontal): Off, "
+ "Swing (Vertical): Off";
+
+ ac.begin();
+ irac.kelvinator(&ac,
+ true, // Power
+ stdAc::opmode_t::kCool, // Mode
+ 19, // Celsius
+ stdAc::fanspeed_t::kMedium, // Fan speed
+ stdAc::swingv_t::kOff, // Veritcal swing
+ stdAc::swingh_t::kOff, // Horizontal swing
+ false, // Quiet
+ false, // Turbo
+ true, // Light
+ true, // Filter
+ true); // Clean
+
+ ASSERT_EQ(expected, ac.toString());
+ ac._irsend.makeDecodeResult();
+ EXPECT_TRUE(capture.decode(&ac._irsend.capture));
+ ASSERT_EQ(KELVINATOR, ac._irsend.capture.decode_type);
+ ASSERT_EQ(kKelvinatorBits, ac._irsend.capture.bits);
+ ac.setRaw(ac._irsend.capture.state);
+ ASSERT_EQ(expected, ac.toString());
+}
+
+TEST(TestIRac, Midea) {
+ IRMideaAC ac(0);
+ IRac irac(0);
+ IRrecv capture(0);
+ char expected[] =
+ "Power: On, Mode: 1 (DRY), Temp: 27C/81F, Fan: 2 (MED), Sleep: On";
+
+ ac.begin();
+ irac.midea(&ac,
+ true, // Power
+ stdAc::opmode_t::kDry, // Mode
+ 27, // Celsius
+ stdAc::fanspeed_t::kMedium, // Fan speed
+ 8 * 60 + 0); // Sleep time
+
+ ASSERT_EQ(expected, ac.toString());
+ ac._irsend.makeDecodeResult();
+ EXPECT_TRUE(capture.decode(&ac._irsend.capture));
+ ASSERT_EQ(MIDEA, ac._irsend.capture.decode_type);
+ ASSERT_EQ(kMideaBits, ac._irsend.capture.bits);
+ ac.setRaw(ac._irsend.capture.value);
+ ASSERT_EQ(expected, ac.toString());
+}
+
+TEST(TestIRac, Mitsubishi) {
+ IRMitsubishiAC ac(0);
+ IRac irac(0);
+ IRrecv capture(0);
+ char expected[] =
+ "Power: On (COOL), Temp: 20C, FAN: 2, VANE: AUTO, Time: 14:30, "
+ "On timer: 00:00, Off timer: 00:00, Timer: -";
+
+ ac.begin();
+ irac.mitsubishi(&ac,
+ true, // Power
+ stdAc::opmode_t::kCool, // Mode
+ 20, // Celsius
+ stdAc::fanspeed_t::kMedium, // Fan speed
+ stdAc::swingv_t::kOff, // Veritcal swing
+ false, // Silent
+ 14 * 60 + 35); // Clock
+ ASSERT_EQ(expected, ac.toString());
+ ac._irsend.makeDecodeResult();
+ EXPECT_TRUE(capture.decode(&ac._irsend.capture));
+ ASSERT_EQ(MITSUBISHI_AC, ac._irsend.capture.decode_type);
+ ASSERT_EQ(kMitsubishiACBits, ac._irsend.capture.bits);
+ ac.setRaw(ac._irsend.capture.state);
+ ASSERT_EQ(expected, ac.toString());
+}
+
+TEST(TestIRac, MitsubishiHeavy88) {
+ IRMitsubishiHeavy88Ac ac(0);
+ IRac irac(0);
+ IRrecv capture(0);
+ char expected[] =
+ "Power: On, Mode: 1 (Cool), Temp: 21C, Fan: 3 (Med), "
+ "Swing (V): 16 (Auto), Swing (H): 0 (Off), Turbo: Off, Econo: Off, "
+ "3D: Off, Clean: On";
+
+ ac.begin();
+ irac.mitsubishiHeavy88(&ac,
+ true, // Power
+ stdAc::opmode_t::kCool, // Mode
+ 21, // Celsius
+ stdAc::fanspeed_t::kMedium, // Fan speed
+ stdAc::swingv_t::kAuto, // Veritcal swing
+ stdAc::swingh_t::kOff, // Horizontal swing
+ false, // Turbo
+ false, // Econo
+ true); // Clean
+ ASSERT_EQ(expected, ac.toString());
+ ac._irsend.makeDecodeResult();
+ EXPECT_TRUE(capture.decode(&ac._irsend.capture));
+ ASSERT_EQ(MITSUBISHI_HEAVY_88, ac._irsend.capture.decode_type);
+ ASSERT_EQ(kMitsubishiHeavy88Bits, ac._irsend.capture.bits);
+ ac.setRaw(ac._irsend.capture.state);
+ ASSERT_EQ(expected, ac.toString());
+}
+
+TEST(TestIRac, MitsubishiHeavy152) {
+ IRMitsubishiHeavy152Ac ac(0);
+ IRac irac(0);
+ IRrecv capture(0);
+ char expected[] =
+ "Power: On, Mode: 1 (Cool), Temp: 20C, Fan: 6 (Econo), "
+ "Swing (V): 6 (Off), Swing (H): 0 (Auto), Silent: On, Turbo: Off, "
+ "Econo: On, Night: On, Filter: On, 3D: Off, Clean: Off";
+
+ ac.begin();
+ irac.mitsubishiHeavy152(&ac,
+ true, // Power
+ stdAc::opmode_t::kCool, // Mode
+ 20, // Celsius
+ stdAc::fanspeed_t::kLow, // Fan speed
+ stdAc::swingv_t::kOff, // Veritcal swing
+ stdAc::swingh_t::kAuto, // Horizontal swing
+ true, // Silent
+ false, // Turbo
+ true, // Econo
+ true, // Filter
+ false, // Clean
+ 8 * 60); // Sleep
+ ASSERT_EQ(expected, ac.toString());
+ ac._irsend.makeDecodeResult();
+ EXPECT_TRUE(capture.decode(&ac._irsend.capture));
+ ASSERT_EQ(MITSUBISHI_HEAVY_152, ac._irsend.capture.decode_type);
+ ASSERT_EQ(kMitsubishiHeavy152Bits, ac._irsend.capture.bits);
+ ac.setRaw(ac._irsend.capture.state);
+ ASSERT_EQ(expected, ac.toString());
+}
+
+TEST(TestIRac, Panasonic) {
+ IRPanasonicAc ac(0);
+ IRac irac(0);
+ IRrecv capture(0);
+ char expected_nke[] =
+ "Model: 2 (NKE), Power: On, Mode: 4 (HEAT), Temp: 28C, Fan: 2 (UNKNOWN), "
+ "Swing (Vertical): 15 (AUTO), Swing (Horizontal): 6 (Middle), Quiet: On, "
+ "Powerful: Off, Clock: 19:17, On Timer: Off, Off Timer: Off";
+
+ ac.begin();
+ irac.panasonic(&ac,
+ kPanasonicNke, // Model
+ true, // Power
+ stdAc::opmode_t::kHeat, // Mode
+ 28, // Celsius
+ stdAc::fanspeed_t::kMedium, // Fan speed
+ stdAc::swingv_t::kAuto, // Veritcal swing
+ stdAc::swingh_t::kLeft, // Horizontal swing
+ true, // Quiet
+ false, // Turbo
+ 19 * 60 + 17); // Clock
+ ASSERT_EQ(expected_nke, ac.toString());
+ ac._irsend.makeDecodeResult();
+ EXPECT_TRUE(capture.decode(&ac._irsend.capture));
+ ASSERT_EQ(PANASONIC_AC, ac._irsend.capture.decode_type);
+ ASSERT_EQ(kPanasonicAcBits, ac._irsend.capture.bits);
+ ac.setRaw(ac._irsend.capture.state);
+ ASSERT_EQ(expected_nke, ac.toString());
+
+ char expected_dke[] =
+ "Model: 3 (DKE), Power: On, Mode: 3 (COOL), Temp: 18C, Fan: 4 (MAX), "
+ "Swing (Vertical): 1 (Full Up), Swing (Horizontal): 6 (Middle), "
+ "Quiet: Off, Powerful: On, Clock: 19:17, On Timer: Off, Off Timer: Off";
+ ac._irsend.reset();
+ irac.panasonic(&ac,
+ kPanasonicDke, // Model
+ true, // Power
+ stdAc::opmode_t::kCool, // Mode
+ 18, // Celsius
+ stdAc::fanspeed_t::kMax, // Fan speed
+ stdAc::swingv_t::kHigh, // Veritcal swing
+ stdAc::swingh_t::kMiddle, // Horizontal swing
+ false, // Quiet
+ true, // Turbo
+ 19 * 60 + 17); // Clock
+ ASSERT_EQ(expected_dke, ac.toString());
+ ac._irsend.makeDecodeResult();
+ EXPECT_TRUE(capture.decode(&ac._irsend.capture));
+ ASSERT_EQ(PANASONIC_AC, ac._irsend.capture.decode_type);
+ ASSERT_EQ(kPanasonicAcBits, ac._irsend.capture.bits);
+ ac.setRaw(ac._irsend.capture.state);
+ ASSERT_EQ(expected_dke, ac.toString());
+}
+
+TEST(TestIRac, Samsung) {
+ IRSamsungAc ac(0);
+ IRac irac(0);
+ IRrecv capture(0);
+ char expected[] =
+ "Power: On, Mode: 0 (AUTO), Temp: 28C, Fan: 6 (AUTO), Swing: On, "
+ "Beep: On, Clean: On, Quiet: On";
+
+ ac.begin();
+ irac.samsung(&ac,
+ true, // Power
+ stdAc::opmode_t::kAuto, // Mode
+ 28, // Celsius
+ stdAc::fanspeed_t::kMedium, // Fan speed
+ stdAc::swingv_t::kAuto, // Veritcal swing
+ true, // Quiet
+ false, // Turbo
+ true, // Clean
+ true, // Beep
+ false); // with the Hack Off
+ ASSERT_EQ(expected, ac.toString());
+ ac._irsend.makeDecodeResult();
+ EXPECT_TRUE(capture.decode(&ac._irsend.capture));
+ ASSERT_EQ(SAMSUNG_AC, ac._irsend.capture.decode_type);
+ ASSERT_EQ(kSamsungAcBits, ac._irsend.capture.bits);
+ ac.setRaw(ac._irsend.capture.state);
+ ASSERT_EQ(expected, ac.toString());
+
+ ac._irsend.reset();
+ irac.samsung(&ac,
+ true, // Power
+ stdAc::opmode_t::kAuto, // Mode
+ 28, // Celsius
+ stdAc::fanspeed_t::kMedium, // Fan speed
+ stdAc::swingv_t::kAuto, // Veritcal swing
+ true, // Quiet
+ false, // Turbo
+ true, // Clean
+ true, // Beep
+ true); // with the Hack On
+ ASSERT_EQ(expected, ac.toString()); // Class should be in the desired mode.
+ ac._irsend.makeDecodeResult();
+ EXPECT_TRUE(capture.decode(&ac._irsend.capture));
+ ASSERT_EQ(SAMSUNG_AC, ac._irsend.capture.decode_type);
+ ASSERT_EQ(kSamsungAcExtendedBits, ac._irsend.capture.bits);
+ ac.setRaw(ac._irsend.capture.state);
+ // However, we expect a plain "on" state as it should be sent before the
+ // desired state.
+ char expected_on[] =
+ "Power: On, Mode: 0 (AUTO), Temp: 16C, Fan: 0 (AUTO), Swing: Off, "
+ "Beep: Off, Clean: Off, Quiet: Off";
+ ASSERT_EQ(expected_on, ac.toString());
+}
+
+TEST(TestIRac, Tcl112) {
+ IRTcl112Ac ac(0);
+ IRac irac(0);
+ IRrecv capture(0);
+ char expected[] =
+ "Power: On, Mode: 3 (COOL), Temp: 20C, Fan: 3 (Med), Econo: On, "
+ "Health: On, Light: On, Turbo: Off, Swing (H): On, Swing (V): Off";
+
+ ac.begin();
+ irac.tcl112(&ac,
+ true, // Power
+ stdAc::opmode_t::kCool, // Mode
+ 20, // Celsius
+ stdAc::fanspeed_t::kMedium, // Fan speed
+ stdAc::swingv_t::kOff, // Veritcal swing
+ stdAc::swingh_t::kAuto, // Horizontal swing
+ false, // Turbo
+ true, // Light
+ true, // Econo
+ true); // Filter (aka. Health)
+ ASSERT_EQ(expected, ac.toString());
+ ac._irsend.makeDecodeResult();
+ EXPECT_TRUE(capture.decode(&ac._irsend.capture));
+ ASSERT_EQ(TCL112AC, ac._irsend.capture.decode_type);
+ ASSERT_EQ(kTcl112AcBits, ac._irsend.capture.bits);
+ ac.setRaw(ac._irsend.capture.state);
+ ASSERT_EQ(expected, ac.toString());
+}
+
+TEST(TestIRac, Teco) {
+ IRTecoAc ac(0);
+ IRac irac(0);
+ IRrecv capture(0);
+ char expected[] =
+ "Power: On, Mode: 0 (AUTO), Temp: 21C, Fan: 2 (Med), Sleep: On, "
+ "Swing: On";
+
+ ac.begin();
+ irac.teco(&ac,
+ true, // Power
+ stdAc::opmode_t::kAuto, // Mode
+ 21, // Celsius
+ stdAc::fanspeed_t::kMedium, // Fan speed
+ stdAc::swingv_t::kAuto, // Veritcal swing
+ 8 * 60 + 30); // Sleep
+ ASSERT_EQ(expected, ac.toString());
+ ac._irsend.makeDecodeResult();
+ EXPECT_TRUE(capture.decode(&ac._irsend.capture));
+ ASSERT_EQ(TECO, ac._irsend.capture.decode_type);
+ ASSERT_EQ(kTecoBits, ac._irsend.capture.bits);
+ ac.setRaw(ac._irsend.capture.value);
+ ASSERT_EQ(expected, ac.toString());
+}
+
+TEST(TestIRac, Toshiba) {
+ IRToshibaAC ac(0);
+ IRac irac(0);
+ IRrecv capture(0);
+ char expected[] = "Power: On, Mode: 2 (DRY), Temp: 29C, Fan: 2";
+
+ ac.begin();
+ irac.toshiba(&ac,
+ true, // Power
+ stdAc::opmode_t::kDry, // Mode
+ 29, // Celsius
+ stdAc::fanspeed_t::kLow); // Fan speed
+ ASSERT_EQ(expected, ac.toString());
+ ac._irsend.makeDecodeResult();
+ EXPECT_TRUE(capture.decode(&ac._irsend.capture));
+ ASSERT_EQ(TOSHIBA_AC, ac._irsend.capture.decode_type);
+ ASSERT_EQ(kToshibaACBits, ac._irsend.capture.bits);
+ ac.setRaw(ac._irsend.capture.state);
+ ASSERT_EQ(expected, ac.toString());
+}
+
+TEST(TestIRac, Trotec) {
+ IRTrotecESP ac(0);
+ IRac irac(0);
+
+ ac.begin();
+ irac.trotec(&ac,
+ true, // Power
+ stdAc::opmode_t::kCool, // Mode
+ 18, // Celsius
+ stdAc::fanspeed_t::kHigh, // Fan speed
+ 8 * 60 + 17); // Sleep
+ EXPECT_TRUE(ac.getPower());
+ EXPECT_EQ(kTrotecCool, ac.getMode());
+ EXPECT_EQ(18, ac.getTemp());
+ EXPECT_EQ(kTrotecFanHigh, ac.getSpeed());
+ EXPECT_TRUE(ac.getSleep());
+}
+
+TEST(TestIRac, Vestel) {
+ IRVestelAc ac(0);
+ IRac irac(0);
+ IRrecv capture(0);
+ char expected[] =
+ "Power: On, Mode: 0 (AUTO), Temp: 22C, Fan: 5 (LOW), Sleep: On, "
+ "Turbo: Off, Ion: On, Swing: On";
+
+ ac.begin();
+ irac.vestel(&ac,
+ true, // Power
+ stdAc::opmode_t::kAuto, // Mode
+ 22, // Celsius
+ stdAc::fanspeed_t::kLow, // Fan speed
+ stdAc::swingv_t::kHigh, // Veritcal swing
+ false, // Turbo
+ true, // Filter
+ 8 * 60 + 0); // Sleep time
+ // 13 * 60 + 45); // Clock
+ ASSERT_EQ(expected, ac.toString());
+ ac._irsend.makeDecodeResult();
+ EXPECT_TRUE(capture.decode(&ac._irsend.capture));
+ ASSERT_EQ(VESTEL_AC, ac._irsend.capture.decode_type);
+ ASSERT_EQ(kVestelAcBits, ac._irsend.capture.bits);
+ ac.setRaw(ac._irsend.capture.state);
+ ASSERT_EQ(expected, ac.toString());
+
+ ac._irsend.reset();
+ char expected_clocks[] =
+ "Time: 13:45, Timer: Off, On Timer: Off, Off Timer: Off";
+
+ ac.begin();
+ irac.vestel(&ac,
+ true, // Power
+ stdAc::opmode_t::kAuto, // Mode
+ 22, // Celsius
+ stdAc::fanspeed_t::kLow, // Fan speed
+ stdAc::swingv_t::kHigh, // Veritcal swing
+ false, // Turbo
+ true, // Filter
+ 8 * 60 + 0, // Sleep time
+ 13 * 60 + 45, // Clock
+ false); // Don't send the normal message.
+ // Just for testing purposes.
+ ASSERT_EQ(expected_clocks, ac.toString());
+ ac._irsend.makeDecodeResult();
+ EXPECT_TRUE(capture.decode(&ac._irsend.capture));
+ ASSERT_EQ(VESTEL_AC, ac._irsend.capture.decode_type);
+ ASSERT_EQ(kVestelAcBits, ac._irsend.capture.bits);
+ ac.setRaw(ac._irsend.capture.state);
+ ASSERT_EQ(expected_clocks, ac.toString());
+
+ // Now check it sends both messages during normal operation when the
+ // clock is set.
+ ac._irsend.reset();
+ ac.begin();
+ irac.vestel(&ac,
+ true, // Power
+ stdAc::opmode_t::kAuto, // Mode
+ 22, // Celsius
+ stdAc::fanspeed_t::kLow, // Fan speed
+ stdAc::swingv_t::kHigh, // Veritcal swing
+ false, // Turbo
+ true, // Filter
+ 8 * 60 + 0, // Sleep time
+ 13 * 60 + 45); // Clock
+
+ EXPECT_EQ(
+ "f38000d50"
+ "m3110s9066"
+ "m520s1535m520s480m520s480m520s480m520s480m520s480m520s480m520s480"
+ "m520s480m520s1535m520s480m520s480m520s480m520s480m520s480m520s480"
+ "m520s1535m520s1535m520s1535m520s1535m520s480m520s1535m520s480m520s1535"
+ "m520s1535m520s1535m520s480m520s480m520s480m520s480m520s480m520s480"
+ "m520s480m520s480m520s480m520s480m520s480m520s1535m520s1535m520s480"
+ "m520s1535m520s480m520s1535m520s480m520s480m520s480m520s480m520s480"
+ "m520s480m520s480m520s1535m520s480m520s1535m520s1535m520s1535m520s1535"
+ "m520s100000"
+ "m3110s9066"
+ "m520s1535m520s480m520s480m520s480m520s480m520s480m520s480m520s480"
+ "m520s480m520s1535m520s480m520s480m520s480m520s1535m520s1535m520s480"
+ "m520s1535m520s1535m520s1535m520s1535m520s480m520s480m520s480m520s480"
+ "m520s480m520s480m520s480m520s480m520s480m520s480m520s480m520s480"
+ "m520s480m520s480m520s480m520s480m520s1535m520s480m520s1535m520s1535"
+ "m520s480m520s480m520s480m520s480m520s1535m520s480m520s1535m520s1535"
+ "m520s480m520s1535m520s480m520s480m520s480m520s480m520s480m520s480"
+ "m520s100000", ac._irsend.outputStr());
+}
+
+
+TEST(TestIRac, Whirlpool) {
+ IRWhirlpoolAc ac(0);
+ IRac irac(0);
+ IRrecv capture(0);
+ char expected[] =
+ "Model: 1 (DG11J13A), Power toggle: On, Mode: 1 (AUTO), Temp: 21C, "
+ "Fan: 3 (LOW), Swing: On, Light: On, Clock: 23:58, On Timer: Off, "
+ "Off Timer: Off, Sleep: On, Super: Off, Command: 1 (POWER)";
+
+ ac.begin();
+ irac.whirlpool(&ac,
+ DG11J13A,
+ true, // Power
+ stdAc::opmode_t::kAuto, // Mode
+ 21, // Celsius
+ stdAc::fanspeed_t::kMedium, // Fan speed
+ stdAc::swingv_t::kAuto, // Veritcal swing
+ false, // Turbo
+ true, // Light
+ 8 * 60 + 30, // Sleep
+ 23 * 60 + 58); // Clock
+ ASSERT_EQ(expected, ac.toString());
+ ac._irsend.makeDecodeResult();
+ EXPECT_TRUE(capture.decode(&ac._irsend.capture));
+ ASSERT_EQ(WHIRLPOOL_AC, ac._irsend.capture.decode_type);
+ ASSERT_EQ(kWhirlpoolAcBits, ac._irsend.capture.bits);
+ ac.setRaw(ac._irsend.capture.state);
+ ASSERT_EQ(expected, ac.toString());
+}
+
+TEST(TestIRac, strToBool) {
+ EXPECT_TRUE(IRac::strToBool("ON"));
+ EXPECT_TRUE(IRac::strToBool("1"));
+ EXPECT_TRUE(IRac::strToBool("TRUE"));
+ EXPECT_TRUE(IRac::strToBool("YES"));
+ EXPECT_FALSE(IRac::strToBool("OFF"));
+ EXPECT_FALSE(IRac::strToBool("0"));
+ EXPECT_FALSE(IRac::strToBool("FALSE"));
+ EXPECT_FALSE(IRac::strToBool("NO"));
+ EXPECT_FALSE(IRac::strToBool("FOOBAR"));
+ EXPECT_TRUE(IRac::strToBool("FOOBAR", true));
+}
+
+TEST(TestIRac, strToOpmode) {
+ EXPECT_EQ(stdAc::opmode_t::kAuto, IRac::strToOpmode("AUTO"));
+ EXPECT_EQ(stdAc::opmode_t::kCool, IRac::strToOpmode("COOL"));
+ EXPECT_EQ(stdAc::opmode_t::kHeat, IRac::strToOpmode("HEAT"));
+ EXPECT_EQ(stdAc::opmode_t::kDry, IRac::strToOpmode("DRY"));
+ EXPECT_EQ(stdAc::opmode_t::kFan, IRac::strToOpmode("FAN"));
+ EXPECT_EQ(stdAc::opmode_t::kFan, IRac::strToOpmode("FAN_ONLY"));
+ EXPECT_EQ(stdAc::opmode_t::kAuto, IRac::strToOpmode("FOOBAR"));
+ EXPECT_EQ(stdAc::opmode_t::kOff, IRac::strToOpmode("OFF"));
+ EXPECT_EQ(stdAc::opmode_t::kOff, IRac::strToOpmode("FOOBAR",
+ stdAc::opmode_t::kOff));
+}
+
+TEST(TestIRac, strToFanspeed) {
+ EXPECT_EQ(stdAc::fanspeed_t::kAuto, IRac::strToFanspeed("AUTO"));
+ EXPECT_EQ(stdAc::fanspeed_t::kMin, IRac::strToFanspeed("MIN"));
+ EXPECT_EQ(stdAc::fanspeed_t::kLow, IRac::strToFanspeed("LOW"));
+ EXPECT_EQ(stdAc::fanspeed_t::kMedium, IRac::strToFanspeed("MEDIUM"));
+ EXPECT_EQ(stdAc::fanspeed_t::kHigh, IRac::strToFanspeed("HIGH"));
+ EXPECT_EQ(stdAc::fanspeed_t::kMax, IRac::strToFanspeed("MAX"));
+ EXPECT_EQ(stdAc::fanspeed_t::kAuto, IRac::strToFanspeed("FOOBAR"));
+ EXPECT_EQ(stdAc::fanspeed_t::kMin,
+ IRac::strToFanspeed("FOOBAR", stdAc::fanspeed_t::kMin));
+}
+
+TEST(TestIRac, strToSwingV) {
+ EXPECT_EQ(stdAc::swingv_t::kAuto, IRac::strToSwingV("AUTO"));
+ EXPECT_EQ(stdAc::swingv_t::kLowest, IRac::strToSwingV("LOWEST"));
+ EXPECT_EQ(stdAc::swingv_t::kLow, IRac::strToSwingV("LOW"));
+ EXPECT_EQ(stdAc::swingv_t::kMiddle, IRac::strToSwingV("MIDDLE"));
+ EXPECT_EQ(stdAc::swingv_t::kHigh, IRac::strToSwingV("HIGH"));
+ EXPECT_EQ(stdAc::swingv_t::kHighest, IRac::strToSwingV("HIGHEST"));
+ EXPECT_EQ(stdAc::swingv_t::kOff, IRac::strToSwingV("OFF"));
+ EXPECT_EQ(stdAc::swingv_t::kOff, IRac::strToSwingV("FOOBAR"));
+ EXPECT_EQ(stdAc::swingv_t::kAuto,
+ IRac::strToSwingV("FOOBAR", stdAc::swingv_t::kAuto));
+}
+
+TEST(TestIRac, strToSwingH) {
+ EXPECT_EQ(stdAc::swingh_t::kAuto, IRac::strToSwingH("AUTO"));
+ EXPECT_EQ(stdAc::swingh_t::kLeftMax, IRac::strToSwingH("MAX LEFT"));
+ EXPECT_EQ(stdAc::swingh_t::kLeft, IRac::strToSwingH("LEFT"));
+ EXPECT_EQ(stdAc::swingh_t::kMiddle, IRac::strToSwingH("CENTRE"));
+ EXPECT_EQ(stdAc::swingh_t::kRight, IRac::strToSwingH("RIGHT"));
+ EXPECT_EQ(stdAc::swingh_t::kRightMax, IRac::strToSwingH("RIGHTMAX"));
+ EXPECT_EQ(stdAc::swingh_t::kOff, IRac::strToSwingH("OFF"));
+ EXPECT_EQ(stdAc::swingh_t::kOff, IRac::strToSwingH("FOOBAR"));
+ EXPECT_EQ(stdAc::swingh_t::kAuto,
+ IRac::strToSwingH("FOOBAR", stdAc::swingh_t::kAuto));
+}
+
+TEST(TestIRac, strToModel) {
+ EXPECT_EQ(panasonic_ac_remote_model_t::kPanasonicLke,
+ IRac::strToModel("LKE"));
+ EXPECT_EQ(panasonic_ac_remote_model_t::kPanasonicLke,
+ IRac::strToModel("PANASONICLKE"));
+ EXPECT_EQ(fujitsu_ac_remote_model_t::ARRAH2E,
+ IRac::strToModel("ARRAH2E"));
+ EXPECT_EQ(whirlpool_ac_remote_model_t::DG11J13A,
+ IRac::strToModel("DG11J13A"));
+ EXPECT_EQ(1, IRac::strToModel("1"));
+ EXPECT_EQ(10, IRac::strToModel("10"));
+ EXPECT_EQ(-1, IRac::strToModel("0"));
+ EXPECT_EQ(-1, IRac::strToModel("FOOBAR"));
+ EXPECT_EQ(0, IRac::strToModel("FOOBAR", 0));
+}
diff --git a/lib/IRremoteESP8266-2.5.2.03/test/IRrecv_test.cpp b/lib/IRremoteESP8266-2.6.0/test/IRrecv_test.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/test/IRrecv_test.cpp
rename to lib/IRremoteESP8266-2.6.0/test/IRrecv_test.cpp
diff --git a/lib/IRremoteESP8266-2.5.2.03/test/IRrecv_test.h b/lib/IRremoteESP8266-2.6.0/test/IRrecv_test.h
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/test/IRrecv_test.h
rename to lib/IRremoteESP8266-2.6.0/test/IRrecv_test.h
diff --git a/lib/IRremoteESP8266-2.6.0/test/IRsend_test.cpp b/lib/IRremoteESP8266-2.6.0/test/IRsend_test.cpp
new file mode 100644
index 000000000..ffd69cf71
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/test/IRsend_test.cpp
@@ -0,0 +1,686 @@
+// Copyright 2017,2019 David Conran
+
+#include "IRsend_test.h"
+#include "IRsend.h"
+#include "IRutils.h"
+#include "gtest/gtest.h"
+
+// Tests sendData().
+
+// Test sending zero bits.
+TEST(TestSendData, SendZeroBits) {
+ IRsendTest irsend(4);
+ irsend.begin();
+ irsend.sendData(1, 2, 3, 4, 0b1, 0, true);
+ EXPECT_EQ("", irsend.outputStr());
+}
+
+// Test sending zero and one.
+TEST(TestSendData, SendSingleBit) {
+ IRsendTest irsend(4);
+ irsend.begin();
+ irsend.sendData(1, 2, 3, 4, 0b1, 1, true);
+ EXPECT_EQ("d50m1s2", irsend.outputStr());
+ irsend.sendData(1, 2, 3, 4, 0b0, 1, true);
+ EXPECT_EQ("d50m3s4", irsend.outputStr());
+}
+
+// Test sending bit order.
+TEST(TestSendData, TestingBitSendOrder) {
+ IRsendTest irsend(4);
+ irsend.begin();
+ irsend.sendData(1, 2, 3, 4, 0b10, 2, true);
+ EXPECT_EQ("d50m1s2m3s4", irsend.outputStr());
+ irsend.sendData(1, 2, 3, 4, 0b10, 2, false);
+ EXPECT_EQ("d50m3s4m1s2", irsend.outputStr());
+ irsend.sendData(1, 2, 3, 4, 0b0001, 4, false);
+ EXPECT_EQ("d50m1s2m3s4m3s4m3s4", irsend.outputStr());
+}
+
+// Test sending typical data.
+TEST(TestSendData, SendTypicalData) {
+ IRsendTest irsend(4);
+ irsend.begin();
+ irsend.sendData(1, 2, 3, 4, 0b1010110011110000, 16, true);
+ EXPECT_EQ(
+ "d50m1s2m3s4m1s2m3s4m1s2m1s2m3s4m3s4m1s2m1s2m1s2m1s2m3s4m3s4m3s4m3s4",
+ irsend.outputStr());
+ irsend.sendData(1, 2, 3, 4, 0x1234567890ABCDEF, 64, true);
+ EXPECT_EQ(
+ "d50"
+ "m3s4m3s4m3s4m1s2m3s4m3s4m1s2m3s4m3s4m3s4m1s2m1s2m3s4m1s2m3s4m3s4"
+ "m3s4m1s2m3s4m1s2m3s4m1s2m1s2m3s4m3s4m1s2m1s2m1s2m1s2m3s4m3s4m3s4"
+ "m1s2m3s4m3s4m1s2m3s4m3s4m3s4m3s4m1s2m3s4m1s2m3s4m1s2m3s4m1s2m1s2"
+ "m1s2m1s2m3s4m3s4m1s2m1s2m3s4m1s2m1s2m1s2m1s2m3s4m1s2m1s2m1s2m1s2",
+ irsend.outputStr());
+}
+
+// Test sending more than expected bits.
+TEST(TestSendData, SendOverLargeData) {
+ IRsendTest irsend(4);
+ irsend.begin();
+ irsend.sendData(1, 2, 3, 4, 0xFFFFFFFFFFFFFFFF, 70, true);
+ EXPECT_EQ(
+ "d50"
+ "m3s4m3s4m3s4m3s4m3s4m3s4"
+ "m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2"
+ "m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2"
+ "m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2"
+ "m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2",
+ irsend.outputStr());
+}
+
+// Test inverting the output.
+TEST(TestIRSend, InvertedOutput) {
+ IRsendTest irsend(4, true);
+ irsend.begin();
+ irsend.sendData(1, 2, 3, 4, 0b1, 1, true);
+ EXPECT_EQ("d50s1m2", irsend.outputStr());
+ irsend.sendData(1, 2, 3, 4, 0b0, 1, true);
+ EXPECT_EQ("d50s3m4", irsend.outputStr());
+}
+
+// Test we correctly pick up frequency changes.
+TEST(TestIRSend, DetectFreqChanges) {
+ IRsendTest irsend(0);
+
+ irsend.begin();
+ irsend.enableIROut(40); // 40kHz
+ irsend.sendData(1, 2, 3, 4, 0b1, 1, true);
+ irsend.enableIROut(38); // 40kHz
+ irsend.sendData(1, 2, 3, 4, 0b1, 1, true);
+ irsend.enableIROut(40); // 40kHz
+ irsend.sendData(1, 2, 3, 4, 0b1, 1, true);
+ irsend.enableIROut(38); // 40kHz
+ irsend.sendData(1, 2, 3, 4, 0b1, 1, true);
+ EXPECT_EQ(
+ "f40000d50"
+ "m1s2"
+ "f38000"
+ "m1s2"
+ "f40000"
+ "m1s2"
+ "f38000"
+ "m1s2",
+ irsend.outputStr());
+ irsend.reset();
+ irsend.enableIROut(40); // 40kHz
+ irsend.sendData(1, 2, 3, 4, 0b1, 1, true);
+ irsend.enableIROut(40); // 40kHz
+ irsend.sendData(1, 2, 3, 4, 0b1, 1, true);
+ irsend.enableIROut(38); // 40kHz
+ irsend.sendData(1, 2, 3, 4, 0b1, 1, true);
+ irsend.enableIROut(38); // 40kHz
+ irsend.sendData(1, 2, 3, 4, 0b1, 1, true);
+ EXPECT_EQ(
+ "f40000d50"
+ "m1s2m1s2"
+ "f38000m1s2m1s2",
+ irsend.outputStr());
+}
+
+// Test we correctly pick up duty cycle changes.
+TEST(TestIRSend, DetectDutyChanges) {
+ IRsendTest irsend(0);
+
+ irsend.begin();
+ irsend.sendGeneric(1, 2, 3, 4, 5, 6, 7, 8, 0b1, 1, 38000, true, 0, 33);
+ EXPECT_EQ(
+ "f38000d33"
+ "m1s2m3s4m7s8",
+ irsend.outputStr());
+
+ irsend.reset();
+ irsend.sendGeneric(1, 2, 3, 4, 5, 6, 7, 8, 0b1, 1, 38000, true, 0, 50);
+ irsend.sendGeneric(1, 2, 3, 4, 5, 6, 7, 8, 0b1, 1, 38000, true, 0, 33);
+ irsend.sendGeneric(1, 2, 3, 4, 5, 6, 7, 8, 0b1, 1, 38000, true, 0, 25);
+ EXPECT_EQ(
+ "f38000d50"
+ "m1s2m3s4m7s8"
+ "d33"
+ "m1s2m3s4m7s8"
+ "d25"
+ "m1s2m3s4m7s8",
+ irsend.outputStr());
+}
+
+
+// Test we correctly pick up frequency AND duty changes.
+TEST(TestIRSend, DetectFreqAndDutyChanges) {
+ IRsendTest irsend(0);
+
+ irsend.begin();
+ irsend.sendGeneric(1, 2, 3, 4, 5, 6, 7, 8, 0b1, 1, 38000, true, 0, 50);
+ irsend.sendGeneric(1, 2, 3, 4, 5, 6, 7, 8, 0b1, 1, 38000, true, 0, 33);
+ irsend.sendGeneric(1, 2, 3, 4, 5, 6, 7, 8, 0b1, 1, 40000, true, 0, 25);
+ EXPECT_EQ(
+ "f38000d50"
+ "m1s2m3s4m7s8"
+ "d33"
+ "m1s2m3s4m7s8"
+ "f40000d25"
+ "m1s2m3s4m7s8",
+ irsend.outputStr());
+}
+
+// Test typical use of sendRaw().
+TEST(TestSendRaw, GeneralUse) {
+ IRsendTest irsend(4);
+ IRrecv irrecv(0);
+
+ 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};
+
+ irsend.sendRaw(rawData, 67, 38);
+ EXPECT_EQ(
+ "f38000d50"
+ "m8950s4500"
+ "m550s1650m600s1650m550s550m600s500m600s550m550s550m600s1650m550s1650"
+ "m600s1650m600s1650m550s1700m550s550m600s550m550s550m600s500m600s550"
+ "m550s1650m600s1650m600s1650m550s550m600s500m600s500m600s550m550s550"
+ "m600s1650m550s1650m600s1650m600s500m650s1600m600s500m600s550m550s550"
+ "m600",
+ irsend.outputStr());
+
+ irsend.reset();
+ irsend.sendRaw(rawData, 67, 38);
+ irsend.makeDecodeResult();
+ 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);
+ EXPECT_EQ(
+ "f38000d50"
+ "m8950s4500"
+ "m550s1650m600s1650m550s550m600s500m600s550m550s550m600s1650m550s1650"
+ "m600s1650m600s1650m550s1700m550s550m600s550m550s550m600s500m600s550"
+ "m550s1650m600s1650m600s1650m550s550m600s500m600s500m600s550m550s550"
+ "m600s1650m550s1650m600s1650m600s500m650s1600m600s500m600s550m550s550"
+ "m600",
+ irsend.outputStr());
+}
+
+// Incorrect handling of decodes from Raw. i.e. There is no gap recorded at
+// the end of a command when using the interrupt code. sendRaw() best emulates
+// this for unit testing purposes. sendGC() and sendXXX() will add the trailing
+// gap. Users won't see this in normal use.
+TEST(TestSendRaw, NoTrailingGap) {
+ IRsendTest irsend(4);
+ IRrecv irrecv(4);
+ 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};
+ irsend.sendRaw(rawData, 67, 38);
+ irsend.makeDecodeResult();
+ EXPECT_TRUE(irrecv.decodeNEC(&irsend.capture));
+ EXPECT_EQ(NEC, irsend.capture.decode_type);
+ EXPECT_EQ(kNECBits, irsend.capture.bits);
+}
+
+TEST(TestLowLevelSend, MarkFrequencyModulationAt38kHz) {
+ IRsendLowLevelTest irsend(0);
+
+ irsend.begin();
+
+ irsend.reset();
+ irsend.enableIROut(38000, 50);
+ EXPECT_EQ(5, irsend.mark(100));
+ EXPECT_EQ(
+ "[On]10usecs[Off]11usecs[On]10usecs[Off]11usecs[On]10usecs[Off]11usecs"
+ "[On]10usecs[Off]11usecs[On]10usecs[Off]6usecs",
+ irsend.low_level_sequence);
+
+ irsend.reset();
+ irsend.enableIROut(38000, 33);
+ EXPECT_EQ(5, irsend.mark(100));
+ EXPECT_EQ(
+ "[On]6usecs[Off]15usecs[On]6usecs[Off]15usecs[On]6usecs[Off]15usecs"
+ "[On]6usecs[Off]15usecs[On]6usecs[Off]10usecs",
+ irsend.low_level_sequence);
+
+ irsend.reset();
+ irsend.enableIROut(38000, 100);
+ EXPECT_EQ(1, irsend.mark(1000));
+ EXPECT_EQ("[On]1000usecs[Off]", irsend.low_level_sequence);
+}
+
+TEST(TestLowLevelSend, MarkFrequencyModulationAt36_7kHz) {
+ IRsendLowLevelTest irsend(0);
+
+ irsend.begin();
+
+ irsend.reset();
+ irsend.enableIROut(36700, 50);
+ EXPECT_EQ(5, irsend.mark(100));
+ EXPECT_EQ(
+ "[On]11usecs[Off]11usecs[On]11usecs[Off]11usecs[On]11usecs[Off]11usecs"
+ "[On]11usecs[Off]11usecs[On]11usecs[Off]1usecs",
+ irsend.low_level_sequence);
+
+ irsend.reset();
+ irsend.enableIROut(36700, 33);
+ EXPECT_EQ(5, irsend.mark(100));
+ EXPECT_EQ(
+ "[On]7usecs[Off]15usecs[On]7usecs[Off]15usecs[On]7usecs[Off]15usecs"
+ "[On]7usecs[Off]15usecs[On]7usecs[Off]5usecs",
+ irsend.low_level_sequence);
+
+ irsend.reset();
+ irsend.enableIROut(36700, 100);
+ EXPECT_EQ(1, irsend.mark(1000));
+ EXPECT_EQ("[On]1000usecs[Off]", irsend.low_level_sequence);
+}
+
+TEST(TestLowLevelSend, MarkFrequencyModulationAt40kHz) {
+ IRsendLowLevelTest irsend(0);
+
+ irsend.begin();
+
+ irsend.reset();
+ irsend.enableIROut(40000, 50);
+ EXPECT_EQ(5, irsend.mark(100));
+ EXPECT_EQ(
+ "[On]10usecs[Off]10usecs[On]10usecs[Off]10usecs[On]10usecs[Off]10usecs"
+ "[On]10usecs[Off]10usecs[On]10usecs[Off]10usecs",
+ irsend.low_level_sequence);
+
+ irsend.reset();
+ irsend.enableIROut(40000, 33);
+ EXPECT_EQ(5, irsend.mark(100));
+ EXPECT_EQ(
+ "[On]6usecs[Off]14usecs[On]6usecs[Off]14usecs[On]6usecs[Off]14usecs"
+ "[On]6usecs[Off]14usecs[On]6usecs[Off]14usecs",
+ irsend.low_level_sequence);
+
+ irsend.reset();
+ irsend.enableIROut(40000, 100);
+ EXPECT_EQ(1, irsend.mark(1000));
+ EXPECT_EQ("[On]1000usecs[Off]", irsend.low_level_sequence);
+}
+
+TEST(TestLowLevelSend, MarkNoModulation) {
+ IRsendLowLevelTest irsend(0, false, false);
+
+ irsend.begin();
+
+ irsend.reset();
+ irsend.enableIROut(38000, 50);
+ EXPECT_EQ(1, irsend.mark(1000));
+ EXPECT_EQ("[On]1000usecs[Off]", irsend.low_level_sequence);
+
+ irsend.reset();
+ irsend.enableIROut(36700, 25);
+ EXPECT_EQ(1, irsend.mark(1000));
+ EXPECT_EQ("[On]1000usecs[Off]", irsend.low_level_sequence);
+
+ irsend.reset();
+ irsend.enableIROut(40000, 75);
+ EXPECT_EQ(1, irsend.mark(1000));
+ EXPECT_EQ("[On]1000usecs[Off]", irsend.low_level_sequence);
+}
+
+TEST(TestLowLevelSend, SpaceFrequencyModulation) {
+ IRsendLowLevelTest irsend(0);
+
+ irsend.reset();
+ irsend.enableIROut(38000);
+ irsend.space(1000);
+ EXPECT_EQ("[Off]1000usecs", irsend.low_level_sequence);
+
+ irsend.reset();
+ irsend.enableIROut(40000, 75);
+ irsend.space(1000);
+ EXPECT_EQ("[Off]1000usecs", irsend.low_level_sequence);
+
+ irsend.reset();
+ irsend.enableIROut(38000, 100);
+ irsend.space(1000);
+ EXPECT_EQ("[Off]1000usecs", irsend.low_level_sequence);
+
+ irsend.reset();
+ irsend.enableIROut(38000, 33);
+ irsend.space(1000);
+ EXPECT_EQ("[Off]1000usecs", irsend.low_level_sequence);
+}
+
+TEST(TestLowLevelSend, SpaceNoModulation) {
+ IRsendLowLevelTest irsend(0, false, false);
+
+ irsend.begin();
+
+ irsend.reset();
+ irsend.enableIROut(38000, 50);
+ irsend.space(1000);
+ EXPECT_EQ("[Off]1000usecs", irsend.low_level_sequence);
+
+ irsend.reset();
+ irsend.enableIROut(36700, 25);
+ irsend.space(1000);
+ EXPECT_EQ("[Off]1000usecs", irsend.low_level_sequence);
+
+ irsend.reset();
+ irsend.enableIROut(40000, 75);
+ irsend.space(1000);
+ EXPECT_EQ("[Off]1000usecs", irsend.low_level_sequence);
+}
+
+// Test expected to work/produce a message for irsend:send()
+TEST(TestSend, GenericSimpleSendMethod) {
+ IRsendTest irsend(0);
+ IRrecv irrecv(0);
+ irsend.begin();
+
+ irsend.reset();
+ ASSERT_TRUE(irsend.send(AIWA_RC_T501, 0x1234, kAiwaRcT501Bits));
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(AIWA_RC_T501, irsend.capture.decode_type);
+ EXPECT_EQ(kAiwaRcT501Bits, irsend.capture.bits);
+ EXPECT_EQ(0x1234, irsend.capture.value);
+
+ irsend.reset();
+ ASSERT_TRUE(irsend.send(CARRIER_AC, 0x1234, kCarrierAcBits));
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(CARRIER_AC, irsend.capture.decode_type);
+ EXPECT_EQ(kCarrierAcBits, irsend.capture.bits);
+ EXPECT_EQ(0x1234, irsend.capture.value);
+
+ irsend.reset();
+ ASSERT_TRUE(irsend.send(COOLIX, 0x1234, kCoolixBits));
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(COOLIX, irsend.capture.decode_type);
+ EXPECT_EQ(kCoolixBits, irsend.capture.bits);
+ EXPECT_EQ(0x1234, irsend.capture.value);
+
+ irsend.reset();
+ ASSERT_TRUE(irsend.send(DENON, 0x1234, kDenonBits));
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(DENON, irsend.capture.decode_type);
+ EXPECT_EQ(kDenonBits, irsend.capture.bits);
+ EXPECT_EQ(0x1234, irsend.capture.value);
+
+ irsend.reset();
+ ASSERT_TRUE(irsend.send(DISH, 0x1234, kDishBits));
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(DISH, irsend.capture.decode_type);
+ EXPECT_EQ(kDishBits, irsend.capture.bits);
+ EXPECT_EQ(0x1234, irsend.capture.value);
+
+ irsend.reset();
+ ASSERT_TRUE(irsend.send(GICABLE, 0x1234, kGicableBits));
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(GICABLE, irsend.capture.decode_type);
+ EXPECT_EQ(kGicableBits, irsend.capture.bits);
+ EXPECT_EQ(0x1234, irsend.capture.value);
+
+ irsend.reset();
+ ASSERT_TRUE(irsend.send(GREE, 0x0009205000200050, kGreeBits));
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(GREE, irsend.capture.decode_type);
+ EXPECT_EQ(kGreeBits, irsend.capture.bits);
+ // No simple value test for gree as it decodes to an Array.
+
+ irsend.reset();
+ ASSERT_TRUE(irsend.send(JVC, 0x1234, kJvcBits));
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(JVC, irsend.capture.decode_type);
+ EXPECT_EQ(kJvcBits, irsend.capture.bits);
+ EXPECT_EQ(0x1234, irsend.capture.value);
+
+ irsend.reset();
+ ASSERT_TRUE(irsend.send(LASERTAG, 0x123, kLasertagBits));
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(LASERTAG, irsend.capture.decode_type);
+ EXPECT_EQ(kLasertagBits, irsend.capture.bits);
+ EXPECT_EQ(0x123, irsend.capture.value);
+
+ irsend.reset();
+ ASSERT_TRUE(irsend.send(LG, 0x700992, kLgBits));
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(LG, irsend.capture.decode_type);
+ EXPECT_EQ(kLgBits, irsend.capture.bits);
+ EXPECT_EQ(0x700992, irsend.capture.value);
+
+ irsend.reset();
+ ASSERT_TRUE(irsend.send(LG, 0x700992, kLg32Bits));
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(LG, irsend.capture.decode_type);
+ EXPECT_EQ(kLg32Bits, irsend.capture.bits);
+ EXPECT_EQ(0x700992, irsend.capture.value);
+
+ irsend.reset();
+ ASSERT_TRUE(irsend.send(LG2, 0x880094D, kLgBits));
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(LG2, irsend.capture.decode_type);
+ EXPECT_EQ(kLgBits, irsend.capture.bits);
+ EXPECT_EQ(0x880094D, irsend.capture.value);
+
+ irsend.reset();
+ ASSERT_TRUE(irsend.send(LUTRON, 0x1234, kLutronBits));
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(LUTRON, irsend.capture.decode_type);
+ EXPECT_EQ(kLutronBits, irsend.capture.bits);
+ EXPECT_EQ(0x1234, irsend.capture.value);
+
+ irsend.reset();
+ ASSERT_TRUE(irsend.send(MAGIQUEST, 0x560F40020455, kMagiquestBits));
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(MAGIQUEST, irsend.capture.decode_type);
+ EXPECT_EQ(kMagiquestBits, irsend.capture.bits);
+ EXPECT_EQ(0x560F40020455, irsend.capture.value);
+
+ irsend.reset();
+ ASSERT_TRUE(irsend.send(MIDEA, 0xA18263FFFF6E, kMideaBits));
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(MIDEA, irsend.capture.decode_type);
+ EXPECT_EQ(kMideaBits, irsend.capture.bits);
+ EXPECT_EQ(0xA18263FFFF6E, irsend.capture.value);
+
+ irsend.reset();
+ ASSERT_TRUE(irsend.send(MITSUBISHI, 0x1234, kMitsubishiBits));
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(MITSUBISHI, irsend.capture.decode_type);
+ EXPECT_EQ(kMitsubishiBits, irsend.capture.bits);
+ EXPECT_EQ(0x1234, irsend.capture.value);
+
+ irsend.reset();
+ ASSERT_TRUE(irsend.send(MITSUBISHI2, 0x1234, kMitsubishiBits));
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(MITSUBISHI2, irsend.capture.decode_type);
+ EXPECT_EQ(kMitsubishiBits, irsend.capture.bits);
+ EXPECT_EQ(0x1234, irsend.capture.value);
+
+ irsend.reset();
+ ASSERT_TRUE(irsend.send(NIKAI, 0x1234, kNikaiBits));
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(NIKAI, irsend.capture.decode_type);
+ EXPECT_EQ(kNikaiBits, irsend.capture.bits);
+ EXPECT_EQ(0x1234, irsend.capture.value);
+
+ irsend.reset();
+ ASSERT_TRUE(irsend.send(NEC, 0x4BB640BF, kNECBits));
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(NEC, irsend.capture.decode_type);
+ EXPECT_EQ(kNECBits, irsend.capture.bits);
+ EXPECT_EQ(0x4BB640BF, irsend.capture.value);
+
+ irsend.reset();
+ ASSERT_TRUE(irsend.send(NEC_LIKE, 0x12345678, kNECBits));
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(NEC_LIKE, irsend.capture.decode_type);
+ EXPECT_EQ(kNECBits, irsend.capture.bits);
+ EXPECT_EQ(0x12345678, irsend.capture.value);
+
+ irsend.reset();
+ ASSERT_TRUE(irsend.send(PANASONIC, 0x40040190ED7C, kPanasonicBits));
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(PANASONIC, irsend.capture.decode_type);
+ EXPECT_EQ(kPanasonicBits, irsend.capture.bits);
+ EXPECT_EQ(0x40040190ED7C, irsend.capture.value);
+
+ irsend.reset();
+ ASSERT_TRUE(irsend.send(PIONEER, 0x659A05FAF50AC53A, kPioneerBits));
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(PIONEER, irsend.capture.decode_type);
+ EXPECT_EQ(kPioneerBits, irsend.capture.bits);
+ EXPECT_EQ(0x659A05FAF50AC53A, irsend.capture.value);
+
+ irsend.reset();
+ ASSERT_TRUE(irsend.send(RC5, 0x175, kRC5Bits));
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(RC5, irsend.capture.decode_type);
+ EXPECT_EQ(kRC5Bits, irsend.capture.bits);
+ EXPECT_EQ(0x175, irsend.capture.value);
+
+ irsend.reset();
+ ASSERT_TRUE(irsend.send(RC6, 0xC800F740C, kRC6_36Bits));
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(RC6, irsend.capture.decode_type);
+ EXPECT_EQ(kRC6_36Bits, irsend.capture.bits);
+ EXPECT_EQ(0xC800F740C, irsend.capture.value);
+
+ irsend.reset();
+ ASSERT_TRUE(irsend.send(RCMM, 0x1234, kRCMMBits));
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(RCMM, irsend.capture.decode_type);
+ EXPECT_EQ(kRCMMBits, irsend.capture.bits);
+ EXPECT_EQ(0x1234, irsend.capture.value);
+
+ irsend.reset();
+ ASSERT_TRUE(irsend.send(SAMSUNG, 0xE0E09966, kSamsungBits));
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(SAMSUNG, irsend.capture.decode_type);
+ EXPECT_EQ(kSamsungBits, irsend.capture.bits);
+ EXPECT_EQ(0xE0E09966, irsend.capture.value);
+
+ irsend.reset();
+ ASSERT_TRUE(irsend.send(SAMSUNG36, 0x1234, kSamsung36Bits));
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(SAMSUNG36, irsend.capture.decode_type);
+ EXPECT_EQ(kSamsung36Bits, irsend.capture.bits);
+ EXPECT_EQ(0x1234, irsend.capture.value);
+
+ irsend.reset();
+ ASSERT_TRUE(irsend.send(SANYO_LC7461, 0x2468DCB56A9, kSanyoLC7461Bits));
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(SANYO_LC7461, irsend.capture.decode_type);
+ EXPECT_EQ(kSanyoLC7461Bits, irsend.capture.bits);
+ EXPECT_EQ(0x2468DCB56A9, irsend.capture.value);
+
+ irsend.reset();
+ ASSERT_TRUE(irsend.send(SHARP, 0x7266, kSharpBits));
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(SHARP, irsend.capture.decode_type);
+ EXPECT_EQ(kSharpBits, irsend.capture.bits);
+ EXPECT_EQ(0x7266, irsend.capture.value);
+
+ irsend.reset();
+ ASSERT_TRUE(irsend.send(SHERWOOD, 0x4BB640BF, kSherwoodBits));
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(NEC, irsend.capture.decode_type);
+ EXPECT_EQ(kSherwoodBits, irsend.capture.bits);
+ EXPECT_EQ(0x4BB640BF, irsend.capture.value);
+
+ irsend.reset();
+ ASSERT_TRUE(irsend.send(SONY, 0x1234, kSony20Bits));
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(SONY, irsend.capture.decode_type);
+ EXPECT_EQ(kSony20Bits, irsend.capture.bits);
+ EXPECT_EQ(0x1234, irsend.capture.value);
+
+ irsend.reset();
+ ASSERT_TRUE(irsend.send(TECO, 0x1234, kTecoBits));
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(TECO, irsend.capture.decode_type);
+ EXPECT_EQ(kTecoBits, irsend.capture.bits);
+ EXPECT_EQ(0x1234, irsend.capture.value);
+
+ irsend.reset();
+ ASSERT_TRUE(irsend.send(VESTEL_AC, 0xF4410001FF1201, kVestelAcBits));
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(VESTEL_AC, irsend.capture.decode_type);
+ EXPECT_EQ(kVestelAcBits, irsend.capture.bits);
+ EXPECT_EQ(0xF4410001FF1201, irsend.capture.value);
+
+ irsend.reset();
+ ASSERT_TRUE(irsend.send(WHYNTER, 0x1234, kWhynterBits));
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(WHYNTER, irsend.capture.decode_type);
+ EXPECT_EQ(kWhynterBits, irsend.capture.bits);
+ EXPECT_EQ(0x1234, irsend.capture.value);
+}
+
+// Test some expected types to NOT work/produce a message via irsend:send()
+TEST(TestSend, GenericSimpleSendMethodFailure) {
+ IRsendTest irsend(0);
+ IRrecv irrecv(0);
+ irsend.begin();
+
+ // Check nothing is sent for unexpected protocols
+ irsend.reset();
+ ASSERT_FALSE(irsend.send(KELVINATOR, 0x1234, kKelvinatorBits));
+ irsend.makeDecodeResult();
+ ASSERT_FALSE(irrecv.decode(&irsend.capture));
+
+ // For every A/C protocol which decodes to having a state[].
+ for (int i = 0; i < 200; i++) {
+ if (hasACState((decode_type_t)i) && i != GREE) { // Gree is an exception.
+ // Check it fails.
+ ASSERT_FALSE(irsend.send((decode_type_t)i, 0, 0));
+ }
+ }
+
+ // Test some other special cases.
+ ASSERT_FALSE(irsend.send(UNKNOWN, 0, 0));
+ ASSERT_FALSE(irsend.send(UNUSED, 0, 0));
+ ASSERT_FALSE(irsend.send(RAW, 0, 0));
+ ASSERT_FALSE(irsend.send(PRONTO, 0, 0));
+ ASSERT_FALSE(irsend.send(GLOBALCACHE, 0, 0));
+}
diff --git a/lib/IRremoteESP8266-2.5.2.03/test/IRsend_test.h b/lib/IRremoteESP8266-2.6.0/test/IRsend_test.h
similarity index 82%
rename from lib/IRremoteESP8266-2.5.2.03/test/IRsend_test.h
rename to lib/IRremoteESP8266-2.6.0/test/IRsend_test.h
index 6d9fe51b8..f43409433 100644
--- a/lib/IRremoteESP8266-2.5.2.03/test/IRsend_test.h
+++ b/lib/IRremoteESP8266-2.6.0/test/IRsend_test.h
@@ -17,12 +17,14 @@
#ifdef UNIT_TEST
// Used to help simulate elapsed time in unit tests.
-uint32_t _IRtimer_unittest_now = 0;
+extern uint32_t _IRtimer_unittest_now;
#endif // UNIT_TEST
class IRsendTest : public IRsend {
public:
uint32_t output[OUTPUT_BUF];
+ uint32_t freq[OUTPUT_BUF];
+ uint8_t duty[OUTPUT_BUF];
uint16_t last;
uint16_t rawbuf[RAW_BUF];
decode_results capture;
@@ -40,8 +42,22 @@ class IRsendTest : public IRsend {
std::string outputStr() {
std::stringstream result;
+ uint8_t lastduty = UINT8_MAX; // An impossible duty cycle value.
+ uint32_t lastfreq = 0; // An impossible frequency value.
if (last == 0 && output[0] == 0) return "";
for (uint16_t i = 0; i <= last; i++) {
+ // Display the frequency only if it changes.
+ if (freq[i] != lastfreq) {
+ result << "f";
+ result << freq[i];
+ lastfreq = freq[i];
+ }
+ // Display the duty cycle only if it changes.
+ if (duty[i] != lastduty) {
+ result << "d";
+ result << static_cast(duty[i]);
+ lastduty = duty[i];
+ }
if ((i & 1) != outputOff) // Odd XOR outputOff
result << "s";
else
@@ -92,6 +108,8 @@ class IRsendTest : public IRsend {
output[++last] = usec;
else
output[last] += usec;
+ duty[last] = _dutycycle;
+ freq[last] = _freq_unittest;
return 0;
}
@@ -103,6 +121,8 @@ class IRsendTest : public IRsend {
} else {
output[++last] = time;
}
+ duty[last] = _dutycycle;
+ freq[last] = _freq_unittest;
}
};
diff --git a/lib/IRremoteESP8266-2.5.2.03/test/IRutils_test.cpp b/lib/IRremoteESP8266-2.6.0/test/IRutils_test.cpp
similarity index 85%
rename from lib/IRremoteESP8266-2.5.2.03/test/IRutils_test.cpp
rename to lib/IRremoteESP8266-2.6.0/test/IRutils_test.cpp
index 91cf4725c..4a4907649 100644
--- a/lib/IRremoteESP8266-2.5.2.03/test/IRutils_test.cpp
+++ b/lib/IRremoteESP8266-2.6.0/test/IRutils_test.cpp
@@ -350,3 +350,68 @@ 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));
+}
+
+TEST(TestStrToDecodeType, strToDecodeType) {
+ EXPECT_EQ(decode_type_t::NEC, strToDecodeType("NEC"));
+ EXPECT_EQ(decode_type_t::KELVINATOR, strToDecodeType("KELVINATOR"));
+ EXPECT_EQ(decode_type_t::UNKNOWN, strToDecodeType("foo"));
+}
+
+TEST(TestUtils, htmlEscape) {
+ EXPECT_EQ("", htmlEscape(""));
+ EXPECT_EQ("No Changes", htmlEscape("No Changes"));
+ EXPECT_EQ("No\tChanges+_%^$@~`\n:\\", htmlEscape("No\tChanges+_%^$@~`\n:\\"));
+ EXPECT_EQ(""With Changes"", htmlEscape("\"With Changes\""));
+ EXPECT_EQ(
+ "';!‐"<>equals;&#{}"
+ "()", htmlEscape("';!-\"<>={}()"));
+ EXPECT_EQ("""", htmlEscape("\"\""));
+ EXPECT_EQ(
+ "";<;&apos;>;&;",
+ htmlEscape(""<'>&"));
+}
diff --git a/lib/IRremoteESP8266-2.5.2.03/test/Makefile b/lib/IRremoteESP8266-2.6.0/test/Makefile
similarity index 71%
rename from lib/IRremoteESP8266-2.5.2.03/test/Makefile
rename to lib/IRremoteESP8266-2.6.0/test/Makefile
index d53014183..9a64aaaaa 100644
--- a/lib/IRremoteESP8266-2.5.2.03/test/Makefile
+++ b/lib/IRremoteESP8266-2.6.0/test/Makefile
@@ -16,6 +16,7 @@ GTEST_DIR = ../lib/googletest/googletest
# Where to find user code.
USER_DIR = ../src
+INCLUDES = -I$(USER_DIR) -I.
# Flags passed to the preprocessor.
# Set Google Test's header directory as a system directory, such that
@@ -23,7 +24,7 @@ USER_DIR = ../src
CPPFLAGS += -isystem $(GTEST_DIR)/include -DUNIT_TEST
# Flags passed to the C++ compiler.
-CXXFLAGS += -g -Wall -Wextra -pthread
+CXXFLAGS += -g -Wall -Wextra -pthread -std=gnu++11
# All tests produced by this Makefile. Remember to add new tests you
# created to the list.
@@ -36,7 +37,8 @@ TESTS = IRutils_test IRsend_test ir_NEC_test ir_GlobalCache_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_Whirlpool_test ir_Lutron_test ir_Electra_test ir_Pioneer_test \
- ir_MWM_test
+ ir_MWM_test ir_Vestel_test ir_Teco_test ir_Tcl_test ir_Lego_test IRac_test \
+ ir_MitsubishiHeavy_test
# All Google Test headers. Usually you shouldn't change this
# definition.
@@ -80,7 +82,8 @@ PROTOCOLS = ir_NEC.o ir_Sony.o ir_Samsung.o ir_JVC.o ir_RCMM.o ir_RC5_RC6.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_Pioneer.o ir_MWM.o ir_Vestel.o ir_Teco.o ir_Tcl.o ir_Lego.o ir_Argo.o \
+ ir_Trotec.o ir_MitsubishiHeavy.o
# All the IR Protocol header files.
PROTOCOLS_H = $(USER_DIR)/ir_Argo.h \
@@ -93,19 +96,24 @@ PROTOCOLS_H = $(USER_DIR)/ir_Argo.h \
$(USER_DIR)/ir_Daikin.h \
$(USER_DIR)/ir_Kelvinator.h \
$(USER_DIR)/ir_Mitsubishi.h \
+ $(USER_DIR)/ir_MitsubishiHeavy.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_Panasonic.h \
+ $(USER_DIR)/ir_Whirlpool.h \
+ $(USER_DIR)/ir_Vestel.h \
+ $(USER_DIR)/ir_Tcl.h \
+ $(USER_DIR)/ir_Teco.h
# Common object files
-COMMON_OBJ = IRutils.o IRtimer.o IRsend.o IRrecv.o ir_GlobalCache.o \
+COMMON_OBJ = IRutils.o IRtimer.o IRsend.o IRrecv.o IRac.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 \
- $(PROTOCOLS_H)
+ $(USER_DIR)/IRac.h $(PROTOCOLS_H)
# Common test dependencies
COMMON_TEST_DEPS = $(COMMON_DEPS) IRrecv_test.h IRsend_test.h
@@ -136,7 +144,7 @@ IRutils.o : $(USER_DIR)/IRutils.cpp $(USER_DIR)/IRutils.h $(USER_DIR)/IRremoteES
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/IRutils.cpp
IRutils_test.o : IRutils_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c IRutils_test.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c IRutils_test.cpp
IRutils_test : IRutils_test.o ir_NEC.o ir_Nikai.o ir_Toshiba.o $(COMMON_OBJ) gtest_main.a
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
@@ -148,7 +156,7 @@ IRsend.o : $(USER_DIR)/IRsend.cpp $(USER_DIR)/IRsend.h $(USER_DIR)/IRremoteESP82
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/IRsend.cpp
IRsend_test.o : IRsend_test.cpp $(USER_DIR)/IRsend.h $(USER_DIR)/IRrecv.h IRsend_test.h $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c IRsend_test.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c IRsend_test.cpp
IRsend_test : IRsend_test.o $(COMMON_OBJ)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
@@ -157,16 +165,25 @@ IRrecv.o : $(USER_DIR)/IRrecv.cpp $(USER_DIR)/IRrecv.h $(USER_DIR)/IRremoteESP82
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/IRrecv.cpp
IRrecv_test.o : IRrecv_test.cpp $(USER_DIR)/IRsend.h $(USER_DIR)/IRrecv.h IRsend_test.h $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c IRrecv_test.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c IRrecv_test.cpp
IRrecv_test : IRrecv_test.o $(COMMON_OBJ)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
+IRac.o : $(USER_DIR)/IRac.cpp $(USER_DIR)/IRac.h $(COMMON_DEPS) $(GTEST_HEADERS)
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/IRac.cpp
+
+IRac_test.o : IRac_test.cpp $(USER_DIR)/IRac.h $(COMMON_DEPS) $(GTEST_HEADERS)
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c IRac_test.cpp
+
+IRac_test : IRac_test.o $(COMMON_OBJ)
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
+
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)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_NEC_test.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_NEC_test.cpp
ir_NEC_test : $(COMMON_OBJ) ir_NEC_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
@@ -175,7 +192,7 @@ ir_GlobalCache.o : $(USER_DIR)/ir_GlobalCache.cpp $(COMMON_DEPS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_GlobalCache.cpp
ir_GlobalCache_test.o : ir_GlobalCache_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_GlobalCache_test.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_GlobalCache_test.cpp
ir_GlobalCache_test : $(COMMON_OBJ) ir_GlobalCache_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
@@ -184,7 +201,7 @@ ir_Sherwood.o : $(USER_DIR)/ir_Sherwood.cpp $(COMMON_DEPS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Sherwood.cpp
ir_Sherwood_test.o : ir_Sherwood_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_Sherwood_test.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_Sherwood_test.cpp
ir_Sherwood_test : $(COMMON_OBJ) ir_Sherwood_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
@@ -193,25 +210,25 @@ ir_Sony.o : $(USER_DIR)/ir_Sony.cpp $(COMMON_DEPS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Sony.cpp
ir_Sony_test.o : ir_Sony_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_Sony_test.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_Sony_test.cpp
ir_Sony_test : $(COMMON_OBJ) ir_Sony_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
ir_Samsung.o : $(USER_DIR)/ir_Samsung.cpp $(USER_DIR)/ir_Samsung.h $(COMMON_DEPS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Samsung.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_Samsung.cpp
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
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_Samsung_test.cpp
ir_Samsung_test : $(COMMON_OBJ) ir_Samsung_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
ir_Kelvinator.o : $(USER_DIR)/ir_Kelvinator.cpp $(USER_DIR)/ir_Kelvinator.h $(COMMON_DEPS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Kelvinator.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_Kelvinator.cpp
ir_Kelvinator_test.o : ir_Kelvinator_test.cpp $(USER_DIR)/ir_Kelvinator.h $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_Kelvinator_test.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_Kelvinator_test.cpp
ir_Kelvinator_test : $(COMMON_OBJ) ir_Kelvinator_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
@@ -220,7 +237,7 @@ ir_JVC.o : $(USER_DIR)/ir_JVC.cpp $(COMMON_DEPS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_JVC.cpp
ir_JVC_test.o : ir_JVC_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_JVC_test.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_JVC_test.cpp
ir_JVC_test : $(COMMON_OBJ) ir_JVC_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
@@ -229,7 +246,7 @@ ir_RCMM.o : $(USER_DIR)/ir_RCMM.cpp $(COMMON_DEPS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_RCMM.cpp
ir_RCMM_test.o : ir_RCMM_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_RCMM_test.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_RCMM_test.cpp
ir_RCMM_test : $(COMMON_OBJ) ir_RCMM_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
@@ -238,25 +255,34 @@ ir_LG.o : $(USER_DIR)/ir_LG.h $(USER_DIR)/ir_LG.cpp $(COMMON_DEPS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_LG.cpp
ir_LG_test.o : ir_LG_test.cpp $(USER_DIR)/ir_LG.h $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_LG_test.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_LG_test.cpp
ir_LG_test : $(COMMON_OBJ) ir_LG_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
ir_Mitsubishi.o : $(USER_DIR)/ir_Mitsubishi.h $(USER_DIR)/ir_Mitsubishi.cpp $(COMMON_DEPS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Mitsubishi.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_Mitsubishi.cpp
ir_Mitsubishi_test.o : ir_Mitsubishi_test.cpp $(USER_DIR)/ir_Mitsubishi.h $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_Mitsubishi_test.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_Mitsubishi_test.cpp
ir_Mitsubishi_test : $(COMMON_OBJ) ir_Mitsubishi_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
+ir_MitsubishiHeavy.o : $(USER_DIR)/ir_MitsubishiHeavy.h $(USER_DIR)/ir_MitsubishiHeavy.cpp $(COMMON_DEPS)
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_MitsubishiHeavy.cpp
+
+ir_MitsubishiHeavy_test.o : ir_MitsubishiHeavy_test.cpp $(USER_DIR)/ir_MitsubishiHeavy.h $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_MitsubishiHeavy_test.cpp
+
+ir_MitsubishiHeavy_test : $(COMMON_OBJ) ir_MitsubishiHeavy_test.o
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
+
ir_Fujitsu.o : $(USER_DIR)/ir_Fujitsu.h $(USER_DIR)/ir_Fujitsu.cpp $(COMMON_DEPS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Fujitsu.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_Fujitsu.cpp
ir_Fujitsu_test.o : ir_Fujitsu_test.cpp $(USER_DIR)/ir_Fujitsu.h $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_Fujitsu_test.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_Fujitsu_test.cpp
ir_Fujitsu_test : $(COMMON_OBJ) ir_Fujitsu_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
@@ -265,7 +291,7 @@ ir_Sharp.o : $(USER_DIR)/ir_Sharp.cpp $(COMMON_DEPS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Sharp.cpp
ir_Sharp_test.o : ir_Sharp_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_Sharp_test.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_Sharp_test.cpp
ir_Sharp_test : $(COMMON_OBJ) ir_Sharp_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
@@ -274,16 +300,16 @@ ir_RC5_RC6.o : $(USER_DIR)/ir_RC5_RC6.cpp $(COMMON_DEPS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_RC5_RC6.cpp
ir_RC5_RC6_test.o : ir_RC5_RC6_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_RC5_RC6_test.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_RC5_RC6_test.cpp
ir_RC5_RC6_test : $(COMMON_OBJ) ir_RC5_RC6_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
ir_Panasonic.o : $(USER_DIR)/ir_Panasonic.cpp $(COMMON_DEPS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Panasonic.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_Panasonic.cpp
ir_Panasonic_test.o : ir_Panasonic_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_Panasonic_test.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_Panasonic_test.cpp
ir_Panasonic_test : $(COMMON_OBJ) ir_Panasonic_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
@@ -292,7 +318,7 @@ ir_Dish.o : $(USER_DIR)/ir_Dish.cpp $(COMMON_DEPS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Dish.cpp
ir_Dish_test.o : ir_Dish_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_Dish_test.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_Dish_test.cpp
ir_Dish_test : $(COMMON_OBJ) ir_Dish_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
@@ -301,16 +327,16 @@ ir_Whynter.o : $(USER_DIR)/ir_Whynter.cpp $(COMMON_DEPS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Whynter.cpp
ir_Whynter_test.o : ir_Whynter_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_Whynter_test.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_Whynter_test.cpp
ir_Whynter_test : $(COMMON_OBJ) ir_Whynter_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
ir_Coolix.o : $(USER_DIR)/ir_Coolix.cpp $(COMMON_DEPS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Coolix.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_Coolix.cpp
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
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_Coolix_test.cpp
ir_Coolix_test : $(COMMON_OBJ) ir_Coolix_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
@@ -319,7 +345,7 @@ ir_Aiwa.o : $(USER_DIR)/ir_Aiwa.cpp $(COMMON_DEPS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Aiwa.cpp
ir_Aiwa_test.o : ir_Aiwa_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_Aiwa_test.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_Aiwa_test.cpp
ir_Aiwa_test : $(COMMON_OBJ) ir_Aiwa_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
@@ -328,7 +354,7 @@ ir_Denon.o : $(USER_DIR)/ir_Denon.cpp $(COMMON_DEPS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Denon.cpp
ir_Denon_test.o : ir_Denon_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_Denon_test.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_Denon_test.cpp
ir_Denon_test : $(COMMON_OBJ) ir_Denon_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
@@ -337,25 +363,25 @@ ir_Sanyo.o : $(USER_DIR)/ir_Sanyo.cpp $(COMMON_DEPS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Sanyo.cpp
ir_Sanyo_test.o : ir_Sanyo_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_Sanyo_test.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_Sanyo_test.cpp
ir_Sanyo_test : $(COMMON_OBJ) ir_Sanyo_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
ir_Daikin.o : $(USER_DIR)/ir_Daikin.cpp $(USER_DIR)/ir_Daikin.h $(COMMON_DEPS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Daikin.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_Daikin.cpp
ir_Daikin_test.o : ir_Daikin_test.cpp $(USER_DIR)/ir_Daikin.h $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_Daikin_test.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_Daikin_test.cpp
ir_Daikin_test : $(COMMON_OBJ) ir_Daikin_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
ir_Gree.o : $(USER_DIR)/ir_Gree.cpp $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Gree.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_Gree.cpp
ir_Gree_test.o : ir_Gree_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_Gree_test.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_Gree_test.cpp
ir_Gree_test : $(COMMON_OBJ) ir_Gree_test.o ir_Kelvinator.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
@@ -364,7 +390,7 @@ ir_Pronto.o : $(USER_DIR)/ir_Pronto.cpp $(GTEST_HEADERS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Pronto.cpp
ir_Pronto_test.o : ir_Pronto_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_Pronto_test.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_Pronto_test.cpp
ir_Pronto_test : $(COMMON_OBJ) ir_Pronto_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
@@ -373,25 +399,25 @@ ir_Nikai.o : $(USER_DIR)/ir_Nikai.cpp $(GTEST_HEADERS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Nikai.cpp
ir_Nikai_test.o : ir_Nikai_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_Nikai_test.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_Nikai_test.cpp
ir_Nikai_test : $(COMMON_OBJ) ir_Nikai_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
ir_Toshiba.o : $(USER_DIR)/ir_Toshiba.cpp $(USER_DIR)/ir_Toshiba.h $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Toshiba.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_Toshiba.cpp
ir_Toshiba_test.o : ir_Toshiba_test.cpp $(USER_DIR)/ir_Toshiba.h $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_Toshiba_test.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_Toshiba_test.cpp
ir_Toshiba_test : $(COMMON_OBJ) ir_Toshiba_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
ir_Midea.o : $(USER_DIR)/ir_Midea.cpp $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Midea.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_Midea.cpp
ir_Midea_test.o : ir_Midea_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_Midea_test.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_Midea_test.cpp
ir_Midea_test : $(COMMON_OBJ) ir_Midea_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
@@ -400,7 +426,7 @@ ir_Magiquest.o : $(USER_DIR)/ir_Magiquest.cpp $(GTEST_HEADERS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Magiquest.cpp
ir_Magiquest_test.o : ir_Magiquest_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_Magiquest_test.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_Magiquest_test.cpp
ir_Magiquest_test : $(COMMON_OBJ) ir_Magiquest_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
@@ -409,7 +435,7 @@ ir_Lasertag.o : $(USER_DIR)/ir_Lasertag.cpp $(USER_DIR)/ir_RC5_RC6.cpp $(GTEST_H
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Lasertag.cpp
ir_Lasertag_test.o : ir_Lasertag_test.cpp $(USER_DIR)/ir_RC5_RC6.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_Lasertag_test.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_Lasertag_test.cpp
ir_Lasertag_test : $(COMMON_OBJ) ir_Lasertag_test.o ir_RC5_RC6.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
@@ -418,25 +444,25 @@ ir_Carrier.o : $(USER_DIR)/ir_Carrier.cpp $(COMMON_DEPS) $(GTEST_HEADERS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Carrier.cpp
ir_Carrier_test.o : ir_Carrier_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_Carrier_test.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_Carrier_test.cpp
ir_Carrier_test : $(COMMON_OBJ) ir_Carrier_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
ir_Haier.o : $(USER_DIR)/ir_Haier.cpp $(USER_DIR)/ir_Haier.h $(COMMON_DEPS) $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Haier.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_Haier.cpp
ir_Haier_test.o : ir_Haier_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_Haier_test.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_Haier_test.cpp
ir_Haier_test : $(COMMON_OBJ) ir_Haier_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
ir_Hitachi.o : $(USER_DIR)/ir_Hitachi.cpp $(COMMON_DEPS) $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Hitachi.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_Hitachi.cpp
ir_Hitachi_test.o : ir_Hitachi_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_Hitachi_test.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_Hitachi_test.cpp
ir_Hitachi_test : $(COMMON_OBJ) ir_Hitachi_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
@@ -445,16 +471,16 @@ ir_GICable.o : $(USER_DIR)/ir_GICable.cpp $(COMMON_DEPS) $(GTEST_HEADERS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_GICable.cpp
ir_GICable_test.o : ir_GICable_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_GICable_test.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_GICable_test.cpp
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
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -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
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_Whirlpool_test.cpp
ir_Whirlpool_test : $(COMMON_OBJ) ir_Whirlpool_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
@@ -463,7 +489,7 @@ 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
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_Lutron_test.cpp
ir_Lutron_test : $(COMMON_OBJ) ir_Lutron_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
@@ -472,7 +498,7 @@ 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
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_Electra_test.cpp
ir_Electra_test : $(COMMON_OBJ) ir_Electra_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
@@ -481,7 +507,7 @@ 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
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_Pioneer_test.cpp
ir_Pioneer_test : $(COMMON_OBJ) ir_Pioneer_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
@@ -490,7 +516,49 @@ 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
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -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) $(INCLUDES) -c $(USER_DIR)/ir_Vestel.cpp
+
+ir_Vestel_test.o : ir_Vestel_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_Vestel_test.cpp
+
+ir_Vestel_test : $(COMMON_OBJ) ir_Vestel_test.o
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
+
+ir_Teco.o : $(USER_DIR)/ir_Teco.cpp $(COMMON_DEPS)
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_Teco.cpp
+
+ir_Teco_test.o : ir_Teco_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_Teco_test.cpp
+
+ir_Teco_test : $(COMMON_OBJ) ir_Teco_test.o
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
+
+ir_Tcl.o : $(USER_DIR)/ir_Tcl.cpp $(COMMON_DEPS)
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_Tcl.cpp
+
+ir_Tcl_test.o : ir_Tcl_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_Tcl_test.cpp
+
+ir_Tcl_test : $(COMMON_OBJ) ir_Tcl_test.o
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
+
+ir_Lego.o : $(USER_DIR)/ir_Lego.cpp $(COMMON_DEPS)
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Lego.cpp
+
+ir_Lego_test.o : ir_Lego_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_Lego_test.cpp
+
+ir_Lego_test : $(COMMON_OBJ) ir_Lego_test.o
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
+
+ir_Argo.o : $(USER_DIR)/ir_Argo.cpp $(COMMON_DEPS)
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_Argo.cpp
+
+ir_Trotec.o : $(USER_DIR)/ir_Trotec.cpp $(COMMON_DEPS)
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_Trotec.cpp
diff --git a/lib/IRremoteESP8266-2.5.2.03/test/ir_Aiwa_test.cpp b/lib/IRremoteESP8266-2.6.0/test/ir_Aiwa_test.cpp
similarity index 99%
rename from lib/IRremoteESP8266-2.5.2.03/test/ir_Aiwa_test.cpp
rename to lib/IRremoteESP8266-2.6.0/test/ir_Aiwa_test.cpp
index c5469d4a5..2fa63afe6 100644
--- a/lib/IRremoteESP8266-2.5.2.03/test/ir_Aiwa_test.cpp
+++ b/lib/IRremoteESP8266-2.6.0/test/ir_Aiwa_test.cpp
@@ -14,6 +14,7 @@ TEST(TestSendAiwa, SendDataOnly) {
irsend.reset();
irsend.sendAiwaRCT501(0x7F); // Aiwa Power Toggle.
EXPECT_EQ(
+ "f38000d33"
"m8960s4480"
"m560s560m560s1680m560s1680m560s1680m560s560m560s1680m560s1680m560s560"
"m560s560m560s560m560s560m560s560m560s560m560s1680m560s560m560s560"
@@ -43,6 +44,7 @@ TEST(TestSendAiwa, SendWithRepeats) {
irsend.reset();
irsend.sendAiwaRCT501(0x7F, kAiwaRcT501Bits, 0); // No repeats.
EXPECT_EQ(
+ "f38000d33"
"m8960s4480"
"m560s560m560s1680m560s1680m560s1680m560s560m560s1680m560s1680m560s560"
"m560s560m560s560m560s560m560s560m560s560m560s1680m560s560m560s560"
@@ -54,6 +56,7 @@ TEST(TestSendAiwa, SendWithRepeats) {
irsend.reset();
irsend.sendAiwaRCT501(0x7F, kAiwaRcT501Bits, 1); // 1 repeat.
EXPECT_EQ(
+ "f38000d33"
"m8960s4480"
"m560s560m560s1680m560s1680m560s1680m560s560m560s1680m560s1680m560s560"
"m560s560m560s560m560s560m560s560m560s560m560s1680m560s560m560s560"
@@ -66,6 +69,7 @@ TEST(TestSendAiwa, SendWithRepeats) {
irsend.reset();
irsend.sendAiwaRCT501(0x7F, kAiwaRcT501Bits, 2); // 2 repeats.
EXPECT_EQ(
+ "f38000d33"
"m8960s4480"
"m560s560m560s1680m560s1680m560s1680m560s560m560s1680m560s1680m560s560"
"m560s560m560s560m560s560m560s560m560s560m560s1680m560s560m560s560"
@@ -86,6 +90,7 @@ TEST(TestSendAiwa, SendUnusualSize) {
irsend.reset();
irsend.sendAiwaRCT501(0x12, 8);
EXPECT_EQ(
+ "f38000d33"
"m8960s4480"
"m560s560m560s1680m560s1680m560s1680m560s560m560s1680m560s1680m560s560"
"m560s560m560s560m560s560m560s560m560s560m560s1680m560s560m560s560"
@@ -98,6 +103,7 @@ TEST(TestSendAiwa, SendUnusualSize) {
irsend.reset();
irsend.sendAiwaRCT501(0x1234567890, 37);
EXPECT_EQ(
+ "f38000d33"
"m8960s4480"
"m560s560m560s1680m560s1680m560s1680m560s560m560s1680m560s1680m560s560"
"m560s560m560s560m560s560m560s560m560s560m560s1680m560s560m560s560"
diff --git a/lib/IRremoteESP8266-2.5.2.03/test/ir_Carrier_test.cpp b/lib/IRremoteESP8266-2.6.0/test/ir_Carrier_test.cpp
similarity index 99%
rename from lib/IRremoteESP8266-2.5.2.03/test/ir_Carrier_test.cpp
rename to lib/IRremoteESP8266-2.6.0/test/ir_Carrier_test.cpp
index 24bdc232a..053b31dd4 100644
--- a/lib/IRremoteESP8266-2.5.2.03/test/ir_Carrier_test.cpp
+++ b/lib/IRremoteESP8266-2.6.0/test/ir_Carrier_test.cpp
@@ -15,6 +15,7 @@ TEST(TestSendCarrierAC, SendDataOnly) {
irsend.reset();
irsend.sendCarrierAC(0x0);
EXPECT_EQ(
+ "f38000d50"
"m8532s4228"
"m628s532m628s532m628s532m628s532m628s532m628s532m628s532m628s532"
"m628s532m628s532m628s532m628s532m628s532m628s532m628s532m628s532"
@@ -37,6 +38,7 @@ TEST(TestSendCarrierAC, SendDataOnly) {
irsend.reset();
irsend.sendCarrierAC(0x12345678);
EXPECT_EQ(
+ "f38000d50"
"m8532s4228"
"m628s532m628s532m628s532m628s1320m628s532m628s532m628s1320m628s532"
"m628s532m628s532m628s1320m628s1320m628s532m628s1320m628s532m628s532"
@@ -60,6 +62,7 @@ TEST(TestSendCarrierAC, SendDataOnly) {
irsend.reset();
irsend.sendCarrierAC(0x4CCA541D);
EXPECT_EQ(
+ "f38000d50"
"m8532s4228"
"m628s532m628s1320m628s532m628s532m628s1320m628s1320m628s532m628s532"
"m628s1320m628s1320m628s532m628s532m628s1320m628s532m628s1320m628s532"
@@ -89,6 +92,7 @@ TEST(TestSendCarrierAC, SendWithRepeats) {
irsend.reset();
irsend.sendCarrierAC(0x12345678, kCarrierAcBits, 2); // two repeats.
EXPECT_EQ(
+ "f38000d50"
"m8532s4228"
"m628s532m628s532m628s532m628s1320m628s532m628s532m628s1320m628s532"
"m628s532m628s532m628s1320m628s1320m628s532m628s1320m628s532m628s532"
diff --git a/lib/IRremoteESP8266-2.5.2.03/test/ir_Coolix_test.cpp b/lib/IRremoteESP8266-2.6.0/test/ir_Coolix_test.cpp
similarity index 70%
rename from lib/IRremoteESP8266-2.5.2.03/test/ir_Coolix_test.cpp
rename to lib/IRremoteESP8266-2.6.0/test/ir_Coolix_test.cpp
index 8b096ffca..0f97c5ead 100644
--- a/lib/IRremoteESP8266-2.5.2.03/test/ir_Coolix_test.cpp
+++ b/lib/IRremoteESP8266-2.6.0/test/ir_Coolix_test.cpp
@@ -15,6 +15,15 @@ TEST(TestSendCoolix, SendDataOnly) {
irsend.reset();
irsend.sendCOOLIX(0x0);
EXPECT_EQ(
+ "f38000d50"
+ "m4480s4480"
+ "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
+ "m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680"
+ "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
+ "m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680"
+ "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
+ "m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680"
+ "m560s5040"
"m4480s4480"
"m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
"m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680"
@@ -28,6 +37,15 @@ TEST(TestSendCoolix, SendDataOnly) {
irsend.reset();
irsend.sendCOOLIX(0xAA55AA);
EXPECT_EQ(
+ "f38000d50"
+ "m4480s4480"
+ "m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560"
+ "m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680"
+ "m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680"
+ "m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560"
+ "m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560"
+ "m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680"
+ "m560s5040"
"m4480s4480"
"m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560"
"m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680"
@@ -41,6 +59,15 @@ TEST(TestSendCoolix, SendDataOnly) {
irsend.reset();
irsend.sendCOOLIX(0xFFFFFF);
EXPECT_EQ(
+ "f38000d50"
+ "m4480s4480"
+ "m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680"
+ "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
+ "m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680"
+ "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
+ "m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680"
+ "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
+ "m560s5040"
"m4480s4480"
"m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680"
"m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
@@ -60,6 +87,7 @@ TEST(TestSendCoolix, SendWithRepeats) {
irsend.reset();
irsend.sendCOOLIX(0xAA55AA, kCoolixBits, 1); // 1 repeat.
EXPECT_EQ(
+ "f38000d50"
"m4480s4480"
"m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560"
"m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680"
@@ -79,6 +107,7 @@ TEST(TestSendCoolix, SendWithRepeats) {
irsend.outputStr());
irsend.sendCOOLIX(0xAA55AA, kCoolixBits, 2); // 2 repeats.
EXPECT_EQ(
+ "f38000d50"
"m4480s4480"
"m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560"
"m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680"
@@ -114,6 +143,11 @@ TEST(TestSendCoolix, SendUnusualSize) {
irsend.reset();
irsend.sendCOOLIX(0x0, 8);
EXPECT_EQ(
+ "f38000d50"
+ "m4480s4480"
+ "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
+ "m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680"
+ "m560s5040"
"m4480s4480"
"m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
"m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680"
@@ -123,6 +157,25 @@ TEST(TestSendCoolix, SendUnusualSize) {
irsend.reset();
irsend.sendCOOLIX(0x1234567890ABCDEF, 64);
EXPECT_EQ(
+ "f38000d50"
+ "m4480s4480"
+ "m560s560m560s560m560s560m560s1680m560s560m560s560m560s1680m560s560"
+ "m560s1680m560s1680m560s1680m560s560m560s1680m560s1680m560s560m560s1680"
+ "m560s560m560s560m560s1680m560s1680m560s560m560s1680m560s560m560s560"
+ "m560s1680m560s1680m560s560m560s560m560s1680m560s560m560s1680m560s1680"
+ "m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s1680m560s560"
+ "m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s560m560s1680"
+ "m560s560m560s1680m560s1680m560s1680m560s1680m560s560m560s560m560s560"
+ "m560s1680m560s560m560s560m560s560m560s560m560s1680m560s1680m560s1680"
+ "m560s1680m560s560m560s560m560s1680m560s560m560s560m560s560m560s560"
+ "m560s560m560s1680m560s1680m560s560m560s1680m560s1680m560s1680m560s1680"
+ "m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s1680"
+ "m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s560"
+ "m560s1680m560s1680m560s560m560s560m560s1680m560s1680m560s560m560s1680"
+ "m560s560m560s560m560s1680m560s1680m560s560m560s560m560s1680m560s560"
+ "m560s1680m560s1680m560s1680m560s560m560s1680m560s1680m560s1680m560s1680"
+ "m560s560m560s560m560s560m560s1680m560s560m560s560m560s560m560s560"
+ "m560s5040"
"m4480s4480"
"m560s560m560s560m560s560m560s1680m560s560m560s560m560s1680m560s560"
"m560s1680m560s1680m560s1680m560s560m560s1680m560s1680m560s560m560s1680"
@@ -411,7 +464,7 @@ TEST(TestCoolixACClass, HumanReadable) {
// Initial starting point.
EXPECT_EQ(
- "Power: On, Fan: 5 (AUTO), Mode: 2 (AUTO), Temp: 25C, "
+ "Power: On, Mode: 2 (AUTO), Fan: 5 (AUTO), Temp: 25C, "
"Zone Follow: Off, Sensor Temp: Ignored",
ircoolix.toString());
@@ -420,11 +473,11 @@ TEST(TestCoolixACClass, HumanReadable) {
ircoolix.setMode(kCoolixCool);
ircoolix.setFan(kCoolixFanMin);
EXPECT_EQ(
- "Power: On, Fan: 4 (MIN), Mode: 0 (COOL), Temp: 22C, "
+ "Power: On, Mode: 0 (COOL), Fan: 4 (MIN), Temp: 22C, "
"Zone Follow: On, Sensor Temp: 24C",
ircoolix.toString());
ircoolix.setSwing();
- EXPECT_EQ("Power: On, Fan: 3 (UNKNOWN), Swing: Toggle", ircoolix.toString());
+ EXPECT_EQ("Power: On, Swing: Toggle", ircoolix.toString());
ircoolix.setPower(false);
EXPECT_EQ("Power: Off", ircoolix.toString());
}
@@ -434,12 +487,113 @@ TEST(TestCoolixACClass, KnownExamples) {
ircoolix.setRaw(0b101100101011111111100100);
EXPECT_EQ(
- "Power: On, Fan: 5 (AUTO), Mode: 4 (FAN), Zone Follow: Off, "
+ "Power: On, Mode: 4 (FAN), Fan: 5 (AUTO), Zone Follow: Off, "
"Sensor Temp: Ignored",
ircoolix.toString());
ircoolix.setRaw(0b101100101001111100000000);
EXPECT_EQ(
- "Power: On, Fan: 4 (MIN), Mode: 0 (COOL), Temp: 17C, "
+ "Power: On, Mode: 0 (COOL), Fan: 4 (MIN), Temp: 17C, "
"Zone Follow: Off, Sensor Temp: Ignored",
ircoolix.toString());
}
+
+TEST(TestCoolixACClass, Issue579FanAuto0) {
+ IRCoolixAC ircoolix(0);
+
+ ircoolix.setRaw(0xB21F28);
+ EXPECT_EQ(
+ "Power: On, Mode: 2 (AUTO), Fan: 0 (AUTO0), 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);
+}
+
+
+// Tests to debug/fix:
+// https://github.com/markszabo/IRremoteESP8266/issues/624
+TEST(TestCoolixACClass, Issue624HandleSpecialStatesBetter) {
+ IRCoolixAC ac(0);
+ ac.begin();
+ // Default
+ EXPECT_EQ(
+ "Power: On, Mode: 2 (AUTO), Fan: 5 (AUTO), Temp: 25C, Zone Follow: Off, "
+ "Sensor Temp: Ignored",
+ ac.toString());
+ EXPECT_EQ(0xB2BFC8, ac.getRaw());
+ // Change of settings.
+ ac.setPower(true);
+ ac.setTemp(24);
+ ac.setMode(kCoolixCool);
+ ac.setFan(kCoolixFanAuto);
+ EXPECT_EQ(
+ "Power: On, Mode: 0 (COOL), Fan: 5 (AUTO), Temp: 24C, Zone Follow: Off, "
+ "Sensor Temp: Ignored",
+ ac.toString());
+ EXPECT_EQ(0xB2BF40, ac.getRaw());
+ // Turn the unit off.
+ ac.setPower(false);
+ EXPECT_EQ(
+ "Power: Off",
+ ac.toString());
+ EXPECT_EQ(kCoolixOff, ac.getRaw());
+ // Repeat change of settings.
+ ac.setPower(true);
+ ac.setTemp(24);
+ ac.setMode(kCoolixCool);
+ ac.setFan(kCoolixFanAuto);
+ EXPECT_EQ(
+ "Power: On, Mode: 0 (COOL), Fan: 5 (AUTO), Temp: 24C, Zone Follow: Off, "
+ "Sensor Temp: Ignored",
+ ac.toString());
+ EXPECT_EQ(0xB2BF40, ac.getRaw());
+
+ // Now test if we setRaw() a special state first.
+ ac.setRaw(kCoolixSwing);
+ // Repeat change of settings.
+ ac.setPower(true);
+ ac.setTemp(24);
+ ac.setMode(kCoolixCool);
+ ac.setFan(kCoolixFanAuto);
+ EXPECT_EQ(
+ "Power: On, Mode: 0 (COOL), Fan: 5 (AUTO), Temp: 24C, Zone Follow: Off, "
+ "Sensor Temp: Ignored",
+ ac.toString());
+ EXPECT_EQ(0xB2BF40, ac.getRaw());
+}
diff --git a/lib/IRremoteESP8266-2.6.0/test/ir_Daikin_test.cpp b/lib/IRremoteESP8266-2.6.0/test/ir_Daikin_test.cpp
new file mode 100644
index 000000000..67d144d54
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/test/ir_Daikin_test.cpp
@@ -0,0 +1,1880 @@
+// Copyright 2017 David Conran
+#include "ir_Daikin.h"
+#include "IRrecv.h"
+#include "IRrecv_test.h"
+#include "IRsend.h"
+#include "IRsend_test.h"
+#include "gtest/gtest.h"
+
+// Tests for sendDaikin().
+
+// Test sending typical data only.
+TEST(TestSendDaikin, SendDataOnly) {
+ IRsendTest irsend(0);
+ irsend.begin();
+
+ uint8_t daikin_code[kDaikinStateLength] = {
+ 0x11, 0xDA, 0x27, 0x00, 0xC5, 0x00, 0x00, 0xD7,
+ 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);
+ EXPECT_EQ(
+ "f38000d50"
+ "m428s428m428s428m428s428m428s428m428s428"
+ "m428s29428"
+ "m3650s1623"
+ "m428s1280m428s428m428s428m428s428m428s1280m428s428m428s428m428s428"
+ "m428s428m428s1280m428s428m428s1280m428s1280m428s428m428s1280m428s1280"
+ "m428s1280m428s1280m428s1280m428s428m428s428m428s1280m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s1280m428s428m428s1280m428s428m428s428m428s428m428s1280m428s1280"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s1280m428s1280m428s1280m428s428m428s1280m428s428m428s1280m428s1280"
+ "m428s29428"
+ "m3650s1623"
+ "m428s1280m428s428m428s428m428s428m428s1280m428s428m428s428m428s428"
+ "m428s428m428s1280m428s428m428s1280m428s1280m428s428m428s1280m428s1280"
+ "m428s1280m428s1280m428s1280m428s428m428s428m428s1280m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s1280m428s1280m428s1280m428s1280"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s1280m428s428m428s428"
+ "m428s29428"
+ "m3650s1623"
+ "m428s1280m428s428m428s428m428s428m428s1280m428s428m428s428m428s428"
+ "m428s428m428s1280m428s428m428s1280m428s1280m428s428m428s1280m428s1280"
+ "m428s1280m428s1280m428s1280m428s428m428s428m428s1280m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s1280m428s428m428s428m428s428m428s428m428s428m428s1280m428s428"
+ "m428s428m428s1280m428s1280m428s1280m428s1280m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s1280m428s1280m428s428m428s1280"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s1280m428s1280"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s1280m428s1280m428s428m428s428m428s428m428s1280m428s1280m428s1280"
+ "m428s29428",
+ irsend.outputStr());
+}
+
+// Test sending with repeats.
+TEST(TestSendDaikin, SendWithRepeats) {
+ IRsendTest irsend(0);
+ irsend.begin();
+
+ irsend.reset();
+ uint8_t daikin_code[kDaikinStateLengthShort] = {
+ 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, kDaikinStateLengthShort, 1);
+ EXPECT_EQ(
+ "f38000d50"
+ "m428s428m428s428m428s428m428s428m428s428"
+ "m428s29428m3650s1623"
+ "m428s1280m428s428m428s428m428s428m428s1280m428s428m428s428m428s428"
+ "m428s428m428s1280m428s428m428s1280m428s1280m428s428m428s1280m428s1280"
+ "m428s1280m428s1280m428s1280m428s428m428s428m428s1280m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s1280m428s428m428s1280m428s428m428s428m428s428m428s1280m428s1280"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s1280m428s1280m428s1280m428s428m428s1280m428s428m428s1280m428s1280"
+ "m428s29428m3650s1623"
+ "m428s1280m428s428m428s428m428s428m428s1280m428s428m428s428m428s428"
+ "m428s428m428s1280m428s428m428s1280m428s1280m428s428m428s1280m428s1280"
+ "m428s1280m428s1280m428s1280m428s428m428s428m428s1280m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s1280m428s1280m428s1280m428s1280"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s1280m428s428m428s428"
+ "m428s29428m3650s1623"
+ "m428s1280m428s428m428s428m428s428m428s1280m428s428m428s428m428s428"
+ "m428s428m428s1280m428s428m428s1280m428s1280m428s428m428s1280m428s1280"
+ "m428s1280m428s1280m428s1280m428s428m428s428m428s1280m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s1280m428s428m428s428m428s428m428s428m428s428m428s1280m428s428"
+ "m428s428m428s1280m428s1280m428s1280m428s1280m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s1280m428s1280m428s428m428s1280"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s1280m428s1280"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s1280m428s1280m428s428m428s428m428s428m428s1280m428s1280m428s1280"
+ "m428s29428"
+ "m428s428m428s428m428s428m428s428m428s428"
+ "m428s29428m3650s1623"
+ "m428s1280m428s428m428s428m428s428m428s1280m428s428m428s428m428s428"
+ "m428s428m428s1280m428s428m428s1280m428s1280m428s428m428s1280m428s1280"
+ "m428s1280m428s1280m428s1280m428s428m428s428m428s1280m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s1280m428s428m428s1280m428s428m428s428m428s428m428s1280m428s1280"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s1280m428s1280m428s1280m428s428m428s1280m428s428m428s1280m428s1280"
+ "m428s29428m3650s1623"
+ "m428s1280m428s428m428s428m428s428m428s1280m428s428m428s428m428s428"
+ "m428s428m428s1280m428s428m428s1280m428s1280m428s428m428s1280m428s1280"
+ "m428s1280m428s1280m428s1280m428s428m428s428m428s1280m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s1280m428s1280m428s1280m428s1280"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s1280m428s428m428s428"
+ "m428s29428m3650s1623"
+ "m428s1280m428s428m428s428m428s428m428s1280m428s428m428s428m428s428"
+ "m428s428m428s1280m428s428m428s1280m428s1280m428s428m428s1280m428s1280"
+ "m428s1280m428s1280m428s1280m428s428m428s428m428s1280m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s1280m428s428m428s428m428s428m428s428m428s428m428s1280m428s428"
+ "m428s428m428s1280m428s1280m428s1280m428s1280m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s1280m428s1280m428s428m428s1280"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s1280m428s1280"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s1280m428s1280m428s428m428s428m428s428m428s1280m428s1280m428s1280"
+ "m428s29428",
+ irsend.outputStr());
+}
+
+// Test sending atypical sizes.
+TEST(TestSendDaikin, SendUnexpectedSizes) {
+ IRsendTest irsend(4);
+ irsend.begin();
+
+ uint8_t daikin_short_code[kDaikinStateLengthShort - 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, kDaikinStateLengthShort - 1);
+ ASSERT_EQ("", irsend.outputStr());
+
+ uint8_t daikin_long_code[kDaikinStateLengthShort + 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, kDaikinStateLengthShort + 1);
+ ASSERT_EQ(
+ "f38000d50"
+ "m428s428m428s428m428s428m428s428m428s428"
+ "m428s29428m3650s1623"
+ "m428s1280m428s428m428s428m428s428m428s1280m428s428m428s428m428s428"
+ "m428s428m428s1280m428s428m428s1280m428s1280m428s428m428s1280m428s1280"
+ "m428s1280m428s1280m428s1280m428s428m428s428m428s1280m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s1280m428s428m428s1280m428s428m428s428m428s428m428s1280m428s1280"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s1280m428s1280m428s1280m428s428m428s1280m428s428m428s1280m428s1280"
+ "m428s29428m3650s1623"
+ "m428s1280m428s428m428s428m428s428m428s1280m428s428m428s428m428s428"
+ "m428s428m428s1280m428s428m428s1280m428s1280m428s428m428s1280m428s1280"
+ "m428s1280m428s1280m428s1280m428s428m428s428m428s1280m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s1280m428s1280m428s1280m428s1280"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s1280m428s428m428s428"
+ "m428s29428m3650s1623"
+ "m428s1280m428s428m428s428m428s428m428s1280m428s428m428s428m428s428"
+ "m428s428m428s1280m428s428m428s1280m428s1280m428s428m428s1280m428s1280"
+ "m428s1280m428s1280m428s1280m428s428m428s428m428s1280m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s1280m428s428m428s428m428s428m428s428m428s428m428s1280m428s428"
+ "m428s428m428s1280m428s1280m428s1280m428s1280m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s1280m428s1280m428s428m428s1280"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s1280m428s1280"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s1280m428s1280m428s428m428s428m428s428m428s1280m428s1280m428s1280"
+ "m428s1280m428s428m428s428m428s428m428s1280m428s428m428s428m428s428"
+ "m428s29428",
+ irsend.outputStr());
+}
+
+// Tests for IRDaikinESP class.
+
+TEST(TestDaikinClass, Power) {
+ IRDaikinESP ac(0);
+ ac.begin();
+
+ 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(TestDaikinClass, Temperature) {
+ IRDaikinESP ac(0);
+ ac.begin();
+
+ ac.setTemp(0);
+ EXPECT_EQ(kDaikinMinTemp, ac.getTemp());
+
+ ac.setTemp(255);
+ EXPECT_EQ(kDaikinMaxTemp, ac.getTemp());
+
+ ac.setTemp(kDaikinMinTemp);
+ EXPECT_EQ(kDaikinMinTemp, ac.getTemp());
+
+ ac.setTemp(kDaikinMaxTemp);
+ EXPECT_EQ(kDaikinMaxTemp, ac.getTemp());
+
+ ac.setTemp(kDaikinMinTemp - 1);
+ EXPECT_EQ(kDaikinMinTemp, ac.getTemp());
+
+ ac.setTemp(kDaikinMaxTemp + 1);
+ EXPECT_EQ(kDaikinMaxTemp, ac.getTemp());
+
+ ac.setTemp(kDaikinMinTemp + 1);
+ EXPECT_EQ(kDaikinMinTemp + 1, ac.getTemp());
+
+ ac.setTemp(21);
+ EXPECT_EQ(21, ac.getTemp());
+
+ ac.setTemp(25);
+ EXPECT_EQ(25, ac.getTemp());
+
+ ac.setTemp(29);
+ EXPECT_EQ(29, ac.getTemp());
+}
+
+TEST(TestDaikinClass, OperatingMode) {
+ IRDaikinESP ac(0);
+ ac.begin();
+
+ ac.setMode(kDaikinAuto);
+ EXPECT_EQ(kDaikinAuto, ac.getMode());
+
+ ac.setMode(kDaikinCool);
+ EXPECT_EQ(kDaikinCool, ac.getMode());
+
+ ac.setMode(kDaikinHeat);
+ EXPECT_EQ(kDaikinHeat, ac.getMode());
+
+ ac.setMode(kDaikinDry);
+ EXPECT_EQ(kDaikinDry, ac.getMode());
+
+ ac.setMode(kDaikinFan);
+ EXPECT_EQ(kDaikinFan, ac.getMode());
+
+ ac.setMode(kDaikinFan + 1);
+ EXPECT_EQ(kDaikinAuto, ac.getMode());
+
+ ac.setMode(kDaikinAuto + 1);
+ EXPECT_EQ(kDaikinAuto, ac.getMode());
+
+ ac.setMode(255);
+ EXPECT_EQ(kDaikinAuto, ac.getMode());
+}
+
+TEST(TestDaikinClass, VaneSwing) {
+ IRDaikinESP ac(0);
+ ac.begin();
+
+ ac.setSwingHorizontal(true);
+ ac.setSwingVertical(false);
+
+ ac.setSwingHorizontal(true);
+ EXPECT_TRUE(ac.getSwingHorizontal());
+ EXPECT_FALSE(ac.getSwingVertical());
+
+ ac.setSwingVertical(true);
+ EXPECT_TRUE(ac.getSwingHorizontal());
+ EXPECT_TRUE(ac.getSwingVertical());
+
+ ac.setSwingHorizontal(false);
+ EXPECT_FALSE(ac.getSwingHorizontal());
+ EXPECT_TRUE(ac.getSwingVertical());
+
+ ac.setSwingVertical(false);
+ EXPECT_FALSE(ac.getSwingHorizontal());
+ EXPECT_FALSE(ac.getSwingVertical());
+}
+
+TEST(TestDaikinClass, QuietMode) {
+ IRDaikinESP 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());
+
+ // Setting Econo mode should NOT change out of quiet mode.
+ ac.setEcono(true);
+ EXPECT_TRUE(ac.getQuiet());
+ ac.setEcono(false);
+ EXPECT_TRUE(ac.getQuiet());
+
+ // But setting Powerful mode should exit out of quiet mode.
+ ac.setPowerful(true);
+ EXPECT_FALSE(ac.getQuiet());
+}
+
+TEST(TestDaikinClass, PowerfulMode) {
+ IRDaikinESP 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());
+
+ ac.setPowerful(true);
+ ac.setEcono(true);
+ EXPECT_FALSE(ac.getPowerful());
+}
+
+TEST(TestDaikinClass, EconoMode) {
+ IRDaikinESP ac(0);
+ ac.begin();
+
+ ac.setEcono(true);
+ EXPECT_TRUE(ac.getEcono());
+
+ ac.setEcono(false);
+ EXPECT_FALSE(ac.getEcono());
+
+ ac.setEcono(true);
+ EXPECT_TRUE(ac.getEcono());
+
+ // Setting Quiet mode should NOT change out of Econo mode.
+ ac.setQuiet(true);
+ EXPECT_TRUE(ac.getEcono());
+ ac.setQuiet(false);
+ EXPECT_TRUE(ac.getEcono());
+
+ // But setting Powerful mode should exit out of Econo mode.
+ ac.setPowerful(true);
+ EXPECT_FALSE(ac.getEcono());
+}
+
+TEST(TestDaikinClass, FanSpeed) {
+ IRDaikinESP 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(TestDaikinClass, CurrentTime) {
+ IRDaikinESP 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(TestDaikinClass, OnOffTimers) {
+ IRDaikinESP 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());
+
+ // Use some canary values around the timers to ensure no accidental
+ // bit flips happen. i.e. Neighbouring bytes in the state.
+ // (Found some during testing on systems with different endian-ness)
+ // Tests here to make sure it never happens again.
+ ac.setSwingHorizontal(true);
+ ac.setPowerful(true);
+ ac.disableOffTimer();
+ ac.disableOnTimer();
+ ASSERT_TRUE(ac.getSwingHorizontal());
+ ASSERT_TRUE(ac.getPowerful());
+ ac.enableOnTimer(123);
+ ac.enableOffTimer(456);
+ ASSERT_TRUE(ac.getSwingHorizontal());
+ ASSERT_TRUE(ac.getPowerful());
+ ac.disableOffTimer();
+ ac.disableOnTimer();
+ ASSERT_TRUE(ac.getSwingHorizontal());
+ ASSERT_TRUE(ac.getPowerful());
+
+ ac.setSwingHorizontal(false);
+ ac.setPowerful(false);
+ ac.disableOffTimer();
+ ac.disableOnTimer();
+ ASSERT_FALSE(ac.getSwingHorizontal());
+ ASSERT_FALSE(ac.getPowerful());
+ ac.enableOnTimer(123);
+ ac.enableOffTimer(456);
+ ASSERT_FALSE(ac.getSwingHorizontal());
+ ASSERT_FALSE(ac.getPowerful());
+ ac.disableOffTimer();
+ ac.disableOnTimer();
+ ASSERT_FALSE(ac.getSwingHorizontal());
+ ASSERT_FALSE(ac.getPowerful());
+}
+
+// Test Eye mode.
+TEST(TestDaikinClass, EyeSetting) {
+ IRDaikinESP ac(0);
+ ac.begin();
+
+ // The Eye setting is stored in the same byte as Econo mode.
+ // Econo mode tests are there to make sure it isn't harmed and vice-versa.
+ ac.setEcono(false);
+ ac.setEye(false);
+ ASSERT_FALSE(ac.getEye());
+ EXPECT_FALSE(ac.getEcono());
+
+ ac.setEye(true);
+ ASSERT_TRUE(ac.getEye());
+ EXPECT_FALSE(ac.getEcono());
+
+ ac.setEcono(false);
+ ASSERT_TRUE(ac.getEye());
+ EXPECT_FALSE(ac.getEcono());
+
+ ac.setEcono(true);
+ ASSERT_TRUE(ac.getEye());
+ EXPECT_TRUE(ac.getEcono());
+
+ ac.setEye(false);
+ ASSERT_FALSE(ac.getEye());
+ EXPECT_TRUE(ac.getEcono());
+}
+
+// Test Mold mode.
+TEST(TestDaikinClass, MoldSetting) {
+ IRDaikinESP 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 Comfort mode.
+TEST(TestDaikinClass, ComfortSetting) {
+ IRDaikinESP ac(0);
+ ac.begin();
+
+ ac.setComfort(false);
+ ASSERT_FALSE(ac.getComfort());
+
+ ac.setComfort(true);
+ ASSERT_TRUE(ac.getComfort());
+
+ ac.setComfort(false);
+ ASSERT_FALSE(ac.getComfort());
+}
+
+// Test Sensor mode.
+TEST(TestDaikinClass, SensorSetting) {
+ IRDaikinESP ac(0);
+ ac.begin();
+
+ ac.setSensor(false);
+ ASSERT_FALSE(ac.getSensor());
+
+ ac.setSensor(true);
+ ASSERT_TRUE(ac.getSensor());
+
+ ac.setSensor(false);
+ ASSERT_FALSE(ac.getSensor());
+}
+
+TEST(TestDaikinClass, RenderTime) {
+ EXPECT_EQ("0:00", IRDaikinESP::renderTime(0));
+ EXPECT_EQ("0:10", IRDaikinESP::renderTime(10));
+ EXPECT_EQ("1:00", IRDaikinESP::renderTime(1 * 60 + 0));
+ EXPECT_EQ("23:59", IRDaikinESP::renderTime(23 * 60 + 59));
+}
+
+TEST(TestDaikinClass, SetAndGetRaw) {
+ IRDaikinESP ac(0);
+ uint8_t shortState[kDaikinStateLengthShort] = {
+ 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 longState[kDaikinStateLength] = {
+ 0x11, 0xDA, 0x27, 0x00, 0xC5, 0x00, 0x00, 0xD7,
+ 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, 0xC5, 0x00, 0x00, 0xD7,
+ 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, 0x5C};
+
+ EXPECT_STATE_EQ(longState, ac.getRaw(), kDaikinBits);
+ // toggle the power state.
+ ac.setPower(!ac.getPower());
+ ac.setTemp(21);
+ ac.setMold(true);
+ EXPECT_STATE_EQ(expectedState, ac.getRaw(), kDaikinBits);
+ ac.setRaw(longState);
+ EXPECT_STATE_EQ(longState, ac.getRaw(), kDaikinBits);
+ ac.setRaw(shortState, kDaikinStateLengthShort);
+ EXPECT_STATE_EQ(longState, ac.getRaw(), kDaikinBits);
+}
+
+TEST(TestDaikinClass, ChecksumValidation) {
+ uint8_t daikin_code[kDaikinStateLength] = {
+ 0x11, 0xDA, 0x27, 0x00, 0xC5, 0x00, 0x00, 0xD7,
+ 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.
+ daikin_code[0] ^= 0xFF;
+ EXPECT_FALSE(IRDaikinESP::validChecksum(daikin_code));
+ // Restore the previous change, and change another byte.
+ daikin_code[0] ^= 0xFF;
+ daikin_code[4] ^= 0xFF;
+ EXPECT_FALSE(IRDaikinESP::validChecksum(daikin_code));
+ daikin_code[4] ^= 0xFF;
+ // Change something in the 2nd block.
+ daikin_code[10] ^= 0xFF;
+ EXPECT_FALSE(IRDaikinESP::validChecksum(daikin_code));
+ daikin_code[10] ^= 0xFF;
+ EXPECT_TRUE(IRDaikinESP::validChecksum(daikin_code));
+ // Change something in the 3rd block.
+ daikin_code[20] ^= 0xFF;
+ EXPECT_FALSE(IRDaikinESP::validChecksum(daikin_code));
+ daikin_code[20] ^= 0xFF;
+ EXPECT_TRUE(IRDaikinESP::validChecksum(daikin_code));
+}
+
+// Test human readable output.
+TEST(TestDaikinClass, HumanReadable) {
+ IRDaikinESP ac(0);
+
+ EXPECT_EQ(
+ "Power: On, Mode: 4 (HEAT), Temp: 15C, Fan: 11 (QUIET), "
+ "Powerful: Off, Quiet: Off, Sensor: Off, Eye: Off, Mold: Off, "
+ "Comfort: Off, Swing (Horizontal): Off, Swing (Vertical): Off, "
+ "Current Time: 0:00, On Time: Off, Off Time: Off",
+ ac.toString());
+ ac.setMode(kDaikinAuto);
+ ac.setTemp(25);
+ ac.setFan(kDaikinFanAuto);
+ ac.setQuiet(true);
+ ac.setSensor(true);
+ ac.setEye(true);
+ ac.setMold(true);
+ ac.setSwingVertical(true);
+ ac.setSwingHorizontal(true);
+ ac.setCurrentTime(9 * 60 + 15);
+ ac.enableOnTimer(8 * 60 + 0);
+ ac.enableOffTimer(17 * 60 + 30);
+ ac.setComfort(true);
+ ac.off();
+ EXPECT_EQ(
+ "Power: Off, Mode: 0 (AUTO), Temp: 25C, Fan: 10 (AUTO), "
+ "Powerful: Off, Quiet: On, Sensor: On, Eye: On, Mold: On, Comfort: On, "
+ "Swing (Horizontal): On, Swing (Vertical): On, "
+ "Current Time: 9:15, On Time: 8:00, Off Time: 17:30",
+ ac.toString());
+}
+
+// Test general message construction after tweaking some settings.
+TEST(TestDaikinClass, MessageConstuction) {
+ IRDaikinESP ac(0);
+ IRsendTest irsend(4);
+ ac.begin();
+ irsend.begin();
+
+ ac.setFan(kDaikinFanMin);
+ ac.setMode(kDaikinCool);
+ ac.setTemp(27);
+ ac.setSwingVertical(false);
+ ac.setSwingHorizontal(true);
+ ac.setQuiet(false);
+ ac.setPower(true);
+
+ // Check everything for kicks.
+ EXPECT_EQ(kDaikinFanMin, ac.getFan());
+ EXPECT_EQ(kDaikinCool, ac.getMode());
+ EXPECT_EQ(27, ac.getTemp());
+ EXPECT_FALSE(ac.getSwingVertical());
+ EXPECT_TRUE(ac.getSwingHorizontal());
+ EXPECT_FALSE(ac.getQuiet());
+ EXPECT_TRUE(ac.getPower());
+
+ irsend.reset();
+ irsend.sendDaikin(ac.getRaw());
+ EXPECT_EQ(
+ "f38000d50"
+ "m428s428m428s428m428s428m428s428m428s428"
+ "m428s29428m3650s1623"
+ "m428s1280m428s428m428s428m428s428m428s1280m428s428m428s428m428s428"
+ "m428s428m428s1280m428s428m428s1280m428s1280m428s428m428s1280m428s1280"
+ "m428s1280m428s1280m428s1280m428s428m428s428m428s1280m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s1280m428s428m428s1280m428s428m428s428m428s428m428s1280m428s1280"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s1280m428s1280m428s1280m428s428m428s1280m428s428m428s1280m428s1280"
+ "m428s29428m3650s1623"
+ "m428s1280m428s428m428s428m428s428m428s1280m428s428m428s428m428s428"
+ "m428s428m428s1280m428s428m428s1280m428s1280m428s428m428s1280m428s1280"
+ "m428s1280m428s1280m428s1280m428s428m428s428m428s1280m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s1280m428s428m428s428m428s428m428s428m428s1280m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s1280m428s428m428s1280m428s428m428s1280m428s428"
+ "m428s29428m3650s1623"
+ "m428s1280m428s428m428s428m428s428m428s1280m428s428m428s428m428s428"
+ "m428s428m428s1280m428s428m428s1280m428s1280m428s428m428s1280m428s1280"
+ "m428s1280m428s1280m428s1280m428s428m428s428m428s1280m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s1280m428s428m428s428m428s1280m428s1280m428s1280m428s428m428s428"
+ "m428s428m428s1280m428s1280m428s428m428s1280m428s1280m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s1280m428s1280m428s428m428s428"
+ "m428s1280m428s1280m428s1280m428s1280m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s1280m428s1280m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s1280m428s1280m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s1280m428s1280"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s1280m428s1280m428s428m428s428m428s1280m428s1280m428s1280"
+ "m428s29428",
+ irsend.outputStr());
+}
+
+// Tests for decodeDaikin().
+
+// Test decoding a message captured from a real IR remote.
+TEST(TestDecodeDaikin, RealExample) {
+ IRDaikinESP ac(0);
+ IRsendTest irsend(0);
+ IRrecv irrecv(0);
+ irsend.begin();
+
+ uint8_t expectedState[kDaikinStateLength] = {
+ 0x11, 0xDA, 0x27, 0x00, 0xC5, 0x00, 0x00, 0xD7,
+ 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[583] = {
+ 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, 583, 38000);
+ irsend.makeDecodeResult();
+ EXPECT_TRUE(irrecv.decode(&irsend.capture));
+ ASSERT_EQ(DAIKIN, irsend.capture.decode_type);
+ ASSERT_EQ(kDaikinBits, irsend.capture.bits);
+ EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits);
+ ac.setRaw(irsend.capture.state);
+ EXPECT_EQ(
+ "Power: On, Mode: 3 (COOL), Temp: 29C, Fan: 10 (AUTO), Powerful: On, "
+ "Quiet: Off, Sensor: Off, Eye: Off, Mold: Off, Comfort: Off, "
+ "Swing (Horizontal): Off, Swing (Vertical): Off, "
+ "Current Time: 22:18, On Time: 21:30, Off Time: 6:10", ac.toString());
+}
+
+// Decoding a message we entirely constructed based solely on a given state.
+TEST(TestDecodeDaikin, ShortSyntheticExample) {
+ IRDaikinESP ac(0);
+ IRsendTest irsend(0);
+ IRrecv irrecv(0);
+ irsend.begin();
+
+ uint8_t shortState[kDaikinStateLengthShort] = {
+ 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 longState[kDaikinStateLength] = {
+ 0x11, 0xDA, 0x27, 0x00, 0xC5, 0x00, 0x00, 0xD7,
+ 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(shortState, kDaikinStateLengthShort);
+ irsend.makeDecodeResult();
+ EXPECT_TRUE(irrecv.decode(&irsend.capture));
+ ASSERT_EQ(DAIKIN, irsend.capture.decode_type);
+ ASSERT_EQ(kDaikinBits, irsend.capture.bits);
+ EXPECT_STATE_EQ(longState, irsend.capture.state, irsend.capture.bits);
+ ac.setRaw(irsend.capture.state);
+ EXPECT_EQ(
+ "Power: On, Mode: 3 (COOL), Temp: 29C, Fan: 10 (AUTO), Powerful: On, "
+ "Quiet: Off, Sensor: Off, Eye: Off, Mold: Off, Comfort: Off, "
+ "Swing (Horizontal): Off, Swing (Vertical): Off, "
+ "Current Time: 22:18, On Time: 21:30, Off Time: 6:10", ac.toString());
+}
+
+// Decoding a message we entirely constructed based solely on a given state.
+TEST(TestDecodeDaikin, LongSyntheticExample) {
+ IRDaikinESP ac(0);
+ IRsendTest irsend(0);
+ IRrecv irrecv(0);
+ irsend.begin();
+
+ uint8_t expectedState[kDaikinStateLength] = {
+ 0x11, 0xDA, 0x27, 0x00, 0xC5, 0x00, 0x00, 0xD7,
+ 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.decodeDaikin(&irsend.capture));
+ ASSERT_EQ(DAIKIN, irsend.capture.decode_type);
+ ASSERT_EQ(kDaikinBits, irsend.capture.bits);
+ EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits);
+ ac.setRaw(irsend.capture.state);
+ EXPECT_EQ(
+ "Power: On, Mode: 3 (COOL), Temp: 29C, Fan: 10 (AUTO), Powerful: On, "
+ "Quiet: Off, Sensor: Off, Eye: Off, Mold: Off, Comfort: Off, "
+ "Swing (Horizontal): Off, Swing (Vertical): Off, "
+ "Current Time: 22:18, On Time: 21:30, Off Time: 6:10", ac.toString());
+}
+
+// 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(TestDaikin2Class, Temperature) {
+ IRDaikin2 ac(0);
+ ac.begin();
+
+ ac.setMode(kDaikinAuto);
+ ac.setTemp(0);
+ EXPECT_EQ(kDaikinMinTemp, ac.getTemp());
+
+ ac.setTemp(255);
+ EXPECT_EQ(kDaikinMaxTemp, ac.getTemp());
+
+ ac.setTemp(kDaikinMinTemp);
+ EXPECT_EQ(kDaikinMinTemp, ac.getTemp());
+
+ ac.setTemp(kDaikinMaxTemp);
+ EXPECT_EQ(kDaikinMaxTemp, ac.getTemp());
+
+ ac.setTemp(kDaikinMinTemp - 1);
+ EXPECT_EQ(kDaikinMinTemp, ac.getTemp());
+
+ ac.setTemp(kDaikinMaxTemp + 1);
+ EXPECT_EQ(kDaikinMaxTemp, ac.getTemp());
+
+ ac.setTemp(kDaikinMinTemp + 1);
+ EXPECT_EQ(kDaikinMinTemp + 1, ac.getTemp());
+
+ // Now try it with Cool mode, which should set the temp to kDaikin2MinCoolTemp
+ ASSERT_TRUE(kDaikinMinTemp + 1 < kDaikin2MinCoolTemp);
+ ac.setMode(kDaikinCool);
+ EXPECT_EQ(kDaikin2MinCoolTemp, ac.getTemp());
+ ac.setTemp(kDaikin2MinCoolTemp - 1);
+ EXPECT_EQ(kDaikin2MinCoolTemp, ac.getTemp());
+ ac.setTemp(kDaikin2MinCoolTemp + 1);
+ EXPECT_EQ(kDaikin2MinCoolTemp + 1, ac.getTemp());
+ // Should be released from that requirement in other modes.
+ ac.setMode(kDaikinAuto);
+ ac.setTemp(kDaikin2MinCoolTemp - 1);
+ EXPECT_EQ(kDaikin2MinCoolTemp - 1, ac.getTemp());
+
+ ac.setTemp(21);
+ EXPECT_EQ(21, ac.getTemp());
+
+ ac.setTemp(25);
+ EXPECT_EQ(25, ac.getTemp());
+
+ ac.setTemp(29);
+ EXPECT_EQ(29, ac.getTemp());
+}
+
+// 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, Housekeeping) {
+ ASSERT_EQ("DAIKIN", typeToString(decode_type_t::DAIKIN));
+ ASSERT_EQ(decode_type_t::DAIKIN, strToDecodeType("DAIKIN"));
+ ASSERT_TRUE(hasACState(decode_type_t::DAIKIN));
+
+ ASSERT_EQ("DAIKIN2", typeToString(decode_type_t::DAIKIN2));
+ ASSERT_EQ(decode_type_t::DAIKIN2, strToDecodeType("DAIKIN2"));
+ ASSERT_TRUE(hasACState(decode_type_t::DAIKIN2));
+
+ ASSERT_EQ("DAIKIN216", typeToString(decode_type_t::DAIKIN216));
+ ASSERT_EQ(decode_type_t::DAIKIN216, strToDecodeType("DAIKIN216"));
+ ASSERT_TRUE(hasACState(decode_type_t::DAIKIN216));
+}
+
+// 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());
+}
+
+// Tests for IRDaikin216 class.
+
+TEST(TestDaikin216Class, Power) {
+ IRDaikin216 ac(0);
+ ac.begin();
+
+ 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(TestDaikin216Class, Temperature) {
+ IRDaikin216 ac(0);
+ ac.begin();
+
+ ac.setTemp(0);
+ EXPECT_EQ(kDaikinMinTemp, ac.getTemp());
+
+ ac.setTemp(255);
+ EXPECT_EQ(kDaikinMaxTemp, ac.getTemp());
+
+ ac.setTemp(kDaikinMinTemp);
+ EXPECT_EQ(kDaikinMinTemp, ac.getTemp());
+
+ ac.setTemp(kDaikinMaxTemp);
+ EXPECT_EQ(kDaikinMaxTemp, ac.getTemp());
+
+ ac.setTemp(kDaikinMinTemp - 1);
+ EXPECT_EQ(kDaikinMinTemp, ac.getTemp());
+
+ ac.setTemp(kDaikinMaxTemp + 1);
+ EXPECT_EQ(kDaikinMaxTemp, ac.getTemp());
+
+ ac.setTemp(kDaikinMinTemp + 1);
+ EXPECT_EQ(kDaikinMinTemp + 1, ac.getTemp());
+
+ ac.setTemp(21);
+ EXPECT_EQ(21, ac.getTemp());
+
+ ac.setTemp(25);
+ EXPECT_EQ(25, ac.getTemp());
+
+ ac.setTemp(29);
+ EXPECT_EQ(29, ac.getTemp());
+}
+
+TEST(TestDaikin216Class, OperatingMode) {
+ IRDaikin216 ac(0);
+ ac.begin();
+
+ ac.setMode(kDaikinAuto);
+ EXPECT_EQ(kDaikinAuto, ac.getMode());
+
+ ac.setMode(kDaikinCool);
+ EXPECT_EQ(kDaikinCool, ac.getMode());
+
+ ac.setMode(kDaikinHeat);
+ EXPECT_EQ(kDaikinHeat, ac.getMode());
+
+ ac.setMode(kDaikinDry);
+ EXPECT_EQ(kDaikinDry, ac.getMode());
+
+ ac.setMode(kDaikinFan);
+ EXPECT_EQ(kDaikinFan, ac.getMode());
+
+ ac.setMode(kDaikinFan + 1);
+ EXPECT_EQ(kDaikinAuto, ac.getMode());
+
+ ac.setMode(kDaikinAuto + 1);
+ EXPECT_EQ(kDaikinAuto, ac.getMode());
+
+ ac.setMode(255);
+ EXPECT_EQ(kDaikinAuto, ac.getMode());
+}
+
+
+TEST(TestDaikin216Class, VaneSwing) {
+ IRDaikin216 ac(0);
+ ac.begin();
+
+ ac.setSwingHorizontal(true);
+ ac.setSwingVertical(false);
+
+ ac.setSwingHorizontal(true);
+ EXPECT_TRUE(ac.getSwingHorizontal());
+ EXPECT_FALSE(ac.getSwingVertical());
+
+ ac.setSwingVertical(true);
+ EXPECT_TRUE(ac.getSwingHorizontal());
+ EXPECT_TRUE(ac.getSwingVertical());
+
+ ac.setSwingHorizontal(false);
+ EXPECT_FALSE(ac.getSwingHorizontal());
+ EXPECT_TRUE(ac.getSwingVertical());
+
+ ac.setSwingVertical(false);
+ EXPECT_FALSE(ac.getSwingHorizontal());
+ EXPECT_FALSE(ac.getSwingVertical());
+}
+
+TEST(TestDaikin216Class, FanSpeed) {
+ IRDaikin216 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(TestDaikin216Class, Quiet) {
+ IRDaikin216 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());
+}
+
+TEST(TestDaikin216Class, ExampleStates) {
+ IRDaikin216 ac(0);
+ ac.begin();
+ // https://github.com/markszabo/IRremoteESP8266/pull/690#issuecomment-487770194
+ uint8_t state[kDaikin216StateLength] = {
+ 0x11, 0xDA, 0x27, 0xF0, 0x00, 0x00, 0x00, 0x02,
+ 0x11, 0xDA, 0x27, 0x00, 0x00, 0x21, 0xC0, 0x00, 0xA0, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x53};
+ ac.setRaw(state);
+ EXPECT_EQ(
+ "Power: On, Mode: 2 (DRY), Temp: 32C, Fan: 10 (AUTO), "
+ "Swing (Horizontal): Off, Swing (Vertical): Off, Quiet: Off",
+ ac.toString());
+}
+
+TEST(TestDaikin216Class, ReconstructKnownState) {
+ IRDaikin216 ac(0);
+ ac.begin();
+ // https://github.com/markszabo/IRremoteESP8266/issues/689#issue-438086949
+ uint8_t expectedState[kDaikin216StateLength] = {
+ 0x11, 0xDA, 0x27, 0xF0, 0x00, 0x00, 0x00, 0x02,
+ 0x11, 0xDA, 0x27, 0x00, 0x00, 0x00, 0x26, 0x00, 0xA0, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x98};
+ ac.setPower(false);
+ ac.setMode(kDaikinAuto);
+ ac.setTemp(19);
+ ac.setFan(kDaikinFanAuto);
+ ac.setSwingHorizontal(false);
+ ac.setSwingVertical(false);
+ ac.setQuiet(false);
+ EXPECT_EQ(
+ "Power: Off, Mode: 0 (AUTO), Temp: 19C, Fan: 10 (AUTO), "
+ "Swing (Horizontal): Off, Swing (Vertical): Off, Quiet: Off",
+ ac.toString());
+
+ EXPECT_STATE_EQ(expectedState, ac.getRaw(), kDaikin216Bits);
+}
+
+// https://github.com/markszabo/IRremoteESP8266/issues/689
+TEST(TestDecodeDaikin216, RealExample) {
+ IRsendTest irsend(0);
+ IRrecv irrecv(0);
+ // https://github.com/markszabo/IRremoteESP8266/issues/689#issue-438086949
+ uint16_t rawData[439] = {
+ 3402, 1770, 382, 1340, 382, 480, 382, 478, 382, 480, 380, 1342, 382, 478,
+ 356, 504, 382, 480, 380, 478, 384, 1342, 380, 480, 380, 1342, 382, 1342,
+ 382, 478, 382, 1340, 382, 1340, 384, 1340, 382, 1342, 382, 1340, 380, 480,
+ 382, 480, 382, 1296, 426, 480, 380, 480, 382, 480, 380, 480, 382, 480,
+ 382, 478, 382, 1342, 382, 1342, 382, 1340, 356, 1368, 382, 478, 382, 480,
+ 382, 478, 380, 480, 382, 480, 382, 480, 382, 478, 382, 480, 382, 478, 358,
+ 504, 382, 480, 380, 480, 382, 480, 382, 480, 380, 480, 382, 478, 382, 480,
+ 382, 478, 382, 480, 354, 506, 354, 506, 380, 480, 382, 480, 382, 480, 382,
+ 480, 380, 1342, 382, 480, 382, 480, 382, 478, 382, 478, 382, 478, 384,
+ 478, 382, 29652, 3426, 1772, 382, 1340, 382, 480, 380, 478, 382, 480, 382,
+ 1342, 382, 480, 382, 480, 382, 478, 356, 506, 382, 1342, 380, 480, 382,
+ 1340, 382, 1340, 382, 478, 356, 1366, 382, 1340, 384, 1340, 382, 1340,
+ 382, 1342, 382, 478, 382, 478, 382, 1340, 382, 478, 382, 478, 382, 478,
+ 382, 480, 382, 480, 384, 478, 358, 504, 382, 478, 382, 480, 382, 478, 382,
+ 480, 382, 480, 382, 478, 382, 480, 382, 478, 382, 478, 382, 478, 382, 478,
+ 384, 478, 382, 478, 360, 500, 358, 504, 382, 478, 382, 480, 382, 480, 382,
+ 478, 382, 478, 382, 1340, 382, 1342, 382, 480, 380, 480, 382, 1342, 382,
+ 478, 382, 480, 356, 506, 382, 478, 382, 480, 382, 480, 356, 506, 382, 478,
+ 382, 480, 382, 478, 382, 480, 382, 478, 382, 480, 380, 480, 380, 480, 382,
+ 1342, 382, 478, 382, 1342, 382, 480, 382, 480, 382, 478, 382, 478, 382,
+ 480, 382, 478, 382, 480, 356, 504, 384, 478, 382, 480, 382, 480, 380, 480,
+ 382, 478, 382, 480, 382, 480, 382, 478, 356, 504, 384, 478, 380, 480, 382,
+ 480, 382, 480, 382, 478, 356, 506, 382, 478, 382, 480, 380, 480, 382, 478,
+ 382, 480, 382, 478, 382, 480, 358, 504, 382, 478, 382, 478, 356, 504, 382,
+ 478, 382, 480, 382, 478, 382, 478, 382, 478, 382, 480, 380, 480, 382, 480,
+ 380, 480, 356, 506, 356, 504, 382, 480, 382, 478, 382, 478, 382, 478, 382,
+ 478, 382, 480, 382, 478, 382, 480, 382, 480, 382, 1340, 382, 1342, 382,
+ 478, 384, 478, 382, 478, 382, 480, 380, 480, 382, 478, 382, 480, 356, 506,
+ 382, 478, 382, 480, 382, 478, 356, 506, 380, 480, 382, 478, 382, 478, 382,
+ 478, 382, 480, 382, 480, 380, 480, 382, 1342, 382, 1340, 382, 480, 356,
+ 504, 382, 1342, 382}; // UNKNOWN E0E32232
+ uint8_t expectedState[kDaikin216StateLength] = {
+ // 8 bytes
+ 0x11, 0xDA, 0x27, 0xF0, 0x00, 0x00, 0x00, 0x02,
+ // 19 bytes
+ 0x11, 0xDA, 0x27, 0x00, 0x00, 0x00, 0x26, 0x00, 0xA0, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x98};
+
+ irsend.begin();
+ irsend.reset();
+ irsend.sendRaw(rawData, 439, 38000);
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ ASSERT_EQ(DAIKIN216, irsend.capture.decode_type);
+ ASSERT_EQ(kDaikin216Bits, irsend.capture.bits);
+ EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits);
+
+ IRDaikin216 ac(0);
+ ac.setRaw(irsend.capture.state);
+ EXPECT_EQ(
+ "Power: Off, Mode: 0 (AUTO), Temp: 19C, Fan: 10 (AUTO), "
+ "Swing (Horizontal): Off, Swing (Vertical): Off, Quiet: Off",
+ ac.toString());
+}
+
+// https://github.com/markszabo/IRremoteESP8266/issues/689
+TEST(TestDecodeDaikin216, SyntheticExample) {
+ IRsendTest irsend(0);
+ IRrecv irrecv(0);
+ // https://github.com/markszabo/IRremoteESP8266/issues/689#issue-438086949
+ uint8_t expectedState[kDaikin216StateLength] = {
+ // 8 bytes
+ 0x11, 0xDA, 0x27, 0xF0, 0x00, 0x00, 0x00, 0x02,
+ // 19 bytes
+ 0x11, 0xDA, 0x27, 0x00, 0x00, 0x00, 0x26, 0x00, 0xA0, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x98};
+
+ irsend.begin();
+ irsend.reset();
+ irsend.sendDaikin216(expectedState);
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ ASSERT_EQ(DAIKIN216, irsend.capture.decode_type);
+ ASSERT_EQ(kDaikin216Bits, irsend.capture.bits);
+ EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits);
+}
diff --git a/lib/IRremoteESP8266-2.5.2.03/test/ir_Denon_test.cpp b/lib/IRremoteESP8266-2.6.0/test/ir_Denon_test.cpp
similarity index 98%
rename from lib/IRremoteESP8266-2.5.2.03/test/ir_Denon_test.cpp
rename to lib/IRremoteESP8266-2.6.0/test/ir_Denon_test.cpp
index 911fd7528..6b80eae02 100644
--- a/lib/IRremoteESP8266-2.5.2.03/test/ir_Denon_test.cpp
+++ b/lib/IRremoteESP8266-2.6.0/test/ir_Denon_test.cpp
@@ -14,6 +14,7 @@ TEST(TestSendDenon, SendDataOnly) {
irsend.reset();
irsend.sendDenon(0x2278); // Denon AVR Power On. (Sharp)
EXPECT_EQ(
+ "f38000d33"
"m260s780m260s1820m260s780m260s780m260s780m260s1820m260s780m260s780"
"m260s1820m260s1820m260s1820m260s1820m260s780m260s780m260s780"
"m260s43602"
@@ -26,6 +27,7 @@ TEST(TestSendDenon, SendDataOnly) {
// Denon Eco Mode On. (Panasonic/Kaseikyo)
irsend.sendDenon(0x2A4C028D6CE3, DENON_48_BITS);
EXPECT_EQ(
+ "f36700d50"
"m3456s1728"
"m432s432m432s432m432s1296m432s432m432s1296m432s432m432s1296m432s432"
"m432s432m432s1296m432s432m432s432m432s1296m432s1296m432s432m432s432"
@@ -45,6 +47,7 @@ TEST(TestSendDenon, SendNormalWithRepeats) {
irsend.reset();
irsend.sendDenon(0x2278, DENON_BITS, 1); // 1 repeat.
EXPECT_EQ(
+ "f38000d33"
"m260s780m260s1820m260s780m260s780m260s780m260s1820m260s780m260s780"
"m260s1820m260s1820m260s1820m260s1820m260s780m260s780m260s780"
"m260s43602"
@@ -60,6 +63,7 @@ TEST(TestSendDenon, SendNormalWithRepeats) {
irsend.outputStr());
irsend.sendDenon(0x2278, DENON_BITS, 2); // 2 repeats.
EXPECT_EQ(
+ "f38000d33"
"m260s780m260s1820m260s780m260s780m260s780m260s1820m260s780m260s780"
"m260s1820m260s1820m260s1820m260s1820m260s780m260s780m260s780"
"m260s43602"
@@ -88,6 +92,7 @@ TEST(TestSendDenon, Send48BitWithRepeats) {
irsend.reset();
irsend.sendDenon(0x2A4C028D6CE3, DENON_48_BITS, 1); // 1 repeat.
EXPECT_EQ(
+ "f36700d50"
"m3456s1728"
"m432s432m432s432m432s1296m432s432m432s1296m432s432m432s1296m432s432"
"m432s432m432s1296m432s432m432s432m432s1296m432s1296m432s432m432s432"
@@ -107,6 +112,7 @@ TEST(TestSendDenon, Send48BitWithRepeats) {
irsend.outputStr());
irsend.sendDenon(0x2A4C028D6CE3, DENON_48_BITS, 2); // 2 repeats.
EXPECT_EQ(
+ "f36700d50"
"m3456s1728"
"m432s432m432s432m432s1296m432s432m432s1296m432s432m432s1296m432s432"
"m432s432m432s1296m432s432m432s432m432s1296m432s1296m432s432m432s432"
@@ -142,6 +148,7 @@ TEST(TestSendDenon, SendUnusualSize) {
irsend.reset();
irsend.sendDenon(0x12, 8);
EXPECT_EQ(
+ "f38000d33"
"m260s780m260s780m260s780m260s1820m260s780m260s780m260s1820m260s780"
"m260s43602"
"m260s1820m260s1820m260s1820m260s780m260s1820m260s1820m260s780m260s1820"
@@ -151,6 +158,7 @@ TEST(TestSendDenon, SendUnusualSize) {
irsend.reset();
irsend.sendDenon(0x1234567890ABCDEF, 64);
EXPECT_EQ(
+ "f36700d50"
"m3456s1728"
"m432s432m432s432m432s432m432s1296m432s432m432s432m432s1296m432s432"
"m432s432m432s432m432s1296m432s1296m432s432m432s1296m432s432m432s432"
diff --git a/lib/IRremoteESP8266-2.5.2.03/test/ir_Dish_test.cpp b/lib/IRremoteESP8266-2.6.0/test/ir_Dish_test.cpp
similarity index 98%
rename from lib/IRremoteESP8266-2.5.2.03/test/ir_Dish_test.cpp
rename to lib/IRremoteESP8266-2.6.0/test/ir_Dish_test.cpp
index 0c58496ce..21286b7ac 100644
--- a/lib/IRremoteESP8266-2.5.2.03/test/ir_Dish_test.cpp
+++ b/lib/IRremoteESP8266-2.6.0/test/ir_Dish_test.cpp
@@ -14,6 +14,7 @@ TEST(TestSendDish, SendDataOnly) {
irsend.reset();
irsend.sendDISH(0x0);
EXPECT_EQ(
+ "f57600d50"
"m400s6100"
"m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800"
"m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800"
@@ -32,6 +33,7 @@ TEST(TestSendDish, SendDataOnly) {
irsend.reset();
irsend.sendDISH(0x9C00); // Power on.
EXPECT_EQ(
+ "f57600d50"
"m400s6100"
"m400s1700m400s2800m400s2800m400s1700m400s1700m400s1700m400s2800m400s2800"
"m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800"
@@ -50,6 +52,7 @@ TEST(TestSendDish, SendDataOnly) {
irsend.reset();
irsend.sendDISH(0xFFFF);
EXPECT_EQ(
+ "f57600d50"
"m400s6100"
"m400s1700m400s1700m400s1700m400s1700m400s1700m400s1700m400s1700m400s1700"
"m400s1700m400s1700m400s1700m400s1700m400s1700m400s1700m400s1700m400s1700"
@@ -74,6 +77,7 @@ TEST(TestSendDish, SendWithRepeats) {
irsend.reset();
irsend.sendDISH(0x9C00, kDishBits, 0); // 0 repeats.
EXPECT_EQ(
+ "f57600d50"
"m400s6100"
"m400s1700m400s2800m400s2800m400s1700m400s1700m400s1700m400s2800m400s2800"
"m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800"
@@ -83,6 +87,7 @@ TEST(TestSendDish, SendWithRepeats) {
irsend.reset();
irsend.sendDISH(0x9C00, kDishBits, 1); // 1 repeat.
EXPECT_EQ(
+ "f57600d50"
"m400s6100"
"m400s1700m400s2800m400s2800m400s1700m400s1700m400s1700m400s2800m400s2800"
"m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800"
@@ -94,6 +99,7 @@ TEST(TestSendDish, SendWithRepeats) {
irsend.sendDISH(0x9C00, kDishBits, 2); // 2 repeats.
EXPECT_EQ(
+ "f57600d50"
"m400s6100"
"m400s1700m400s2800m400s2800m400s1700m400s1700m400s1700m400s2800m400s2800"
"m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800"
@@ -115,6 +121,7 @@ TEST(TestSendDish, SendUnusualSize) {
irsend.reset();
irsend.sendDISH(0x0, 8);
EXPECT_EQ(
+ "f57600d50"
"m400s6100"
"m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800"
"m400s6100"
@@ -129,6 +136,7 @@ TEST(TestSendDish, SendUnusualSize) {
irsend.reset();
irsend.sendDISH(0x1234567890ABCDEF, 64);
EXPECT_EQ(
+ "f57600d50"
"m400s6100"
"m400s2800m400s2800m400s2800m400s1700m400s2800m400s2800m400s1700m400s2800"
"m400s2800m400s2800m400s1700m400s1700m400s2800m400s1700m400s2800m400s2800"
diff --git a/lib/IRremoteESP8266-2.5.2.03/test/ir_Electra_test.cpp b/lib/IRremoteESP8266-2.6.0/test/ir_Electra_test.cpp
similarity index 84%
rename from lib/IRremoteESP8266-2.5.2.03/test/ir_Electra_test.cpp
rename to lib/IRremoteESP8266-2.6.0/test/ir_Electra_test.cpp
index df5dd7a5c..7d6d0c915 100644
--- a/lib/IRremoteESP8266-2.5.2.03/test/ir_Electra_test.cpp
+++ b/lib/IRremoteESP8266-2.6.0/test/ir_Electra_test.cpp
@@ -12,12 +12,13 @@
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};
+ uint8_t data[kElectraAcStateLength] = {0xC3, 0x87, 0xF6, 0x28, 0x60,
+ 0x00, 0x20, 0x00, 0x00, 0x20,
+ 0x00, 0x05, 0x0D};
irsend.sendElectraAC(data);
EXPECT_EQ(
+ "f38000d50"
"m9166s4470"
"m646s1647m646s1647m646s547m646s547m646s547m646s547m646s1647m646s1647"
"m646s1647m646s1647m646s1647m646s547m646s547m646s547m646s547m646s1647"
@@ -46,9 +47,9 @@ TEST(TestDecodeElectraAC, SyntheticDecode) {
// Synthesised Normal ElectraAC message.
irsend.reset();
- uint8_t expectedState[kElectraAcStateLength] = {0xC3, 0xE1, 0x6F, 0x14, 0x06,
- 0x00, 0x04, 0x00, 0x00, 0x04,
- 0x00, 0xA0, 0xB0};
+ uint8_t expectedState[kElectraAcStateLength] = {0xC3, 0x87, 0xF6, 0x28, 0x60,
+ 0x00, 0x20, 0x00, 0x00, 0x20,
+ 0x00, 0x05, 0x0D};
irsend.sendElectraAC(expectedState);
irsend.makeDecodeResult();
EXPECT_TRUE(irrecv.decode(&irsend.capture));
@@ -84,9 +85,9 @@ TEST(TestDecodeElectraAC, RealExampleDecode) {
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};
+ uint8_t expectedState[kElectraAcStateLength] = {0xC3, 0x87, 0xF6, 0x28, 0x60,
+ 0x00, 0x20, 0x00, 0x00, 0x20,
+ 0x00, 0x05, 0x0D};
irsend.reset();
irsend.sendRaw(rawData, 211, 38000);
diff --git a/lib/IRremoteESP8266-2.5.2.03/test/ir_Fujitsu_test.cpp b/lib/IRremoteESP8266-2.6.0/test/ir_Fujitsu_test.cpp
similarity index 99%
rename from lib/IRremoteESP8266-2.5.2.03/test/ir_Fujitsu_test.cpp
rename to lib/IRremoteESP8266-2.6.0/test/ir_Fujitsu_test.cpp
index 23fa3e7a7..b895e4d9b 100644
--- a/lib/IRremoteESP8266-2.5.2.03/test/ir_Fujitsu_test.cpp
+++ b/lib/IRremoteESP8266-2.6.0/test/ir_Fujitsu_test.cpp
@@ -183,6 +183,7 @@ TEST(TestSendFujitsuAC, GenerateMessage) {
irsend.reset();
irsend.sendFujitsuAC(fujitsu.getRaw(), kFujitsuAcStateLength);
EXPECT_EQ(
+ "f38000d50"
"m3324s1574"
"m448s390m448s390m448s1182m448s390m448s1182m448s390m448s390m448s390"
"m448s1182m448s1182m448s390m448s390m448s390m448s1182m448s1182m448s390"
@@ -217,6 +218,7 @@ TEST(TestSendFujitsuAC, GenerateShortMessage) {
irsend.reset();
irsend.sendFujitsuAC(fujitsu.getRaw(), kFujitsuAcStateLengthShort);
EXPECT_EQ(
+ "f38000d50"
"m3324s1574m448s390m448s390m448s1182m448s390m448s1182m448s390m448s390m448"
"s390m448s1182m448s1182m448s390m448s390m448s390m448s1182m448s1182m448s390"
"m448s390m448s390m448s390m448s390m448s390m448s390m448s390m448s390m448s390"
@@ -238,6 +240,7 @@ TEST(TestSendFujitsuAC, Issue275) {
fujitsu.setCmd(kFujitsuAcCmdTurnOff);
irsend.sendFujitsuAC(fujitsu.getRaw(), kFujitsuAcStateLengthShort);
EXPECT_EQ(
+ "f38000d50"
// Header
"m3324s1574"
// 0 0 1 0 1 0 0 0 (0x28)
@@ -272,6 +275,7 @@ TEST(TestSendFujitsuAC, Issue275) {
450, 1250, 450};
irsend.sendRaw(off, 115, 38);
EXPECT_EQ(
+ "f38000d50"
// Header
"m3350s1650"
// 0 0 1 0 1 0 0 0 (0x28)
@@ -534,6 +538,7 @@ TEST(TestDecodeFujitsuAC, Issue414) {
ASSERT_EQ(kFujitsuAcBits, irsend.capture.bits);
EXPECT_TRUE(ArraysMatch(state, irsend.capture.state));
EXPECT_EQ(
+ "f38000d50"
"m3324s1574"
"m448s390m448s390m448s1182m448s390m448s1182m448s390m448s390m448s390"
"m448s1182m448s1182m448s390m448s390m448s390m448s1182m448s1182m448s390"
diff --git a/lib/IRremoteESP8266-2.5.2.03/test/ir_GICable_test.cpp b/lib/IRremoteESP8266-2.6.0/test/ir_GICable_test.cpp
similarity index 98%
rename from lib/IRremoteESP8266-2.5.2.03/test/ir_GICable_test.cpp
rename to lib/IRremoteESP8266-2.6.0/test/ir_GICable_test.cpp
index b9bfce997..bad9bbded 100644
--- a/lib/IRremoteESP8266-2.5.2.03/test/ir_GICable_test.cpp
+++ b/lib/IRremoteESP8266-2.6.0/test/ir_GICable_test.cpp
@@ -12,6 +12,7 @@ TEST(TestSendGICable, SendDataOnly) {
irsend.begin();
irsend.sendGICable(0);
EXPECT_EQ(
+ "f39000d50"
"m9000s4400"
"m550s2200m550s2200m550s2200m550s2200m550s2200m550s2200m550s2200m550s2200"
"m550s2200m550s2200m550s2200m550s2200m550s2200m550s2200m550s2200m550s2200"
@@ -20,6 +21,7 @@ TEST(TestSendGICable, SendDataOnly) {
irsend.outputStr());
irsend.sendGICable(0x8807);
EXPECT_EQ(
+ "f39000d50"
"m9000s4400"
"m550s4400m550s2200m550s2200m550s2200m550s4400m550s2200m550s2200m550s2200"
"m550s2200m550s2200m550s2200m550s2200m550s2200m550s4400m550s4400m550s4400"
@@ -28,6 +30,7 @@ TEST(TestSendGICable, SendDataOnly) {
irsend.outputStr());
irsend.sendGICable(0xFFFF);
EXPECT_EQ(
+ "f39000d50"
"m9000s4400"
"m550s4400m550s4400m550s4400m550s4400m550s4400m550s4400m550s4400m550s4400"
"m550s4400m550s4400m550s4400m550s4400m550s4400m550s4400m550s4400m550s4400"
@@ -43,6 +46,7 @@ TEST(TestSendGICable, SendWithRepeats) {
// Send a command with 0 repeats.
irsend.sendGICable(0x8807, kGicableBits, 0);
EXPECT_EQ(
+ "f39000d50"
"m9000s4400"
"m550s4400m550s2200m550s2200m550s2200m550s4400m550s2200m550s2200m550s2200"
"m550s2200m550s2200m550s2200m550s2200m550s2200m550s4400m550s4400m550s4400"
@@ -51,6 +55,7 @@ TEST(TestSendGICable, SendWithRepeats) {
// Send a command with 1 repeat.
irsend.sendGICable(0x8807, kGicableBits, 1);
EXPECT_EQ(
+ "f39000d50"
"m9000s4400"
"m550s4400m550s2200m550s2200m550s2200m550s4400m550s2200m550s2200m550s2200"
"m550s2200m550s2200m550s2200m550s2200m550s2200m550s4400m550s4400m550s4400"
@@ -60,6 +65,7 @@ TEST(TestSendGICable, SendWithRepeats) {
// Send a command with 3 repeats.
irsend.sendGICable(0x8807, kGicableBits, 3);
EXPECT_EQ(
+ "f39000d50"
"m9000s4400"
"m550s4400m550s2200m550s2200m550s2200m550s4400m550s2200m550s2200m550s2200"
"m550s2200m550s2200m550s2200m550s2200m550s2200m550s4400m550s4400m550s4400"
diff --git a/lib/IRremoteESP8266-2.5.2.03/test/ir_GlobalCache_test.cpp b/lib/IRremoteESP8266-2.6.0/test/ir_GlobalCache_test.cpp
similarity index 98%
rename from lib/IRremoteESP8266-2.5.2.03/test/ir_GlobalCache_test.cpp
rename to lib/IRremoteESP8266-2.6.0/test/ir_GlobalCache_test.cpp
index 16a556b57..00742aeda 100644
--- a/lib/IRremoteESP8266-2.5.2.03/test/ir_GlobalCache_test.cpp
+++ b/lib/IRremoteESP8266-2.6.0/test/ir_GlobalCache_test.cpp
@@ -29,6 +29,7 @@ TEST(TestSendGlobalCache, NonRepeatingCode) {
EXPECT_EQ(0x4, irsend.capture.address);
EXPECT_EQ(0x41, irsend.capture.command);
EXPECT_EQ(
+ "f38000d50"
"m8892s4472m546s572m546s546m546s1690m546s546m546s572m546s572"
"m546s546m546s572m546s1690m546s1690m546s572m546s1690m546s1690"
"m546s1690m546s1690m546s1690m546s1690m546s572m546s572m546s546"
@@ -60,6 +61,7 @@ TEST(TestSendGlobalCache, RepeatCode) {
EXPECT_EQ(0x4583, irsend.capture.address);
EXPECT_EQ(0x11, irsend.capture.command);
EXPECT_EQ(
+ "f38000d50"
"m8866s4446m546s1664m546s1664m546s546m546s546m546s546m546s546"
"m546s546m546s1664m546s1664m546s546m546s1664m546s546m546s546"
"m546s546m546s1664m546s546m546s1664m546s546m546s546m546s546"
diff --git a/lib/IRremoteESP8266-2.5.2.03/test/ir_Gree_test.cpp b/lib/IRremoteESP8266-2.6.0/test/ir_Gree_test.cpp
similarity index 98%
rename from lib/IRremoteESP8266-2.5.2.03/test/ir_Gree_test.cpp
rename to lib/IRremoteESP8266-2.6.0/test/ir_Gree_test.cpp
index 6c7a1f637..a05b06391 100644
--- a/lib/IRremoteESP8266-2.5.2.03/test/ir_Gree_test.cpp
+++ b/lib/IRremoteESP8266-2.6.0/test/ir_Gree_test.cpp
@@ -20,7 +20,8 @@ TEST(TestSendGreeChars, SendData) {
irsend.reset();
irsend.sendGree(gree_code);
EXPECT_EQ(
- "m9000s4000"
+ "f38000d50"
+ "m9000s4500"
"m620s540m620s1600m620s540m620s540m620s1600m620s540m620s540m620s540"
"m620s540m620s540m620s1600m620s540m620s1600m620s1600m620s540m620s540"
"m620s540m620s1600m620s1600m620s540m620s1600m620s540m620s1600m620s540"
@@ -42,7 +43,8 @@ TEST(TestSendGreeUint64, SendData) {
irsend.reset();
irsend.sendGree(0x1234567890ABCDEF);
EXPECT_EQ(
- "m9000s4000"
+ "f38000d50"
+ "m9000s4500"
"m620s540m620s1600m620s540m620s540m620s1600m620s540m620s540m620s540"
"m620s540m620s540m620s1600m620s540m620s1600m620s1600m620s540m620s540"
"m620s540m620s1600m620s1600m620s540m620s1600m620s540m620s1600m620s540"
@@ -69,7 +71,8 @@ TEST(TestSendGreeChars, SendWithRepeats) {
irsend.sendGree(gree_code, kGreeStateLength, 1);
EXPECT_EQ(
- "m9000s4000"
+ "f38000d50"
+ "m9000s4500"
"m620s540m620s1600m620s540m620s540m620s1600m620s540m620s540m620s540"
"m620s540m620s540m620s1600m620s540m620s1600m620s1600m620s540m620s540"
"m620s540m620s1600m620s1600m620s540m620s1600m620s540m620s1600m620s540"
@@ -81,7 +84,7 @@ TEST(TestSendGreeChars, SendWithRepeats) {
"m620s1600m620s540m620s1600m620s1600m620s540m620s540m620s1600m620s1600"
"m620s1600m620s1600m620s1600m620s1600m620s540m620s1600m620s1600m620s1600"
"m620s19000"
- "m9000s4000"
+ "m9000s4500"
"m620s540m620s1600m620s540m620s540m620s1600m620s540m620s540m620s540"
"m620s540m620s540m620s1600m620s540m620s1600m620s1600m620s540m620s540"
"m620s540m620s1600m620s1600m620s540m620s1600m620s540m620s1600m620s540"
@@ -103,7 +106,8 @@ TEST(TestSendGreeUint64, SendWithRepeats) {
irsend.reset();
irsend.sendGree(0x1234567890ABCDEF, kGreeBits, 1);
EXPECT_EQ(
- "m9000s4000"
+ "f38000d50"
+ "m9000s4500"
"m620s540m620s1600m620s540m620s540m620s1600m620s540m620s540m620s540"
"m620s540m620s540m620s1600m620s540m620s1600m620s1600m620s540m620s540"
"m620s540m620s1600m620s1600m620s540m620s1600m620s540m620s1600m620s540"
@@ -115,7 +119,7 @@ TEST(TestSendGreeUint64, SendWithRepeats) {
"m620s1600m620s540m620s1600m620s1600m620s540m620s540m620s1600m620s1600"
"m620s1600m620s1600m620s1600m620s1600m620s540m620s1600m620s1600m620s1600"
"m620s19000"
- "m9000s4000"
+ "m9000s4500"
"m620s540m620s1600m620s540m620s540m620s1600m620s540m620s540m620s540"
"m620s540m620s540m620s1600m620s540m620s1600m620s1600m620s540m620s540"
"m620s540m620s1600m620s1600m620s540m620s1600m620s540m620s1600m620s540"
@@ -146,7 +150,8 @@ TEST(TestSendGreeChars, SendUnexpectedSizes) {
irsend.reset();
irsend.sendGree(gree_long_code, kGreeStateLength + 1);
ASSERT_EQ(
- "m9000s4000"
+ "f38000d50"
+ "m9000s4500"
"m620s540m620s1600m620s540m620s540m620s1600m620s540m620s540m620s540"
"m620s540m620s540m620s1600m620s540m620s1600m620s1600m620s540m620s540"
"m620s540m620s1600m620s1600m620s540m620s1600m620s540m620s1600m620s540"
@@ -486,7 +491,7 @@ TEST(TestDecodeGree, NormalSynthetic) {
EXPECT_STATE_EQ(gree_code, irsend.capture.state, kGreeBits);
}
-// Decode a synthetic Gree message.
+// Decode a real Gree message.
TEST(TestDecodeGree, NormalRealExample) {
IRsendTest irsend(4);
IRrecv irrecv(4);
diff --git a/lib/IRremoteESP8266-2.5.2.03/test/ir_Haier_test.cpp b/lib/IRremoteESP8266-2.6.0/test/ir_Haier_test.cpp
similarity index 90%
rename from lib/IRremoteESP8266-2.5.2.03/test/ir_Haier_test.cpp
rename to lib/IRremoteESP8266-2.6.0/test/ir_Haier_test.cpp
index 11848e00a..8d306cb0b 100644
--- a/lib/IRremoteESP8266-2.5.2.03/test/ir_Haier_test.cpp
+++ b/lib/IRremoteESP8266-2.6.0/test/ir_Haier_test.cpp
@@ -19,6 +19,7 @@ TEST(TestSendHaierAC, SendDataOnly) {
irsend.reset();
irsend.sendHaierAC(haier_zero);
EXPECT_EQ(
+ "f38000d50"
"m3000s3000m3000s4300"
"m520s650m520s650m520s650m520s650m520s650m520s650m520s650m520s650"
"m520s650m520s650m520s650m520s650m520s650m520s650m520s650m520s650"
@@ -37,6 +38,7 @@ TEST(TestSendHaierAC, SendDataOnly) {
irsend.reset();
irsend.sendHaierAC(haier_test);
EXPECT_EQ(
+ "f38000d50"
"m3000s3000m3000s4300"
"m520s1650m520s650m520s1650m520s650m520s650m520s1650m520s650m520s1650"
"m520s650m520s650m520s650m520s650m520s650m520s650m520s650m520s1650"
@@ -62,6 +64,7 @@ TEST(TestSendHaierAC, SendWithRepeats) {
irsend.reset();
irsend.sendHaierAC(haier_test, kHaierACStateLength, 2); // two repeats.
EXPECT_EQ(
+ "f38000d50"
"m3000s3000m3000s4300"
"m520s1650m520s650m520s1650m520s650m520s650m520s1650m520s650m520s1650"
"m520s650m520s650m520s650m520s650m520s650m520s650m520s650m520s1650"
@@ -404,7 +407,7 @@ TEST(TestHaierACClass, MessageConstuction) {
haier.toString());
uint8_t expectedState[kHaierACStateLength] = {0xA5, 0x96, 0xEA, 0xCF, 0x32,
- 0x2D, 0x0D, 0x74, 0xD4};
+ 0xED, 0x2D, 0x74, 0xB4};
EXPECT_STATE_EQ(expectedState, haier.getRaw(), kHaierACBits);
// Check that the checksum is valid.
@@ -987,3 +990,91 @@ TEST(TestDecodeHaierAC_YRW02, RealExample) {
" Health: On",
haier.toString());
}
+
+// Default state of the remote needed to include hidden data.
+// Ref: https://github.com/markszabo/IRremoteESP8266/issues/668
+TEST(TestHaierAcIssues, Issue668) {
+ IRHaierAC ac(0);
+ IRHaierAC acText(1);
+ IRrecv irrecv(0);
+ ac.begin();
+
+ // Turn on the AC.
+ ac._irsend.reset();
+ char expected_on[] =
+ "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";
+ // State taken from real capture:
+ // https://github.com/markszabo/IRremoteESP8266/issues/668#issuecomment-483531895
+ uint8_t expected_on_state[9] = {
+ 0xA5, 0x91, 0x20, 0x00, 0x0C, 0xC0, 0x20, 0x00, 0x42};
+ ac.setCommand(kHaierAcCmdOn);
+ EXPECT_EQ(expected_on, ac.toString());
+ ac.send();
+ ac._irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&ac._irsend.capture));
+ ASSERT_EQ(HAIER_AC, ac._irsend.capture.decode_type);
+ EXPECT_EQ(kHaierACBits, ac._irsend.capture.bits);
+ EXPECT_STATE_EQ(expected_on_state,
+ ac._irsend.capture.state, ac._irsend.capture.bits);
+ acText.setRaw(ac._irsend.capture.state);
+ EXPECT_EQ(expected_on, acText.toString());
+
+ // Set the temp to 25C
+ ac._irsend.reset();
+ ac.setTemp(25);
+ EXPECT_EQ(expected_on, ac.toString());
+ ASSERT_EQ(25, ac.getTemp());
+ ac.send();
+ ac._irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&ac._irsend.capture));
+ ASSERT_EQ(HAIER_AC, ac._irsend.capture.decode_type);
+ EXPECT_EQ(kHaierACBits, ac._irsend.capture.bits);
+ EXPECT_STATE_EQ(expected_on_state,
+ ac._irsend.capture.state, ac._irsend.capture.bits);
+ acText.setRaw(ac._irsend.capture.state);
+ EXPECT_EQ(expected_on, acText.toString());
+
+ // Increase the temp by 1.
+ ac._irsend.reset();
+ char expected_temp_plus_one[] =
+ "Command: 6 (Temp Up), Mode: 0 (AUTO), Temp: 26C, Fan: 0 (AUTO), "
+ "Swing: 0 (Off), Sleep: Off, Health: Off, Current Time: 00:00, "
+ "On Timer: Off, Off Timer: Off";
+ // State taken from real capture:
+ // https://github.com/markszabo/IRremoteESP8266/issues/668#issuecomment-483531895
+ uint8_t expected_temp_plus_one_state[9] = {
+ 0xA5, 0xA6, 0x20, 0x00, 0x0C, 0xC0, 0x20, 0x00, 0x57};
+ ASSERT_EQ(25, ac.getTemp());
+ ac.setTemp(ac.getTemp() + 1);
+ ASSERT_EQ(26, ac.getTemp());
+ EXPECT_EQ(expected_temp_plus_one, ac.toString());
+ ac.send();
+ ac._irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&ac._irsend.capture));
+ ASSERT_EQ(HAIER_AC, ac._irsend.capture.decode_type);
+ EXPECT_EQ(kHaierACBits, ac._irsend.capture.bits);
+ EXPECT_STATE_EQ(expected_temp_plus_one_state,
+ ac._irsend.capture.state, ac._irsend.capture.bits);
+ acText.setRaw(ac._irsend.capture.state);
+ EXPECT_EQ(expected_temp_plus_one, acText.toString());
+
+ // Decrease the temp by 1.
+ ac._irsend.reset();
+ char expected_temp_minus_one[] =
+ "Command: 7 (Temp Down), 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";
+ ASSERT_EQ(26, ac.getTemp());
+ ac.setTemp(ac.getTemp() - 1);
+ ASSERT_EQ(25, ac.getTemp());
+ EXPECT_EQ(expected_temp_minus_one, ac.toString());
+ ac.send();
+ ac._irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&ac._irsend.capture));
+ ASSERT_EQ(HAIER_AC, ac._irsend.capture.decode_type);
+ EXPECT_EQ(kHaierACBits, ac._irsend.capture.bits);
+ acText.setRaw(ac._irsend.capture.state);
+ EXPECT_EQ(expected_temp_minus_one, acText.toString());
+}
diff --git a/lib/IRremoteESP8266-2.5.2.03/test/ir_Hitachi_test.cpp b/lib/IRremoteESP8266-2.6.0/test/ir_Hitachi_test.cpp
similarity index 99%
rename from lib/IRremoteESP8266-2.5.2.03/test/ir_Hitachi_test.cpp
rename to lib/IRremoteESP8266-2.6.0/test/ir_Hitachi_test.cpp
index de0a4a2a1..a2471c4aa 100644
--- a/lib/IRremoteESP8266-2.5.2.03/test/ir_Hitachi_test.cpp
+++ b/lib/IRremoteESP8266-2.6.0/test/ir_Hitachi_test.cpp
@@ -22,6 +22,7 @@ TEST(TestSendHitachiAC, SendData) {
irsend.reset();
irsend.sendHitachiAC(hitachi_code);
EXPECT_EQ(
+ "f38000d50"
"m3300s1700"
"m400s1250m400s500m400s500m400s500m400s500m400s500m400s500m400s500"
"m400s500m400s500m400s500m400s500m400s1250m400s500m400s500m400s500"
@@ -68,6 +69,7 @@ TEST(TestSendHitachiAC, SendWithRepeats) {
irsend.sendHitachiAC(hitachi_code, kHitachiAcStateLength, 1);
EXPECT_EQ(
+ "f38000d50"
"m3300s1700"
"m400s1250m400s500m400s500m400s500m400s500m400s500m400s500m400s500"
"m400s500m400s500m400s500m400s500m400s1250m400s500m400s500m400s500"
@@ -151,6 +153,7 @@ TEST(TestSendHitachiAC, SendUnexpectedSizes) {
irsend.reset();
irsend.sendHitachiAC(hitachi_long_code, kHitachiAcStateLength + 1);
ASSERT_EQ(
+ "f38000d50"
"m3300s1700"
"m400s1250m400s500m400s500m400s500m400s500m400s500m400s500m400s500"
"m400s500m400s500m400s500m400s500m400s1250m400s500m400s500m400s500"
@@ -511,6 +514,7 @@ TEST(TestSendHitachiAC1, SendData) {
irsend.reset();
irsend.sendHitachiAC1(hitachi_code);
EXPECT_EQ(
+ "f38000d50"
"m3400s3400"
"m400s1250m400s500m400s1250m400s1250m400s500m400s500m400s1250m400s500"
"m400s1250m400s500m400s1250m400s500m400s1250m400s1250m400s1250m400s500"
@@ -585,6 +589,7 @@ TEST(TestSendHitachiAC2, SendData) {
irsend.reset();
irsend.sendHitachiAC2(hitachi_code);
EXPECT_EQ(
+ "f38000d50"
"m3300s1700"
"m400s1250m400s500m400s500m400s500m400s500m400s500m400s500m400s500"
"m400s500m400s500m400s500m400s500m400s1250m400s500m400s500m400s500"
diff --git a/lib/IRremoteESP8266-2.5.2.03/test/ir_JVC_test.cpp b/lib/IRremoteESP8266-2.6.0/test/ir_JVC_test.cpp
similarity index 99%
rename from lib/IRremoteESP8266-2.5.2.03/test/ir_JVC_test.cpp
rename to lib/IRremoteESP8266-2.6.0/test/ir_JVC_test.cpp
index c899fa8c6..3cd99c3aa 100644
--- a/lib/IRremoteESP8266-2.5.2.03/test/ir_JVC_test.cpp
+++ b/lib/IRremoteESP8266-2.6.0/test/ir_JVC_test.cpp
@@ -14,6 +14,7 @@ TEST(TestSendJVC, SendDataOnly) {
irsend.reset();
irsend.sendJVC(0xC2B8); // JVC VCR Power On.
EXPECT_EQ(
+ "f38000d33"
"m8400s4200"
"m525s1725m525s1725m525s525m525s525m525s525m525s525m525s1725m525s525"
"m525s1725m525s525m525s1725m525s1725m525s1725m525s525m525s525m525s525"
@@ -29,6 +30,7 @@ TEST(TestSendJVC, SendWithRepeats) {
irsend.reset();
irsend.sendJVC(0xC2B8, kJvcBits, 1); // 1 repeat.
EXPECT_EQ(
+ "f38000d33"
"m8400s4200"
"m525s1725m525s1725m525s525m525s525m525s525m525s525m525s1725m525s525"
"m525s1725m525s525m525s1725m525s1725m525s1725m525s525m525s525m525s525"
@@ -39,6 +41,7 @@ TEST(TestSendJVC, SendWithRepeats) {
irsend.outputStr());
irsend.sendJVC(0xC2B8, kJvcBits, 2); // 2 repeats.
EXPECT_EQ(
+ "f38000d33"
"m8400s4200"
"m525s1725m525s1725m525s525m525s525m525s525m525s525m525s1725m525s525"
"m525s1725m525s525m525s1725m525s1725m525s1725m525s525m525s525m525s525"
@@ -60,6 +63,7 @@ TEST(TestSendJVC, SendUnusualSize) {
irsend.reset();
irsend.sendJVC(0x0, 8);
EXPECT_EQ(
+ "f38000d33"
"m8400s4200"
"m525s525m525s525m525s525m525s525m525s525m525s525m525s525m525s525"
"m525s38475",
@@ -68,6 +72,7 @@ TEST(TestSendJVC, SendUnusualSize) {
irsend.reset();
irsend.sendJVC(0x1234567890ABCDEF, 64);
EXPECT_EQ(
+ "f38000d33"
"m8400s4200"
"m525s525m525s525m525s525m525s1725m525s525m525s525m525s1725m525s525"
"m525s525m525s525m525s1725m525s1725m525s525m525s1725m525s525m525s525"
diff --git a/lib/IRremoteESP8266-2.5.2.03/test/ir_Kelvinator_test.cpp b/lib/IRremoteESP8266-2.6.0/test/ir_Kelvinator_test.cpp
similarity index 99%
rename from lib/IRremoteESP8266-2.5.2.03/test/ir_Kelvinator_test.cpp
rename to lib/IRremoteESP8266-2.6.0/test/ir_Kelvinator_test.cpp
index 001f8bcf2..38a298e58 100644
--- a/lib/IRremoteESP8266-2.5.2.03/test/ir_Kelvinator_test.cpp
+++ b/lib/IRremoteESP8266-2.6.0/test/ir_Kelvinator_test.cpp
@@ -21,6 +21,7 @@ TEST(TestSendKelvinator, SendDataOnly) {
irsend.reset();
irsend.sendKelvinator(kelv_code);
EXPECT_EQ(
+ "f38000d50"
"m9010s4505"
"m680s1530m680s510m680s510m680s1530m680s1530m680s510m680s510m680s510"
"m680s1530m680s1530m680s510m680s1530m680s510m680s510m680s510m680s510"
@@ -61,6 +62,7 @@ TEST(TestSendKelvinator, SendWithRepeats) {
irsend.sendKelvinator(kelv_code, kKelvinatorStateLength, 1);
EXPECT_EQ(
+ "f38000d50"
"m9010s4505"
"m680s1530m680s510m680s510m680s1530m680s1530m680s510m680s510m680s510"
"m680s1530m680s1530m680s510m680s1530m680s510m680s510m680s510m680s510"
@@ -131,6 +133,7 @@ TEST(TestSendKelvinator, SendUnexpectedSizes) {
// extra data.
irsend.sendKelvinator(kelv_long_code, 17);
ASSERT_EQ(
+ "f38000d50"
"m9010s4505"
"m680s1530m680s510m680s510m680s1530m680s1530m680s510m680s510m680s510"
"m680s1530m680s1530m680s510m680s1530m680s510m680s510m680s510m680s510"
@@ -472,6 +475,7 @@ TEST(TestKelvinatorClass, MessageConstuction) {
irsend.reset();
irsend.sendKelvinator(irkelv.getRaw());
EXPECT_EQ(
+ "f38000d50"
"m9010s4505"
"m680s1530m680s510m680s510m680s1530m680s1530m680s510m680s1530m680s510"
"m680s1530m680s1530m680s510m680s1530m680s510m680s510m680s510m680s510"
diff --git a/lib/IRremoteESP8266-2.5.2.03/test/ir_LG_test.cpp b/lib/IRremoteESP8266-2.6.0/test/ir_LG_test.cpp
similarity index 88%
rename from lib/IRremoteESP8266-2.5.2.03/test/ir_LG_test.cpp
rename to lib/IRremoteESP8266-2.6.0/test/ir_LG_test.cpp
index 8ab24a731..2925494b9 100644
--- a/lib/IRremoteESP8266-2.5.2.03/test/ir_LG_test.cpp
+++ b/lib/IRremoteESP8266-2.6.0/test/ir_LG_test.cpp
@@ -30,6 +30,7 @@ TEST(TestSendLG, SendDataOnly) {
irsend.reset();
irsend.sendLG(0x4B4AE51);
EXPECT_EQ(
+ "f38000d50"
"m8500s4250"
"m550s550m550s1600m550s550m550s550"
"m550s1600m550s550m550s1600m550s1600m550s550m550s1600m550s550m550s550"
@@ -41,6 +42,7 @@ TEST(TestSendLG, SendDataOnly) {
irsend.reset();
irsend.sendLG(0xB4B4AE51, kLg32Bits);
EXPECT_EQ(
+ "f38000d33"
"m4480s4480"
"m560s1680m560s560m560s1680m560s1680m560s560m560s1680m560s560m560s560"
"m560s1680m560s560m560s1680m560s1680m560s560m560s1680m560s560m560s560"
@@ -59,6 +61,7 @@ TEST(TestSendLG, SendWithRepeats) {
irsend.reset();
irsend.sendLG(0x4B4AE51, kLgBits, 1);
EXPECT_EQ(
+ "f38000d50"
"m8500s4250"
"m550s550m550s1600m550s550m550s550"
"m550s1600m550s550m550s1600m550s1600m550s550m550s1600m550s550m550s550"
@@ -71,6 +74,7 @@ TEST(TestSendLG, SendWithRepeats) {
irsend.reset();
irsend.sendLG(0xB4B4AE51, kLg32Bits, 1);
EXPECT_EQ(
+ "f38000d33"
"m4480s4480"
"m560s1680m560s560m560s1680m560s1680m560s560m560s1680m560s560m560s560"
"m560s1680m560s560m560s1680m560s1680m560s560m560s1680m560s560m560s560"
@@ -90,6 +94,7 @@ TEST(TestSendLG, SendUnusualSize) {
irsend.reset();
irsend.sendLG(0x0, 31);
EXPECT_EQ(
+ "f38000d50"
"m8500s4250"
"m550s550m550s550m550s550m550s550m550s550m550s550m550s550m550s550"
"m550s550m550s550m550s550m550s550m550s550m550s550m550s550m550s550"
@@ -101,6 +106,7 @@ TEST(TestSendLG, SendUnusualSize) {
irsend.reset();
irsend.sendLG(0x0, 64);
EXPECT_EQ(
+ "f38000d33"
"m4480s4480"
"m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
"m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
@@ -373,6 +379,7 @@ TEST(TestSendLG2, SendDataOnly) {
irsend.reset();
irsend.sendLG2(0x880094D);
EXPECT_EQ(
+ "f38000d50"
"m3200s9850"
"m550s1600m550s550m550s550m550s550m550s1600m550s550m550s550m550s550"
"m550s550m550s550m550s550m550s550m550s550m550s550m550s550m550s550"
@@ -420,3 +427,54 @@ TEST(TestDecodeLG2, RealLG2Example) {
EXPECT_EQ(kLgBits, irsend.capture.bits);
EXPECT_EQ(0x880094D, irsend.capture.value);
}
+
+// Tests for issue reported in
+// https://github.com/markszabo/IRremoteESP8266/issues/620
+TEST(TestDecodeLG, Issue620) {
+ IRsendTest irsend(0);
+ IRrecv irrecv(0);
+ irsend.begin();
+
+ // Raw data as reported in initial comment of Issue #620
+ uint16_t rawData[59] = {
+ 8886, 4152,
+ 560, 1538, 532, 502, 532, 504, 530, 484, 558, 1536,
+ 508, 516, 558, 502, 532, 484, 558, 502, 532, 500,
+ 534, 508, 532, 502, 532, 1518, 558, 510, 532, 484,
+ 556, 486, 556, 510, 532, 1518, 558, 1560, 532, 1528,
+ 556, 504, 530, 506, 530, 1520, 558, 508, 534, 500,
+ 532, 512, 530, 484, 556, 1536, 532}; // LG 8808721
+ irsend.sendRaw(rawData, 59, 38000);
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(LG, irsend.capture.decode_type);
+ EXPECT_EQ(28, irsend.capture.bits);
+ EXPECT_EQ(0x8808721, irsend.capture.value);
+ EXPECT_EQ(0x88, irsend.capture.address);
+ EXPECT_EQ(0x872, irsend.capture.command);
+
+ irsend.reset();
+
+ // Resend the same code as the report is a sent code doesn't decode
+ // to the same message code.
+ irsend.sendLG(0x8808721);
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(LG, irsend.capture.decode_type);
+ EXPECT_EQ(28, irsend.capture.bits);
+ EXPECT_EQ(0x8808721, irsend.capture.value);
+ EXPECT_EQ(0x88, irsend.capture.address);
+ EXPECT_EQ(0x872, irsend.capture.command);
+ // The following seems to match the rawData above.
+ EXPECT_EQ(
+ "f38000d50"
+ "m8500s4250"
+ "m550s1600m550s550m550s550m550s550m550s1600"
+ "m550s550m550s550m550s550m550s550m550s550"
+ "m550s550m550s550m550s1600m550s550m550s550"
+ "m550s550m550s550m550s1600m550s1600m550s1600"
+ "m550s550m550s550m550s1600m550s550m550s550"
+ "m550s550m550s550m550s1600m550"
+ "s55550",
+ irsend.outputStr());
+}
diff --git a/lib/IRremoteESP8266-2.5.2.03/test/ir_Lasertag_test.cpp b/lib/IRremoteESP8266-2.6.0/test/ir_Lasertag_test.cpp
similarity index 98%
rename from lib/IRremoteESP8266-2.5.2.03/test/ir_Lasertag_test.cpp
rename to lib/IRremoteESP8266-2.6.0/test/ir_Lasertag_test.cpp
index 041109fb8..bad724f76 100644
--- a/lib/IRremoteESP8266-2.5.2.03/test/ir_Lasertag_test.cpp
+++ b/lib/IRremoteESP8266-2.6.0/test/ir_Lasertag_test.cpp
@@ -20,6 +20,7 @@ TEST(TestSendLasertag, SendDataOnly) {
irsend.reset();
irsend.sendLasertag(0x1); // Red 1
EXPECT_EQ(
+ "f36000d25"
"m333s333m333s333m333s333m333s333m333s333m333s333m333s333m333s333m333"
"s333m333s333m333s333m333s666m333s100000",
irsend.outputStr());
@@ -27,6 +28,7 @@ TEST(TestSendLasertag, SendDataOnly) {
irsend.reset();
irsend.sendLasertag(0x2); // Red 2
EXPECT_EQ(
+ "f36000d25"
"m333s333m333s333m333s333m333s333m333s333m333s333m333s333"
"m333s333m333s333m333s333m333s666m666s100333",
irsend.outputStr());
@@ -38,6 +40,7 @@ TEST(TestSendLasertag, SendDataOnly) {
EXPECT_EQ(
// m364s364m332s336m384s276m332s364m332s304m416s584
// m692s724m640s360m304s332m392s612m380
+ "f36000d25"
"m333s333m333s333m333s333m333s333m333s333m333s666"
"m666s666m666s333m333s333m333s666m333s100000",
irsend.outputStr());
@@ -49,6 +52,7 @@ TEST(TestSendLasertag, SendDataOnly) {
EXPECT_EQ(
// m332s308m412s280m360s336m332s304m444s248m332s644
// m744s612m696s692m668s636m360
+ "f36000d25"
"m333s333m333s333m333s333m333s333m333s333m333s666"
"m666s666m666s666m666s666m333s100000",
irsend.outputStr());
@@ -61,6 +65,7 @@ TEST(TestSendLasertag, SendDataWithRepeat) {
irsend.reset();
irsend.sendLasertag(0x1, kLasertagBits, 1); // Red 1, one repeat.
EXPECT_EQ(
+ "f36000d25"
"m333s333m333s333m333s333m333s333m333s333m333s333m333s333m333s333"
"m333s333m333s333m333s333m333s666m333s100000"
"m333s333m333s333m333s333m333s333m333s333m333s333m333s333m333s333"
@@ -70,6 +75,7 @@ TEST(TestSendLasertag, SendDataWithRepeat) {
irsend.reset();
irsend.sendLasertag(0x52, kLasertagBits, 2); // Green 2, two repeats.
EXPECT_EQ(
+ "f36000d25"
"m333s333m333s333m333s333m333s333m333s333m333s666m666s666m666s333"
"m333s666m666s100333"
"m333s333m333s333m333s333m333s333m333s333m333s666m666s666m666s333"
@@ -86,7 +92,8 @@ TEST(TestSendLasertag, SmallestMessageSize) {
irsend.reset();
irsend.sendLasertag(0x1555); // Alternating bit pattern will be the smallest.
// i.e. 7 actual 'mark' pulses, which is a rawlen of 13.
- EXPECT_EQ("m0s333m666s666m666s666m666s666m666s666m666s666m666s666m333s100000",
+ EXPECT_EQ("f36000d25"
+ "m0s333m666s666m666s666m666s666m666s666m666s666m666s666m333s100000",
irsend.outputStr());
}
diff --git a/lib/IRremoteESP8266-2.6.0/test/ir_Lego_test.cpp b/lib/IRremoteESP8266-2.6.0/test/ir_Lego_test.cpp
new file mode 100644
index 000000000..4e859b170
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/test/ir_Lego_test.cpp
@@ -0,0 +1,196 @@
+// Copyright 2019 David Conran
+
+#include "IRrecv.h"
+#include "IRrecv_test.h"
+#include "IRsend.h"
+#include "IRsend_test.h"
+#include "gtest/gtest.h"
+
+// General housekeeping
+TEST(TestLego, Housekeeping) {
+ ASSERT_EQ("LEGOPF", typeToString(LEGOPF));
+ ASSERT_FALSE(hasACState(LEGOPF)); // Uses uint64_t, not uint8_t*.
+}
+
+// Tests for sendLego().
+
+// Test sending typical data only.
+TEST(TestSendLegoPf, SendDataOnly) {
+ IRsendTest irsend(0);
+ irsend.begin();
+
+ irsend.reset();
+ irsend.sendLegoPf(0x1234);
+ EXPECT_EQ(
+ "f38000d50"
+ "m158s1026"
+ "m158s263m158s263m158s263m158s553m158s263m158s263m158s553m158s263"
+ "m158s263m158s263m158s553m158s553m158s263m158s553m158s263m158s263"
+ "m158s70472", irsend.outputStr());
+
+ irsend.reset();
+ irsend.send(LEGOPF, 0x1234, kLegoPfBits);
+ EXPECT_EQ(
+ "f38000d50"
+ "m158s1026"
+ "m158s263m158s263m158s263m158s553m158s263m158s263m158s553m158s263"
+ "m158s263m158s263m158s553m158s553m158s263m158s553m158s263m158s263"
+ "m158s70472", irsend.outputStr());
+}
+
+// Test sending typical repeat data.
+TEST(TestSendLegoPf, SendDataWithRepeats) {
+ IRsendTest irsend(0);
+ irsend.begin();
+
+ irsend.reset();
+ irsend.sendLegoPf(0x1234, kLegoPfBits, 1);
+ EXPECT_EQ(
+ "f38000d50"
+ "m0s32000"
+ "m158s1026"
+ "m158s263m158s263m158s263m158s553m158s263m158s263m158s553m158s263"
+ "m158s263m158s263m158s553m158s553m158s263m158s553m158s263m158s263"
+ "m158s70472"
+ "m158s1026"
+ "m158s263m158s263m158s263m158s553m158s263m158s263m158s553m158s263"
+ "m158s263m158s263m158s553m158s553m158s263m158s553m158s263m158s263"
+ "m158s70472"
+ "m158s1026"
+ "m158s263m158s263m158s263m158s553m158s263m158s263m158s553m158s263"
+ "m158s263m158s263m158s553m158s553m158s263m158s553m158s263m158s263"
+ "m158s150472"
+ "m158s1026"
+ "m158s263m158s263m158s263m158s553m158s263m158s263m158s553m158s263"
+ "m158s263m158s263m158s553m158s553m158s263m158s553m158s263m158s263"
+ "m158s150472"
+ "m158s1026"
+ "m158s263m158s263m158s263m158s553m158s263m158s263m158s553m158s263"
+ "m158s263m158s263m158s553m158s553m158s263m158s553m158s263m158s263"
+ "m158s150472", irsend.outputStr());
+
+ irsend.reset();
+ irsend.sendLegoPf(0x2345, kLegoPfBits, 2);
+ EXPECT_EQ(
+ "f38000d50"
+ "m0s16000"
+ "m158s1026"
+ "m158s263m158s263m158s553m158s263m158s263m158s263m158s553m158s553"
+ "m158s263m158s553m158s263m158s263m158s263m158s553m158s263m158s553"
+ "m158s70182"
+ "m158s1026"
+ "m158s263m158s263m158s553m158s263m158s263m158s263m158s553m158s553"
+ "m158s263m158s553m158s263m158s263m158s263m158s553m158s263m158s553"
+ "m158s70182"
+ "m158s1026"
+ "m158s263m158s263m158s553m158s263m158s263m158s263m158s553m158s553"
+ "m158s263m158s553m158s263m158s263m158s263m158s553m158s263m158s553"
+ "m158s182182"
+ "m158s1026"
+ "m158s263m158s263m158s553m158s263m158s263m158s263m158s553m158s553"
+ "m158s263m158s553m158s263m158s263m158s263m158s553m158s263m158s553"
+ "m158s182182"
+ "m158s1026"
+ "m158s263m158s263m158s553m158s263m158s263m158s263m158s553m158s553"
+ "m158s263m158s553m158s263m158s263m158s263m158s553m158s263m158s553"
+ "m158s182182", irsend.outputStr());
+
+ irsend.reset();
+ irsend.sendLegoPf(0x3456, kLegoPfBits, 7);
+ EXPECT_EQ(
+ "f38000d50"
+ "m158s1026"
+ "m158s263m158s263m158s553m158s553m158s263m158s553m158s263m158s263"
+ "m158s263m158s553m158s263m158s553m158s263m158s553m158s553m158s263"
+ "m158s69892"
+ "m158s1026"
+ "m158s263m158s263m158s553m158s553m158s263m158s553m158s263m158s263"
+ "m158s263m158s553m158s263m158s553m158s263m158s553m158s553m158s263"
+ "m158s69892"
+ "m158s1026"
+ "m158s263m158s263m158s553m158s553m158s263m158s553m158s263m158s263"
+ "m158s263m158s553m158s263m158s553m158s263m158s553m158s553m158s263"
+ "m158s213892"
+ "m158s1026"
+ "m158s263m158s263m158s553m158s553m158s263m158s553m158s263m158s263"
+ "m158s263m158s553m158s263m158s553m158s263m158s553m158s553m158s263"
+ "m158s213892"
+ "m158s1026"
+ "m158s263m158s263m158s553m158s553m158s263m158s553m158s263m158s263"
+ "m158s263m158s553m158s263m158s553m158s263m158s553m158s553m158s263"
+ "m158s213892"
+ "m158s1026"
+ "m158s263m158s263m158s553m158s553m158s263m158s553m158s263m158s263"
+ "m158s263m158s553m158s263m158s553m158s263m158s553m158s553m158s263"
+ "m158s213892"
+ "m158s1026"
+ "m158s263m158s263m158s553m158s553m158s263m158s553m158s263m158s263"
+ "m158s263m158s553m158s263m158s553m158s263m158s553m158s553m158s263"
+ "m158s213892", irsend.outputStr());
+}
+
+// Tests for decodeLego().
+
+// Decode normal "synthetic" messages.
+TEST(TestDecodeLegoPf, SyntheticDecode) {
+ IRsendTest irsend(0);
+ IRrecv irrecv(0);
+ irsend.begin();
+
+ irsend.reset();
+ irsend.sendLegoPf(0x000F);
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(LEGOPF, irsend.capture.decode_type);
+ EXPECT_EQ(kLegoPfBits, irsend.capture.bits);
+ EXPECT_FALSE(irsend.capture.repeat);
+ EXPECT_EQ(0x000F, irsend.capture.value);
+ EXPECT_EQ(1, irsend.capture.address);
+ EXPECT_EQ(0, irsend.capture.command);
+
+ irsend.reset();
+ irsend.sendLegoPf(0x100E);
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(LEGOPF, irsend.capture.decode_type);
+ EXPECT_EQ(kLegoPfBits, irsend.capture.bits);
+ EXPECT_FALSE(irsend.capture.repeat);
+ EXPECT_EQ(0x100E, irsend.capture.value);
+ EXPECT_EQ(2, irsend.capture.address);
+ EXPECT_EQ(0, irsend.capture.command);
+
+ irsend.reset();
+ irsend.sendLegoPf(0x221E);
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(LEGOPF, irsend.capture.decode_type);
+ EXPECT_EQ(kLegoPfBits, irsend.capture.bits);
+ EXPECT_FALSE(irsend.capture.repeat);
+ EXPECT_EQ(0x221E, irsend.capture.value);
+ EXPECT_EQ(3, irsend.capture.address);
+ EXPECT_EQ(0x21, irsend.capture.command);
+
+ // Test a bad LRC is not matched.
+ irsend.reset();
+ irsend.sendLegoPf(0x001F); // LRC should be 0xE, not 0xF.
+ irsend.makeDecodeResult();
+ irrecv.decode(&irsend.capture);
+ EXPECT_NE(LEGOPF, irsend.capture.decode_type);
+}
+
+// Decode normal "synthetic" message with releats.
+TEST(TestDecodeLegoPf, SyntheticDecodeWithRepeat) {
+ IRsendTest irsend(0);
+ IRrecv irrecv(0);
+ irsend.begin();
+
+ irsend.reset();
+ irsend.sendLegoPf(0x330F, kLegoPfBits, 1);
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(LEGOPF, irsend.capture.decode_type);
+ EXPECT_EQ(kLegoPfBits, irsend.capture.bits);
+ EXPECT_EQ(0x330F, irsend.capture.value);
+ EXPECT_EQ(4, irsend.capture.address);
+ EXPECT_EQ(0x30, irsend.capture.command);
+}
diff --git a/lib/IRremoteESP8266-2.5.2.03/test/ir_Lutron_test.cpp b/lib/IRremoteESP8266-2.6.0/test/ir_Lutron_test.cpp
similarity index 95%
rename from lib/IRremoteESP8266-2.5.2.03/test/ir_Lutron_test.cpp
rename to lib/IRremoteESP8266-2.6.0/test/ir_Lutron_test.cpp
index 6c99b9904..d682967ca 100644
--- a/lib/IRremoteESP8266-2.5.2.03/test/ir_Lutron_test.cpp
+++ b/lib/IRremoteESP8266-2.6.0/test/ir_Lutron_test.cpp
@@ -11,17 +11,19 @@ TEST(TestSendLutron, SendDataOnly) {
IRsendTest irsend(0);
irsend.begin();
irsend.sendLutron(0);
- EXPECT_EQ("m2288s230080", irsend.outputStr());
+ EXPECT_EQ("f40000d40m2288s230080", irsend.outputStr());
irsend.sendLutron(0xAAAAAAAAA); // Longest possible sequence. (I think)
EXPECT_EQ(
+ "f40000d40"
"m2288s2288m2288s2288m2288s2288m2288s2288m2288s2288m2288s2288m2288s2288"
"m2288s2288m2288s2288m2288s2288m2288s2288m2288s2288m2288s2288m2288s2288"
"m2288s2288m2288s2288m2288s2288m2288s152288",
irsend.outputStr());
irsend.sendLutron(0x7FFFFFFFF);
- EXPECT_EQ("m82368s150000", irsend.outputStr());
+ EXPECT_EQ("f40000d40m82368s150000", irsend.outputStr());
irsend.sendLutron(0x7F88BD120);
EXPECT_EQ(
+ "f40000d40"
"m20592s6864m2288s6864m2288s2288m9152s2288m2288s6864m2288s4576m2288"
"s161440",
irsend.outputStr());
@@ -34,12 +36,14 @@ TEST(TestSendLutron, SendWithRepeats) {
// Send a command with 0 repeats.
irsend.sendLutron(0x7F88BD120, kLutronBits, 0);
EXPECT_EQ(
+ "f40000d40"
"m20592s6864m2288s6864m2288s2288m9152s2288m2288s6864m2288s4576m2288"
"s161440",
irsend.outputStr());
// Send a command with 1 repeat.
irsend.sendLutron(0x7F88BD120, kLutronBits, 1);
EXPECT_EQ(
+ "f40000d40"
"m20592s6864m2288s6864m2288s2288m9152s2288m2288s6864m2288s4576m2288"
"s161440"
"m20592s6864m2288s6864m2288s2288m9152s2288m2288s6864m2288s4576m2288"
@@ -48,6 +52,7 @@ TEST(TestSendLutron, SendWithRepeats) {
// Send a command with 3 repeats.
irsend.sendLutron(0x7F88BD120, kLutronBits, 3);
EXPECT_EQ(
+ "f40000d40"
"m20592s6864m2288s6864m2288s2288m9152s2288m2288s6864m2288s4576m2288"
"s161440"
"m20592s6864m2288s6864m2288s2288m9152s2288m2288s6864m2288s4576m2288"
diff --git a/lib/IRremoteESP8266-2.5.2.03/test/ir_MWM_test.cpp b/lib/IRremoteESP8266-2.6.0/test/ir_MWM_test.cpp
similarity index 99%
rename from lib/IRremoteESP8266-2.5.2.03/test/ir_MWM_test.cpp
rename to lib/IRremoteESP8266-2.6.0/test/ir_MWM_test.cpp
index 9ecd0eac1..2ca69ac83 100644
--- a/lib/IRremoteESP8266-2.5.2.03/test/ir_MWM_test.cpp
+++ b/lib/IRremoteESP8266-2.6.0/test/ir_MWM_test.cpp
@@ -36,6 +36,7 @@ TEST(TestSendMWM, SendDataOnly) {
*/
irsend.sendMWM(test1, sizeof(test1), 0);
EXPECT_EQ(
+ "f38000d25"
"m834s834m417s417m834s834"
"m417s417m834s834m1251s417"
"m2085s417m1251s417"
@@ -65,6 +66,7 @@ TEST(TestSendMWM, SendDataOnly) {
};
irsend.sendMWM(test2, sizeof(test2), 0);
EXPECT_EQ(
+ "f38000d25"
"m417s417m834s834m834s834"
"m834s834m834s417m834s417"
"m834s834m834s834m417s417"
diff --git a/lib/IRremoteESP8266-2.5.2.03/test/ir_Magiquest_test.cpp b/lib/IRremoteESP8266-2.6.0/test/ir_Magiquest_test.cpp
similarity index 99%
rename from lib/IRremoteESP8266-2.5.2.03/test/ir_Magiquest_test.cpp
rename to lib/IRremoteESP8266-2.6.0/test/ir_Magiquest_test.cpp
index e1c3da83d..bbc5f3366 100644
--- a/lib/IRremoteESP8266-2.5.2.03/test/ir_Magiquest_test.cpp
+++ b/lib/IRremoteESP8266-2.6.0/test/ir_Magiquest_test.cpp
@@ -26,6 +26,7 @@ TEST(TestSendMagiQuest, SendDataOnly) {
irsend.reset();
irsend.sendMagiQuest(0x0);
EXPECT_EQ(
+ "f36000d50"
"m280s850m280s850m280s850m280s850m280s850m280s850m280s850m280s850"
"m280s850m280s850m280s850m280s850m280s850m280s850m280s850m280s850"
"m280s850m280s850m280s850m280s850m280s850m280s850m280s850m280s850"
@@ -37,6 +38,7 @@ TEST(TestSendMagiQuest, SendDataOnly) {
irsend.reset();
irsend.sendMagiQuest(0x123456789ABC);
EXPECT_EQ(
+ "f36000d50"
"m280s850m280s850m280s850m280s850m280s850m280s850m280s850m280s850"
"m280s850m280s850m280s850m580s600m280s850m280s850m580s600m280s850"
"m280s850m280s850m580s600m580s600m280s850m580s600m280s850m280s850"
@@ -55,6 +57,7 @@ TEST(TestSendMagiQuest, SendWithRepeats) {
irsend.reset();
irsend.sendMagiQuest(0x12345678ABCD, kMagiquestBits, 2); // two repeats.
EXPECT_EQ(
+ "f36000d50"
"m280s850m280s850m280s850m280s850m280s850m280s850m280s850m280s850"
"m280s850m280s850m280s850m580s600m280s850m280s850m580s600m280s850"
"m280s850m280s850m580s600m580s600m280s850m580s600m280s850m280s850"
diff --git a/lib/IRremoteESP8266-2.5.2.03/test/ir_Midea_test.cpp b/lib/IRremoteESP8266-2.6.0/test/ir_Midea_test.cpp
similarity index 99%
rename from lib/IRremoteESP8266-2.5.2.03/test/ir_Midea_test.cpp
rename to lib/IRremoteESP8266-2.6.0/test/ir_Midea_test.cpp
index 5d5f5e932..ced3ea10c 100644
--- a/lib/IRremoteESP8266-2.5.2.03/test/ir_Midea_test.cpp
+++ b/lib/IRremoteESP8266-2.6.0/test/ir_Midea_test.cpp
@@ -15,6 +15,7 @@ TEST(TestSendMidea, SendDataOnly) {
irsend.reset();
irsend.sendMidea(0x0);
EXPECT_EQ(
+ "f38000d50"
"m4480s4480"
"m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
"m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
@@ -36,6 +37,7 @@ TEST(TestSendMidea, SendDataOnly) {
irsend.reset();
irsend.sendMidea(0x55AA55AA55AA);
EXPECT_EQ(
+ "f38000d50"
"m4480s4480"
"m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680"
"m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560"
@@ -57,6 +59,7 @@ TEST(TestSendMidea, SendDataOnly) {
irsend.reset();
irsend.sendMidea(0xFFFFFFFFFFFF);
EXPECT_EQ(
+ "f38000d50"
"m4480s4480"
"m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680"
"m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680"
@@ -84,6 +87,7 @@ TEST(TestSendMidea, SendWithRepeats) {
irsend.reset();
irsend.sendMidea(0x55AA55AA55AA, kMideaBits, 1); // 1 repeat.
EXPECT_EQ(
+ "f38000d50"
"m4480s4480"
"m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680"
"m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560"
@@ -119,6 +123,7 @@ TEST(TestSendMidea, SendWithRepeats) {
irsend.outputStr());
irsend.sendMidea(0x55AA55AA55AA, kMideaBits, 2); // 2 repeats.
EXPECT_EQ(
+ "f38000d50"
"m4480s4480"
"m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680"
"m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560"
@@ -178,6 +183,7 @@ TEST(TestSendMidea, SendUnusualSize) {
irsend.reset();
irsend.sendMidea(0x0, 8);
EXPECT_EQ(
+ "f38000d50"
"m4480s4480"
"m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
"m560s5600"
@@ -189,6 +195,7 @@ TEST(TestSendMidea, SendUnusualSize) {
irsend.reset();
irsend.sendMidea(0x1234567890ABCDEF, 64);
EXPECT_EQ(
+ "f38000d50"
"m4480s4480"
"m560s560m560s560m560s560m560s1680m560s560m560s560m560s1680m560s560"
"m560s560m560s560m560s1680m560s1680m560s560m560s1680m560s560m560s560"
diff --git a/lib/IRremoteESP8266-2.6.0/test/ir_MitsubishiHeavy_test.cpp b/lib/IRremoteESP8266-2.6.0/test/ir_MitsubishiHeavy_test.cpp
new file mode 100644
index 000000000..340a04078
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/test/ir_MitsubishiHeavy_test.cpp
@@ -0,0 +1,851 @@
+// Copyright 2019 David Conran
+
+#include "ir_MitsubishiHeavy.h"
+#include "IRrecv.h"
+#include "IRrecv_test.h"
+#include "IRremoteESP8266.h"
+#include "IRsend.h"
+#include "IRsend_test.h"
+#include "gtest/gtest.h"
+
+// General housekeeping
+TEST(TestMitsubishiHeavy, Housekeeping) {
+ ASSERT_EQ("MITSUBISHI_HEAVY_88", typeToString(MITSUBISHI_HEAVY_88));
+ ASSERT_TRUE(hasACState(MITSUBISHI_HEAVY_88));
+ ASSERT_EQ("MITSUBISHI_HEAVY_152", typeToString(MITSUBISHI_HEAVY_152));
+ ASSERT_TRUE(hasACState(MITSUBISHI_HEAVY_152));
+}
+
+// Tests for IRMitsubishiHeavy152Ac class.
+
+TEST(TestMitsubishiHeavy152AcClass, Power) {
+ IRMitsubishiHeavy152Ac ac(0);
+ ac.begin();
+
+ 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(TestMitsubishiHeavy152AcClass, Temperature) {
+ IRMitsubishiHeavy152Ac ac(0);
+ ac.begin();
+
+ ac.setMode(kMitsubishiHeavyCool);
+
+ ac.setTemp(0);
+ EXPECT_EQ(kMitsubishiHeavyMinTemp, ac.getTemp());
+
+ ac.setTemp(255);
+ EXPECT_EQ(kMitsubishiHeavyMaxTemp, ac.getTemp());
+
+ ac.setTemp(kMitsubishiHeavyMinTemp);
+ EXPECT_EQ(kMitsubishiHeavyMinTemp, ac.getTemp());
+
+ ac.setTemp(kMitsubishiHeavyMaxTemp);
+ EXPECT_EQ(kMitsubishiHeavyMaxTemp, ac.getTemp());
+
+ ac.setTemp(kMitsubishiHeavyMinTemp - 1);
+ EXPECT_EQ(kMitsubishiHeavyMinTemp, ac.getTemp());
+
+ ac.setTemp(kMitsubishiHeavyMaxTemp + 1);
+ EXPECT_EQ(kMitsubishiHeavyMaxTemp, ac.getTemp());
+
+ ac.setTemp(19);
+ EXPECT_EQ(19, ac.getTemp());
+
+ ac.setTemp(21);
+ EXPECT_EQ(21, ac.getTemp());
+
+ ac.setTemp(25);
+ EXPECT_EQ(25, ac.getTemp());
+
+ ac.setTemp(29);
+ EXPECT_EQ(29, ac.getTemp());
+}
+
+TEST(TestMitsubishiHeavy152AcClass, OperatingMode) {
+ IRMitsubishiHeavy152Ac ac(0);
+ ac.begin();
+
+ ac.setMode(kMitsubishiHeavyAuto);
+ EXPECT_EQ(kMitsubishiHeavyAuto, ac.getMode());
+
+ ac.setMode(kMitsubishiHeavyCool);
+ EXPECT_EQ(kMitsubishiHeavyCool, ac.getMode());
+
+ ac.setMode(kMitsubishiHeavyHeat);
+ EXPECT_EQ(kMitsubishiHeavyHeat, ac.getMode());
+
+ ac.setMode(kMitsubishiHeavyDry);
+ EXPECT_EQ(kMitsubishiHeavyDry, ac.getMode());
+
+ ac.setMode(kMitsubishiHeavyFan);
+ EXPECT_EQ(kMitsubishiHeavyFan, ac.getMode());
+
+ ac.setMode(kMitsubishiHeavyHeat + 1);
+ EXPECT_EQ(kMitsubishiHeavyAuto, ac.getMode());
+
+ ac.setMode(255);
+ EXPECT_EQ(kMitsubishiHeavyAuto, ac.getMode());
+}
+
+
+TEST(TestMitsubishiHeavy152AcClass, Filter) {
+ IRMitsubishiHeavy152Ac ac(0);
+ ac.begin();
+
+ ac.setFilter(true);
+ EXPECT_TRUE(ac.getFilter());
+
+ ac.setFilter(false);
+ EXPECT_FALSE(ac.getFilter());
+
+ ac.setFilter(true);
+ EXPECT_TRUE(ac.getFilter());
+}
+
+TEST(TestMitsubishiHeavy152AcClass, Turbo) {
+ IRMitsubishiHeavy152Ac ac(0);
+ ac.begin();
+
+ ac.setTurbo(true);
+ EXPECT_TRUE(ac.getTurbo());
+
+ ac.setTurbo(false);
+ EXPECT_FALSE(ac.getTurbo());
+
+ ac.setTurbo(true);
+ EXPECT_TRUE(ac.getTurbo());
+}
+
+TEST(TestMitsubishiHeavy152AcClass, Econo) {
+ IRMitsubishiHeavy152Ac ac(0);
+ ac.begin();
+
+ ac.setEcono(true);
+ EXPECT_TRUE(ac.getEcono());
+
+ ac.setEcono(false);
+ EXPECT_FALSE(ac.getEcono());
+
+ ac.setEcono(true);
+ EXPECT_TRUE(ac.getEcono());
+}
+
+TEST(TestMitsubishiHeavy152AcClass, 3D) {
+ IRMitsubishiHeavy152Ac ac(0);
+ ac.begin();
+
+ ac.set3D(true);
+ EXPECT_TRUE(ac.get3D());
+
+ ac.set3D(false);
+ EXPECT_FALSE(ac.get3D());
+
+ ac.set3D(true);
+ EXPECT_TRUE(ac.get3D());
+}
+
+TEST(TestMitsubishiHeavy152AcClass, Night) {
+ IRMitsubishiHeavy152Ac ac(0);
+ ac.begin();
+
+ ac.setNight(true);
+ EXPECT_TRUE(ac.getNight());
+
+ ac.setNight(false);
+ EXPECT_FALSE(ac.getNight());
+
+ ac.setNight(true);
+ EXPECT_TRUE(ac.getNight());
+}
+
+TEST(TestMitsubishiHeavy152AcClass, Clean) {
+ IRMitsubishiHeavy152Ac ac(0);
+ ac.begin();
+
+ ac.setClean(true);
+ EXPECT_TRUE(ac.getClean());
+
+ ac.setClean(false);
+ EXPECT_FALSE(ac.getClean());
+
+ ac.setClean(true);
+ EXPECT_TRUE(ac.getClean());
+}
+
+TEST(TestMitsubishiHeavy152AcClass, FanSpeed) {
+ IRMitsubishiHeavy152Ac ac(0);
+ ac.begin();
+
+ ac.setFan(kMitsubishiHeavy152FanLow);
+ EXPECT_EQ(kMitsubishiHeavy152FanLow, ac.getFan());
+
+ ac.setFan(kMitsubishiHeavy152FanAuto);
+ EXPECT_EQ(kMitsubishiHeavy152FanAuto, ac.getFan());
+
+
+ ac.setFan(255);
+ EXPECT_EQ(kMitsubishiHeavy152FanAuto, ac.getFan());
+
+ ac.setFan(kMitsubishiHeavy152FanMax);
+ EXPECT_EQ(kMitsubishiHeavy152FanMax, ac.getFan());
+
+ ac.setFan(kMitsubishiHeavy152FanMax + 1);
+ EXPECT_EQ(kMitsubishiHeavy152FanAuto, ac.getFan());
+
+ ac.setFan(kMitsubishiHeavy152FanMax - 1);
+ EXPECT_EQ(kMitsubishiHeavy152FanMax - 1, ac.getFan());
+
+ ac.setFan(kMitsubishiHeavy152FanLow + 1);
+ EXPECT_EQ(kMitsubishiHeavy152FanLow + 1, ac.getFan());
+
+ ac.setFan(kMitsubishiHeavy152FanEcono);
+ EXPECT_EQ(kMitsubishiHeavy152FanEcono, ac.getFan());
+
+ ac.setFan(kMitsubishiHeavy152FanTurbo);
+ EXPECT_EQ(kMitsubishiHeavy152FanTurbo, ac.getFan());
+}
+
+TEST(TestMitsubishiHeavy152AcClass, VerticalSwing) {
+ IRMitsubishiHeavy152Ac ac(0);
+ ac.begin();
+ ac.setSwingVertical(kMitsubishiHeavy152SwingVAuto);
+ EXPECT_EQ(kMitsubishiHeavy152SwingVAuto, ac.getSwingVertical());
+
+ ac.setSwingVertical(kMitsubishiHeavy152SwingVHighest);
+ EXPECT_EQ(kMitsubishiHeavy152SwingVHighest, ac.getSwingVertical());
+
+ ac.setSwingVertical(kMitsubishiHeavy152SwingVHighest + 1);
+ EXPECT_EQ(kMitsubishiHeavy152SwingVHighest + 1, ac.getSwingVertical());
+
+ ac.setSwingVertical(kMitsubishiHeavy152SwingVOff);
+ EXPECT_EQ(kMitsubishiHeavy152SwingVOff, ac.getSwingVertical());
+
+ ac.setSwingVertical(kMitsubishiHeavy152SwingVOff + 1);
+ EXPECT_EQ(kMitsubishiHeavy152SwingVOff, ac.getSwingVertical());
+
+ // Out of bounds.
+ ac.setSwingVertical(255);
+ EXPECT_EQ(kMitsubishiHeavy152SwingVOff, ac.getSwingVertical());
+}
+
+TEST(TestMitsubishiHeavy152AcClass, HorizontalSwing) {
+ IRMitsubishiHeavy152Ac ac(0);
+ ac.begin();
+ ac.setSwingHorizontal(kMitsubishiHeavy152SwingHAuto);
+ EXPECT_EQ(kMitsubishiHeavy152SwingHAuto, ac.getSwingHorizontal());
+
+ ac.setSwingHorizontal(kMitsubishiHeavy152SwingHLeftMax);
+ EXPECT_EQ(kMitsubishiHeavy152SwingHLeftMax, ac.getSwingHorizontal());
+
+ ac.setSwingHorizontal(kMitsubishiHeavy152SwingHLeftMax + 1);
+ EXPECT_EQ(kMitsubishiHeavy152SwingHLeftMax + 1, ac.getSwingHorizontal());
+
+ ac.setSwingHorizontal(kMitsubishiHeavy152SwingHRightMax);
+ EXPECT_EQ(kMitsubishiHeavy152SwingHRightMax, ac.getSwingHorizontal());
+
+ ac.setSwingHorizontal(kMitsubishiHeavy152SwingHRightMax - 1);
+ EXPECT_EQ(kMitsubishiHeavy152SwingHRightMax - 1, ac.getSwingHorizontal());
+
+ ac.setSwingHorizontal(kMitsubishiHeavy152SwingHOff);
+ EXPECT_EQ(kMitsubishiHeavy152SwingHOff, ac.getSwingHorizontal());
+
+ ac.setSwingHorizontal(kMitsubishiHeavy152SwingHOff + 1);
+ EXPECT_EQ(kMitsubishiHeavy152SwingHOff, ac.getSwingHorizontal());
+
+ // Out of bounds.
+ ac.setSwingHorizontal(255);
+ EXPECT_EQ(kMitsubishiHeavy152SwingHOff, ac.getSwingHorizontal());
+}
+
+TEST(TestMitsubishiHeavy152AcClass, Checksums) {
+ IRMitsubishiHeavy152Ac ac(0);
+ ac.begin();
+
+ EXPECT_TRUE(ac.validChecksum(ac.getRaw()));
+
+ uint8_t expected[kMitsubishiHeavy152StateLength] = {
+ 0xAD, 0x51, 0x3C, 0xE5, 0x1A, 0x0C, 0xF3, 0x07,
+ 0xF8, 0x04, 0xFB, 0x00, 0xFF, 0x00, 0xFF, 0x00,
+ 0xFF, 0x80, 0x7F};
+ EXPECT_TRUE(IRMitsubishiHeavy152Ac::validChecksum(expected));
+
+ // Screw up the "checksum" to test it fails.
+ expected[kMitsubishiHeavy152StateLength - 1] = 0x55;
+ EXPECT_FALSE(IRMitsubishiHeavy152Ac::validChecksum(expected));
+ // getting the after getRaw() should repair it.
+ ac.setRaw(expected);
+ EXPECT_TRUE(ac.validChecksum(ac.getRaw()));
+ EXPECT_TRUE(IRMitsubishiHeavy152Ac::validChecksum(ac.getRaw()));
+}
+
+TEST(TestMitsubishiHeavy152AcClass, HumanReadable) {
+ IRMitsubishiHeavy152Ac ac(0);
+
+ EXPECT_EQ(
+ "Power: Off, Mode: 0 (Auto), Temp: 17C, Fan: 0 (Auto), "
+ "Swing (V): 0 (Auto), Swing (H): 0 (Auto), Silent: Off, Turbo: Off, "
+ "Econo: Off, Night: Off, Filter: Off, 3D: Off, Clean: Off",
+ ac.toString());
+ ac.on();
+ ac.setMode(kMitsubishiHeavyCool);
+ ac.setTemp(kMitsubishiHeavyMinTemp);
+ ac.setFan(kMitsubishiHeavy152FanMax);
+ ac.setFilter(true);
+ ac.setNight(true);
+ ac.setTurbo(false);
+ ac.setSilent(true);
+ ac.setEcono(false);
+ ac.set3D(true);
+ ac.setSwingVertical(kMitsubishiHeavy152SwingVAuto);
+ ac.setSwingHorizontal(kMitsubishiHeavy152SwingHAuto);
+ EXPECT_EQ(
+ "Power: On, Mode: 1 (Cool), Temp: 17C, Fan: 4 (Max), "
+ "Swing (V): 0 (Auto), Swing (H): 0 (Auto), Silent: On, Turbo: Off, "
+ "Econo: Off, Night: On, Filter: On, 3D: On, Clean: Off",
+ ac.toString());
+
+ ac.setMode(kMitsubishiHeavyHeat);
+ ac.setTemp(kMitsubishiHeavyMaxTemp);
+ ac.setFilter(true);
+ ac.setNight(false);
+ ac.setTurbo(true);
+ ac.setEcono(false);
+ ac.setSilent(false);
+ ac.set3D(false);
+ ac.setSwingVertical(kMitsubishiHeavy152SwingVLowest);
+ ac.setSwingHorizontal(kMitsubishiHeavy152SwingHLeftMax);
+
+ EXPECT_EQ(
+ "Power: On, Mode: 4 (Heat), Temp: 31C, Fan: 8 (Turbo), "
+ "Swing (V): 5 (Lowest), Swing (H): 1 (Max Left), Silent: Off, Turbo: On, "
+ "Econo: Off, Night: Off, Filter: On, 3D: Off, Clean: Off",
+ ac.toString());
+
+ ac.setClean(true);
+ ac.setEcono(true);
+ ac.setMode(kMitsubishiHeavyAuto);
+ ac.setSwingVertical(kMitsubishiHeavy152SwingVOff);
+
+ EXPECT_EQ(
+ "Power: On, Mode: 0 (Auto), Temp: 31C, Fan: 6 (Econo), "
+ "Swing (V): 6 (Off), Swing (H): 1 (Max Left), Silent: Off, "
+ "Turbo: Off, Econo: On, Night: Off, Filter: On, 3D: Off, Clean: On",
+ ac.toString());
+
+ ac.setClean(false);
+ ac.setTemp(25);
+ ac.setEcono(false);
+ ac.setMode(kMitsubishiHeavyDry);
+ ac.setSwingHorizontal(kMitsubishiHeavy152SwingHLeftRight);
+ EXPECT_EQ(
+ "Power: On, Mode: 2 (Dry), Temp: 25C, Fan: 0 (Auto), "
+ "Swing (V): 6 (Off), Swing (H): 7 (Left Right), Silent: Off, "
+ "Turbo: Off, Econo: Off, Night: Off, Filter: Off, 3D: Off, Clean: Off",
+ ac.toString());
+}
+
+TEST(TestMitsubishiHeavy152AcClass, ReconstructKnownExample) {
+ IRMitsubishiHeavy152Ac ac(0);
+
+ EXPECT_EQ(
+ "Power: Off, Mode: 0 (Auto), Temp: 17C, Fan: 0 (Auto), "
+ "Swing (V): 0 (Auto), Swing (H): 0 (Auto), Silent: Off, Turbo: Off, "
+ "Econo: Off, Night: Off, Filter: Off, 3D: Off, Clean: Off",
+ ac.toString());
+ ac.on();
+ ac.setMode(kMitsubishiHeavyHeat);
+ ac.setTemp(24);
+ ac.setFan(kMitsubishiHeavy152FanMax);
+ ac.setFilter(true);
+ ac.setNight(false);
+ ac.setTurbo(false);
+ ac.setSilent(false);
+ ac.setEcono(false);
+ ac.set3D(false);
+ ac.setClean(false);
+ ac.setSwingVertical(kMitsubishiHeavy152SwingVAuto);
+ ac.setSwingHorizontal(kMitsubishiHeavy152SwingHAuto);
+ EXPECT_EQ(
+ "Power: On, Mode: 4 (Heat), Temp: 24C, Fan: 4 (Max), "
+ "Swing (V): 0 (Auto), Swing (H): 0 (Auto), Silent: Off, Turbo: Off, "
+ "Econo: Off, Night: Off, Filter: Off, 3D: Off, Clean: Off",
+ ac.toString());
+
+ uint8_t expected[kMitsubishiHeavy152StateLength] = {
+ 0xAD, 0x51, 0x3C, 0xE5, 0x1A, 0x0C, 0xF3, 0x07,
+ 0xF8, 0x04, 0xFB, 0x00, 0xFF, 0x00, 0xFF, 0x00,
+ 0xFF, 0x80, 0x7F};
+ EXPECT_STATE_EQ(expected, ac.getRaw(), kMitsubishiHeavy152Bits);
+}
+
+// Tests for IRMitsubishiHeavy88Ac class.
+
+TEST(TestMitsubishiHeavy88AcClass, Power) {
+ IRMitsubishiHeavy88Ac ac(0);
+ ac.begin();
+
+ 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(TestMitsubishiHeavy88AcClass, Temperature) {
+ IRMitsubishiHeavy88Ac ac(0);
+ ac.begin();
+
+ ac.setMode(kMitsubishiHeavyCool);
+
+ ac.setTemp(0);
+ EXPECT_EQ(kMitsubishiHeavyMinTemp, ac.getTemp());
+
+ ac.setTemp(255);
+ EXPECT_EQ(kMitsubishiHeavyMaxTemp, ac.getTemp());
+
+ ac.setTemp(kMitsubishiHeavyMinTemp);
+ EXPECT_EQ(kMitsubishiHeavyMinTemp, ac.getTemp());
+
+ ac.setTemp(kMitsubishiHeavyMaxTemp);
+ EXPECT_EQ(kMitsubishiHeavyMaxTemp, ac.getTemp());
+
+ ac.setTemp(kMitsubishiHeavyMinTemp - 1);
+ EXPECT_EQ(kMitsubishiHeavyMinTemp, ac.getTemp());
+
+ ac.setTemp(kMitsubishiHeavyMaxTemp + 1);
+ EXPECT_EQ(kMitsubishiHeavyMaxTemp, ac.getTemp());
+
+ ac.setTemp(19);
+ EXPECT_EQ(19, ac.getTemp());
+
+ ac.setTemp(21);
+ EXPECT_EQ(21, ac.getTemp());
+
+ ac.setTemp(25);
+ EXPECT_EQ(25, ac.getTemp());
+
+ ac.setTemp(29);
+ EXPECT_EQ(29, ac.getTemp());
+}
+
+TEST(TestMitsubishiHeavy88AcClass, OperatingMode) {
+ IRMitsubishiHeavy88Ac ac(0);
+ ac.begin();
+
+ ac.setMode(kMitsubishiHeavyAuto);
+ EXPECT_EQ(kMitsubishiHeavyAuto, ac.getMode());
+
+ ac.setMode(kMitsubishiHeavyCool);
+ EXPECT_EQ(kMitsubishiHeavyCool, ac.getMode());
+
+ ac.setMode(kMitsubishiHeavyHeat);
+ EXPECT_EQ(kMitsubishiHeavyHeat, ac.getMode());
+
+ ac.setMode(kMitsubishiHeavyDry);
+ EXPECT_EQ(kMitsubishiHeavyDry, ac.getMode());
+
+ ac.setMode(kMitsubishiHeavyFan);
+ EXPECT_EQ(kMitsubishiHeavyFan, ac.getMode());
+
+ ac.setMode(kMitsubishiHeavyHeat + 1);
+ EXPECT_EQ(kMitsubishiHeavyAuto, ac.getMode());
+
+ ac.setMode(255);
+ EXPECT_EQ(kMitsubishiHeavyAuto, ac.getMode());
+}
+
+TEST(TestMitsubishiHeavy88AcClass, Turbo) {
+ IRMitsubishiHeavy88Ac ac(0);
+ ac.begin();
+
+ ac.setTurbo(true);
+ EXPECT_TRUE(ac.getTurbo());
+
+ ac.setTurbo(false);
+ EXPECT_FALSE(ac.getTurbo());
+
+ ac.setTurbo(true);
+ EXPECT_TRUE(ac.getTurbo());
+}
+
+TEST(TestMitsubishiHeavy88AcClass, Econo) {
+ IRMitsubishiHeavy88Ac ac(0);
+ ac.begin();
+
+ ac.setEcono(true);
+ EXPECT_TRUE(ac.getEcono());
+
+ ac.setEcono(false);
+ EXPECT_FALSE(ac.getEcono());
+
+ ac.setEcono(true);
+ EXPECT_TRUE(ac.getEcono());
+}
+
+TEST(TestMitsubishiHeavy88AcClass, 3D) {
+ IRMitsubishiHeavy88Ac ac(0);
+ ac.begin();
+
+ ac.set3D(true);
+ EXPECT_TRUE(ac.get3D());
+
+ ac.set3D(false);
+ EXPECT_FALSE(ac.get3D());
+
+ ac.set3D(true);
+ EXPECT_TRUE(ac.get3D());
+}
+
+TEST(TestMitsubishiHeavy88AcClass, Clean) {
+ IRMitsubishiHeavy88Ac ac(0);
+ ac.begin();
+
+ ac.setClean(true);
+ EXPECT_TRUE(ac.getClean());
+
+ ac.setClean(false);
+ EXPECT_FALSE(ac.getClean());
+
+ ac.setClean(true);
+ EXPECT_TRUE(ac.getClean());
+}
+
+TEST(TestMitsubishiHeavy88AcClass, FanSpeed) {
+ IRMitsubishiHeavy88Ac ac(0);
+ ac.begin();
+
+ ac.setFan(kMitsubishiHeavy88FanLow);
+ EXPECT_EQ(kMitsubishiHeavy88FanLow, ac.getFan());
+
+ ac.setFan(kMitsubishiHeavy88FanAuto);
+ EXPECT_EQ(kMitsubishiHeavy88FanAuto, ac.getFan());
+
+
+ ac.setFan(255);
+ EXPECT_EQ(kMitsubishiHeavy88FanAuto, ac.getFan());
+
+ ac.setFan(kMitsubishiHeavy88FanHigh);
+ EXPECT_EQ(kMitsubishiHeavy88FanHigh, ac.getFan());
+
+ ac.setFan(kMitsubishiHeavy88FanHigh + 1);
+ EXPECT_EQ(kMitsubishiHeavy88FanAuto, ac.getFan());
+
+ ac.setFan(kMitsubishiHeavy88FanHigh - 1);
+ EXPECT_EQ(kMitsubishiHeavy88FanHigh - 1, ac.getFan());
+
+ ac.setFan(kMitsubishiHeavy88FanLow + 1);
+ EXPECT_EQ(kMitsubishiHeavy88FanLow + 1, ac.getFan());
+
+ ac.setFan(kMitsubishiHeavy88FanEcono);
+ EXPECT_EQ(kMitsubishiHeavy88FanEcono, ac.getFan());
+
+ ac.setFan(kMitsubishiHeavy88FanTurbo);
+ EXPECT_EQ(kMitsubishiHeavy88FanTurbo, ac.getFan());
+}
+
+TEST(TestMitsubishiHeavy88AcClass, VerticalSwing) {
+ IRMitsubishiHeavy88Ac ac(0);
+ ac.begin();
+ ac.setSwingVertical(kMitsubishiHeavy88SwingVAuto);
+ EXPECT_EQ(kMitsubishiHeavy88SwingVAuto, ac.getSwingVertical());
+
+ ac.setSwingVertical(kMitsubishiHeavy88SwingVHighest);
+ EXPECT_EQ(kMitsubishiHeavy88SwingVHighest, ac.getSwingVertical());
+
+ ac.setSwingVertical(kMitsubishiHeavy88SwingVOff);
+ EXPECT_EQ(kMitsubishiHeavy88SwingVOff, ac.getSwingVertical());
+
+ ac.setSwingVertical(kMitsubishiHeavy88SwingVHighest + 1);
+ EXPECT_EQ(kMitsubishiHeavy88SwingVOff, ac.getSwingVertical());
+
+ ac.setSwingVertical(kMitsubishiHeavy88SwingVOff + 1);
+ EXPECT_EQ(kMitsubishiHeavy88SwingVOff, ac.getSwingVertical());
+
+ // Out of bounds.
+ ac.setSwingVertical(255);
+ EXPECT_EQ(kMitsubishiHeavy88SwingVOff, ac.getSwingVertical());
+}
+
+TEST(TestMitsubishiHeavy88AcClass, HorizontalSwing) {
+ IRMitsubishiHeavy88Ac ac(0);
+ ac.begin();
+ ac.setSwingHorizontal(kMitsubishiHeavy88SwingHAuto);
+ EXPECT_EQ(kMitsubishiHeavy88SwingHAuto, ac.getSwingHorizontal());
+
+ ac.setSwingHorizontal(kMitsubishiHeavy88SwingHLeftMax);
+ EXPECT_EQ(kMitsubishiHeavy88SwingHLeftMax, ac.getSwingHorizontal());
+
+ ac.setSwingHorizontal(kMitsubishiHeavy88SwingHLeftMax + 1);
+ EXPECT_EQ(kMitsubishiHeavy88SwingHOff, ac.getSwingHorizontal());
+
+ ac.setSwingHorizontal(kMitsubishiHeavy88SwingHRightMax);
+ EXPECT_EQ(kMitsubishiHeavy88SwingHRightMax, ac.getSwingHorizontal());
+
+ ac.setSwingHorizontal(kMitsubishiHeavy88SwingHRightMax - 1);
+ EXPECT_EQ(kMitsubishiHeavy88SwingHOff, ac.getSwingHorizontal());
+
+ ac.setSwingHorizontal(kMitsubishiHeavy88SwingHOff);
+ EXPECT_EQ(kMitsubishiHeavy88SwingHOff, ac.getSwingHorizontal());
+
+ ac.setSwingHorizontal(kMitsubishiHeavy88SwingHOff + 1);
+ EXPECT_EQ(kMitsubishiHeavy88SwingHOff, ac.getSwingHorizontal());
+
+ // Out of bounds.
+ ac.setSwingHorizontal(255);
+ EXPECT_EQ(kMitsubishiHeavy88SwingHOff, ac.getSwingHorizontal());
+}
+
+TEST(TestMitsubishiHeavy88AcClass, Checksums) {
+ IRMitsubishiHeavy88Ac ac(0);
+ ac.begin();
+
+ EXPECT_TRUE(ac.validChecksum(ac.getRaw()));
+
+ uint8_t expected[kMitsubishiHeavy88StateLength] = {
+ 0xAD, 0x51, 0x3C, 0xD9, 0x26, 0x48, 0xB7, 0x00, 0xFF, 0x8A, 0x75};
+ EXPECT_TRUE(IRMitsubishiHeavy88Ac::validChecksum(expected));
+
+ // Screw up the "checksum" to test it fails.
+ expected[kMitsubishiHeavy88StateLength - 1] = 0x55;
+ EXPECT_FALSE(IRMitsubishiHeavy88Ac::validChecksum(expected));
+ // getting the after getRaw() should repair it.
+ ac.setRaw(expected);
+ EXPECT_TRUE(ac.validChecksum(ac.getRaw()));
+ EXPECT_TRUE(IRMitsubishiHeavy88Ac::validChecksum(ac.getRaw()));
+}
+
+TEST(TestMitsubishiHeavy88AcClass, HumanReadable) {
+ IRMitsubishiHeavy88Ac ac(0);
+
+ EXPECT_EQ(
+ "Power: Off, Mode: 0 (Auto), Temp: 17C, Fan: 0 (Auto), "
+ "Swing (V): 0 (Off), Swing (H): 0 (Off), "
+ "Turbo: Off, Econo: Off, 3D: Off, Clean: Off",
+ ac.toString());
+ ac.on();
+ ac.setMode(kMitsubishiHeavyCool);
+ ac.setTemp(kMitsubishiHeavyMinTemp);
+ ac.setFan(kMitsubishiHeavy88FanHigh);
+ ac.setTurbo(false);
+ ac.setEcono(false);
+ ac.set3D(true);
+ ac.setSwingVertical(kMitsubishiHeavy88SwingVAuto);
+ EXPECT_EQ(
+ "Power: On, Mode: 1 (Cool), Temp: 17C, Fan: 4 (High), "
+ "Swing (V): 16 (Auto), Swing (H): 200 (3D), "
+ "Turbo: Off, Econo: Off, 3D: On, Clean: Off",
+ ac.toString());
+
+ ac.setMode(kMitsubishiHeavyHeat);
+ ac.setTemp(kMitsubishiHeavyMaxTemp);
+ ac.setTurbo(true);
+ ac.setEcono(false);
+ ac.set3D(false);
+ ac.setSwingVertical(kMitsubishiHeavy88SwingVLowest);
+ ac.setSwingHorizontal(kMitsubishiHeavy88SwingHLeftMax);
+
+ EXPECT_EQ(
+ "Power: On, Mode: 4 (Heat), Temp: 31C, Fan: 6 (Turbo), "
+ "Swing (V): 26 (Lowest), Swing (H): 4 (Max Left), Turbo: On, Econo: Off, "
+ "3D: Off, Clean: Off",
+ ac.toString());
+
+ ac.setClean(true);
+ ac.setEcono(true);
+ ac.setMode(kMitsubishiHeavyAuto);
+ ac.setSwingVertical(kMitsubishiHeavy88SwingVOff);
+
+ EXPECT_EQ(
+ "Power: On, Mode: 0 (Auto), Temp: 31C, Fan: 7 (Econo), "
+ "Swing (V): 0 (Off), Swing (H): 4 (Max Left), Turbo: Off, Econo: On, "
+ "3D: Off, Clean: On",
+ ac.toString());
+
+ ac.setClean(false);
+ ac.setTemp(25);
+ ac.setEcono(false);
+ ac.setMode(kMitsubishiHeavyDry);
+ ac.setSwingHorizontal(kMitsubishiHeavy88SwingHLeftRight);
+ EXPECT_EQ(
+ "Power: On, Mode: 2 (Dry), Temp: 25C, Fan: 0 (Auto), "
+ "Swing (V): 0 (Off), Swing (H): 72 (Left Right), Turbo: Off, Econo: Off, "
+ "3D: Off, Clean: Off",
+ ac.toString());
+}
+
+// Tests for decodeMitsubishiHeavy().
+
+// Decode a real MitsubishiHeavy 152Bit message.
+TEST(TestDecodeMitsubishiHeavy, ZmsRealExample) {
+ IRsendTest irsend(0);
+ IRrecv irrecv(0);
+ IRMitsubishiHeavy152Ac ac(0);
+ irsend.begin();
+
+ uint8_t expected[kMitsubishiHeavy152StateLength] = {
+ 0xAD, 0x51, 0x3C, 0xE5, 0x1A, 0x0C, 0xF3, 0x07,
+ 0xF8, 0x04, 0xFB, 0x00, 0xFF, 0x00, 0xFF, 0x00,
+ 0xFF, 0x80, 0x7F};
+
+ // Ref: https://github.com/markszabo/IRremoteESP8266/issues/660#issuecomment-480571466
+ uint16_t rawData[307] = {
+ 3136, 1638, 364, 428, 366, 1224, 362, 432, 364, 430, 364, 1226, 362, 432,
+ 364, 1224, 366, 428, 366, 430, 366, 1224, 362, 1228, 362, 1228, 362, 432,
+ 364, 1224, 364, 432, 364, 1226, 364, 1224, 366, 1226, 364, 428, 364, 430,
+ 364, 430, 364, 432, 366, 1226, 364, 1224, 364, 430, 364, 1226, 364, 428,
+ 364, 1224, 368, 1224, 364, 428, 364, 430, 366, 430, 364, 1158, 430, 432,
+ 366, 1222, 366, 430, 366, 430, 364, 1226, 364, 1224, 364, 1224, 364, 1224,
+ 366, 1224, 364, 430, 364, 430, 364, 1228, 362, 1226, 364, 1226, 366, 1222,
+ 366, 430, 364, 430, 364, 1224, 366, 1224, 364, 430, 364, 430, 364, 432,
+ 364, 430, 364, 428, 364, 430, 364, 430, 366, 1226, 362, 1154, 434, 1228,
+ 364, 1226, 362, 1226, 364, 1226, 364, 1228, 362, 1226, 362, 432, 364, 430,
+ 364, 428, 364, 430, 364, 430, 364, 1228, 362, 1228, 362, 432, 364, 1224,
+ 368, 1224, 364, 1226, 362, 1226, 364, 1226, 366, 428, 366, 430, 364, 1224,
+ 364, 430, 366, 430, 366, 430, 364, 430, 364, 430, 364, 1226, 364, 1226,
+ 366, 1224, 366, 1224, 366, 1226, 364, 1224, 366, 1224, 366, 1224, 366,
+ 428, 364, 430, 366, 428, 364, 430, 364, 430, 366, 428, 364, 430, 364, 432,
+ 364, 1226, 364, 1226, 364, 1226, 364, 1228, 364, 1222, 370, 1222, 362,
+ 1228, 362, 1226, 362, 430, 364, 430, 364, 430, 364, 432, 364, 428, 364,
+ 432, 364, 428, 364, 430, 366, 1226, 362, 1224, 364, 1226, 364, 1226, 364,
+ 1226, 362, 1226, 366, 1224, 366, 1224, 364, 430, 364, 432, 364, 428, 364,
+ 432, 364, 428, 364, 430, 366, 430, 364, 430, 364, 1226, 362, 1226, 364,
+ 1224, 366, 1226, 362, 1228, 364, 1224, 366, 1224, 364, 430, 364, 432, 364,
+ 428, 364, 430, 364, 430, 364, 430, 366, 430, 364, 430, 338, 1252, 362
+ }; // UNKNOWN 5138D49D
+
+ irsend.reset();
+ irsend.sendRaw(rawData, 307, 38000);
+ irsend.makeDecodeResult();
+ EXPECT_TRUE(irrecv.decode(&irsend.capture));
+ ASSERT_EQ(MITSUBISHI_HEAVY_152, irsend.capture.decode_type);
+ ASSERT_EQ(kMitsubishiHeavy152Bits, irsend.capture.bits);
+ EXPECT_STATE_EQ(expected, irsend.capture.state, irsend.capture.bits);
+ ac.setRaw(irsend.capture.state);
+ EXPECT_EQ(
+ "Power: On, Mode: 4 (Heat), Temp: 24C, Fan: 4 (Max), "
+ "Swing (V): 0 (Auto), Swing (H): 0 (Auto), Silent: Off, Turbo: Off, "
+ "Econo: Off, Night: Off, Filter: Off, 3D: Off, Clean: Off",
+ ac.toString());
+}
+
+// Decode a Synthetic MitsubishiHeavy 152Bit message.
+TEST(TestDecodeMitsubishiHeavy, ZmsSyntheticExample) {
+ IRsendTest irsend(0);
+ IRrecv irrecv(0);
+ IRMitsubishiHeavy152Ac ac(0);
+ irsend.begin();
+
+ uint8_t expected[kMitsubishiHeavy152StateLength] = {
+ 0xAD, 0x51, 0x3C, 0xE5, 0x1A, 0x0C, 0xF3, 0x07,
+ 0xF8, 0x04, 0xFB, 0x00, 0xFF, 0x00, 0xFF, 0x00,
+ 0xFF, 0x80, 0x7F};
+
+ irsend.reset();
+ irsend.sendMitsubishiHeavy152(expected);
+ irsend.makeDecodeResult();
+ EXPECT_TRUE(irrecv.decode(&irsend.capture));
+ ASSERT_EQ(MITSUBISHI_HEAVY_152, irsend.capture.decode_type);
+ ASSERT_EQ(kMitsubishiHeavy152Bits, irsend.capture.bits);
+ EXPECT_STATE_EQ(expected, irsend.capture.state, irsend.capture.bits);
+ ac.setRaw(irsend.capture.state);
+ EXPECT_EQ(
+ "Power: On, Mode: 4 (Heat), Temp: 24C, Fan: 4 (Max), "
+ "Swing (V): 0 (Auto), Swing (H): 0 (Auto), Silent: Off, Turbo: Off, "
+ "Econo: Off, Night: Off, Filter: Off, 3D: Off, Clean: Off",
+ ac.toString());
+}
+
+// Decode a real MitsubishiHeavy 152Bit message.
+TEST(TestDecodeMitsubishiHeavy, ZmsRealExample2) {
+ IRsendTest irsend(0);
+ IRrecv irrecv(0);
+ IRMitsubishiHeavy152Ac ac(0);
+ irsend.begin();
+
+ uint8_t expected[kMitsubishiHeavy152StateLength] = {
+ 0xAD, 0x51, 0x3C, 0xE5, 0x1A, 0x04, 0xFB, 0x07,
+ 0xF8, 0x04, 0xFB, 0x00, 0xFF, 0x00, 0xFF, 0x00,
+ 0xFF, 0x80, 0x7F};
+
+ // Ref: https://github.com/markszabo/IRremoteESP8266/issues/660#issuecomment-480571466
+ uint16_t rawData[307] = {
+ 3196, 1580, 398, 390, 404, 1190, 400, 390, 402, 390, 402, 1192, 402, 388,
+ 402, 1192, 400, 390, 402, 392, 402, 1192, 400, 1188, 400, 1188, 400, 390,
+ 404, 1192, 398, 392, 400, 1192, 402, 1188, 400, 1190, 402, 388, 402, 392,
+ 404, 392, 402, 392, 404, 1188, 400, 1190, 398, 392, 404, 1188, 398, 392,
+ 402, 1192, 398, 1190, 400, 390, 404, 390, 402, 392, 404, 1188, 398, 392,
+ 404, 1190, 400, 392, 400, 394, 402, 1192, 398, 1190, 398, 1192, 398, 1190,
+ 400, 1190, 398, 392, 402, 1192, 398, 1190, 398, 1190, 398, 1192, 396,
+ 1192, 398, 396, 400, 394, 398, 1194, 396, 394, 400, 394, 398, 396, 398,
+ 396, 400, 402, 390, 394, 402, 392, 398, 396, 398, 1194, 396, 1194, 398,
+ 1192, 398, 1192, 396, 1194, 396, 1192, 396, 1196, 398, 1190, 398, 392,
+ 402, 392, 402, 394, 398, 394, 400, 394, 400, 1192, 398, 1192, 400, 390,
+ 402, 1190, 398, 1190, 398, 1192, 402, 1188, 398, 1190, 400, 390, 402, 392,
+ 402, 1190, 400, 390, 404, 390, 402, 394, 402, 392, 402, 390, 404, 1190,
+ 400, 1188, 400, 1190, 400, 1190, 402, 1188, 402, 1188, 400, 1188, 402,
+ 1190, 400, 388, 402, 394, 404, 392, 404, 388, 404, 390, 404, 392, 402,
+ 394, 402, 390, 402, 1190, 402, 1186, 402, 1190, 400, 1190, 398, 1190, 402,
+ 1186, 402, 1190, 400, 1188, 400, 390, 404, 392, 404, 390, 402, 392, 402,
+ 392, 400, 394, 402, 392, 402, 394, 400, 1192, 400, 1190, 400, 1188, 400,
+ 1192, 400, 1186, 402, 1190, 400, 1190, 400, 1188, 402, 388, 402, 390, 404,
+ 392, 402, 392, 402, 392, 402, 392, 404, 392, 402, 392, 404, 1190, 400,
+ 1190, 398, 1190, 400, 1190, 400, 1190, 400, 1188, 400, 1188, 400, 392,
+ 402, 392, 404, 390, 402, 392, 402, 392, 402, 392, 402, 390, 402, 392, 402,
+ 1192, 398}; // UNKNOWN A650F2C1
+
+ irsend.reset();
+ irsend.sendRaw(rawData, 307, 38000);
+ irsend.makeDecodeResult();
+ EXPECT_TRUE(irrecv.decode(&irsend.capture));
+ ASSERT_EQ(MITSUBISHI_HEAVY_152, irsend.capture.decode_type);
+ ASSERT_EQ(kMitsubishiHeavy152Bits, irsend.capture.bits);
+ EXPECT_STATE_EQ(expected, irsend.capture.state, irsend.capture.bits);
+ ac.setRaw(irsend.capture.state);
+ EXPECT_EQ(
+ "Power: Off, Mode: 4 (Heat), Temp: 24C, Fan: 4 (Max), "
+ "Swing (V): 0 (Auto), Swing (H): 0 (Auto), Silent: Off, Turbo: Off, "
+ "Econo: Off, Night: Off, Filter: Off, 3D: Off, Clean: Off",
+ ac.toString());
+}
+
+// Decode a Synthetic MitsubishiHeavy 88 Bit message.
+TEST(TestDecodeMitsubishiHeavy, ZjsSyntheticExample) {
+ IRsendTest irsend(0);
+ IRrecv irrecv(0);
+ IRMitsubishiHeavy88Ac ac(0);
+ irsend.begin();
+
+ uint8_t expected[kMitsubishiHeavy88StateLength] = {
+ 0xAD, 0x51, 0x3C, 0xD9, 0x26, 0x48, 0xB7, 0x00, 0xFF, 0x8A, 0x75};
+
+ irsend.reset();
+ irsend.sendMitsubishiHeavy88(expected);
+ irsend.makeDecodeResult();
+ EXPECT_TRUE(irrecv.decode(&irsend.capture));
+ ASSERT_EQ(MITSUBISHI_HEAVY_88, irsend.capture.decode_type);
+ ASSERT_EQ(kMitsubishiHeavy88Bits, irsend.capture.bits);
+ EXPECT_STATE_EQ(expected, irsend.capture.state, irsend.capture.bits);
+ ac.setRaw(irsend.capture.state);
+ EXPECT_EQ(
+ "Power: On, Mode: 2 (Dry), Temp: 25C, Fan: 0 (Auto), "
+ "Swing (V): 0 (Off), Swing (H): 72 (Left Right), Turbo: Off, Econo: Off, "
+ "3D: Off, Clean: Off",
+ ac.toString());
+}
diff --git a/lib/IRremoteESP8266-2.5.2.03/test/ir_Mitsubishi_test.cpp b/lib/IRremoteESP8266-2.6.0/test/ir_Mitsubishi_test.cpp
similarity index 99%
rename from lib/IRremoteESP8266-2.5.2.03/test/ir_Mitsubishi_test.cpp
rename to lib/IRremoteESP8266-2.6.0/test/ir_Mitsubishi_test.cpp
index 7b8eb2192..6c9480b31 100644
--- a/lib/IRremoteESP8266-2.5.2.03/test/ir_Mitsubishi_test.cpp
+++ b/lib/IRremoteESP8266-2.6.0/test/ir_Mitsubishi_test.cpp
@@ -17,6 +17,7 @@ TEST(TestSendMitsubishi, SendDataOnly) {
irsend.reset();
irsend.sendMitsubishi(0xE242);
EXPECT_EQ(
+ "f33000d50"
"m300s2100m300s2100m300s2100m300s900m300s900m300s900m300s2100m300s900"
"m300s900m300s2100m300s900m300s900m300s900m300s900m300s2100m300s900"
"m300s28080"
@@ -28,6 +29,7 @@ TEST(TestSendMitsubishi, SendDataOnly) {
irsend.reset();
irsend.sendMitsubishi(0x0);
EXPECT_EQ(
+ "f33000d50"
"m300s900m300s900m300s900m300s900m300s900m300s900m300s900m300s900"
"m300s900m300s900m300s900m300s900m300s900m300s900m300s900m300s900"
"m300s34080"
@@ -39,6 +41,7 @@ TEST(TestSendMitsubishi, SendDataOnly) {
irsend.reset();
irsend.sendMitsubishi(0x4321);
EXPECT_EQ(
+ "f33000d50"
"m300s900m300s2100m300s900m300s900m300s900m300s900m300s2100m300s2100"
"m300s900m300s900m300s2100m300s900m300s900m300s900m300s900m300s2100"
"m300s28080"
@@ -56,6 +59,7 @@ TEST(TestSendMitsubishi, SendWithRepeats) {
irsend.reset();
irsend.sendMitsubishi(0xE242, kMitsubishiBits, 0); // 0 repeat.
EXPECT_EQ(
+ "f33000d50"
"m300s2100m300s2100m300s2100m300s900m300s900m300s900m300s2100m300s900"
"m300s900m300s2100m300s900m300s900m300s900m300s900m300s2100m300s900"
"m300s28080",
@@ -64,6 +68,7 @@ TEST(TestSendMitsubishi, SendWithRepeats) {
irsend.reset();
irsend.sendMitsubishi(0xE242, kMitsubishiBits, 1); // 1 repeat.
EXPECT_EQ(
+ "f33000d50"
"m300s2100m300s2100m300s2100m300s900m300s900m300s900m300s2100m300s900"
"m300s900m300s2100m300s900m300s900m300s900m300s900m300s2100m300s900"
"m300s28080"
@@ -73,6 +78,7 @@ TEST(TestSendMitsubishi, SendWithRepeats) {
irsend.outputStr());
irsend.sendMitsubishi(0xE242, kMitsubishiBits, 2); // 2 repeats.
EXPECT_EQ(
+ "f33000d50"
"m300s2100m300s2100m300s2100m300s900m300s900m300s900m300s2100m300s900"
"m300s900m300s2100m300s900m300s900m300s900m300s900m300s2100m300s900"
"m300s28080"
@@ -93,6 +99,7 @@ TEST(TestSendMitsubishi, SendUnusualSize) {
irsend.reset();
irsend.sendMitsubishi(0x0, 8);
EXPECT_EQ(
+ "f33000d50"
"m300s900m300s900m300s900m300s900m300s900m300s900m300s900m300s900"
"m300s43680"
"m300s900m300s900m300s900m300s900m300s900m300s900m300s900m300s900"
@@ -102,6 +109,7 @@ TEST(TestSendMitsubishi, SendUnusualSize) {
irsend.reset();
irsend.sendMitsubishi(0x1234567890ABCDEF, 64);
EXPECT_EQ(
+ "f33000d50"
"m300s900m300s900m300s900m300s2100m300s900m300s900m300s2100m300s900"
"m300s900m300s900m300s2100m300s2100m300s900m300s2100m300s900m300s900"
"m300s900m300s2100m300s900m300s2100m300s900m300s2100m300s2100m300s900"
@@ -305,6 +313,7 @@ TEST(TestSendMitsubishiAC, SendDataOnly) {
irsend.reset();
irsend.sendMitsubishiAC(mitsub_code);
EXPECT_EQ(
+ "f38000d50"
"m3400s1750"
"m450s1300m450s1300m450s420m450s420m450s420m450s1300m450s420m450s420"
"m450s1300m450s1300m450s420m450s1300m450s420m450s420m450s1300m450s1300"
@@ -360,6 +369,7 @@ TEST(TestSendMitsubishiAC, SendWithRepeats) {
irsend.sendMitsubishiAC(mitsub_code, kMitsubishiACStateLength, 0);
EXPECT_EQ(
+ "f38000d50"
"m3400s1750"
"m450s1300m450s1300m450s420m450s420m450s420m450s1300m450s420m450s420"
"m450s1300m450s1300m450s420m450s1300m450s420m450s420m450s1300m450s1300"
@@ -385,6 +395,7 @@ TEST(TestSendMitsubishiAC, SendWithRepeats) {
irsend.reset();
irsend.sendMitsubishiAC(mitsub_code, kMitsubishiACStateLength, 2);
EXPECT_EQ(
+ "f38000d50"
"m3400s1750"
"m450s1300m450s1300m450s420m450s420m450s420m450s1300m450s420m450s420"
"m450s1300m450s1300m450s420m450s1300m450s420m450s420m450s1300m450s1300"
@@ -466,6 +477,7 @@ TEST(TestSendMitsubishiAC, SendUnexpectedSizes) {
irsend.reset();
irsend.sendMitsubishiAC(mitsub_long_code, 19);
ASSERT_EQ(
+ "f38000d50"
"m3400s1750"
"m450s1300m450s1300m450s420m450s420m450s420m450s1300m450s420m450s420"
"m450s1300m450s1300m450s420m450s1300m450s420m450s420m450s1300m450s1300"
@@ -665,6 +677,7 @@ TEST(TestMitsubishiACClass, MessageConstuction) {
irsend.reset();
irsend.sendMitsubishiAC(mitsub.getRaw());
EXPECT_EQ(
+ "f38000d50"
"m3400s1750"
"m450s1300m450s1300m450s420m450s420m450s420m450s1300m450s420m450s420"
"m450s1300m450s1300m450s420m450s1300m450s420m450s420m450s1300m450s1300"
@@ -984,6 +997,7 @@ TEST(TestSendMitsubishi2, SendDataOnly) {
irsend.reset();
irsend.sendMitsubishi2(0xF82);
EXPECT_EQ(
+ "f33000d50"
"m8400s4200"
"m560s520m560s520m560s520m560s520m560s1560m560s1560m560s1560m560s1560"
"m560s4200"
@@ -999,6 +1013,7 @@ TEST(TestSendMitsubishi2, SendDataOnly) {
irsend.reset();
irsend.sendMitsubishi2(0x0);
EXPECT_EQ(
+ "f33000d50"
"m8400s4200"
"m560s520m560s520m560s520m560s520m560s520m560s520m560s520m560s520"
"m560s4200"
@@ -1020,6 +1035,7 @@ TEST(TestSendMitsubishi2, Repeats) {
irsend.reset();
irsend.sendMitsubishi2(0xF82, kMitsubishiBits, 0);
EXPECT_EQ(
+ "f33000d50"
"m8400s4200"
"m560s520m560s520m560s520m560s520m560s1560m560s1560m560s1560m560s1560"
"m560s4200"
@@ -1030,6 +1046,7 @@ TEST(TestSendMitsubishi2, Repeats) {
irsend.reset();
irsend.sendMitsubishi2(0xF82, kMitsubishiBits, 2);
EXPECT_EQ(
+ "f33000d50"
"m8400s4200"
"m560s520m560s520m560s520m560s520m560s1560m560s1560m560s1560m560s1560"
"m560s4200"
diff --git a/lib/IRremoteESP8266-2.5.2.03/test/ir_NEC_test.cpp b/lib/IRremoteESP8266-2.6.0/test/ir_NEC_test.cpp
similarity index 98%
rename from lib/IRremoteESP8266-2.5.2.03/test/ir_NEC_test.cpp
rename to lib/IRremoteESP8266-2.6.0/test/ir_NEC_test.cpp
index 6b84b0ec9..c881b7b44 100644
--- a/lib/IRremoteESP8266-2.5.2.03/test/ir_NEC_test.cpp
+++ b/lib/IRremoteESP8266-2.6.0/test/ir_NEC_test.cpp
@@ -12,6 +12,7 @@ TEST(TestSendNEC, SendDataOnly) {
irsend.begin();
irsend.sendNEC(0);
EXPECT_EQ(
+ "f38000d33"
"m8960s4480m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
"m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
"m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
@@ -20,6 +21,7 @@ TEST(TestSendNEC, SendDataOnly) {
irsend.outputStr());
irsend.sendNEC(0xAA00FF55);
EXPECT_EQ(
+ "f38000d33"
"m8960s4480m560s1680m560s560m560s1680m560s560m560s1680m560s560"
"m560s1680m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
"m560s560m560s560m560s1680m560s1680m560s1680m560s1680m560s1680"
@@ -33,15 +35,17 @@ TEST(TestSendNEC, SendSmallData) {
IRsendTest irsend(4);
irsend.begin();
irsend.sendNEC(0xA, 4); // Send only 4 data bits.
- EXPECT_EQ("m8960s4480m560s1680m560s560m560s1680m560s560m560s87360",
+ EXPECT_EQ("f38000d33m8960s4480m560s1680m560s560m560s1680m560s560m560s87360",
irsend.outputStr());
irsend.sendNEC(0, 8); // Send only 8 data bits.
EXPECT_EQ(
+ "f38000d33"
"m8960s4480m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
"m560s560m560s85120",
irsend.outputStr());
irsend.sendNEC(0x1234567890ABCDEF, 64); // Send 64 data bits.
EXPECT_EQ(
+ "f38000d33"
"m8960s4480m560s560m560s560m560s560m560s1680m560s560m560s560"
"m560s1680m560s560m560s560m560s560m560s1680m560s1680m560s560"
"m560s1680m560s560m560s560m560s560m560s1680m560s560m560s1680"
@@ -61,17 +65,20 @@ TEST(TestSendNEC, SendWithRepeats) {
irsend.begin();
irsend.sendNEC(0, 8, 0); // Send a command with 0 repeats.
EXPECT_EQ(
+ "f38000d33"
"m8960s4480m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
"m560s560m560s85120",
irsend.outputStr());
irsend.sendNEC(0xAA, 8, 1); // Send a command with 1 repeat.
EXPECT_EQ(
+ "f38000d33"
"m8960s4480m560s1680m560s560m560s1680m560s560m560s1680m560s560"
"m560s1680m560s560m560s80640"
"m8960s2240m560s96320",
irsend.outputStr());
irsend.sendNEC(0xAA, 8, 3); // Send a command with 3 repeats.
EXPECT_EQ(
+ "f38000d33"
"m8960s4480m560s1680m560s560m560s1680m560s560m560s1680m560s560"
"m560s1680m560s560m560s80640"
"m8960s2240m560s96320"
diff --git a/lib/IRremoteESP8266-2.5.2.03/test/ir_Nikai_test.cpp b/lib/IRremoteESP8266-2.6.0/test/ir_Nikai_test.cpp
similarity index 99%
rename from lib/IRremoteESP8266-2.5.2.03/test/ir_Nikai_test.cpp
rename to lib/IRremoteESP8266-2.6.0/test/ir_Nikai_test.cpp
index 4a4ea05bb..fff242326 100644
--- a/lib/IRremoteESP8266-2.5.2.03/test/ir_Nikai_test.cpp
+++ b/lib/IRremoteESP8266-2.6.0/test/ir_Nikai_test.cpp
@@ -13,6 +13,7 @@ TEST(TestSendNikai, SendDataOnly) {
irsend.reset();
irsend.sendNikai(0xD5F2A); // Nikai TV Power Off.
EXPECT_EQ(
+ "f38000d33"
"m4000s4000"
"m500s2000m500s2000m500s2000m500s2000m500s1000m500s1000m500s2000"
"m500s1000m500s2000m500s1000m500s2000m500s1000m500s1000m500s1000"
@@ -31,6 +32,7 @@ TEST(TestSendNikai, SendWithRepeats) {
irsend.reset();
irsend.sendNikai(0xD5F2A, kNikaiBits, 1); // 1 repeat.
EXPECT_EQ(
+ "f38000d33"
"m4000s4000"
"m500s2000m500s2000m500s2000m500s2000m500s1000m500s1000m500s2000"
"m500s1000m500s2000m500s1000m500s2000m500s1000m500s1000m500s1000"
@@ -44,6 +46,7 @@ TEST(TestSendNikai, SendWithRepeats) {
irsend.outputStr());
irsend.sendNikai(0xD5F2A, kNikaiBits, 2); // 2 repeat.
EXPECT_EQ(
+ "f38000d33"
"m4000s4000"
"m500s2000m500s2000m500s2000m500s2000m500s1000m500s1000m500s2000"
"m500s1000m500s2000m500s1000m500s2000m500s1000m500s1000m500s1000"
diff --git a/lib/IRremoteESP8266-2.5.2.03/test/ir_Panasonic_test.cpp b/lib/IRremoteESP8266-2.6.0/test/ir_Panasonic_test.cpp
similarity index 99%
rename from lib/IRremoteESP8266-2.5.2.03/test/ir_Panasonic_test.cpp
rename to lib/IRremoteESP8266-2.6.0/test/ir_Panasonic_test.cpp
index a1d8a7979..4d10f8fb1 100644
--- a/lib/IRremoteESP8266-2.5.2.03/test/ir_Panasonic_test.cpp
+++ b/lib/IRremoteESP8266-2.6.0/test/ir_Panasonic_test.cpp
@@ -32,6 +32,7 @@ TEST(TestSendPanasonic64, SendDataOnly) {
irsend.reset();
irsend.sendPanasonic64(0x0);
EXPECT_EQ(
+ "f36700d50"
"m3456s1728"
"m432s432m432s432m432s432m432s432m432s432m432s432m432s432m432s432"
"m432s432m432s432m432s432m432s432m432s432m432s432m432s432m432s432"
@@ -45,6 +46,7 @@ TEST(TestSendPanasonic64, SendDataOnly) {
irsend.reset();
irsend.sendPanasonic64(0x40040190ED7C);
EXPECT_EQ(
+ "f36700d50"
"m3456s1728"
"m432s432m432s1296m432s432m432s432m432s432m432s432m432s432m432s432"
"m432s432m432s432m432s432m432s432m432s432m432s1296m432s432m432s432"
@@ -58,6 +60,7 @@ TEST(TestSendPanasonic64, SendDataOnly) {
irsend.reset();
irsend.sendPanasonic64(0xFFFFFFFFFFFF);
EXPECT_EQ(
+ "f36700d50"
"m3456s1728"
"m432s1296m432s1296m432s1296m432s1296m432s1296m432s1296m432s1296m432s1296"
"m432s1296m432s1296m432s1296m432s1296m432s1296m432s1296m432s1296m432s1296"
@@ -77,6 +80,7 @@ TEST(TestSendPanasonic64, SendWithRepeats) {
irsend.reset();
irsend.sendPanasonic64(0x40040190ED7C, kPanasonicBits, 0); // 0 repeats.
EXPECT_EQ(
+ "f36700d50"
"m3456s1728"
"m432s432m432s1296m432s432m432s432m432s432m432s432m432s432m432s432"
"m432s432m432s432m432s432m432s432m432s432m432s1296m432s432m432s432"
@@ -90,6 +94,7 @@ TEST(TestSendPanasonic64, SendWithRepeats) {
irsend.reset();
irsend.sendPanasonic64(0x40040190ED7C, kPanasonicBits, 1); // 1 repeat.
EXPECT_EQ(
+ "f36700d50"
"m3456s1728"
"m432s432m432s1296m432s432m432s432m432s432m432s432m432s432m432s432"
"m432s432m432s432m432s432m432s432m432s432m432s1296m432s432m432s432"
@@ -110,6 +115,7 @@ TEST(TestSendPanasonic64, SendWithRepeats) {
irsend.sendPanasonic64(0x40040190ED7C, kPanasonicBits, 2); // 2 repeats.
EXPECT_EQ(
+ "f36700d50"
"m3456s1728"
"m432s432m432s1296m432s432m432s432m432s432m432s432m432s432m432s432"
"m432s432m432s432m432s432m432s432m432s432m432s1296m432s432m432s432"
@@ -145,6 +151,7 @@ TEST(TestSendPanasonic64, SendUnusualSize) {
irsend.reset();
irsend.sendPanasonic64(0x0, 8);
EXPECT_EQ(
+ "f36700d50"
"m3456s1728"
"m432s432m432s432m432s432m432s432m432s432m432s432m432s432m432s432"
"m432s150768",
@@ -153,6 +160,7 @@ TEST(TestSendPanasonic64, SendUnusualSize) {
irsend.reset();
irsend.sendPanasonic64(0x1234567890ABCDEF, 64);
EXPECT_EQ(
+ "f36700d50"
"m3456s1728"
"m432s432m432s432m432s432m432s1296m432s432m432s432m432s1296m432s432"
"m432s432m432s432m432s1296m432s1296m432s432m432s1296m432s432m432s432"
@@ -483,6 +491,7 @@ TEST(TestSendPanasonicAC, SendDataOnly) {
0x00, 0x06, 0x60, 0x00, 0x00, 0x80, 0x00, 0x06, 0x83};
irsend.sendPanasonicAC(state);
EXPECT_EQ(
+ "f36700d50"
"m3456s1728"
"m432s432m432s1296m432s432m432s432m432s432m432s432m432s432m432s432"
"m432s432m432s432m432s432m432s432m432s432m432s1296m432s432m432s432"
diff --git a/lib/IRremoteESP8266-2.5.2.03/test/ir_Pioneer_test.cpp b/lib/IRremoteESP8266-2.6.0/test/ir_Pioneer_test.cpp
similarity index 99%
rename from lib/IRremoteESP8266-2.5.2.03/test/ir_Pioneer_test.cpp
rename to lib/IRremoteESP8266-2.6.0/test/ir_Pioneer_test.cpp
index b78469add..36d61c706 100644
--- a/lib/IRremoteESP8266-2.5.2.03/test/ir_Pioneer_test.cpp
+++ b/lib/IRremoteESP8266-2.6.0/test/ir_Pioneer_test.cpp
@@ -13,6 +13,7 @@ TEST(TestSendPioneer, SendDataOnly) {
irsend.begin();
irsend.sendPioneer(0);
EXPECT_EQ(
+ "f38000d33"
"m8960s4480"
"m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
"m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
@@ -28,6 +29,7 @@ TEST(TestSendPioneer, SendDataOnly) {
irsend.outputStr());
irsend.sendPioneer(0x55FF00AAAA00FF55);
EXPECT_EQ(
+ "f38000d33"
"m8960s4480"
"m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680"
"m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680"
@@ -136,6 +138,7 @@ TEST(TestDecodePioneer, SyntheticPioneerMessage) {
irsend.reset();
irsend.sendPioneer(0x659A857AF50A3DC2, 64, 0);
EXPECT_EQ(
+ "f38000d33"
"m8960s4480"
"m560s560m560s1680m560s1680m560s560m560s560m560s1680m560s560m560s1680"
"m560s1680m560s560m560s560m560s1680m560s1680m560s560m560s1680m560s560"
diff --git a/lib/IRremoteESP8266-2.5.2.03/test/ir_Pronto_test.cpp b/lib/IRremoteESP8266-2.6.0/test/ir_Pronto_test.cpp
similarity index 96%
rename from lib/IRremoteESP8266-2.5.2.03/test/ir_Pronto_test.cpp
rename to lib/IRremoteESP8266-2.6.0/test/ir_Pronto_test.cpp
index e52c6dd90..513f985da 100644
--- a/lib/IRremoteESP8266-2.5.2.03/test/ir_Pronto_test.cpp
+++ b/lib/IRremoteESP8266-2.6.0/test/ir_Pronto_test.cpp
@@ -58,7 +58,8 @@ TEST(TestSendPronto, MoreDataThanNeededInNormal) {
uint16_t pronto_test[8] = {0x0000, 0x0067, 0x0001, 0x0000,
0x0001, 0x0002, 0x0003, 0x0004};
irsend.sendPronto(pronto_test, 8);
- EXPECT_EQ("m25s50", irsend.outputStr()); // Only send the data required.
+ EXPECT_EQ("f40244d50m25s50",
+ irsend.outputStr()); // Only send the data required.
}
TEST(TestSendPronto, MoreDataThanNeededInRepeat) {
@@ -70,7 +71,8 @@ TEST(TestSendPronto, MoreDataThanNeededInRepeat) {
uint16_t pronto_test[8] = {0x0000, 0x0067, 0x0000, 0x0001,
0x0001, 0x0002, 0x0003, 0x0004};
irsend.sendPronto(pronto_test, 8);
- EXPECT_EQ("m25s50", irsend.outputStr()); // Only send the data required.
+ EXPECT_EQ("f40244d50m25s50",
+ irsend.outputStr()); // Only send the data required.
}
TEST(TestSendPronto, MoreDataThanNeededInBoth) {
@@ -82,9 +84,11 @@ TEST(TestSendPronto, MoreDataThanNeededInBoth) {
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.
+ EXPECT_EQ("f40244d50m25s50",
+ irsend.outputStr()); // Only send the data required.
irsend.sendPronto(pronto_test, 10, 1);
- EXPECT_EQ("m25s50m75s100", irsend.outputStr()); // Only the data required.
+ EXPECT_EQ("f40244d50m25s50m75s100",
+ irsend.outputStr()); // Only the data required.
}
TEST(TestSendPronto, ShortestValidCodeThatSendsNothing) {
@@ -134,6 +138,7 @@ TEST(TestSendPronto, NonRepeatingCode) {
EXPECT_EQ(0x1, irsend.capture.address);
EXPECT_EQ(0x0, irsend.capture.command);
EXPECT_EQ(
+ "f40244d50"
"m2400s600"
"m600s600m600s600m600s600m600s600m600s600m600s600m600s600m1200s600"
"m600s600m600s600m600s600m600s27650"
@@ -160,6 +165,7 @@ TEST(TestSendPronto, NonRepeatingCode) {
EXPECT_EQ(0x1, irsend.capture.address);
EXPECT_EQ(0x0, irsend.capture.command);
EXPECT_EQ(
+ "f40244d50"
"m2400s600"
"m600s600m600s600m600s600m600s600m600s600m600s600m600s600m1200s600"
"m600s600m600s600m600s600m600s27650"
@@ -201,6 +207,7 @@ TEST(TestSendPronto, RepeatSequenceOnlyForSony) {
EXPECT_EQ(0x1A, irsend.capture.address);
EXPECT_EQ(0x24AE, irsend.capture.command);
EXPECT_EQ(
+ "f40244d50"
"m2400s600"
"m600s600m1200s600m1200s600m1200s600m600s600m1200s600m600s600m600s600"
"m1200s600m600s600m1200s600m1200s600m1200s600m600s600m600s600m1200s600"
@@ -218,6 +225,7 @@ TEST(TestSendPronto, RepeatSequenceOnlyForSony) {
EXPECT_EQ(0x1A, irsend.capture.address);
EXPECT_EQ(0x24AE, irsend.capture.command);
EXPECT_EQ(
+ "f40244d50"
"m2400s600"
"m600s600m1200s600m1200s600m1200s600m600s600m1200s600m600s600m600s600"
"m1200s600m600s600m1200s600m1200s600m1200s600m600s600m600s600m1200s600"
@@ -265,6 +273,7 @@ TEST(TestSendPronto, RepeatSequenceOnlyForPanasonic) {
EXPECT_EQ(0x4004, irsend.capture.address);
EXPECT_EQ(0x1007C7D, irsend.capture.command);
EXPECT_EQ(
+ "f36682d50"
"m3456s1701"
"m432s432m432s1296m432s432m432s432m432s432m432s432m432s432m432s432"
"m432s432m432s432m432s432m432s432m432s432m432s1296m432s432m432s432"
@@ -305,6 +314,7 @@ TEST(TestSendPronto, NormalPlusRepeatSequence) {
EXPECT_EQ(0x18, irsend.capture.address);
EXPECT_EQ(0x8, irsend.capture.command);
EXPECT_EQ(
+ "f38028d50"
"m8892s4446"
"m546s546m546s546m546s546m546s1664m546s1664m546s546m546s546m546s546"
"m546s1664m546s1664m546s1664m546s546m546s546m546s1664m546s1664m546s1664"
@@ -324,6 +334,7 @@ TEST(TestSendPronto, NormalPlusRepeatSequence) {
EXPECT_EQ(0x18, irsend.capture.address);
EXPECT_EQ(0x8, irsend.capture.command);
EXPECT_EQ(
+ "f38028d50"
"m8892s4446"
"m546s546m546s546m546s546m546s1664m546s1664m546s546m546s546m546s546"
"m546s1664m546s1664m546s1664m546s546m546s546m546s1664m546s1664m546s1664"
@@ -344,6 +355,7 @@ TEST(TestSendPronto, NormalPlusRepeatSequence) {
EXPECT_EQ(0x18, irsend.capture.address);
EXPECT_EQ(0x8, irsend.capture.command);
EXPECT_EQ(
+ "f38028d50"
"m8892s4446"
"m546s546m546s546m546s546m546s1664m546s1664m546s546m546s546m546s546"
"m546s1664m546s1664m546s1664m546s546m546s546m546s1664m546s1664m546s1664"
diff --git a/lib/IRremoteESP8266-2.5.2.03/test/ir_RC5_RC6_test.cpp b/lib/IRremoteESP8266-2.6.0/test/ir_RC5_RC6_test.cpp
similarity index 98%
rename from lib/IRremoteESP8266-2.5.2.03/test/ir_RC5_RC6_test.cpp
rename to lib/IRremoteESP8266-2.6.0/test/ir_RC5_RC6_test.cpp
index e8aa9bfc1..da9fa027c 100644
--- a/lib/IRremoteESP8266-2.5.2.03/test/ir_RC5_RC6_test.cpp
+++ b/lib/IRremoteESP8266-2.6.0/test/ir_RC5_RC6_test.cpp
@@ -79,6 +79,7 @@ TEST(TestSendRC5, SendDataOnly) {
irsend.reset();
irsend.sendRC5(0x0, kRC5Bits);
EXPECT_EQ(
+ "f36000d25"
"m889s889m1778s889m889s889m889s889m889s889m889s889m889"
"s889m889s889m889s889m889s889m889s889m889s889m889s90664",
irsend.outputStr());
@@ -86,6 +87,7 @@ TEST(TestSendRC5, SendDataOnly) {
irsend.reset();
irsend.sendRC5(0x1AAA, kRC5Bits);
EXPECT_EQ(
+ "f36000d25"
"m889s889m889s889m1778s1778m1778s1778m1778s1778"
"m1778s1778m1778s1778m1778s90664",
irsend.outputStr());
@@ -93,6 +95,7 @@ TEST(TestSendRC5, SendDataOnly) {
irsend.reset();
irsend.sendRC5(0x175, kRC5Bits);
EXPECT_EQ(
+ "f36000d25"
"m889s889m1778s889m889s889m889s1778m1778s1778"
"m889s889m889s889m1778s1778m1778s1778m889s89775",
irsend.outputStr());
@@ -100,6 +103,7 @@ TEST(TestSendRC5, SendDataOnly) {
irsend.reset();
irsend.sendRC5(0x3FFF, kRC5Bits);
EXPECT_EQ(
+ "f36000d25"
"m889s889m889s889m889s889m889s889m889s889m889s889m889s889"
"m889s889m889s889m889s889m889s889m889s889m889s889m889s89775",
irsend.outputStr());
@@ -107,6 +111,7 @@ TEST(TestSendRC5, SendDataOnly) {
irsend.reset();
irsend.sendRC5(0x0, kRC5XBits);
EXPECT_EQ(
+ "f36000d25"
"m889s889m1778s889m889s889m889s889m889s889m889s889m889"
"s889m889s889m889s889m889s889m889s889m889s889m889s90664",
irsend.outputStr());
@@ -114,6 +119,7 @@ TEST(TestSendRC5, SendDataOnly) {
irsend.reset();
irsend.sendRC5(0x1AAA, kRC5XBits);
EXPECT_EQ(
+ "f36000d25"
"m1778s1778m1778s1778m1778s1778m1778"
"s1778m1778s1778m1778s1778m1778s90664",
irsend.outputStr());
@@ -121,6 +127,7 @@ TEST(TestSendRC5, SendDataOnly) {
irsend.reset();
irsend.sendRC5(0x175, kRC5XBits);
EXPECT_EQ(
+ "f36000d25"
"m889s889m1778s889m889s889m889s1778m1778s1778"
"m889s889m889s889m1778s1778m1778s1778m889s89775",
irsend.outputStr());
@@ -128,6 +135,7 @@ TEST(TestSendRC5, SendDataOnly) {
irsend.reset();
irsend.sendRC5(0x3FFF, kRC5XBits);
EXPECT_EQ(
+ "f36000d25"
"m1778s1778m889s889m889s889m889s889m889s889m889s889m889"
"s889m889s889m889s889m889s889m889s889m889s889m889s89775",
irsend.outputStr());
@@ -141,6 +149,7 @@ TEST(TestSendRC5, SendWithRepeats) {
irsend.reset();
irsend.sendRC5(0x175, kRC5Bits, 1);
EXPECT_EQ(
+ "f36000d25"
"m889s889m1778s889m889s889m889s1778m1778s1778"
"m889s889m889s889m1778s1778m1778s1778m889s90664"
"m889s889m1778s889m889s889m889s1778m1778s1778"
@@ -150,6 +159,7 @@ TEST(TestSendRC5, SendWithRepeats) {
irsend.reset();
irsend.sendRC5(0x175, kRC5Bits, 2);
EXPECT_EQ(
+ "f36000d25"
"m889s889m1778s889m889s889m889s1778m1778s1778"
"m889s889m889s889m1778s1778m1778s1778m889s90664"
"m889s889m1778s889m889s889m889s1778m1778s1778"
@@ -161,6 +171,7 @@ TEST(TestSendRC5, SendWithRepeats) {
irsend.reset();
irsend.sendRC5(0x175, kRC5XBits, 1);
EXPECT_EQ(
+ "f36000d25"
"m889s889m1778s889m889s889m889s1778m1778s1778"
"m889s889m889s889m1778s1778m1778s1778m889s90664"
"m889s889m1778s889m889s889m889s1778m1778s1778"
@@ -170,6 +181,7 @@ TEST(TestSendRC5, SendWithRepeats) {
irsend.reset();
irsend.sendRC5(0x1175, kRC5XBits, 2);
EXPECT_EQ(
+ "f36000d25"
"m1778s889m889s889m889s889m889s1778m1778s1778"
"m889s889m889s889m1778s1778m1778s1778m889s90664"
"m1778s889m889s889m889s889m889s1778m1778s1778"
@@ -444,6 +456,7 @@ TEST(TestSendRC6, SendMode0DataOnly) {
irsend.reset();
irsend.sendRC6(0x0);
EXPECT_EQ(
+ "f36000d33"
"m2664s888"
"m444s888m444s444m444s444m444s888m888s444m444s444m444s444"
"m444s444m444s444m444s444m444s444m444s444m444s444m444s444"
@@ -454,6 +467,7 @@ TEST(TestSendRC6, SendMode0DataOnly) {
irsend.reset();
irsend.sendRC6(0x1FFFF);
EXPECT_EQ(
+ "f36000d33"
"m2664s888"
"m444s888m444s444m444s444m1332s888m444s444m444s444m444s444"
"m444s444m444s444m444s444m444s444m444s444m444s444m444s444"
@@ -464,6 +478,7 @@ TEST(TestSendRC6, SendMode0DataOnly) {
irsend.reset();
irsend.sendRC6(0x15555);
EXPECT_EQ(
+ "f36000d33"
"m2664s888"
"m444s888m444s444m444s444m1332s1332m888s888m888s888"
"m888s888m888s888m888s888m888s888m888s888m888"
@@ -479,6 +494,7 @@ TEST(TestSendRC6, Send36BitDataOnly) {
irsend.reset();
irsend.sendRC6(0x0, kRC6_36Bits);
EXPECT_EQ(
+ "f36000d33"
"m2664s888"
"m444s888m444s444m444s444m444"
"s888m888"
@@ -492,6 +508,7 @@ TEST(TestSendRC6, Send36BitDataOnly) {
irsend.reset();
irsend.sendRC6(0xFFFFFFFFF, kRC6_36Bits);
EXPECT_EQ(
+ "f36000d33"
"m2664s888"
"m444s444m444s444m444s444m444s444"
"m888s888"
@@ -505,6 +522,7 @@ TEST(TestSendRC6, Send36BitDataOnly) {
irsend.reset();
irsend.sendRC6(0xAAAAAAAAAA, kRC6_36Bits);
EXPECT_EQ(
+ "f36000d33"
"m2664s888m444s444m444s888m888"
"s1332m1332"
"s888m888s888m888s888m888s888m888s888m888s888m888s888m888s888m888s888m888"
@@ -514,6 +532,7 @@ TEST(TestSendRC6, Send36BitDataOnly) {
irsend.reset();
irsend.sendRC6(0xC800F740C, kRC6_36Bits); // Xbox 360 OnOff code
EXPECT_EQ(
+ "f36000d33"
"m2664s888"
"m444s444m444s444m444s888m444"
"s888m1332"
@@ -526,6 +545,7 @@ TEST(TestSendRC6, Send36BitDataOnly) {
irsend.sendRC6(irsend.toggleRC6(0xC800F740C, kRC6_36Bits),
kRC6_36Bits); // Xbox 360 OnOff code (toggled)
EXPECT_EQ(
+ "f36000d33"
"m2664s888"
"m444s444m444s444m444s888m444"
"s888m1332"
@@ -544,6 +564,7 @@ TEST(TestSendRC6, SendMode0WithRepeats) {
irsend.reset();
irsend.sendRC6(0x175, kRC6Mode0Bits, 0);
EXPECT_EQ(
+ "f36000d33"
"m2664s888"
"m444s888m444s444m444s444m444"
"s888m888"
@@ -554,6 +575,7 @@ TEST(TestSendRC6, SendMode0WithRepeats) {
irsend.reset();
irsend.sendRC6(0x175, kRC6Mode0Bits, 1);
EXPECT_EQ(
+ "f36000d33"
"m2664s888"
"m444s888m444s444m444s444m444"
"s888m888"
@@ -569,6 +591,7 @@ TEST(TestSendRC6, SendMode0WithRepeats) {
irsend.reset();
irsend.sendRC6(0x175, kRC6Mode0Bits, 2);
EXPECT_EQ(
+ "f36000d33"
"m2664s888"
"m444s888m444s444m444s444m444"
"s888m888"
@@ -595,6 +618,7 @@ TEST(TestSendRC6, Send36BitWithRepeats) {
irsend.reset();
irsend.sendRC6(0x175, kRC6_36Bits, 0);
EXPECT_EQ(
+ "f36000d33"
"m2664s888"
"m444s888m444s444m444s444m444"
"s888m888"
@@ -607,6 +631,7 @@ TEST(TestSendRC6, Send36BitWithRepeats) {
irsend.reset();
irsend.sendRC6(0x175, kRC6_36Bits, 1);
EXPECT_EQ(
+ "f36000d33"
"m2664s888"
"m444s888m444s444m444s444m444"
"s888m888"
@@ -626,6 +651,7 @@ TEST(TestSendRC6, Send36BitWithRepeats) {
irsend.reset();
irsend.sendRC6(0x175, kRC6_36Bits, 2);
EXPECT_EQ(
+ "f36000d33"
"m2664s888"
"m444s888m444s444m444s444m444"
"s888m888"
diff --git a/lib/IRremoteESP8266-2.5.2.03/test/ir_RCMM_test.cpp b/lib/IRremoteESP8266-2.6.0/test/ir_RCMM_test.cpp
similarity index 98%
rename from lib/IRremoteESP8266-2.5.2.03/test/ir_RCMM_test.cpp
rename to lib/IRremoteESP8266-2.6.0/test/ir_RCMM_test.cpp
index 028dbd8b3..22306a59b 100644
--- a/lib/IRremoteESP8266-2.5.2.03/test/ir_RCMM_test.cpp
+++ b/lib/IRremoteESP8266-2.6.0/test/ir_RCMM_test.cpp
@@ -14,6 +14,7 @@ TEST(TestSendRCMM, SendDataOnly) {
irsend.reset();
irsend.sendRCMM(0xe0a600);
EXPECT_EQ(
+ "f36000d33"
"m416s277"
"m166s777m166s611m166s277m166s277"
"m166s611m166s611m166s444m166s611m166s277m166s277m166s277m166s277"
@@ -22,6 +23,7 @@ TEST(TestSendRCMM, SendDataOnly) {
irsend.reset();
irsend.sendRCMM(0x28e0a600UL, 32);
EXPECT_EQ(
+ "f36000d33"
"m416s277"
"m166s277m166s611m166s611m166s277m166s777m166s611m166s277m166s277"
"m166s611m166s611m166s444m166s611m166s277m166s277m166s277m166s277"
@@ -37,6 +39,7 @@ TEST(TestSendRCMM, SendWithRepeats) {
irsend.reset();
irsend.sendRCMM(0x28e0a600, 32, 2); // 2 repeats.
EXPECT_EQ(
+ "f36000d33"
"m416s277"
"m166s277m166s611m166s611m166s277m166s777m166s611m166s277m166s277"
"m166s611m166s611m166s444m166s611m166s277m166s277m166s277m166s277"
@@ -60,6 +63,7 @@ TEST(TestSendRCMM, SendUnusualSize) {
irsend.reset();
irsend.sendRCMM(0xE0, 8);
EXPECT_EQ(
+ "f36000d33"
"m416s277"
"m166s777m166s611m166s277m166s277"
"m166s24313",
@@ -67,6 +71,7 @@ TEST(TestSendRCMM, SendUnusualSize) {
irsend.reset();
irsend.sendRCMM(0x28e0a60000UL, 40);
EXPECT_EQ(
+ "f36000d33"
"m416s277"
"m166s277m166s611m166s611m166s277m166s777m166s611m166s277m166s277"
"m166s611m166s611m166s444m166s611m166s277m166s277m166s277m166s277"
diff --git a/lib/IRremoteESP8266-2.5.2.03/test/ir_Samsung_test.cpp b/lib/IRremoteESP8266-2.6.0/test/ir_Samsung_test.cpp
similarity index 77%
rename from lib/IRremoteESP8266-2.5.2.03/test/ir_Samsung_test.cpp
rename to lib/IRremoteESP8266-2.6.0/test/ir_Samsung_test.cpp
index 9ee1fcabb..8670ac4ab 100644
--- a/lib/IRremoteESP8266-2.5.2.03/test/ir_Samsung_test.cpp
+++ b/lib/IRremoteESP8266-2.6.0/test/ir_Samsung_test.cpp
@@ -1,4 +1,4 @@
-// Copyright 2017 David Conran
+// Copyright 2017, 2018, 2019 David Conran
#include "ir_Samsung.h"
#include "IRrecv.h"
@@ -7,6 +7,13 @@
#include "IRsend_test.h"
#include "gtest/gtest.h"
+
+// General housekeeping
+TEST(TestSamsung, Housekeeping) {
+ ASSERT_EQ("SAMSUNG", typeToString(SAMSUNG));
+ ASSERT_FALSE(hasACState(SAMSUNG));
+}
+
// Tests for sendSAMSUNG().
// Test sending typical data only.
@@ -17,6 +24,7 @@ TEST(TestSendSamsung, SendDataOnly) {
irsend.reset();
irsend.sendSAMSUNG(0xE0E09966); // Samsung TV Power On.
EXPECT_EQ(
+ "f38000d33"
"m4480s4480"
"m560s1680m560s1680m560s1680m560s560m560s560m560s560m560s560"
"m560s560m560s1680m560s1680m560s1680m560s560m560s560m560s560"
@@ -36,6 +44,7 @@ TEST(TestSendSamsung, SendWithRepeats) {
irsend.reset();
irsend.sendSAMSUNG(0xE0E09966, kSamsungBits, 1); // 1 repeat.
EXPECT_EQ(
+ "f38000d33"
"m4480s4480"
"m560s1680m560s1680m560s1680m560s560m560s560m560s560m560s560"
"m560s560m560s1680m560s1680m560s1680m560s560m560s560m560s560"
@@ -51,6 +60,7 @@ TEST(TestSendSamsung, SendWithRepeats) {
irsend.outputStr());
irsend.sendSAMSUNG(0xE0E09966, kSamsungBits, 2); // 2 repeats.
EXPECT_EQ(
+ "f38000d33"
"m4480s4480"
"m560s1680m560s1680m560s1680m560s560m560s560m560s560m560s560"
"m560s560m560s1680m560s1680m560s1680m560s560m560s560m560s560"
@@ -281,17 +291,24 @@ TEST(TestDecodeSamsung, FailToDecodeNonSamsungExample) {
ASSERT_FALSE(irrecv.decodeSAMSUNG(&irsend.capture, kSamsungBits, false));
}
+// General housekeeping
+TEST(TestSamsungAC, Housekeeping) {
+ ASSERT_EQ("SAMSUNG_AC", typeToString(SAMSUNG_AC));
+ ASSERT_TRUE(hasACState(SAMSUNG_AC));
+}
+
// 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};
+ uint8_t data[kSamsungAcStateLength] = {
+ 0x02, 0x92, 0x0F, 0x00, 0x00, 0x00, 0xF0,
+ 0x01, 0x02, 0xAF, 0x71, 0x00, 0x15, 0xF0};
irsend.sendSamsungAC(data);
EXPECT_EQ(
+ "f38000d50"
"m690s17844"
"m3086s8864"
"m586s436m586s1432m586s436m586s436m586s436m586s436m586s436m586s436"
@@ -320,10 +337,12 @@ TEST(TestSendSamsungAC, SendExtendedData) {
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};
+ 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(
+ "f38000d50"
"m690s17844"
"m3086s8864"
"m586s436m586s1432m586s436m586s436m586s436m586s436m586s436m586s436"
@@ -358,15 +377,16 @@ TEST(TestSendSamsungAC, SendExtendedData) {
// 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};
+ 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};
+ 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);
@@ -496,9 +516,15 @@ TEST(TestIRSamsungAcClass, ChecksumCalculation) {
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};
+ 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));
@@ -516,6 +542,9 @@ TEST(TestIRSamsungAcClass, ChecksumCalculation) {
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) {
@@ -585,9 +614,9 @@ TEST(TestDecodeSamsungAC, SyntheticDecode) {
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};
+ 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();
@@ -626,9 +655,9 @@ TEST(TestDecodeSamsungAC, DecodeRealExample) {
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};
+ 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();
@@ -675,9 +704,9 @@ TEST(TestDecodeSamsungAC, DecodeRealExample2) {
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};
+ 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();
@@ -735,8 +764,9 @@ TEST(TestDecodeSamsungAC, DecodePowerOnSample) {
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};
+ 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();
@@ -794,8 +824,9 @@ TEST(TestDecodeSamsungAC, DecodePowerOffSample) {
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};
+ 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();
@@ -840,9 +871,9 @@ TEST(TestDecodeSamsungAC, DecodeHeatSample) {
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};
+ 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();
@@ -887,9 +918,9 @@ TEST(TestDecodeSamsungAC, DecodeCoolSample) {
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};
+ 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();
@@ -905,3 +936,195 @@ TEST(TestDecodeSamsungAC, DecodeCoolSample) {
"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());
+}
+
+TEST(TestSendSamsung36, SendDataOnly) {
+ IRsendTest irsend(0);
+ irsend.begin();
+
+ irsend.reset();
+ irsend.sendSamsung36(0);
+ EXPECT_EQ(
+ "f38000d50"
+ "m4480s4480"
+ "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
+ "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
+ "m560s4480"
+ "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
+ "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
+ "m560s560m560s560m560s560m560s560"
+ "m560s26880",
+ irsend.outputStr());
+ irsend.sendSamsung36(0x400E00FF);
+ EXPECT_EQ(
+ "f38000d50"
+ "m4480s4480"
+ "m560s560m560s560m560s560m560s560m560s560m560s1680m560s560m560s560"
+ "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
+ "m560s4480"
+ "m560s1680m560s1680m560s1680m560s560m560s560m560s560m560s560m560s560"
+ "m560s560m560s560m560s560m560s560m560s1680m560s1680m560s1680m560s1680"
+ "m560s1680m560s1680m560s1680m560s1680"
+ "m560s26880",
+ irsend.outputStr());
+ irsend.reset();
+}
+
+// General housekeeping
+TEST(TestSamsung36, Housekeeping) {
+ ASSERT_EQ("SAMSUNG36", typeToString(SAMSUNG36));
+ ASSERT_FALSE(hasACState(SAMSUNG36));
+}
+
+// Test sending with different repeats.
+TEST(TestSendSamsung36, SendWithRepeats) {
+ IRsendTest irsend(0);
+ irsend.begin();
+
+ irsend.reset();
+ irsend.sendSamsung36(0x400E00FF, kSamsung36Bits, 1); // 1 repeat.
+ EXPECT_EQ(
+ "f38000d50"
+ "m4480s4480"
+ "m560s560m560s560m560s560m560s560m560s560m560s1680m560s560m560s560"
+ "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
+ "m560s4480"
+ "m560s1680m560s1680m560s1680m560s560m560s560m560s560m560s560m560s560"
+ "m560s560m560s560m560s560m560s560m560s1680m560s1680m560s1680m560s1680"
+ "m560s1680m560s1680m560s1680m560s1680"
+ "m560s26880"
+ "m4480s4480"
+ "m560s560m560s560m560s560m560s560m560s560m560s1680m560s560m560s560"
+ "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
+ "m560s4480"
+ "m560s1680m560s1680m560s1680m560s560m560s560m560s560m560s560m560s560"
+ "m560s560m560s560m560s560m560s560m560s1680m560s1680m560s1680m560s1680"
+ "m560s1680m560s1680m560s1680m560s1680"
+ "m560s26880",
+ irsend.outputStr());
+ irsend.sendSamsung36(0x400E00FF, kSamsung36Bits, 2); // 2 repeats.
+ EXPECT_EQ(
+ "f38000d50"
+ "m4480s4480"
+ "m560s560m560s560m560s560m560s560m560s560m560s1680m560s560m560s560"
+ "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
+ "m560s4480"
+ "m560s1680m560s1680m560s1680m560s560m560s560m560s560m560s560m560s560"
+ "m560s560m560s560m560s560m560s560m560s1680m560s1680m560s1680m560s1680"
+ "m560s1680m560s1680m560s1680m560s1680"
+ "m560s26880"
+ "m4480s4480"
+ "m560s560m560s560m560s560m560s560m560s560m560s1680m560s560m560s560"
+ "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
+ "m560s4480"
+ "m560s1680m560s1680m560s1680m560s560m560s560m560s560m560s560m560s560"
+ "m560s560m560s560m560s560m560s560m560s1680m560s1680m560s1680m560s1680"
+ "m560s1680m560s1680m560s1680m560s1680"
+ "m560s26880"
+ "m4480s4480"
+ "m560s560m560s560m560s560m560s560m560s560m560s1680m560s560m560s560"
+ "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
+ "m560s4480"
+ "m560s1680m560s1680m560s1680m560s560m560s560m560s560m560s560m560s560"
+ "m560s560m560s560m560s560m560s560m560s1680m560s1680m560s1680m560s1680"
+ "m560s1680m560s1680m560s1680m560s1680"
+ "m560s26880",
+ irsend.outputStr());
+}
+
+TEST(TestDecodeSamsung36, RealExample) {
+ IRsendTest irsend(0);
+ IRrecv irrecv(0);
+ irsend.begin();
+
+ irsend.reset();
+ uint16_t rawData[77] = {
+ 4542, 4438, 568, 432, 562, 436, 536, 462, 538, 460, 538, 460, 564, 1434,
+ 564, 434, 534, 464, 536, 462, 562, 436, 536, 464, 564, 432, 538, 462, 536,
+ 464, 534, 464, 564, 420, 566, 4414, 538, 1462, 566, 1432, 562, 1436, 536,
+ 462, 564, 436, 562, 436, 560, 436, 562, 436, 562, 436, 560, 438, 536, 462,
+ 562, 436, 562, 1436, 562, 1434, 536, 1462, 564, 1434, 562, 1436, 564,
+ 1436, 534, 1462, 534, 1464, 536}; // UNKNOWN E4CD1208
+
+ irsend.sendRaw(rawData, 77, 38000);
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ ASSERT_EQ(SAMSUNG36, irsend.capture.decode_type);
+ EXPECT_EQ(kSamsung36Bits, irsend.capture.bits);
+ EXPECT_EQ(0x400E00FF, irsend.capture.value);
+ EXPECT_EQ(0xE00FF, irsend.capture.command);
+ EXPECT_EQ(0x400, irsend.capture.address);
+}
+
+TEST(TestDecodeSamsung36, SyntheticExample) {
+ IRsendTest irsend(0);
+ IRrecv irrecv(0);
+ irsend.begin();
+ irsend.reset();
+
+ irsend.sendSamsung36(0x400E00FF);
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decodeSamsung36(&irsend.capture));
+ ASSERT_EQ(SAMSUNG36, irsend.capture.decode_type);
+ EXPECT_EQ(kSamsung36Bits, irsend.capture.bits);
+ EXPECT_EQ(0x400E00FF, irsend.capture.value);
+ EXPECT_EQ(0xE00FF, irsend.capture.command);
+ EXPECT_EQ(0x400, irsend.capture.address);
+}
diff --git a/lib/IRremoteESP8266-2.5.2.03/test/ir_Sanyo_test.cpp b/lib/IRremoteESP8266-2.6.0/test/ir_Sanyo_test.cpp
similarity index 99%
rename from lib/IRremoteESP8266-2.5.2.03/test/ir_Sanyo_test.cpp
rename to lib/IRremoteESP8266-2.6.0/test/ir_Sanyo_test.cpp
index 14c1c7da0..165e29f17 100644
--- a/lib/IRremoteESP8266-2.5.2.03/test/ir_Sanyo_test.cpp
+++ b/lib/IRremoteESP8266-2.6.0/test/ir_Sanyo_test.cpp
@@ -27,6 +27,7 @@ TEST(TestEncodeSanyoLC7461, SendDataOnly) {
irsend.reset();
irsend.sendSanyoLC7461(0x1D8113F00FF);
EXPECT_EQ(
+ "f38000d33"
"m8960s4480"
"m560s560m560s1680m560s1680m560s1680m560s560m560s1680m560s1680m560s560"
"m560s560m560s560m560s560m560s560m560s560m560s1680m560s560m560s560"
@@ -45,6 +46,7 @@ TEST(TestEncodeSanyoLC7461, SendWithRepeats) {
irsend.reset();
irsend.sendSanyoLC7461(0x1D8113F00FF, kSanyoLC7461Bits, 1); // 1 repeat.
EXPECT_EQ(
+ "f38000d33"
"m8960s4480"
"m560s560m560s1680m560s1680m560s1680m560s560m560s1680m560s1680m560s560"
"m560s560m560s560m560s560m560s560m560s560m560s1680m560s560m560s560"
diff --git a/lib/IRremoteESP8266-2.5.2.03/test/ir_Sharp_test.cpp b/lib/IRremoteESP8266-2.6.0/test/ir_Sharp_test.cpp
similarity index 98%
rename from lib/IRremoteESP8266-2.5.2.03/test/ir_Sharp_test.cpp
rename to lib/IRremoteESP8266-2.6.0/test/ir_Sharp_test.cpp
index 8481a4649..c9d3e851b 100644
--- a/lib/IRremoteESP8266-2.5.2.03/test/ir_Sharp_test.cpp
+++ b/lib/IRremoteESP8266-2.6.0/test/ir_Sharp_test.cpp
@@ -47,6 +47,7 @@ TEST(TestSendSharp, SendDataOnly) {
irsend.reset();
irsend.sendSharp(0x11, 0x52);
EXPECT_EQ(
+ "f38000d33"
"m260s1820m260s780m260s780m260s780m260s1820m260s780m260s1820m260s780"
"m260s1820m260s780m260s780m260s1820m260s780m260s1820m260s780"
"m260s43602"
@@ -64,6 +65,7 @@ TEST(TestSendSharp, SendWithRepeats) {
irsend.reset();
irsend.sendSharp(0x11, 0x52, kSharpBits, 1); // 1 repeat.
EXPECT_EQ(
+ "f38000d33"
"m260s1820m260s780m260s780m260s780m260s1820m260s780m260s1820m260s780"
"m260s1820m260s780m260s780m260s1820m260s780m260s1820m260s780"
"m260s43602"
@@ -87,6 +89,7 @@ TEST(TestSendSharp, SendUnusualSize) {
irsend.reset();
irsend.sendSharp(0x0, 0x0, 8);
EXPECT_EQ(
+ "f38000d33"
"m260s780m260s780m260s780m260s780m260s780m260s780m260s1820m260s780"
"m260s43602"
"m260s1820m260s1820m260s1820m260s1820m260s1820m260s1820m260s780m260s1820"
@@ -96,6 +99,7 @@ TEST(TestSendSharp, SendUnusualSize) {
irsend.reset();
irsend.sendSharp(0x0, 0x0, 16);
EXPECT_EQ(
+ "f38000d33"
"m260s780m260s780m260s780m260s780m260s780m260s780m260s780m260s780"
"m260s780m260s780m260s780m260s780m260s780m260s780m260s1820m260s780"
"m260s43602"
@@ -115,6 +119,7 @@ TEST(TestSendSharpRaw, SendDataOnly) {
irsend.reset();
irsend.sendSharpRaw(0x454A);
EXPECT_EQ(
+ "f38000d33"
"m260s1820m260s780m260s780m260s780m260s1820m260s780m260s1820m260s780"
"m260s1820m260s780m260s780m260s1820m260s780m260s1820m260s780"
"m260s43602"
@@ -132,6 +137,7 @@ TEST(TestSendSharpRaw, SendWithRepeats) {
irsend.reset();
irsend.sendSharpRaw(0x454A, kSharpBits, 1); // 1 repeat.
EXPECT_EQ(
+ "f38000d33"
"m260s1820m260s780m260s780m260s780m260s1820m260s780m260s1820m260s780"
"m260s1820m260s780m260s780m260s1820m260s780m260s1820m260s780"
"m260s43602"
@@ -155,6 +161,7 @@ TEST(TestSendSharpRaw, SendUnusualSize) {
irsend.reset();
irsend.sendSharpRaw(0x2, 8);
EXPECT_EQ(
+ "f38000d33"
"m260s780m260s780m260s780m260s780m260s780m260s780m260s1820m260s780"
"m260s43602"
"m260s1820m260s1820m260s1820m260s1820m260s1820m260s1820m260s780m260s1820"
@@ -164,6 +171,7 @@ TEST(TestSendSharpRaw, SendUnusualSize) {
irsend.reset();
irsend.sendSharpRaw(0x2, 16);
EXPECT_EQ(
+ "f38000d33"
"m260s780m260s780m260s780m260s780m260s780m260s780m260s780m260s780"
"m260s780m260s780m260s780m260s780m260s780m260s780m260s1820m260s780"
"m260s43602"
diff --git a/lib/IRremoteESP8266-2.5.2.03/test/ir_Sherwood_test.cpp b/lib/IRremoteESP8266-2.6.0/test/ir_Sherwood_test.cpp
similarity index 97%
rename from lib/IRremoteESP8266-2.5.2.03/test/ir_Sherwood_test.cpp
rename to lib/IRremoteESP8266-2.6.0/test/ir_Sherwood_test.cpp
index 22d9ead38..f1f41d9c8 100644
--- a/lib/IRremoteESP8266-2.5.2.03/test/ir_Sherwood_test.cpp
+++ b/lib/IRremoteESP8266-2.6.0/test/ir_Sherwood_test.cpp
@@ -14,6 +14,7 @@ TEST(TestSendSherwood, SendDataOnly) {
irsend.reset();
irsend.sendSherwood(0xC1A28877);
EXPECT_EQ(
+ "f38000d33"
"m8960s4480m560s1680m560s1680m560s560m560s560m560s560m560s560"
"m560s560m560s1680m560s1680m560s560m560s1680m560s560m560s560"
"m560s560m560s1680m560s560m560s1680m560s560m560s560m560s560"
@@ -31,6 +32,7 @@ TEST(TestSendSherwood, SendDataWithRepeats) {
irsend.reset();
irsend.sendSherwood(0xC1A28877, 32, 2);
EXPECT_EQ(
+ "f38000d33"
"m8960s4480m560s1680m560s1680m560s560m560s560m560s560m560s560"
"m560s560m560s1680m560s1680m560s560m560s1680m560s560m560s560"
"m560s560m560s1680m560s560m560s1680m560s560m560s560m560s560"
@@ -50,6 +52,7 @@ TEST(TestSendSherwood, SendDataWithZeroRepeats) {
irsend.sendSherwood(0xC1A28877, 32, 0);
// Should have a single NEC repeat, as we always send one.
EXPECT_EQ(
+ "f38000d33"
"m8960s4480m560s1680m560s1680m560s560m560s560m560s560m560s560"
"m560s560m560s1680m560s1680m560s560m560s1680m560s560m560s560"
"m560s560m560s1680m560s560m560s1680m560s560m560s560m560s560"
diff --git a/lib/IRremoteESP8266-2.5.2.03/test/ir_Sony_test.cpp b/lib/IRremoteESP8266-2.6.0/test/ir_Sony_test.cpp
similarity index 99%
rename from lib/IRremoteESP8266-2.5.2.03/test/ir_Sony_test.cpp
rename to lib/IRremoteESP8266-2.6.0/test/ir_Sony_test.cpp
index c79ff6175..35c3287b0 100644
--- a/lib/IRremoteESP8266-2.5.2.03/test/ir_Sony_test.cpp
+++ b/lib/IRremoteESP8266-2.6.0/test/ir_Sony_test.cpp
@@ -15,6 +15,7 @@ TEST(TestSendSony, SendDataOnly) {
irsend.sendSony(0);
// We expect three 20-bit commands to be sent.
EXPECT_EQ(
+ "f40000d33"
"m2400s600m600s600m600s600m600s600m600s600m600s600m600s600m600s600"
"m600s600m600s600m600s600m600s600m600s600m600s600m600s600m600s600"
"m600s600m600s600m600s600m600s600m600s18600"
@@ -30,6 +31,7 @@ TEST(TestSendSony, SendDataOnly) {
irsend.sendSony(0x240C, kSony20Bits);
// We expect three 20-bit commands to be sent.
EXPECT_EQ(
+ "f40000d33"
"m2400s600m600s600m600s600m600s600m600s600m600s600m600s600m1200s600"
"m600s600m600s600m1200s600m600s600m600s600m600s600m600s600m600s600"
"m600s600m1200s600m1200s600m600s600m600s16200"
@@ -45,6 +47,7 @@ TEST(TestSendSony, SendDataOnly) {
irsend.sendSony(0x240C, kSony15Bits);
// We expect three 15-bit commands to be sent.
EXPECT_EQ(
+ "f40000d33"
"m2400s600m600s600m1200s600m600s600m600s600m1200s600m600s600"
"m600s600m600s600m600s600m600s600m600s600m1200s600m1200s600m600s600"
"m600s22200"
@@ -60,6 +63,7 @@ TEST(TestSendSony, SendDataOnly) {
irsend.sendSony(0xA90, kSony12Bits);
// We expect three 15-bit commands to be sent.
EXPECT_EQ(
+ "f40000d33"
"m2400s600m1200s600m600s600m1200s600m600s600m1200s600m600s600"
"m600s600m1200s600m600s600m600s600m600s600m600s25800"
"m2400s600m1200s600m600s600m1200s600m600s600m1200s600m600s600"
@@ -77,12 +81,14 @@ TEST(TestSendSony, SendWithDiffRepeats) {
irsend.reset();
irsend.sendSony(0x240C, kSony20Bits, 0); // Send a command with 0 repeats.
EXPECT_EQ(
+ "f40000d33"
"m2400s600m600s600m600s600m600s600m600s600m600s600m600s600m1200s600"
"m600s600m600s600m1200s600m600s600m600s600m600s600m600s600m600s600"
"m600s600m1200s600m1200s600m600s600m600s16200",
irsend.outputStr());
irsend.sendSony(0x240C, kSony20Bits, 1); // Send a command with 1 repeat.
EXPECT_EQ(
+ "f40000d33"
"m2400s600m600s600m600s600m600s600m600s600m600s600m600s600m1200s600"
"m600s600m600s600m1200s600m600s600m600s600m600s600m600s600m600s600"
"m600s600m1200s600m1200s600m600s600m600s16200"
@@ -92,6 +98,7 @@ TEST(TestSendSony, SendWithDiffRepeats) {
irsend.outputStr());
irsend.sendSony(0x240C, kSony20Bits, 3); // Send a command with 3 repeats.
EXPECT_EQ(
+ "f40000d33"
"m2400s600m600s600m600s600m600s600m600s600m600s600m600s600m1200s600"
"m600s600m600s600m1200s600m600s600m600s600m600s600m600s600m600s600"
"m600s600m1200s600m1200s600m600s600m600s16200"
diff --git a/lib/IRremoteESP8266-2.6.0/test/ir_Tcl_test.cpp b/lib/IRremoteESP8266-2.6.0/test/ir_Tcl_test.cpp
new file mode 100644
index 000000000..249dcc637
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/test/ir_Tcl_test.cpp
@@ -0,0 +1,384 @@
+// Copyright 2019 David Conran
+
+#include "ir_Tcl.h"
+#include "IRrecv.h"
+#include "IRrecv_test.h"
+#include "IRsend.h"
+#include "IRsend_test.h"
+#include "gtest/gtest.h"
+
+// General housekeeping
+TEST(TestTcl112Ac, Housekeeping) {
+ ASSERT_EQ("TCL112AC", typeToString(TCL112AC));
+ ASSERT_TRUE(hasACState(TCL112AC));
+}
+
+// Tests for decodeTcl112Ac().
+
+// Decode a real Tcl112Ac A/C example from Issue #619
+TEST(TestDecodeTcl112Ac, DecodeRealExample) {
+ IRsendTest irsend(0);
+ IRrecv irrecv(0);
+ irsend.begin();
+
+ irsend.reset();
+ // Tcl112Ac A/C example from Issue #619 On.txt
+ uint16_t rawData[227] = {
+ 3030, 1658, 494, 1066, 494, 1068, 498, 320, 494,
+ 326, 498, 320, 494, 1068, 500, 320, 494, 332,
+ 494, 1068, 500, 1062, 496, 324, 492, 1044, 524,
+ 322, 492, 326, 498, 1062, 494, 1074, 494, 326,
+ 500, 1062, 496, 1066, 490, 328, 496, 322, 492,
+ 1070, 498, 322, 494, 332, 492, 1068, 498, 320,
+ 494, 326, 498, 320, 496, 324, 500, 320, 494,
+ 324, 490, 336, 500, 320, 496, 324, 490, 328,
+ 496, 322, 492, 328, 498, 322, 492, 326, 498,
+ 328, 496, 322, 492, 328, 498, 1064, 494, 326,
+ 498, 320, 494, 1066, 490, 330, 496, 330, 494,
+ 1066, 490, 1070, 498, 322, 492, 328, 498, 322,
+ 492, 326, 498, 322, 492, 332, 492, 1068, 498,
+ 1062, 494, 1066, 500, 318, 496, 324, 490, 328,
+ 496, 324, 492, 334, 490, 328, 496, 324, 492,
+ 328, 496, 322, 492, 328, 498, 320, 494, 1068,
+ 500, 326, 500, 320, 492, 326, 500, 320, 496,
+ 324, 500, 318, 496, 324, 490, 328, 496, 330,
+ 496, 324, 490, 328, 496, 324, 490, 328, 498,
+ 322, 492, 328, 498, 320, 492, 334, 492, 328,
+ 498, 322, 494, 326, 498, 320, 494, 324, 500,
+ 322, 492, 324, 490, 336, 498, 320, 494, 324,
+ 500, 320, 496, 324, 490, 328, 498, 322, 492,
+ 328, 496, 1070, 496, 1064, 492, 1070, 498, 322,
+ 494, 326, 500, 320, 494, 324, 500, 320, 494,
+ 324, 470}; // UNKNOWN CE60D6B9
+ uint8_t expectedState[kTcl112AcStateLength] = {
+ 0x23, 0xCB, 0x26, 0x01, 0x00, 0x24, 0x03,
+ 0x07, 0x40, 0x00, 0x00, 0x00, 0x80, 0x03};
+
+ irsend.sendRaw(rawData, 227, 38000);
+ irsend.makeDecodeResult();
+
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ ASSERT_EQ(TCL112AC, irsend.capture.decode_type);
+ EXPECT_EQ(kTcl112AcBits, irsend.capture.bits);
+ EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits);
+
+ IRTcl112Ac ac(0);
+ ac.setRaw(irsend.capture.state);
+ EXPECT_EQ(
+ "Power: On, Mode: 3 (COOL), Temp: 24C, Fan: 0 (Auto), Econo: Off, "
+ "Health: Off, Light: On, Turbo: Off, Swing (H): Off, Swing (V): Off",
+ ac.toString());
+}
+
+// Decode a synthetic Tcl112Ac A/C example from Issue #619
+TEST(TestDecodeTcl112Ac, DecodeSyntheticExample) {
+ IRsendTest irsend(0);
+ IRrecv irrecv(0);
+ irsend.begin();
+
+ irsend.reset();
+
+ uint8_t expectedState[kTcl112AcStateLength] = {0x23, 0xCB, 0x26, 0x01, 0x00,
+ 0x24, 0x03, 0x07, 0x40, 0x00,
+ 0x00, 0x00, 0x80, 0x03};
+
+ irsend.sendTcl112Ac(expectedState);
+ irsend.makeDecodeResult();
+
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ ASSERT_EQ(TCL112AC, irsend.capture.decode_type);
+ EXPECT_EQ(kTcl112AcBits, irsend.capture.bits);
+ EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits);
+}
+
+TEST(TestTcl112AcClass, Temperature) {
+ const uint8_t temp16C[kTcl112AcStateLength] = {
+ 0x23, 0xCB, 0x26, 0x01, 0x00, 0x24, 0x03,
+ 0x0F, 0x00, 0x00, 0x00, 0x00, 0x80, 0xCB};
+ const uint8_t temp16point5C[kTcl112AcStateLength] = {
+ 0x23, 0xCB, 0x26, 0x01, 0x00, 0x24, 0x03,
+ 0x0F, 0x00, 0x00, 0x00, 0x00, 0xA0, 0xEB};
+ const uint8_t temp19point5C[kTcl112AcStateLength] = {
+ 0x23, 0xCB, 0x26, 0x01, 0x00, 0x24, 0x03,
+ 0x0C, 0x00, 0x00, 0x00, 0x00, 0xA0, 0xE8};
+ const uint8_t temp31C[kTcl112AcStateLength] = {
+ 0x23, 0xCB, 0x26, 0x01, 0x00, 0x24, 0x03,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xBC};
+ IRTcl112Ac ac(0);
+ ac.setRaw(temp16C);
+ EXPECT_EQ(
+ "Power: On, Mode: 3 (COOL), Temp: 16C, Fan: 0 (Auto), Econo: Off, "
+ "Health: Off, Light: On, Turbo: Off, Swing (H): Off, Swing (V): Off",
+ ac.toString());
+ ac.setRaw(temp16point5C);
+ EXPECT_EQ(
+ "Power: On, Mode: 3 (COOL), Temp: 16.5C, Fan: 0 (Auto), Econo: Off, "
+ "Health: Off, Light: On, Turbo: Off, Swing (H): Off, Swing (V): Off",
+ ac.toString());
+ ac.setRaw(temp19point5C);
+ EXPECT_EQ(
+ "Power: On, Mode: 3 (COOL), Temp: 19.5C, Fan: 0 (Auto), Econo: Off, "
+ "Health: Off, Light: On, Turbo: Off, Swing (H): Off, Swing (V): Off",
+ ac.toString());
+ ac.setRaw(temp31C);
+ EXPECT_EQ(
+ "Power: On, Mode: 3 (COOL), Temp: 31C, Fan: 0 (Auto), Econo: Off, "
+ "Health: Off, Light: On, Turbo: Off, Swing (H): Off, Swing (V): Off",
+ ac.toString());
+
+ ac.setTemp(kTcl112AcTempMin);
+ EXPECT_EQ(kTcl112AcTempMin, ac.getTemp());
+
+ ac.setTemp(kTcl112AcTempMin + 1);
+ EXPECT_EQ(kTcl112AcTempMin + 1, ac.getTemp());
+
+ ac.setTemp(kTcl112AcTempMax);
+ EXPECT_EQ(kTcl112AcTempMax, ac.getTemp());
+
+ ac.setTemp(kTcl112AcTempMin - 1);
+ EXPECT_EQ(kTcl112AcTempMin, ac.getTemp());
+
+ ac.setTemp(kTcl112AcTempMax + 0.5);
+ EXPECT_EQ(kTcl112AcTempMax, ac.getTemp());
+
+ ac.setTemp(23);
+ EXPECT_EQ(23, ac.getTemp());
+
+ ac.setTemp(27.4);
+ EXPECT_EQ(27, ac.getTemp());
+
+ ac.setTemp(22.5);
+ EXPECT_EQ(22.5, ac.getTemp());
+
+ ac.setTemp(25.6);
+ EXPECT_EQ(25.5, ac.getTemp());
+
+ ac.setTemp(0);
+ EXPECT_EQ(kTcl112AcTempMin, ac.getTemp());
+
+ ac.setTemp(255);
+ EXPECT_EQ(kTcl112AcTempMax, ac.getTemp());
+}
+
+TEST(TestTcl112AcClass, OperatingMode) {
+ IRTcl112Ac ac(0);
+ ac.begin();
+
+ ac.setMode(kTcl112AcAuto);
+ EXPECT_EQ(kTcl112AcAuto, ac.getMode());
+
+ ac.setMode(kTcl112AcCool);
+ EXPECT_EQ(kTcl112AcCool, ac.getMode());
+
+ ac.setMode(kTcl112AcHeat);
+ EXPECT_EQ(kTcl112AcHeat, ac.getMode());
+
+ ac.setFan(kTcl112AcFanAuto);
+ ac.setMode(kTcl112AcFan); // Should set fan speed to High.
+ EXPECT_EQ(kTcl112AcFan, ac.getMode());
+ EXPECT_EQ(kTcl112AcFanHigh, ac.getFan());
+
+ ac.setMode(kTcl112AcDry);
+ EXPECT_EQ(kTcl112AcDry, ac.getMode());
+
+ ac.setMode(kTcl112AcHeat - 1);
+ EXPECT_EQ(kTcl112AcAuto, ac.getMode());
+
+ ac.setMode(kTcl112AcCool);
+ EXPECT_EQ(kTcl112AcCool, ac.getMode());
+
+ ac.setMode(kTcl112AcAuto + 1);
+ EXPECT_EQ(kTcl112AcAuto, ac.getMode());
+
+ ac.setMode(kTcl112AcCool);
+ ac.setMode(255);
+ EXPECT_EQ(kTcl112AcAuto, ac.getMode());
+
+ ac.setMode(kTcl112AcCool);
+ ac.setMode(0);
+ EXPECT_EQ(kTcl112AcAuto, ac.getMode());
+
+ const uint8_t automode[] = {
+ 0x23, 0xCB, 0x26, 0x01, 0x00, 0x24, 0x08,
+ 0x07, 0x00, 0x00, 0x00, 0x00, 0x80, 0x48};
+ ac.setRaw(automode);
+ EXPECT_EQ(
+ "Power: On, Mode: 8 (AUTO), Temp: 24C, Fan: 0 (Auto), Econo: Off, "
+ "Health: Off, Light: On, Turbo: Off, Swing (H): Off, Swing (V): Off",
+ ac.toString());
+}
+
+TEST(TestTcl112AcClass, Power) {
+ IRTcl112Ac 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());
+
+ const uint8_t on[kTcl112AcStateLength] = {
+ 0x23, 0xCB, 0x26, 0x01, 0x00, 0x24, 0x03,
+ 0x0F, 0x00, 0x00, 0x00, 0x00, 0x80, 0xCB};
+ ac.setRaw(on);
+ EXPECT_EQ(
+ "Power: On, Mode: 3 (COOL), Temp: 16C, Fan: 0 (Auto), Econo: Off, "
+ "Health: Off, Light: On, Turbo: Off, Swing (H): Off, Swing (V): Off",
+ ac.toString());
+
+ const uint8_t off[kTcl112AcStateLength] = {
+ 0x23, 0xCB, 0x26, 0x01, 0x00, 0x20, 0x03,
+ 0x07, 0x40, 0x00, 0x00, 0x00, 0x80, 0xCB};
+ ac.setRaw(off);
+ EXPECT_EQ(
+ "Power: Off, Mode: 3 (COOL), Temp: 24C, Fan: 0 (Auto), Econo: Off, "
+ "Health: Off, Light: On, Turbo: Off, Swing (H): Off, Swing (V): Off",
+ ac.toString());
+}
+
+
+TEST(TestTcl112AcClass, Checksum) {
+ uint8_t temp16C[kTcl112AcStateLength] = {
+ 0x23, 0xCB, 0x26, 0x01, 0x00, 0x24, 0x03,
+ 0x0F, 0x00, 0x00, 0x00, 0x00, 0x80, 0xCB};
+ uint8_t temp31C[kTcl112AcStateLength] = {
+ 0x23, 0xCB, 0x26, 0x01, 0x00, 0x24, 0x03,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xBC};
+ IRTcl112Ac ac(0);
+ EXPECT_EQ(0xCB, ac.calcChecksum(temp16C));
+ ac.setRaw(temp16C);
+ EXPECT_EQ(
+ "Power: On, Mode: 3 (COOL), Temp: 16C, Fan: 0 (Auto), Econo: Off, "
+ "Health: Off, Light: On, Turbo: Off, Swing (H): Off, Swing (V): Off",
+ ac.toString());
+ ac.setRaw(temp31C);
+ EXPECT_EQ(
+ "Power: On, Mode: 3 (COOL), Temp: 31C, Fan: 0 (Auto), Econo: Off, "
+ "Health: Off, Light: On, Turbo: Off, Swing (H): Off, Swing (V): Off",
+ ac.toString());
+ EXPECT_EQ(0xBC, ac.calcChecksum(temp31C));
+
+ EXPECT_TRUE(IRTcl112Ac::validChecksum(temp16C));
+ EXPECT_TRUE(IRTcl112Ac::validChecksum(temp31C));
+ EXPECT_TRUE(ac.validChecksum(temp31C));
+ ac.setRaw(temp16C);
+ EXPECT_TRUE(ac.validChecksum(ac.getRaw()));
+ ac.setTemp(31);
+ EXPECT_TRUE(ac.validChecksum(ac.getRaw()));
+ EXPECT_EQ(0xBC, ac.calcChecksum(ac.getRaw()));
+}
+
+TEST(TestTcl112AcClass, Econo) {
+ IRTcl112Ac ac(0);
+ ac.begin();
+
+ ac.setEcono(true);
+ EXPECT_TRUE(ac.getEcono());
+ ac.setEcono(false);
+ EXPECT_EQ(false, ac.getEcono());
+ ac.setEcono(true);
+ EXPECT_TRUE(ac.getEcono());
+}
+
+TEST(TestTcl112AcClass, Health) {
+ IRTcl112Ac ac(0);
+ ac.begin();
+
+ ac.setHealth(true);
+ EXPECT_TRUE(ac.getHealth());
+ ac.setHealth(false);
+ EXPECT_EQ(false, ac.getHealth());
+ ac.setHealth(true);
+ EXPECT_TRUE(ac.getHealth());
+}
+
+TEST(TestTcl112AcClass, Light) {
+ IRTcl112Ac ac(0);
+ ac.begin();
+
+ ac.setLight(true);
+ EXPECT_TRUE(ac.getLight());
+ ac.setLight(false);
+ EXPECT_EQ(false, ac.getLight());
+ ac.setLight(true);
+ EXPECT_TRUE(ac.getLight());
+}
+
+TEST(TestTcl112AcClass, SwingHorizontal) {
+ IRTcl112Ac ac(0);
+ ac.begin();
+
+ ac.setSwingHorizontal(true);
+ EXPECT_TRUE(ac.getSwingHorizontal());
+ ac.setSwingHorizontal(false);
+ EXPECT_EQ(false, ac.getSwingHorizontal());
+ ac.setSwingHorizontal(true);
+ EXPECT_TRUE(ac.getSwingHorizontal());
+}
+
+TEST(TestTcl112AcClass, SwingVertical) {
+ IRTcl112Ac ac(0);
+ ac.begin();
+
+ ac.setSwingVertical(true);
+ EXPECT_TRUE(ac.getSwingVertical());
+ ac.setSwingVertical(false);
+ EXPECT_EQ(false, ac.getSwingVertical());
+ ac.setSwingVertical(true);
+ EXPECT_TRUE(ac.getSwingVertical());
+}
+
+TEST(TestTcl112AcClass, Turbo) {
+ IRTcl112Ac ac(0);
+ ac.begin();
+
+ ac.setFan(kTcl112AcFanLow);
+ ac.setSwingHorizontal(false);
+
+ ac.setTurbo(false);
+ EXPECT_FALSE(ac.getTurbo());
+ EXPECT_FALSE(ac.getSwingVertical());
+ EXPECT_EQ(kTcl112AcFanLow, ac.getFan());
+
+ ac.setTurbo(true);
+ EXPECT_TRUE(ac.getTurbo());
+ EXPECT_TRUE(ac.getSwingVertical());
+ EXPECT_EQ(kTcl112AcFanHigh, ac.getFan());
+
+ ac.setTurbo(false);
+ EXPECT_FALSE(ac.getTurbo());
+ ac.setTurbo(true);
+ EXPECT_TRUE(ac.getTurbo());
+}
+
+TEST(TestTcl112AcClass, FanSpeed) {
+ IRTcl112Ac ac(0);
+ ac.begin();
+
+ // Unexpected value should default to Auto.
+ ac.setFan(255);
+ EXPECT_EQ(kTcl112AcFanAuto, ac.getFan());
+
+ ac.setFan(kTcl112AcFanLow);
+ EXPECT_EQ(kTcl112AcFanLow, ac.getFan());
+ ac.setFan(kTcl112AcFanMed);
+ EXPECT_EQ(kTcl112AcFanMed, ac.getFan());
+ ac.setFan(kTcl112AcFanHigh);
+ EXPECT_EQ(kTcl112AcFanHigh, ac.getFan());
+ ac.setFan(kTcl112AcFanAuto);
+ EXPECT_EQ(kTcl112AcFanAuto, ac.getFan());
+
+ // Beyond High should default to Auto.
+ ac.setFan(kTcl112AcFanHigh + 1);
+ EXPECT_EQ(kTcl112AcFanAuto, ac.getFan());
+}
diff --git a/lib/IRremoteESP8266-2.6.0/test/ir_Teco_test.cpp b/lib/IRremoteESP8266-2.6.0/test/ir_Teco_test.cpp
new file mode 100644
index 000000000..6b03a671d
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/test/ir_Teco_test.cpp
@@ -0,0 +1,358 @@
+// Copyright 2019 David Conran
+
+#include "ir_Teco.h"
+#include "IRrecv.h"
+#include "IRrecv_test.h"
+#include "IRsend.h"
+#include "IRsend_test.h"
+#include "gtest/gtest.h"
+
+// General housekeeping
+TEST(TestTeco, Housekeeping) {
+ ASSERT_EQ("TECO", typeToString(TECO));
+ ASSERT_FALSE(hasACState(TECO)); // Uses uint64_t, not uint8_t*.
+}
+
+// Tests for sendTeco()
+
+// Test sending typical data only.
+TEST(TestSendTeco, SendDataOnly) {
+ IRsendTest irsend(0);
+ irsend.begin();
+
+ irsend.reset();
+ irsend.sendTeco(0x250002BC9);
+ EXPECT_EQ(
+ "f38000d50"
+ "m9000s4440"
+ "m620s1650m620s580m620s580m620s1650m620s580m620s580m620s1650m620s1650"
+ "m620s1650m620s1650m620s580m620s1650m620s580m620s1650m620s580m620s580"
+ "m620s580m620s580m620s580m620s580m620s580m620s580m620s580m620s580"
+ "m620s580m620s580m620s580m620s580m620s1650m620s580m620s1650m620s580"
+ "m620s580m620s1650m620s580"
+ "m620s100000",
+ irsend.outputStr());
+}
+
+// Test sending typical data with repeats.
+TEST(TestSendTeco, SendWithRepeats) {
+ IRsendTest irsend(0);
+ irsend.begin();
+
+ irsend.reset();
+ irsend.sendTeco(0x250002BC9, kTecoBits, 2); // two repeats.
+ EXPECT_EQ(
+ "f38000d50"
+ "m9000s4440"
+ "m620s1650m620s580m620s580m620s1650m620s580m620s580m620s1650m620s1650"
+ "m620s1650m620s1650m620s580m620s1650m620s580m620s1650m620s580m620s580"
+ "m620s580m620s580m620s580m620s580m620s580m620s580m620s580m620s580"
+ "m620s580m620s580m620s580m620s580m620s1650m620s580m620s1650m620s580"
+ "m620s580m620s1650m620s580"
+ "m620s100000"
+ "m9000s4440"
+ "m620s1650m620s580m620s580m620s1650m620s580m620s580m620s1650m620s1650"
+ "m620s1650m620s1650m620s580m620s1650m620s580m620s1650m620s580m620s580"
+ "m620s580m620s580m620s580m620s580m620s580m620s580m620s580m620s580"
+ "m620s580m620s580m620s580m620s580m620s1650m620s580m620s1650m620s580"
+ "m620s580m620s1650m620s580"
+ "m620s100000"
+ "m9000s4440"
+ "m620s1650m620s580m620s580m620s1650m620s580m620s580m620s1650m620s1650"
+ "m620s1650m620s1650m620s580m620s1650m620s580m620s1650m620s580m620s580"
+ "m620s580m620s580m620s580m620s580m620s580m620s580m620s580m620s580"
+ "m620s580m620s580m620s580m620s580m620s1650m620s580m620s1650m620s580"
+ "m620s580m620s1650m620s580"
+ "m620s100000",
+ irsend.outputStr());
+}
+
+
+// Tests for IRTeco class.
+
+TEST(TestTecoACClass, Power) {
+ IRTecoAc 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());
+}
+
+TEST(TestTecoACClass, OperatingMode) {
+ IRTecoAc ac(0);
+ ac.begin();
+
+ ac.setMode(kTecoAuto);
+ EXPECT_EQ(kTecoAuto, ac.getMode());
+
+ ac.setMode(kTecoCool);
+ EXPECT_EQ(kTecoCool, ac.getMode());
+
+ ac.setMode(kTecoHeat);
+ EXPECT_EQ(kTecoHeat, ac.getMode());
+
+ ac.setMode(kTecoFan);
+ EXPECT_EQ(kTecoFan, ac.getMode());
+
+ ac.setMode(kTecoDry);
+ EXPECT_EQ(kTecoDry, ac.getMode());
+
+ ac.setMode(kTecoAuto - 1);
+ EXPECT_EQ(kTecoAuto, ac.getMode());
+
+ ac.setMode(kTecoCool);
+ EXPECT_EQ(kTecoCool, ac.getMode());
+
+ ac.setMode(kTecoHeat + 1);
+ EXPECT_EQ(kTecoAuto, ac.getMode());
+
+ ac.setMode(255);
+ EXPECT_EQ(kTecoAuto, ac.getMode());
+}
+
+TEST(TestTecoACClass, Temperature) {
+ IRTecoAc ac(0);
+ ac.begin();
+
+ ac.setTemp(kTecoMinTemp);
+ EXPECT_EQ(kTecoMinTemp, ac.getTemp());
+
+ ac.setTemp(kTecoMinTemp + 1);
+ EXPECT_EQ(kTecoMinTemp + 1, ac.getTemp());
+
+ ac.setTemp(kTecoMaxTemp);
+ EXPECT_EQ(kTecoMaxTemp, ac.getTemp());
+
+ ac.setTemp(kTecoMinTemp - 1);
+ EXPECT_EQ(kTecoMinTemp, ac.getTemp());
+
+ ac.setTemp(kTecoMaxTemp + 1);
+ EXPECT_EQ(kTecoMaxTemp, ac.getTemp());
+
+ ac.setTemp(23);
+ EXPECT_EQ(23, ac.getTemp());
+
+ ac.setTemp(0);
+ EXPECT_EQ(kTecoMinTemp, ac.getTemp());
+
+ ac.setTemp(255);
+ EXPECT_EQ(kTecoMaxTemp, ac.getTemp());
+}
+
+TEST(TestTecoACClass, FanSpeed) {
+ IRTecoAc ac(0);
+ ac.begin();
+ ac.setFan(kTecoFanLow);
+
+ ac.setFan(kTecoFanAuto);
+ EXPECT_EQ(kTecoFanAuto, ac.getFan());
+
+ ac.setFan(kTecoFanLow);
+ EXPECT_EQ(kTecoFanLow, ac.getFan());
+ ac.setFan(kTecoFanMed);
+ EXPECT_EQ(kTecoFanMed, ac.getFan());
+ ac.setFan(kTecoFanHigh);
+ EXPECT_EQ(kTecoFanHigh, ac.getFan());
+
+ ac.setFan(kTecoFanHigh);
+ EXPECT_EQ(kTecoFanHigh, ac.getFan());
+}
+
+TEST(TestTecoACClass, Swing) {
+ IRTecoAc 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());
+}
+
+TEST(TestTecoACClass, Sleep) {
+ IRTecoAc 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());
+}
+
+TEST(TestTecoACClass, MessageConstuction) {
+ IRTecoAc ac(0);
+
+ EXPECT_EQ(
+ "Power: Off, Mode: 0 (AUTO), Temp: 16C, Fan: 0 (Auto), Sleep: Off, "
+ "Swing: Off",
+ ac.toString());
+ ac.setPower(true);
+ ac.setMode(kTecoCool);
+ ac.setTemp(21);
+ ac.setFan(kTecoFanHigh);
+ ac.setSwing(false);
+ EXPECT_EQ(
+ "Power: On, Mode: 1 (COOL), Temp: 21C, Fan: 3 (High), Sleep: Off, "
+ "Swing: Off",
+ ac.toString());
+ ac.setSwing(true);
+ EXPECT_EQ(
+ "Power: On, Mode: 1 (COOL), Temp: 21C, Fan: 3 (High), Sleep: Off, "
+ "Swing: On",
+ ac.toString());
+ ac.setSwing(false);
+ ac.setFan(kTecoFanLow);
+ ac.setSleep(true);
+ ac.setMode(kTecoHeat);
+ EXPECT_EQ(
+ "Power: On, Mode: 4 (HEAT), Temp: 21C, Fan: 1 (Low), Sleep: On, "
+ "Swing: Off",
+ ac.toString());
+ ac.setSleep(false);
+ EXPECT_EQ(
+ "Power: On, Mode: 4 (HEAT), Temp: 21C, Fan: 1 (Low), Sleep: Off, "
+ "Swing: Off",
+ ac.toString());
+ ac.setTemp(25);
+ EXPECT_EQ(
+ "Power: On, Mode: 4 (HEAT), Temp: 25C, Fan: 1 (Low), Sleep: Off, "
+ "Swing: Off",
+ ac.toString());
+}
+
+TEST(TestTecoACClass, ReconstructKnownMessage) {
+ IRTecoAc ac(0);
+
+ const uint64_t expected = 0x250002BC9;
+ ASSERT_FALSE(ac.getRaw() == expected);
+ ac.setPower(true);
+ ac.setMode(kTecoCool);
+ ac.setTemp(27);
+ ac.setFan(kTecoFanAuto);
+ ac.setSleep(true);
+ ac.setSwing(true);
+ EXPECT_EQ(expected, ac.getRaw());
+ EXPECT_EQ(
+ "Power: On, Mode: 1 (COOL), Temp: 27C, Fan: 0 (Auto), Sleep: On, "
+ "Swing: On",
+ ac.toString());
+}
+
+// Tests for decodeTeco().
+
+// Decode normal "synthetic" messages.
+TEST(TestDecodeTeco, NormalDecodeWithStrict) {
+ IRsendTest irsend(0);
+ IRrecv irrecv(0);
+ irsend.begin();
+
+ // With the specific decoder.
+ uint64_t expectedState = kTecoReset;
+ irsend.reset();
+ irsend.sendTeco(expectedState);
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decodeTeco(&irsend.capture, kTecoBits, true));
+ EXPECT_EQ(TECO, irsend.capture.decode_type);
+ EXPECT_EQ(kTecoBits, 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.sendTeco(expectedState);
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(TECO, irsend.capture.decode_type);
+ EXPECT_EQ(kTecoBits, 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);
+
+ IRTecoAc ac(0);
+ ac.begin();
+ ac.setRaw(irsend.capture.value);
+ EXPECT_EQ(
+ "Power: Off, Mode: 0 (AUTO), Temp: 16C, Fan: 0 (Auto), Sleep: Off, "
+ "Swing: Off",
+ ac.toString());
+}
+
+// Decode a real message from Raw Data.
+TEST(TestDecodeTeco, RealNormalExample) {
+ IRsendTest irsend(0);
+ IRrecv irrecv(0);
+ IRTecoAc ac(0);
+ irsend.begin();
+
+ uint16_t rawData1[73] = {
+ 9076, 4442, 670, 1620, 670, 516, 670, 516, 666, 1626, 670, 516,
+ 664, 520, 666, 1626, 666, 1626, 664, 1626, 666, 1626, 666, 520,
+ 666, 1626, 666, 520, 666, 1626, 666, 520, 666, 516, 670, 514,
+ 670, 516, 666, 520, 670, 516, 666, 520, 666, 516, 672, 514, 670,
+ 516, 666, 520, 666, 516, 672, 514, 670, 516, 666, 1624, 666, 520,
+ 666, 1626, 666, 520, 666, 516, 672, 1620, 670, 516, 670};
+ uint64_t expected1 = 0b01001010000000000000010101111001001; // 0x250002BC9
+ irsend.reset();
+ irsend.sendRaw(rawData1, 73, 38);
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(TECO, irsend.capture.decode_type);
+ EXPECT_EQ(kTecoBits, irsend.capture.bits);
+ EXPECT_FALSE(irsend.capture.repeat);
+ EXPECT_EQ(expected1, 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: 1 (COOL), Temp: 27C, Fan: 0 (Auto), Sleep: On, "
+ "Swing: On",
+ ac.toString());
+
+ uint16_t rawData2[73] = {
+ 9048, 4472, 636, 548, 636, 1654, 638, 546, 642, 1650, 642, 546, 638,
+ 1654, 638, 1654, 638, 546, 638, 1654, 636, 546, 642, 1650, 640, 548,
+ 636, 548, 638, 546, 636, 546, 642, 542, 642, 546, 638, 546, 638, 546,
+ 636, 548, 642, 542, 642, 546, 636, 548, 636, 546, 642, 542, 642, 546,
+ 638, 546, 638, 546, 636, 1654, 642, 542, 642, 1650, 642, 546, 638, 546,
+ 638, 1654, 638, 546, 642}; // TECO 25000056A
+ uint64_t expected2 = 0b01001010000000000000000010101101010; // 0x25000056A
+ irsend.reset();
+ irsend.sendRaw(rawData2, 73, 38);
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(TECO, irsend.capture.decode_type);
+ EXPECT_EQ(kTecoBits, irsend.capture.bits);
+ EXPECT_FALSE(irsend.capture.repeat);
+ EXPECT_EQ(expected2, 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: 2 (DRY), Temp: 21C, Fan: 2 (Med), Sleep: Off, "
+ "Swing: On",
+ ac.toString());
+}
diff --git a/lib/IRremoteESP8266-2.5.2.03/test/ir_Toshiba_test.cpp b/lib/IRremoteESP8266-2.6.0/test/ir_Toshiba_test.cpp
similarity index 99%
rename from lib/IRremoteESP8266-2.5.2.03/test/ir_Toshiba_test.cpp
rename to lib/IRremoteESP8266-2.6.0/test/ir_Toshiba_test.cpp
index b5e1e07a9..d74866f92 100644
--- a/lib/IRremoteESP8266-2.5.2.03/test/ir_Toshiba_test.cpp
+++ b/lib/IRremoteESP8266-2.6.0/test/ir_Toshiba_test.cpp
@@ -18,6 +18,7 @@ TEST(TestSendToshibaAC, SendDataOnly) {
irsend.reset();
irsend.sendToshibaAC(toshiba_code);
EXPECT_EQ(
+ "f38000d50"
"m4400s4300"
"m543s1623m543s1623m543s1623m543s1623m543s472m543s472m543s1623m543s472"
"m543s472m543s472m543s472m543s472m543s1623m543s1623m543s472m543s1623"
@@ -54,6 +55,7 @@ TEST(TestSendToshibaAC, SendWithRepeats) {
irsend.sendToshibaAC(toshiba_code, kToshibaACStateLength, 0);
EXPECT_EQ(
+ "f38000d50"
"m4400s4300"
"m543s1623m543s1623m543s1623m543s1623m543s472m543s472m543s1623m543s472"
"m543s472m543s472m543s472m543s472m543s1623m543s1623m543s472m543s1623"
@@ -70,6 +72,7 @@ TEST(TestSendToshibaAC, SendWithRepeats) {
irsend.reset();
irsend.sendToshibaAC(toshiba_code, kToshibaACStateLength, 2);
EXPECT_EQ(
+ "f38000d50"
"m4400s4300"
"m543s1623m543s1623m543s1623m543s1623m543s472m543s472m543s1623m543s472"
"m543s472m543s472m543s472m543s472m543s1623m543s1623m543s472m543s1623"
@@ -122,6 +125,7 @@ TEST(TestSendToshibaAC, SendUnexpectedSizes) {
irsend.reset();
irsend.sendToshibaAC(toshiba_long_code, kToshibaACStateLength + 1);
ASSERT_EQ(
+ "f38000d50"
"m4400s4300"
"m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s1623"
"m543s472m543s472m543s472m543s472m543s472m543s472m543s1623m543s472"
@@ -380,6 +384,7 @@ TEST(TestToshibaACClass, MessageConstuction) {
irsend.reset();
irsend.sendToshibaAC(toshiba.getRaw());
EXPECT_EQ(
+ "f38000d50"
"m4400s4300"
"m543s1623m543s1623m543s1623m543s1623m543s472m543s472m543s1623m543s472"
"m543s472m543s472m543s472m543s472m543s1623m543s1623m543s472m543s1623"
@@ -415,6 +420,7 @@ TEST(TestToshibaACClass, MessageConstuction) {
irsend.reset();
irsend.sendToshibaAC(toshiba.getRaw());
EXPECT_EQ(
+ "f38000d50"
"m4400s4300"
"m543s1623m543s1623m543s1623m543s1623m543s472m543s472m543s1623m543s472"
"m543s472m543s472m543s472m543s472m543s1623m543s1623m543s472m543s1623"
@@ -450,6 +456,7 @@ TEST(TestToshibaACClass, MessageConstuction) {
irsend.reset();
irsend.sendToshibaAC(toshiba.getRaw());
EXPECT_EQ(
+ "f38000d50"
"m4400s4300"
"m543s1623m543s1623m543s1623m543s1623m543s472m543s472m543s1623m543s472"
"m543s472m543s472m543s472m543s472m543s1623m543s1623m543s472m543s1623"
diff --git a/lib/IRremoteESP8266-2.6.0/test/ir_Vestel_test.cpp b/lib/IRremoteESP8266-2.6.0/test/ir_Vestel_test.cpp
new file mode 100644
index 000000000..077a0a25e
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/test/ir_Vestel_test.cpp
@@ -0,0 +1,513 @@
+// 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(
+ "f38000d50"
+ "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(
+ "f38000d50"
+ "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-2.6.0/test/ir_Whirlpool_test.cpp b/lib/IRremoteESP8266-2.6.0/test/ir_Whirlpool_test.cpp
new file mode 100644
index 000000000..e282989f0
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/test/ir_Whirlpool_test.cpp
@@ -0,0 +1,585 @@
+// 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(
+ "f38000d50"
+ "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-2.5.2.03/test/ir_Whynter_test.cpp b/lib/IRremoteESP8266-2.6.0/test/ir_Whynter_test.cpp
similarity index 98%
rename from lib/IRremoteESP8266-2.5.2.03/test/ir_Whynter_test.cpp
rename to lib/IRremoteESP8266-2.6.0/test/ir_Whynter_test.cpp
index 748a4c9bf..92ced5cf6 100644
--- a/lib/IRremoteESP8266-2.5.2.03/test/ir_Whynter_test.cpp
+++ b/lib/IRremoteESP8266-2.6.0/test/ir_Whynter_test.cpp
@@ -14,6 +14,7 @@ TEST(TestSendWhynter, SendDataOnly) {
irsend.reset();
irsend.sendWhynter(0x0);
EXPECT_EQ(
+ "f38000d50"
"m750s750m2850s2850"
"m750s750m750s750m750s750m750s750m750s750m750s750m750s750m750s750"
"m750s750m750s750m750s750m750s750m750s750m750s750m750s750m750s750"
@@ -25,6 +26,7 @@ TEST(TestSendWhynter, SendDataOnly) {
irsend.reset();
irsend.sendWhynter(0xFFFFFFFF);
EXPECT_EQ(
+ "f38000d50"
"m750s750m2850s2850"
"m750s2150m750s2150m750s2150m750s2150m750s2150m750s2150m750s2150m750s2150"
"m750s2150m750s2150m750s2150m750s2150m750s2150m750s2150m750s2150m750s2150"
@@ -36,6 +38,7 @@ TEST(TestSendWhynter, SendDataOnly) {
irsend.reset();
irsend.sendWhynter(0x87654321);
EXPECT_EQ(
+ "f38000d50"
"m750s750m2850s2850"
"m750s2150m750s750m750s750m750s750m750s750m750s2150m750s2150m750s2150"
"m750s750m750s2150m750s2150m750s750m750s750m750s2150m750s750m750s2150"
@@ -53,6 +56,7 @@ TEST(TestSendWhynter, SendWithRepeats) {
irsend.reset();
irsend.sendWhynter(0x87654321, kWhynterBits, 0); // 0 repeats.
EXPECT_EQ(
+ "f38000d50"
"m750s750m2850s2850"
"m750s2150m750s750m750s750m750s750m750s750m750s2150m750s2150m750s2150"
"m750s750m750s2150m750s2150m750s750m750s750m750s2150m750s750m750s2150"
@@ -64,6 +68,7 @@ TEST(TestSendWhynter, SendWithRepeats) {
irsend.reset();
irsend.sendWhynter(0x87654321, kWhynterBits, 1); // 1 repeat.
EXPECT_EQ(
+ "f38000d50"
"m750s750m2850s2850"
"m750s2150m750s750m750s750m750s750m750s750m750s2150m750s2150m750s2150"
"m750s750m750s2150m750s2150m750s750m750s750m750s2150m750s750m750s2150"
@@ -81,6 +86,7 @@ TEST(TestSendWhynter, SendWithRepeats) {
irsend.reset();
irsend.sendWhynter(0x87654321, kWhynterBits, 2); // 2 repeats.
EXPECT_EQ(
+ "f38000d50"
"m750s750m2850s2850"
"m750s2150m750s750m750s750m750s750m750s750m750s2150m750s2150m750s2150"
"m750s750m750s2150m750s2150m750s750m750s750m750s2150m750s750m750s2150"
@@ -110,6 +116,7 @@ TEST(TestSendWhynter, SendUnusualSize) {
irsend.reset();
irsend.sendWhynter(0x0, 8);
EXPECT_EQ(
+ "f38000d50"
"m750s750m2850s2850"
"m750s750m750s750m750s750m750s750m750s750m750s750m750s750m750s750"
"m750s88050",
@@ -118,6 +125,7 @@ TEST(TestSendWhynter, SendUnusualSize) {
irsend.reset();
irsend.sendWhynter(0x1234567890ABCDEF, 64);
EXPECT_EQ(
+ "f38000d50"
"m750s750m2850s2850"
"m750s750m750s750m750s750m750s2150m750s750m750s750m750s2150m750s750"
"m750s750m750s750m750s2150m750s2150m750s750m750s2150m750s750m750s750"
diff --git a/lib/IRremoteESP8266-2.5.2.03/tools/Makefile b/lib/IRremoteESP8266-2.6.0/tools/Makefile
similarity index 76%
rename from lib/IRremoteESP8266-2.5.2.03/tools/Makefile
rename to lib/IRremoteESP8266-2.6.0/tools/Makefile
index c303e051d..08488949c 100644
--- a/lib/IRremoteESP8266-2.5.2.03/tools/Makefile
+++ b/lib/IRremoteESP8266-2.6.0/tools/Makefile
@@ -14,13 +14,14 @@ USER_DIR = ../src
# Where to find test code.
TEST_DIR = ../test
+INCLUDES = -I$(USER_DIR) -I$(TEST_DIR)
# Flags passed to the preprocessor.
# Set Google Test's header directory as a system directory, such that
# the compiler doesn't generate warnings in Google Test headers.
CPPFLAGS += -DUNIT_TEST
# Flags passed to the C++ compiler.
-CXXFLAGS += -g -Wall -Wextra -pthread
+CXXFLAGS += -g -Wall -Wextra -pthread -std=gnu++11
all : gc_decode mode2_decode
@@ -48,25 +49,27 @@ PROTOCOLS = ir_NEC.o ir_Sony.o ir_Samsung.o ir_JVC.o ir_RCMM.o ir_RC5_RC6.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_Whirlpool.o ir_Lutron.o ir_Electra.o ir_Pioneer.o \
- ir_MWM.o
+ ir_MWM.o ir_Vestel.o ir_Teco.o ir_Tcl.o ir_Lego.o \
+ ir_MitsubishiHeavy.o
# Common object files
COMMON_OBJ = IRutils.o IRtimer.o IRsend.o IRrecv.o $(PROTOCOLS)
# 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 \
+ $(TEST_DIR)/IRsend_test.h
# Common test dependencies
COMMON_TEST_DEPS = $(COMMON_DEPS) $(TEST_DIR)/IRsend_test.h
gc_decode.o : gc_decode.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -I$(TEST_DIR) -c gc_decode.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c gc_decode.cpp
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
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c mode2_decode.cpp
mode2_decode : $(COMMON_OBJ) mode2_decode.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
@@ -83,7 +86,6 @@ IRsend.o : $(USER_DIR)/IRsend.cpp $(USER_DIR)/IRsend.h $(USER_DIR)/IRremoteESP82
IRrecv.o : $(USER_DIR)/IRrecv.cpp $(USER_DIR)/IRrecv.h $(USER_DIR)/IRremoteESP8266.h $(GTEST_HEADERS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/IRrecv.cpp
-
ir_NEC.o : $(USER_DIR)/ir_NEC.cpp $(COMMON_DEPS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_NEC.cpp
@@ -97,10 +99,10 @@ 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 $(USER_DIR)/ir_Samsung.h $(COMMON_DEPS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Samsung.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_Samsung.cpp
ir_Kelvinator.o : $(USER_DIR)/ir_Kelvinator.cpp $(USER_DIR)/ir_Kelvinator.h $(COMMON_DEPS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Kelvinator.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_Kelvinator.cpp
ir_JVC.o : $(USER_DIR)/ir_JVC.cpp $(COMMON_DEPS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_JVC.cpp
@@ -112,10 +114,13 @@ ir_LG.o : $(USER_DIR)/ir_LG.h $(USER_DIR)/ir_LG.cpp $(COMMON_DEPS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_LG.cpp
ir_Mitsubishi.o : $(USER_DIR)/ir_Mitsubishi.h $(USER_DIR)/ir_Mitsubishi.cpp $(COMMON_DEPS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Mitsubishi.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_Mitsubishi.cpp
+
+ir_MitsubishiHeavy.o : $(USER_DIR)/ir_MitsubishiHeavy.h $(USER_DIR)/ir_MitsubishiHeavy.cpp $(COMMON_DEPS)
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_MitsubishiHeavy.cpp
ir_Fujitsu.o : $(USER_DIR)/ir_Fujitsu.h $(USER_DIR)/ir_Fujitsu.cpp $(COMMON_DEPS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Fujitsu.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_Fujitsu.cpp
ir_Sharp.o : $(USER_DIR)/ir_Sharp.cpp $(COMMON_DEPS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Sharp.cpp
@@ -124,7 +129,7 @@ ir_RC5_RC6.o : $(USER_DIR)/ir_RC5_RC6.cpp $(COMMON_DEPS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_RC5_RC6.cpp
ir_Panasonic.o : $(USER_DIR)/ir_Panasonic.cpp $(COMMON_DEPS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Panasonic.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_Panasonic.cpp
ir_Dish.o : $(USER_DIR)/ir_Dish.cpp $(COMMON_DEPS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Dish.cpp
@@ -133,7 +138,7 @@ ir_Whynter.o : $(USER_DIR)/ir_Whynter.cpp $(COMMON_DEPS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Whynter.cpp
ir_Coolix.o : $(USER_DIR)/ir_Coolix.cpp $(COMMON_DEPS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Coolix.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_Coolix.cpp
ir_Aiwa.o : $(USER_DIR)/ir_Aiwa.cpp $(COMMON_DEPS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Aiwa.cpp
@@ -145,10 +150,10 @@ ir_Sanyo.o : $(USER_DIR)/ir_Sanyo.cpp $(COMMON_DEPS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Sanyo.cpp
ir_Daikin.o : $(USER_DIR)/ir_Daikin.cpp $(USER_DIR)/ir_Daikin.h $(COMMON_DEPS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Daikin.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_Daikin.cpp
ir_Gree.o : $(USER_DIR)/ir_Gree.cpp $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Gree.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_Gree.cpp
ir_Pronto.o : $(USER_DIR)/ir_Pronto.cpp $(GTEST_HEADERS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Pronto.cpp
@@ -157,10 +162,10 @@ ir_Nikai.o : $(USER_DIR)/ir_Nikai.cpp $(GTEST_HEADERS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Nikai.cpp
ir_Toshiba.o : $(USER_DIR)/ir_Toshiba.h $(USER_DIR)/ir_Toshiba.cpp $(COMMON_DEPS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Toshiba.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_Toshiba.cpp
ir_Midea.o : $(USER_DIR)/ir_Midea.cpp $(COMMON_DEPS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Midea.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_Midea.cpp
ir_Magiquest.o : $(USER_DIR)/ir_Magiquest.cpp $(GTEST_HEADERS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Magiquest.cpp
@@ -172,16 +177,16 @@ ir_Carrier.o : $(USER_DIR)/ir_Carrier.cpp $(GTEST_HEADERS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Carrier.cpp
ir_Haier.o : $(USER_DIR)/ir_Haier.cpp $(USER_DIR)/ir_Haier.h $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Haier.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_Haier.cpp
ir_Hitachi.o : $(USER_DIR)/ir_Hitachi.cpp $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Hitachi.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_Hitachi.cpp
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
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -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
@@ -194,3 +199,15 @@ ir_Pioneer.o : $(USER_DIR)/ir_Pioneer.cpp $(GTEST_HEADERS)
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) $(INCLUDES) -c $(USER_DIR)/ir_Vestel.cpp
+
+ir_Teco.o : $(USER_DIR)/ir_Teco.cpp $(GTEST_HEADERS)
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_Teco.cpp
+
+ir_Tcl.o : $(USER_DIR)/ir_Tcl.cpp $(USER_DIR)/ir_Tcl.h $(GTEST_HEADERS)
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_Tcl.cpp
+
+ir_Lego.o : $(USER_DIR)/ir_Lego.cpp $(GTEST_HEADERS)
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Lego.cpp
diff --git a/lib/IRremoteESP8266-2.5.2.03/tools/RawToGlobalCache.sh b/lib/IRremoteESP8266-2.6.0/tools/RawToGlobalCache.sh
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/tools/RawToGlobalCache.sh
rename to lib/IRremoteESP8266-2.6.0/tools/RawToGlobalCache.sh
diff --git a/lib/IRremoteESP8266-2.5.2.03/tools/auto_analyse_raw_data.py b/lib/IRremoteESP8266-2.6.0/tools/auto_analyse_raw_data.py
similarity index 98%
rename from lib/IRremoteESP8266-2.5.2.03/tools/auto_analyse_raw_data.py
rename to lib/IRremoteESP8266-2.6.0/tools/auto_analyse_raw_data.py
index 5fd399807..b23cdb46f 100644
--- a/lib/IRremoteESP8266-2.5.2.03/tools/auto_analyse_raw_data.py
+++ b/lib/IRremoteESP8266-2.6.0/tools/auto_analyse_raw_data.py
@@ -85,9 +85,9 @@ 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, footer=True):
"""Add the common "data" sequence of code to send the bulk of a message."""
diff --git a/lib/IRremoteESP8266-2.5.2.03/tools/auto_analyse_raw_data_test.py b/lib/IRremoteESP8266-2.6.0/tools/auto_analyse_raw_data_test.py
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/tools/auto_analyse_raw_data_test.py
rename to lib/IRremoteESP8266-2.6.0/tools/auto_analyse_raw_data_test.py
diff --git a/lib/IRremoteESP8266-2.5.2.03/tools/gc_decode.cpp b/lib/IRremoteESP8266-2.6.0/tools/gc_decode.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/tools/gc_decode.cpp
rename to lib/IRremoteESP8266-2.6.0/tools/gc_decode.cpp
diff --git a/lib/IRremoteESP8266-2.5.2.03/tools/mkkeywords b/lib/IRremoteESP8266-2.6.0/tools/mkkeywords
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/tools/mkkeywords
rename to lib/IRremoteESP8266-2.6.0/tools/mkkeywords
diff --git a/lib/IRremoteESP8266-2.5.2.03/tools/mode2_decode.cpp b/lib/IRremoteESP8266-2.6.0/tools/mode2_decode.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/tools/mode2_decode.cpp
rename to lib/IRremoteESP8266-2.6.0/tools/mode2_decode.cpp
diff --git a/lib/Joba_Tsl2561-2.0.10/.gitignore b/lib/Joba_Tsl2561-2.0.10/.gitignore
new file mode 100644
index 000000000..2f4f2baeb
--- /dev/null
+++ b/lib/Joba_Tsl2561-2.0.10/.gitignore
@@ -0,0 +1,8 @@
+.pioenvs
+.piolibdeps
+.clang_complete
+.gcc-flags.json
+examples/*/platformio.ini
+examples/*/lib
+examples/*/.gitignore
+examples/*/.travis.yml
diff --git a/lib/Joba_Tsl2561-2.0.10/.hgignore b/lib/Joba_Tsl2561-2.0.10/.hgignore
new file mode 100644
index 000000000..5dac9f52f
--- /dev/null
+++ b/lib/Joba_Tsl2561-2.0.10/.hgignore
@@ -0,0 +1,4 @@
+.pioenvs
+.piolibdeps
+.clang_complete
+.gcc-flags.json
diff --git a/lib/Joba_Tsl2561-2.0.10/.travis.yml b/lib/Joba_Tsl2561-2.0.10/.travis.yml
new file mode 100644
index 000000000..52072efd6
--- /dev/null
+++ b/lib/Joba_Tsl2561-2.0.10/.travis.yml
@@ -0,0 +1,55 @@
+# Continuous Integration (CI) is the practice, in software
+# engineering, of merging all developer working copies with a shared mainline
+# several times a day < http://docs.platformio.org/page/ci/index.html >
+#
+# Documentation:
+#
+# * Travis CI Embedded Builds with PlatformIO
+# < https://docs.travis-ci.com/user/integration/platformio/ >
+#
+# * PlatformIO integration with Travis CI
+# < http://docs.platformio.org/page/ci/travis.html >
+#
+# * User Guide for `platformio ci` command
+# < http://docs.platformio.org/page/userguide/cmd_ci.html >
+#
+#
+# Please choice one of the following templates (proposed below) and uncomment
+# it (remove "# " before each line) or use own configuration according to the
+# Travis CI documentation (see above).
+#
+
+
+#
+# Template #1: General project. Test it using existing `platformio.ini`.
+#
+
+# language: python
+# python:
+# - "2.7"
+#
+# install:
+# - pip install -U platformio
+#
+# script:
+# - platformio run
+
+
+#
+# Template #2: The project is intended to by used as a library with examples
+#
+
+# language: python
+# python:
+# - "2.7"
+#
+# env:
+# - PLATFORMIO_CI_SRC=path/to/test/file.c
+# - PLATFORMIO_CI_SRC=examples/file.ino
+# - PLATFORMIO_CI_SRC=path/to/test/directory
+#
+# install:
+# - pip install -U platformio
+#
+# script:
+# - platformio ci --lib="." --board=ID_1 --board=ID_2 --board=ID_N
diff --git a/lib/Joba_Tsl2561-2.0.7/COPYING b/lib/Joba_Tsl2561-2.0.10/COPYING
similarity index 100%
rename from lib/Joba_Tsl2561-2.0.7/COPYING
rename to lib/Joba_Tsl2561-2.0.10/COPYING
diff --git a/lib/Joba_Tsl2561-2.0.7/COPYING.LESSER b/lib/Joba_Tsl2561-2.0.10/COPYING.LESSER
similarity index 100%
rename from lib/Joba_Tsl2561-2.0.7/COPYING.LESSER
rename to lib/Joba_Tsl2561-2.0.10/COPYING.LESSER
diff --git a/lib/Joba_Tsl2561-2.0.7/README b/lib/Joba_Tsl2561-2.0.10/README
similarity index 87%
rename from lib/Joba_Tsl2561-2.0.7/README
rename to lib/Joba_Tsl2561-2.0.10/README
index 86c1f1a0b..d95e731d5 100644
--- a/lib/Joba_Tsl2561-2.0.7/README
+++ b/lib/Joba_Tsl2561-2.0.10/README
@@ -1,4 +1,4 @@
-This is a library for the TSL2561 digital luminosity sensors from Ams (Taos).
+This is an Arduino library for the TSL2561 digital luminosity sensors from Ams (Taos).
Design goals:
* It is modularized so you can use only what you need if space/ram is constrained.
@@ -18,3 +18,5 @@ The library has 3 classes:
Tsl2561 All register access as described in the datasheet, except for interrupts
Tsl2561Util Convenience functions like lux calculation or automatic gain
Tsl2561Int TODO, Interrupt related stuff (not needed if int pin unconnected)
+
+Tested with boards Nano, ESP8266 and ESP32
diff --git a/lib/Joba_Tsl2561-2.0.7/examples/Autogain/Autogain.ino b/lib/Joba_Tsl2561-2.0.10/examples/Autogain/Autogain.ino
similarity index 96%
rename from lib/Joba_Tsl2561-2.0.7/examples/Autogain/Autogain.ino
rename to lib/Joba_Tsl2561-2.0.10/examples/Autogain/Autogain.ino
index 169d2b6e3..9547af45b 100644
--- a/lib/Joba_Tsl2561-2.0.7/examples/Autogain/Autogain.ino
+++ b/lib/Joba_Tsl2561-2.0.10/examples/Autogain/Autogain.ino
@@ -21,7 +21,7 @@ This file is part of the Joba_Tsl2561 Library.
#include
-// to mimic Serial.printf() of esp8266 core for other platforms
+// to mimic Serial.printf() of esp cores for other platforms
char *format( const char *fmt, ... ) {
static char buf[128];
va_list arg;
@@ -37,7 +37,7 @@ uint8_t id;
void setup() {
Serial.begin(115200);
- Wire.begin();
+ Wire.begin(TSL2561_SDA, TSL2561_SCL);
while( !Tsl.begin() )
; // wait until chip detected or wdt reset
Serial.println("\nStarting Tsl2561Util autogain loop");
diff --git a/lib/Joba_Tsl2561-2.0.7/examples/Simple/Simple.ino b/lib/Joba_Tsl2561-2.0.10/examples/Simple/Simple.ino
similarity index 88%
rename from lib/Joba_Tsl2561-2.0.7/examples/Simple/Simple.ino
rename to lib/Joba_Tsl2561-2.0.10/examples/Simple/Simple.ino
index 5bebb7e50..b63f71b94 100644
--- a/lib/Joba_Tsl2561-2.0.7/examples/Simple/Simple.ino
+++ b/lib/Joba_Tsl2561-2.0.10/examples/Simple/Simple.ino
@@ -21,7 +21,7 @@ This file is part of the Joba_Tsl2561 Library.
#include
-// to mimic Serial.printf() of esp8266 core for other platforms
+// to mimic Serial.printf() of esp cores for other platforms
char *format( const char *fmt, ... ) {
static char buf[128];
va_list arg;
@@ -36,7 +36,7 @@ Tsl2561 Tsl(Wire);
void setup() {
Serial.begin(115200);
- Wire.begin();
+ Wire.begin(TSL2561_SDA, TSL2561_SCL);
Serial.println("\nStarting Tsl2561 simple loop");
}
@@ -60,7 +60,7 @@ void loop() {
Tsl.off();
}
else {
- Serial.println("No Tsl2561 found. Check wiring.");
+ Serial.print(format("No Tsl2561 found. Check wiring: SCL=%u, SDA=%u\n", TSL2561_SCL, TSL2561_SDA));
}
delay(5000);
diff --git a/lib/Joba_Tsl2561-2.0.7/examples/Testing/Testing.ino b/lib/Joba_Tsl2561-2.0.10/examples/Testing/Testing.ino
similarity index 97%
rename from lib/Joba_Tsl2561-2.0.7/examples/Testing/Testing.ino
rename to lib/Joba_Tsl2561-2.0.10/examples/Testing/Testing.ino
index 0dbeb09be..861891666 100644
--- a/lib/Joba_Tsl2561-2.0.7/examples/Testing/Testing.ino
+++ b/lib/Joba_Tsl2561-2.0.10/examples/Testing/Testing.ino
@@ -22,7 +22,7 @@ This file is part of the Joba_Tsl2561 Library.
#include
-// to mimic Serial.printf() of esp8266 core for other platforms
+// to mimic Serial.printf() of esp cores for other platforms
char *format( const char *fmt, ... ) {
static char buf[128];
va_list arg;
@@ -158,7 +158,7 @@ void test( Tsl2561 &tsl ) {
void setup() {
Serial.begin(115200);
- Wire.begin();
+ Wire.begin(TSL2561_SDA, TSL2561_SCL);
Serial.println("\nStarting Tsl2561 testing loop");
}
diff --git a/lib/Joba_Tsl2561-2.0.7/examples/Utility/Utility.ino b/lib/Joba_Tsl2561-2.0.10/examples/Utility/Utility.ino
similarity index 93%
rename from lib/Joba_Tsl2561-2.0.7/examples/Utility/Utility.ino
rename to lib/Joba_Tsl2561-2.0.10/examples/Utility/Utility.ino
index d05549616..14ba320d0 100644
--- a/lib/Joba_Tsl2561-2.0.7/examples/Utility/Utility.ino
+++ b/lib/Joba_Tsl2561-2.0.10/examples/Utility/Utility.ino
@@ -21,7 +21,7 @@ This file is part of the Joba_Tsl2561 Library.
#include
-// to mimic Serial.printf() of esp8266 core for other platforms
+// to mimic Serial.printf() of esp cores for other platforms
char *format( const char *fmt, ... ) {
static char buf[128];
va_list arg;
@@ -37,7 +37,7 @@ Tsl2561 Tsl(Wire);
void setup() {
Serial.begin(115200);
- Wire.begin();
+ Wire.begin(TSL2561_SDA, TSL2561_SCL);
Serial.println("\nStarting Tsl2561Util loop");
}
@@ -91,7 +91,7 @@ void loop() {
}
if( !found ) {
- Serial.println("No Tsl2561 found. Check wiring.");
+ Serial.print(format("No Tsl2561 found. Check wiring: SCL=%u, SDA=%u\n", TSL2561_SCL, TSL2561_SDA));
}
delay(5000);
diff --git a/lib/Joba_Tsl2561-2.0.7/platformio.ini b/lib/Joba_Tsl2561-2.0.10/examples/platformio.ini
similarity index 67%
rename from lib/Joba_Tsl2561-2.0.7/platformio.ini
rename to lib/Joba_Tsl2561-2.0.10/examples/platformio.ini
index ea6847aaa..07efee0d2 100644
--- a/lib/Joba_Tsl2561-2.0.7/platformio.ini
+++ b/lib/Joba_Tsl2561-2.0.10/examples/platformio.ini
@@ -18,9 +18,13 @@
[platformio]
+src_dir = .
+lib_dir = ../..
+
; uncomment one, if you want to build only one
; env_default = nodemcuv2
; env_default = nano328
+; env_default = espressif32
[env:nodemcuv2]
@@ -28,12 +32,12 @@
; ------------
; GND <-> GND
; VCC <-> 3V
-; SCL <-> D1
-; SDA <-> D2
+; SCL <-> D1 (other pin can be defined below)
+; SDA <-> D2 (other pin can be defined below)
platform = espressif8266
board = nodemcuv2
framework = arduino
-build_flags = -Wall
+build_flags = -Wall -DTSL2561_SCL=D1 -DTSL2561_SDA=D2
monitor_speed = 115200
@@ -53,6 +57,25 @@ upload_resetmethod = nodemcu
platform = atmelavr
board = nanoatmega328
framework = arduino
-build_flags = -Wall
+build_flags = -Wall -DTSL2561_SCL=A5 -DTSL2561_SDA=A4
monitor_speed = 115200
+;upload_port = /dev/ttyUSB[1-9]
+
+
+[env:espressif32]
+; TSL <-> ESP32
+; ------------
+; GND <-> GND
+; VCC <-> 3V
+; SCL <-> IO22 (other pin can be defined below)
+; SDA <-> IO21 (other pin can be defined below)
+platform = espressif32
+board = mhetesp32minikit
+framework = arduino
+build_flags = -Wall -DTSL2561_SCL=22 -DTSL2561_SDA=21
+
+monitor_speed = 115200
+
+upload_speed = 921600
+;upload_port = /dev/ttyUSB[1-9]
diff --git a/lib/Joba_Tsl2561-2.0.7/examples/platformio.sh b/lib/Joba_Tsl2561-2.0.10/examples/platformio.sh
similarity index 100%
rename from lib/Joba_Tsl2561-2.0.7/examples/platformio.sh
rename to lib/Joba_Tsl2561-2.0.10/examples/platformio.sh
diff --git a/lib/Joba_Tsl2561-2.0.7/lib/readme.txt b/lib/Joba_Tsl2561-2.0.10/lib/readme.txt
similarity index 100%
rename from lib/Joba_Tsl2561-2.0.7/lib/readme.txt
rename to lib/Joba_Tsl2561-2.0.10/lib/readme.txt
diff --git a/lib/Joba_Tsl2561-2.0.7/library.json b/lib/Joba_Tsl2561-2.0.10/library.json
similarity index 62%
rename from lib/Joba_Tsl2561-2.0.7/library.json
rename to lib/Joba_Tsl2561-2.0.10/library.json
index 94585c488..86545a6a0 100644
--- a/lib/Joba_Tsl2561-2.0.7/library.json
+++ b/lib/Joba_Tsl2561-2.0.10/library.json
@@ -1,8 +1,8 @@
{
"name": "Joba_Tsl2561",
- "version": "2.0.7",
+ "version": "2.0.10",
"keywords": "twowire, i2c, bus, sensor, luminosity, illuminance, lux",
- "description": "Arduino Library for ams (taos) luminance chip Tsl2561 with autogain",
+ "description": "Arduino library for ams (taos) luminance chip Tsl2561 with autogain. Tested with Nano, Esp8266 and Esp32.",
"repository":
{
"type": "git",
diff --git a/lib/Joba_Tsl2561-2.0.7/library.properties b/lib/Joba_Tsl2561-2.0.10/library.properties
similarity index 67%
rename from lib/Joba_Tsl2561-2.0.7/library.properties
rename to lib/Joba_Tsl2561-2.0.10/library.properties
index ba1840764..5d83edb31 100644
--- a/lib/Joba_Tsl2561-2.0.7/library.properties
+++ b/lib/Joba_Tsl2561-2.0.10/library.properties
@@ -1,9 +1,9 @@
name=Joba Tsl2561 Library
-version=2.0.7
+version=2.0.10
author=joba-1
maintainer=joba-1
sentence=IoT library for using the Tsl2561 luminosity sensor
-paragraph=Luminosity measurement in lux with autogain
+paragraph=Luminosity measurement in lux with autogain. Tested with Nano, Esp8266 and Esp32.
category=Sensors
url=https://github.com/joba-1/Joba_Tsl2561
architectures=*
diff --git a/lib/Joba_Tsl2561-2.0.7/examples/platformio.ini b/lib/Joba_Tsl2561-2.0.10/platformio.ini
similarity index 75%
rename from lib/Joba_Tsl2561-2.0.7/examples/platformio.ini
rename to lib/Joba_Tsl2561-2.0.10/platformio.ini
index ef71e03ae..87d88e183 100644
--- a/lib/Joba_Tsl2561-2.0.7/examples/platformio.ini
+++ b/lib/Joba_Tsl2561-2.0.10/platformio.ini
@@ -18,20 +18,19 @@
[platformio]
-src_dir = .
-lib_dir = ../..
-
; uncomment one, if you want to build only one
; env_default = nodemcuv2
; env_default = nano328
+; env_default = espressif32
+
[env:nodemcuv2]
; TSL <-> ESP8266
; ------------
; GND <-> GND
; VCC <-> 3V
-; SCL <-> D1
-; SDA <-> D2
+; SCL <-> D1 (other pin can be defined below)
+; SDA <-> D2 (other pin can be defined below)
platform = espressif8266
board = nodemcuv2
framework = arduino
@@ -58,4 +57,21 @@ framework = arduino
build_flags = -Wall
monitor_speed = 115200
+
+
+[env:espressif32]
+; TSL <-> ESP32
+; ------------
+; GND <-> GND
+; VCC <-> 3V
+; SCL <-> IO22 (other pin can be defined below)
+; SDA <-> IO21 (other pin can be defined below)
+platform = espressif32
+board = mhetesp32minikit
+framework = arduino
+build_flags = -Wall -DTSL2561_SCL=22 -DTSL2561_SDA=21
+
+monitor_speed = 115200
+
+upload_speed = 921600
;upload_port = /dev/ttyUSB[1-9]
diff --git a/lib/Joba_Tsl2561-2.0.7/src/Tsl2561.cpp b/lib/Joba_Tsl2561-2.0.10/src/Tsl2561.cpp
similarity index 100%
rename from lib/Joba_Tsl2561-2.0.7/src/Tsl2561.cpp
rename to lib/Joba_Tsl2561-2.0.10/src/Tsl2561.cpp
diff --git a/lib/Joba_Tsl2561-2.0.7/src/Tsl2561.h b/lib/Joba_Tsl2561-2.0.10/src/Tsl2561.h
similarity index 94%
rename from lib/Joba_Tsl2561-2.0.7/src/Tsl2561.h
rename to lib/Joba_Tsl2561-2.0.10/src/Tsl2561.h
index 75056f912..147db2a77 100644
--- a/lib/Joba_Tsl2561-2.0.7/src/Tsl2561.h
+++ b/lib/Joba_Tsl2561-2.0.10/src/Tsl2561.h
@@ -23,6 +23,14 @@ This file is part of the Joba_Tsl2561 Library.
#include
#include
+// To be able to override pin definitions in build flags (used in examples)
+#ifndef TSL2561_SDA
+ #define TSL2561_SDA SDA
+#endif
+#ifndef TSL2561_SCL
+ #define TSL2561_SCL SCL
+#endif
+
class Tsl2561 {
public:
diff --git a/lib/Joba_Tsl2561-2.0.7/src/Tsl2561Util.cpp b/lib/Joba_Tsl2561-2.0.10/src/Tsl2561Util.cpp
similarity index 83%
rename from lib/Joba_Tsl2561-2.0.7/src/Tsl2561Util.cpp
rename to lib/Joba_Tsl2561-2.0.10/src/Tsl2561Util.cpp
index ae811f743..aa738bb9f 100644
--- a/lib/Joba_Tsl2561-2.0.7/src/Tsl2561Util.cpp
+++ b/lib/Joba_Tsl2561-2.0.10/src/Tsl2561Util.cpp
@@ -22,9 +22,10 @@ This file is part of the Joba_Tsl2561 Library.
namespace Tsl2561Util {
// Tsl2561Util::normalizedLuminosity returncode false can mean:
-// - saturation: full and/or ir have value ~0 (aka -1)
+// - saturation: full and/or ir have value ~0 (aka -1) and not shortest exposure
// - manual exposure time: full and ir are corrected only for gain
-// If true, full and ir have values as if exposure was 402 and gain 16.
+// If true, full and ir have values as if exposure was 402 and gain 16
+// or ~0 if saturated even at shortest exposure
bool normalizedLuminosity( bool gain, Tsl2561::exposure_t exposure, uint32_t &full, uint32_t &ir ) {
uint16_t scaledFull = (uint16_t)full;
@@ -39,8 +40,8 @@ bool normalizedLuminosity( bool gain, Tsl2561::exposure_t exposure, uint32_t &fu
switch( exposure ) {
case Tsl2561::EXP_14:
- full = (scaledFull >= 5047/4*3) ? 0xffffffff : ((full + 5) * 322) / 11;
- ir = (scaledIr >= 5047/4*3) ? 0xffffffff : ((ir + 5) * 322) / 11;
+ full = (scaledFull == 5047) ? 0xffffffff : ((full + 5) * 322) / 11;
+ ir = (scaledIr == 5047) ? 0xffffffff : ((ir + 5) * 322) / 11;
break;
case Tsl2561::EXP_101:
full = (scaledFull >= 37177/4*3) ? 0xffffffff : ((full + 40) * 322) / 81;
@@ -54,7 +55,7 @@ bool normalizedLuminosity( bool gain, Tsl2561::exposure_t exposure, uint32_t &fu
return false;
}
- return full != 0xffffffff && ir != 0xffffffff;
+ return exposure == Tsl2561::EXP_14 || (full != 0xffffffff && ir != 0xffffffff);
}
return false;
@@ -93,6 +94,8 @@ bool autoGain( Tsl2561 &tsl, bool &gain, Tsl2561::exposure_t &exposure, uint16_t
{ true, Tsl2561::EXP_402 } // max
};
+ // Serial.printf("autoGain start: gain=%u, expo=%u\n", gain, exposure);
+
// get current sensitivity
if( !tsl.getSensitivity(gain, exposure) ) {
return false; // I2C error
@@ -110,9 +113,10 @@ bool autoGain( Tsl2561 &tsl, bool &gain, Tsl2561::exposure_t &exposure, uint16_t
return false; // should not happen...
}
- // in a loop wait for next sample, get values and adjust sensitivity if needed
+ // sometimes sensor reports high brightness although it is darker.
uint8_t retryOnSaturated = 10;
+ // in a loop wait for next sample, get values and adjust sensitivity if needed
while( true ) {
waitNext(exposure);
@@ -122,11 +126,14 @@ bool autoGain( Tsl2561 &tsl, bool &gain, Tsl2561::exposure_t &exposure, uint16_t
uint16_t limit = getLimit(exposure);
if( full >= 1000 && full <= limit ) {
- return true; // new value within limits
+ // Serial.printf("autoGain normal full=%u, limits=1000-%u, curr=%u\n", full, limit, curr);
+ return true; // new value within limits of good accuracy
}
+ // adjust sensitivity, if possible
if( (full < 1000 && ++curr < sizeof(sensitivity)/sizeof(sensitivity[0]))
|| (full > limit && curr-- > 0) ) {
+ // Serial.printf("autoGain adjust full=%u, limits=1000-%u, curr=%u\n", full, limit, curr);
if( !tsl.setSensitivity(sensitivity[curr].gain, sensitivity[curr].exposure) ) {
return false; // I2C error
}
@@ -134,7 +141,10 @@ bool autoGain( Tsl2561 &tsl, bool &gain, Tsl2561::exposure_t &exposure, uint16_t
exposure = sensitivity[curr].exposure;
}
else {
- if( ++curr > 0 && retryOnSaturated-- == 0 ) {
+ // sensitivity already is at minimum or maximum
+ if( ++curr > 0 || retryOnSaturated-- == 0 ) {
+ // Serial.printf("autoGain limit full=%u, ir=%u, limits=1000-%u, curr=%u, retry=%u\n", full, ir, limit, curr, retryOnSaturated);
+ // dark, or repeatedly confirmed high brightness
return true; // saturated, but best we can do
}
}
@@ -176,6 +186,11 @@ bool milliLux( uint32_t full, uint32_t ir, uint32_t &mLux, bool csType, uint8_t
return true;
}
+ if( full == 0xffffffff || ir == 0xffffffff ) {
+ mLux = 99999999; // indicates saturation at shortest exposure
+ return true;
+ }
+
uint32_t milliRatio = ir * 1000 / full;
if( csType ) {
diff --git a/lib/Joba_Tsl2561-2.0.7/src/Tsl2561Util.h b/lib/Joba_Tsl2561-2.0.10/src/Tsl2561Util.h
similarity index 100%
rename from lib/Joba_Tsl2561-2.0.7/src/Tsl2561Util.h
rename to lib/Joba_Tsl2561-2.0.10/src/Tsl2561Util.h
diff --git a/lib/PubSubClient-EspEasy-2.6.09/tests/testcases/mqtt_basic.py b/lib/PubSubClient-EspEasy-2.6.09/tests/testcases/mqtt_basic.py
deleted file mode 100644
index 1b0cc65bb..000000000
--- a/lib/PubSubClient-EspEasy-2.6.09/tests/testcases/mqtt_basic.py
+++ /dev/null
@@ -1,43 +0,0 @@
-import unittest
-import settings
-
-import time
-import mosquitto
-
-import serial
-
-def on_message(mosq, obj, msg):
- obj.message_queue.append(msg)
-
-class mqtt_basic(unittest.TestCase):
-
- message_queue = []
-
- @classmethod
- def setUpClass(self):
- self.client = mosquitto.Mosquitto("pubsubclient_ut", clean_session=True,obj=self)
- self.client.connect(settings.server_ip)
- self.client.on_message = on_message
- self.client.subscribe("outTopic",0)
-
- @classmethod
- def tearDownClass(self):
- self.client.disconnect()
-
- def test_one(self):
- i=30
- while len(self.message_queue) == 0 and i > 0:
- self.client.loop()
- time.sleep(0.5)
- i -= 1
- self.assertTrue(i>0, "message receive timed-out")
- self.assertEqual(len(self.message_queue), 1, "unexpected number of messages received")
- msg = self.message_queue[0]
- self.assertEqual(msg.mid,0,"message id not 0")
- self.assertEqual(msg.topic,"outTopic","message topic incorrect")
- self.assertEqual(msg.payload,"hello world")
- self.assertEqual(msg.qos,0,"message qos not 0")
- self.assertEqual(msg.retain,False,"message retain flag incorrect")
-
-
-
diff --git a/lib/PubSubClient-EspEasy-2.6.09/tests/testcases/mqtt_publish_in_callback.py b/lib/PubSubClient-EspEasy-2.6.09/tests/testcases/mqtt_publish_in_callback.py
deleted file mode 100644
index 7989f7f17..000000000
--- a/lib/PubSubClient-EspEasy-2.6.09/tests/testcases/mqtt_publish_in_callback.py
+++ /dev/null
@@ -1,64 +0,0 @@
-import unittest
-import settings
-
-import time
-import mosquitto
-
-import serial
-
-def on_message(mosq, obj, msg):
- obj.message_queue.append(msg)
-
-class mqtt_publish_in_callback(unittest.TestCase):
-
- message_queue = []
-
- @classmethod
- def setUpClass(self):
- self.client = mosquitto.Mosquitto("pubsubclient_ut", clean_session=True,obj=self)
- self.client.connect(settings.server_ip)
- self.client.on_message = on_message
- self.client.subscribe("outTopic",0)
-
- @classmethod
- def tearDownClass(self):
- self.client.disconnect()
-
- def test_connect(self):
- i=30
- while len(self.message_queue) == 0 and i > 0:
- self.client.loop()
- time.sleep(0.5)
- i -= 1
- self.assertTrue(i>0, "message receive timed-out")
- self.assertEqual(len(self.message_queue), 1, "unexpected number of messages received")
- msg = self.message_queue.pop(0)
- self.assertEqual(msg.mid,0,"message id not 0")
- self.assertEqual(msg.topic,"outTopic","message topic incorrect")
- self.assertEqual(msg.payload,"hello world")
- self.assertEqual(msg.qos,0,"message qos not 0")
- self.assertEqual(msg.retain,False,"message retain flag incorrect")
-
-
- def test_publish(self):
- self.assertEqual(len(self.message_queue), 0, "message queue not empty")
- payload = "abcdefghij"
- self.client.publish("inTopic",payload)
-
- i=30
- while len(self.message_queue) == 0 and i > 0:
- self.client.loop()
- time.sleep(0.5)
- i -= 1
-
- self.assertTrue(i>0, "message receive timed-out")
- self.assertEqual(len(self.message_queue), 1, "unexpected number of messages received")
- msg = self.message_queue.pop(0)
- self.assertEqual(msg.mid,0,"message id not 0")
- self.assertEqual(msg.topic,"outTopic","message topic incorrect")
- self.assertEqual(msg.payload,payload)
- self.assertEqual(msg.qos,0,"message qos not 0")
- self.assertEqual(msg.retain,False,"message retain flag incorrect")
-
-
-
diff --git a/lib/PubSubClient-EspEasy-2.6.09/tests/testsuite.py b/lib/PubSubClient-EspEasy-2.6.09/tests/testsuite.py
deleted file mode 100644
index 0a8e70dfd..000000000
--- a/lib/PubSubClient-EspEasy-2.6.09/tests/testsuite.py
+++ /dev/null
@@ -1,179 +0,0 @@
-#!/usr/bin/env python
-import os
-import os.path
-import sys
-import shutil
-from subprocess import call
-import importlib
-import unittest
-import re
-
-from testcases import settings
-
-class Workspace(object):
-
- def __init__(self):
- self.root_dir = os.getcwd()
- self.build_dir = os.path.join(self.root_dir,"tmpbin");
- self.log_dir = os.path.join(self.root_dir,"logs");
- self.tests_dir = os.path.join(self.root_dir,"testcases");
- self.examples_dir = os.path.join(self.root_dir,"../PubSubClient/examples")
- self.examples = []
- self.tests = []
- if not os.path.isdir("../PubSubClient"):
- raise Exception("Cannot find PubSubClient library")
- try:
- import ino
- except:
- raise Exception("ino tool not installed")
-
- def init(self):
- if os.path.isdir(self.build_dir):
- shutil.rmtree(self.build_dir)
- os.mkdir(self.build_dir)
- if os.path.isdir(self.log_dir):
- shutil.rmtree(self.log_dir)
- os.mkdir(self.log_dir)
-
- os.chdir(self.build_dir)
- call(["ino","init"])
-
- shutil.copytree("../../PubSubClient","lib/PubSubClient")
-
- filenames = []
- for root, dirs, files in os.walk(self.examples_dir):
- filenames += [os.path.join(root,f) for f in files if f.endswith(".ino")]
- filenames.sort()
- for e in filenames:
- self.examples.append(Sketch(self,e))
-
- filenames = []
- for root, dirs, files in os.walk(self.tests_dir):
- filenames += [os.path.join(root,f) for f in files if f.endswith(".ino")]
- filenames.sort()
- for e in filenames:
- self.tests.append(Sketch(self,e))
-
- def clean(self):
- shutil.rmtree(self.build_dir)
-
-class Sketch(object):
- def __init__(self,wksp,fn):
- self.w = wksp
- self.filename = fn
- self.basename = os.path.basename(self.filename)
- self.build_log = os.path.join(self.w.log_dir,"%s.log"%(os.path.basename(self.filename),))
- self.build_err_log = os.path.join(self.w.log_dir,"%s.err.log"%(os.path.basename(self.filename),))
- self.build_upload_log = os.path.join(self.w.log_dir,"%s.upload.log"%(os.path.basename(self.filename),))
-
- def build(self):
- sys.stdout.write(" Build: ")
- sys.stdout.flush()
-
- # Copy sketch over, replacing IP addresses as necessary
- fin = open(self.filename,"r")
- lines = fin.readlines()
- fin.close()
- fout = open(os.path.join(self.w.build_dir,"src","sketch.ino"),"w")
- for l in lines:
- if re.match(r"^byte server\[\] = {",l):
- fout.write("byte server[] = { %s };\n"%(settings.server_ip.replace(".",", "),))
- elif re.match(r"^byte ip\[\] = {",l):
- fout.write("byte ip[] = { %s };\n"%(settings.arduino_ip.replace(".",", "),))
- else:
- fout.write(l)
- fout.flush()
- fout.close()
-
- # Run build
- fout = open(self.build_log, "w")
- ferr = open(self.build_err_log, "w")
- rc = call(["ino","build"],stdout=fout,stderr=ferr)
- fout.close()
- ferr.close()
- if rc == 0:
- sys.stdout.write("pass")
- sys.stdout.write("\n")
- return True
- else:
- sys.stdout.write("fail")
- sys.stdout.write("\n")
- with open(self.build_err_log) as f:
- for line in f:
- print " ",line,
- return False
-
- def upload(self):
- sys.stdout.write(" Upload: ")
- sys.stdout.flush()
- fout = open(self.build_upload_log, "w")
- rc = call(["ino","upload"],stdout=fout,stderr=fout)
- fout.close()
- if rc == 0:
- sys.stdout.write("pass")
- sys.stdout.write("\n")
- return True
- else:
- sys.stdout.write("fail")
- sys.stdout.write("\n")
- with open(self.build_upload_log) as f:
- for line in f:
- print " ",line,
- return False
-
-
- def test(self):
- # import the matching test case, if it exists
- try:
- basename = os.path.basename(self.filename)[:-4]
- i = importlib.import_module("testcases."+basename)
- except:
- sys.stdout.write(" Test: no tests found")
- sys.stdout.write("\n")
- return
- c = getattr(i,basename)
-
- testmethods = [m for m in dir(c) if m.startswith("test_")]
- testmethods.sort()
- tests = []
- for m in testmethods:
- tests.append(c(m))
-
- result = unittest.TestResult()
- c.setUpClass()
- if self.upload():
- sys.stdout.write(" Test: ")
- sys.stdout.flush()
- for t in tests:
- t.run(result)
- print "%d/%d"%(result.testsRun-len(result.failures)-len(result.errors),result.testsRun)
- if not result.wasSuccessful():
- if len(result.failures) > 0:
- for f in result.failures:
- print "-- %s"%(str(f[0]),)
- print f[1]
- if len(result.errors) > 0:
- print " Errors:"
- for f in result.errors:
- print "-- %s"%(str(f[0]),)
- print f[1]
- c.tearDownClass()
-
-if __name__ == '__main__':
- run_tests = True
-
- w = Workspace()
- w.init()
-
- for e in w.examples:
- print "--------------------------------------"
- print "[%s]"%(e.basename,)
- if e.build() and run_tests:
- e.test()
- for e in w.tests:
- print "--------------------------------------"
- print "[%s]"%(e.basename,)
- if e.build() and run_tests:
- e.test()
-
- w.clean()
diff --git a/lib/PubSubClient-EspEasy-2.6.09/.gitignore b/lib/PubSubClient-EspEasy-2.7.12/.gitignore
similarity index 100%
rename from lib/PubSubClient-EspEasy-2.6.09/.gitignore
rename to lib/PubSubClient-EspEasy-2.7.12/.gitignore
diff --git a/lib/PubSubClient-EspEasy-2.6.09/.travis.yml b/lib/PubSubClient-EspEasy-2.7.12/.travis.yml
similarity index 100%
rename from lib/PubSubClient-EspEasy-2.6.09/.travis.yml
rename to lib/PubSubClient-EspEasy-2.7.12/.travis.yml
diff --git a/lib/PubSubClient-EspEasy-2.6.09/CHANGES.txt b/lib/PubSubClient-EspEasy-2.7.12/CHANGES.txt
similarity index 86%
rename from lib/PubSubClient-EspEasy-2.6.09/CHANGES.txt
rename to lib/PubSubClient-EspEasy-2.7.12/CHANGES.txt
index 8c8bef64e..ff4da62ab 100644
--- a/lib/PubSubClient-EspEasy-2.6.09/CHANGES.txt
+++ b/lib/PubSubClient-EspEasy-2.7.12/CHANGES.txt
@@ -1,8 +1,16 @@
+2.7
+ * Fix remaining-length handling to prevent buffer overrun
+ * Add large-payload API - beginPublish/write/publish/endPublish
+ * Add yield call to improve reliability on ESP
+ * Add Clean Session flag to connect options
+ * Add ESP32 support for functional callback signature
+ * Various other fixes
+
2.4
* Add MQTT_SOCKET_TIMEOUT to prevent it blocking indefinitely
whilst waiting for inbound data
* Fixed return code when publishing >256 bytes
-
+
2.3
* Add publish(topic,payload,retained) function
diff --git a/lib/PubSubClient-EspEasy-2.6.09/LICENSE.txt b/lib/PubSubClient-EspEasy-2.7.12/LICENSE.txt
similarity index 100%
rename from lib/PubSubClient-EspEasy-2.6.09/LICENSE.txt
rename to lib/PubSubClient-EspEasy-2.7.12/LICENSE.txt
diff --git a/lib/PubSubClient-EspEasy-2.6.09/README.md b/lib/PubSubClient-EspEasy-2.7.12/README.md
similarity index 95%
rename from lib/PubSubClient-EspEasy-2.6.09/README.md
rename to lib/PubSubClient-EspEasy-2.7.12/README.md
index 83176919c..69cbb8f0c 100644
--- a/lib/PubSubClient-EspEasy-2.6.09/README.md
+++ b/lib/PubSubClient-EspEasy-2.7.12/README.md
@@ -8,7 +8,7 @@ a server that supports MQTT.
The library comes with a number of example sketches. See File > Examples > PubSubClient
within the Arduino application.
-Full API documentation is available here: http://pubsubclient.knolleary.net
+Full API documentation is available here: https://pubsubclient.knolleary.net
## Limitations
@@ -37,6 +37,7 @@ boards and shields, including:
- TI CC3000 WiFi - [library](https://github.com/sparkfun/SFE_CC3000_Library)
- Intel Galileo/Edison
- ESP8266
+ - ESP32
The library cannot currently be used with hardware based on the ENC28J60 chip –
such as the Nanode or the Nuelectronics Ethernet Shield. For those, there is an
diff --git a/lib/PubSubClient-EspEasy-2.6.09/examples/mqtt_auth/mqtt_auth.ino b/lib/PubSubClient-EspEasy-2.7.12/examples/mqtt_auth/mqtt_auth.ino
similarity index 100%
rename from lib/PubSubClient-EspEasy-2.6.09/examples/mqtt_auth/mqtt_auth.ino
rename to lib/PubSubClient-EspEasy-2.7.12/examples/mqtt_auth/mqtt_auth.ino
diff --git a/lib/PubSubClient-EspEasy-2.6.09/examples/mqtt_basic/mqtt_basic.ino b/lib/PubSubClient-EspEasy-2.7.12/examples/mqtt_basic/mqtt_basic.ino
similarity index 100%
rename from lib/PubSubClient-EspEasy-2.6.09/examples/mqtt_basic/mqtt_basic.ino
rename to lib/PubSubClient-EspEasy-2.7.12/examples/mqtt_basic/mqtt_basic.ino
diff --git a/lib/PubSubClient-EspEasy-2.6.09/examples/mqtt_esp8266/mqtt_esp8266.ino b/lib/PubSubClient-EspEasy-2.7.12/examples/mqtt_esp8266/mqtt_esp8266.ino
similarity index 92%
rename from lib/PubSubClient-EspEasy-2.6.09/examples/mqtt_esp8266/mqtt_esp8266.ino
rename to lib/PubSubClient-EspEasy-2.7.12/examples/mqtt_esp8266/mqtt_esp8266.ino
index e46f85f3e..e7357b507 100644
--- a/lib/PubSubClient-EspEasy-2.6.09/examples/mqtt_esp8266/mqtt_esp8266.ino
+++ b/lib/PubSubClient-EspEasy-2.7.12/examples/mqtt_esp8266/mqtt_esp8266.ino
@@ -38,14 +38,6 @@ long lastMsg = 0;
char msg[50];
int value = 0;
-void setup() {
- pinMode(BUILTIN_LED, OUTPUT); // Initialize the BUILTIN_LED pin as an output
- Serial.begin(115200);
- setup_wifi();
- client.setServer(mqtt_server, 1883);
- client.setCallback(callback);
-}
-
void setup_wifi() {
delay(10);
@@ -61,6 +53,8 @@ void setup_wifi() {
Serial.print(".");
}
+ randomSeed(micros());
+
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
@@ -80,7 +74,7 @@ void callback(char* topic, byte* payload, unsigned int length) {
if ((char)payload[0] == '1') {
digitalWrite(BUILTIN_LED, LOW); // Turn the LED on (Note that LOW is the voltage level
// but actually the LED is on; this is because
- // it is acive low on the ESP-01)
+ // it is active low on the ESP-01)
} else {
digitalWrite(BUILTIN_LED, HIGH); // Turn the LED off by making the voltage HIGH
}
@@ -91,8 +85,11 @@ void reconnect() {
// Loop until we're reconnected
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
+ // Create a random client ID
+ String clientId = "ESP8266Client-";
+ clientId += String(random(0xffff), HEX);
// Attempt to connect
- if (client.connect("ESP8266Client")) {
+ if (client.connect(clientId.c_str())) {
Serial.println("connected");
// Once connected, publish an announcement...
client.publish("outTopic", "hello world");
@@ -107,6 +104,15 @@ void reconnect() {
}
}
}
+
+void setup() {
+ pinMode(BUILTIN_LED, OUTPUT); // Initialize the BUILTIN_LED pin as an output
+ Serial.begin(115200);
+ setup_wifi();
+ client.setServer(mqtt_server, 1883);
+ client.setCallback(callback);
+}
+
void loop() {
if (!client.connected()) {
@@ -118,7 +124,7 @@ void loop() {
if (now - lastMsg > 2000) {
lastMsg = now;
++value;
- snprintf (msg, 75, "hello world #%ld", value);
+ snprintf (msg, 50, "hello world #%ld", value);
Serial.print("Publish message: ");
Serial.println(msg);
client.publish("outTopic", msg);
diff --git a/lib/PubSubClient-EspEasy-2.7.12/examples/mqtt_large_message/mqtt_large_message.ino b/lib/PubSubClient-EspEasy-2.7.12/examples/mqtt_large_message/mqtt_large_message.ino
new file mode 100644
index 000000000..e048c3ed3
--- /dev/null
+++ b/lib/PubSubClient-EspEasy-2.7.12/examples/mqtt_large_message/mqtt_large_message.ino
@@ -0,0 +1,179 @@
+/*
+ Long message ESP8266 MQTT example
+
+ This sketch demonstrates sending arbitrarily large messages in combination
+ with the ESP8266 board/library.
+
+ It connects to an MQTT server then:
+ - publishes "hello world" to the topic "outTopic"
+ - subscribes to the topic "greenBottles/#", printing out any messages
+ it receives. NB - it assumes the received payloads are strings not binary
+ - If the sub-topic is a number, it publishes a "greenBottles/lyrics" message
+ with a payload consisting of the lyrics to "10 green bottles", replacing
+ 10 with the number given in the sub-topic.
+
+ It will reconnect to the server if the connection is lost using a blocking
+ reconnect function. See the 'mqtt_reconnect_nonblocking' example for how to
+ achieve the same result without blocking the main loop.
+
+ To install the ESP8266 board, (using Arduino 1.6.4+):
+ - Add the following 3rd party board manager under "File -> Preferences -> Additional Boards Manager URLs":
+ http://arduino.esp8266.com/stable/package_esp8266com_index.json
+ - Open the "Tools -> Board -> Board Manager" and click install for the ESP8266"
+ - Select your ESP8266 in "Tools -> Board"
+
+*/
+
+#include
+#include
+
+// Update these with values suitable for your network.
+
+const char* ssid = "........";
+const char* password = "........";
+const char* mqtt_server = "broker.mqtt-dashboard.com";
+
+WiFiClient espClient;
+PubSubClient client(espClient);
+long lastMsg = 0;
+char msg[50];
+int value = 0;
+
+void setup_wifi() {
+
+ delay(10);
+ // We start by connecting to a WiFi network
+ Serial.println();
+ Serial.print("Connecting to ");
+ Serial.println(ssid);
+
+ WiFi.begin(ssid, password);
+
+ while (WiFi.status() != WL_CONNECTED) {
+ delay(500);
+ Serial.print(".");
+ }
+
+ randomSeed(micros());
+
+ Serial.println("");
+ Serial.println("WiFi connected");
+ Serial.println("IP address: ");
+ Serial.println(WiFi.localIP());
+}
+
+void callback(char* topic, byte* payload, unsigned int length) {
+ Serial.print("Message arrived [");
+ Serial.print(topic);
+ Serial.print("] ");
+ for (int i = 0; i < length; i++) {
+ Serial.print((char)payload[i]);
+ }
+ Serial.println();
+
+ // Find out how many bottles we should generate lyrics for
+ String topicStr(topic);
+ int bottleCount = 0; // assume no bottles unless we correctly parse a value from the topic
+ if (topicStr.indexOf('/') >= 0) {
+ // The topic includes a '/', we'll try to read the number of bottles from just after that
+ topicStr.remove(0, topicStr.indexOf('/')+1);
+ // Now see if there's a number of bottles after the '/'
+ bottleCount = topicStr.toInt();
+ }
+
+ if (bottleCount > 0) {
+ // Work out how big our resulting message will be
+ int msgLen = 0;
+ for (int i = bottleCount; i > 0; i--) {
+ String numBottles(i);
+ msgLen += 2*numBottles.length();
+ if (i == 1) {
+ msgLen += 2*String(" green bottle, standing on the wall\n").length();
+ } else {
+ msgLen += 2*String(" green bottles, standing on the wall\n").length();
+ }
+ msgLen += String("And if one green bottle should accidentally fall\nThere'll be ").length();
+ switch (i) {
+ case 1:
+ msgLen += String("no green bottles, standing on the wall\n\n").length();
+ break;
+ case 2:
+ msgLen += String("1 green bottle, standing on the wall\n\n").length();
+ break;
+ default:
+ numBottles = i-1;
+ msgLen += numBottles.length();
+ msgLen += String(" green bottles, standing on the wall\n\n").length();
+ break;
+ };
+ }
+
+ // Now we can start to publish the message
+ client.beginPublish("greenBottles/lyrics", msgLen, false);
+ for (int i = bottleCount; i > 0; i--) {
+ for (int j = 0; j < 2; j++) {
+ client.print(i);
+ if (i == 1) {
+ client.print(" green bottle, standing on the wall\n");
+ } else {
+ client.print(" green bottles, standing on the wall\n");
+ }
+ }
+ client.print("And if one green bottle should accidentally fall\nThere'll be ");
+ switch (i) {
+ case 1:
+ client.print("no green bottles, standing on the wall\n\n");
+ break;
+ case 2:
+ client.print("1 green bottle, standing on the wall\n\n");
+ break;
+ default:
+ client.print(i-1);
+ client.print(" green bottles, standing on the wall\n\n");
+ break;
+ };
+ }
+ // Now we're done!
+ client.endPublish();
+ }
+}
+
+void reconnect() {
+ // Loop until we're reconnected
+ while (!client.connected()) {
+ Serial.print("Attempting MQTT connection...");
+ // Create a random client ID
+ String clientId = "ESP8266Client-";
+ clientId += String(random(0xffff), HEX);
+ // Attempt to connect
+ if (client.connect(clientId.c_str())) {
+ Serial.println("connected");
+ // Once connected, publish an announcement...
+ client.publish("outTopic", "hello world");
+ // ... and resubscribe
+ client.subscribe("greenBottles/#");
+ } else {
+ Serial.print("failed, rc=");
+ Serial.print(client.state());
+ Serial.println(" try again in 5 seconds");
+ // Wait 5 seconds before retrying
+ delay(5000);
+ }
+ }
+}
+
+void setup() {
+ pinMode(BUILTIN_LED, OUTPUT); // Initialize the BUILTIN_LED pin as an output
+ Serial.begin(115200);
+ setup_wifi();
+ client.setServer(mqtt_server, 1883);
+ client.setCallback(callback);
+}
+
+void loop() {
+
+ if (!client.connected()) {
+ reconnect();
+ }
+ client.loop();
+}
diff --git a/lib/PubSubClient-EspEasy-2.6.09/examples/mqtt_publish_in_callback/mqtt_publish_in_callback.ino b/lib/PubSubClient-EspEasy-2.7.12/examples/mqtt_publish_in_callback/mqtt_publish_in_callback.ino
similarity index 100%
rename from lib/PubSubClient-EspEasy-2.6.09/examples/mqtt_publish_in_callback/mqtt_publish_in_callback.ino
rename to lib/PubSubClient-EspEasy-2.7.12/examples/mqtt_publish_in_callback/mqtt_publish_in_callback.ino
diff --git a/lib/PubSubClient-EspEasy-2.6.09/examples/mqtt_reconnect_nonblocking/mqtt_reconnect_nonblocking.ino b/lib/PubSubClient-EspEasy-2.7.12/examples/mqtt_reconnect_nonblocking/mqtt_reconnect_nonblocking.ino
similarity index 100%
rename from lib/PubSubClient-EspEasy-2.6.09/examples/mqtt_reconnect_nonblocking/mqtt_reconnect_nonblocking.ino
rename to lib/PubSubClient-EspEasy-2.7.12/examples/mqtt_reconnect_nonblocking/mqtt_reconnect_nonblocking.ino
diff --git a/lib/PubSubClient-EspEasy-2.6.09/examples/mqtt_stream/mqtt_stream.ino b/lib/PubSubClient-EspEasy-2.7.12/examples/mqtt_stream/mqtt_stream.ino
similarity index 100%
rename from lib/PubSubClient-EspEasy-2.6.09/examples/mqtt_stream/mqtt_stream.ino
rename to lib/PubSubClient-EspEasy-2.7.12/examples/mqtt_stream/mqtt_stream.ino
diff --git a/lib/PubSubClient-EspEasy-2.6.09/keywords.txt b/lib/PubSubClient-EspEasy-2.7.12/keywords.txt
similarity index 91%
rename from lib/PubSubClient-EspEasy-2.6.09/keywords.txt
rename to lib/PubSubClient-EspEasy-2.7.12/keywords.txt
index b979588fe..1ee23d0fa 100644
--- a/lib/PubSubClient-EspEasy-2.6.09/keywords.txt
+++ b/lib/PubSubClient-EspEasy-2.7.12/keywords.txt
@@ -16,6 +16,9 @@ connect KEYWORD2
disconnect KEYWORD2
publish KEYWORD2
publish_P KEYWORD2
+beginPublish KEYWORD2
+endPublish KEYWORD2
+write KEYWORD2
subscribe KEYWORD2
unsubscribe KEYWORD2
loop KEYWORD2
diff --git a/lib/PubSubClient-EspEasy-2.6.09/library.json b/lib/PubSubClient-EspEasy-2.7.12/library.json
similarity index 97%
rename from lib/PubSubClient-EspEasy-2.6.09/library.json
rename to lib/PubSubClient-EspEasy-2.7.12/library.json
index b96739078..8a36a1c5e 100644
--- a/lib/PubSubClient-EspEasy-2.6.09/library.json
+++ b/lib/PubSubClient-EspEasy-2.7.12/library.json
@@ -6,7 +6,7 @@
"type": "git",
"url": "https://github.com/knolleary/pubsubclient.git"
},
- "version": "2.6",
+ "version": "2.7",
"exclude": "tests",
"examples": "examples/*/*.ino",
"frameworks": "arduino",
diff --git a/lib/PubSubClient-EspEasy-2.6.09/library.properties b/lib/PubSubClient-EspEasy-2.7.12/library.properties
similarity index 98%
rename from lib/PubSubClient-EspEasy-2.6.09/library.properties
rename to lib/PubSubClient-EspEasy-2.7.12/library.properties
index 3ceeda81c..1ae97882e 100644
--- a/lib/PubSubClient-EspEasy-2.6.09/library.properties
+++ b/lib/PubSubClient-EspEasy-2.7.12/library.properties
@@ -1,5 +1,5 @@
name=PubSubClient
-version=2.6
+version=2.7
author=Nick O'Leary
maintainer=Nick O'Leary
sentence=A client library for MQTT messaging.
diff --git a/lib/PubSubClient-EspEasy-2.6.09/src/PubSubClient.cpp b/lib/PubSubClient-EspEasy-2.7.12/src/PubSubClient.cpp
similarity index 79%
rename from lib/PubSubClient-EspEasy-2.6.09/src/PubSubClient.cpp
rename to lib/PubSubClient-EspEasy-2.7.12/src/PubSubClient.cpp
index 79eb2d52e..9fe15006a 100644
--- a/lib/PubSubClient-EspEasy-2.6.09/src/PubSubClient.cpp
+++ b/lib/PubSubClient-EspEasy-2.7.12/src/PubSubClient.cpp
@@ -102,30 +102,41 @@ PubSubClient::PubSubClient(const char* domain, uint16_t port, MQTT_CALLBACK_SIGN
}
boolean PubSubClient::connect(const char *id) {
- return connect(id,NULL,NULL,0,0,0,0);
+ return connect(id,NULL,NULL,0,0,0,0,1);
}
boolean PubSubClient::connect(const char *id, const char *user, const char *pass) {
- return connect(id,user,pass,0,0,0,0);
+ return connect(id,user,pass,0,0,0,0,1);
}
boolean PubSubClient::connect(const char *id, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage) {
- return connect(id,NULL,NULL,willTopic,willQos,willRetain,willMessage);
+ return connect(id,NULL,NULL,willTopic,willQos,willRetain,willMessage,1);
}
boolean PubSubClient::connect(const char *id, const char *user, const char *pass, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage) {
+ return connect(id,user,pass,willTopic,willQos,willRetain,willMessage,1);
+}
+
+boolean PubSubClient::connect(const char *id, const char *user, const char *pass, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage, boolean cleanSession) {
if (!connected()) {
int result = 0;
- if (domain.length() != 0) {
- result = _client->connect(this->domain.c_str(), this->port);
+ if (_client == nullptr) {
+ return false;
+ }
+ if (_client->connected()) {
+ result = 1;
} else {
- result = _client->connect(this->ip, this->port);
+ if (domain != NULL) {
+ result = _client->connect(this->domain.c_str(), this->port);
+ } else {
+ result = _client->connect(this->ip, this->port);
+ }
}
if (result == 1) {
nextMsgId = 1;
// Leave room in the buffer for header and variable length field
- uint16_t length = 5;
+ uint16_t length = MQTT_MAX_HEADER_SIZE;
unsigned int j;
#if MQTT_VERSION == MQTT_VERSION_3_1
@@ -141,9 +152,12 @@ boolean PubSubClient::connect(const char *id, const char *user, const char *pass
uint8_t v;
if (willTopic) {
- v = 0x06|(willQos<<3)|(willRetain<<5);
+ v = 0x04|(willQos<<3)|(willRetain<<5);
} else {
- v = 0x02;
+ v = 0x00;
+ }
+ if (cleanSession) {
+ v = v|0x02;
}
if(user != NULL) {
@@ -158,24 +172,31 @@ boolean PubSubClient::connect(const char *id, const char *user, const char *pass
buffer[length++] = ((MQTT_KEEPALIVE) >> 8);
buffer[length++] = ((MQTT_KEEPALIVE) & 0xFF);
+
+ CHECK_STRING_LENGTH(length,id)
length = writeString(id,buffer,length);
if (willTopic) {
+ CHECK_STRING_LENGTH(length,willTopic)
length = writeString(willTopic,buffer,length);
+ CHECK_STRING_LENGTH(length,willMessage)
length = writeString(willMessage,buffer,length);
}
if(user != NULL) {
+ CHECK_STRING_LENGTH(length,user)
length = writeString(user,buffer,length);
if(pass != NULL) {
+ CHECK_STRING_LENGTH(length,pass)
length = writeString(pass,buffer,length);
}
}
- write(MQTTCONNECT,buffer,length-5);
+ write(MQTTCONNECT,buffer,length-MQTT_MAX_HEADER_SIZE);
lastInActivity = lastOutActivity = millis();
while (!_client->available()) {
+ delay(0); // Prevent watchdog crashes
unsigned long t = millis();
if (t-lastInActivity >= ((int32_t) MQTT_SOCKET_TIMEOUT*1000UL)) {
_state = MQTT_CONNECTION_TIMEOUT;
@@ -207,9 +228,12 @@ boolean PubSubClient::connect(const char *id, const char *user, const char *pass
// reads a byte into result
boolean PubSubClient::readByte(uint8_t * result) {
+ if (_client == nullptr) {
+ return false;
+ }
uint32_t previousMillis = millis();
while(!_client->available()) {
- delay(1); // Add esp8266 de-blocking (Tasmota #790, EspEasy #1943)
+ delay(1); // Prevent watchdog crashes
uint32_t currentMillis = millis();
if(currentMillis - previousMillis >= ((int32_t) MQTT_SOCKET_TIMEOUT * 1000)){
return false;
@@ -241,7 +265,7 @@ uint16_t PubSubClient::readPacket(uint8_t* lengthLength) {
uint8_t start = 0;
do {
- if (len == 6) {
+ if (len == 5) {
// Invalid remaining length encoding - kill the connection
_state = MQTT_DISCONNECTED;
_client->stop();
@@ -353,11 +377,13 @@ boolean PubSubClient::loop() {
}
boolean PubSubClient::publish(const char* topic, const char* payload) {
- return publish(topic,(const uint8_t*)payload,strlen(payload),false);
+ size_t plength = (payload != nullptr) ? strlen(payload) : 0;
+ return publish(topic,(const uint8_t*)payload,plength,false);
}
boolean PubSubClient::publish(const char* topic, const char* payload, boolean retained) {
- return publish(topic,(const uint8_t*)payload,strlen(payload),retained);
+ size_t plength = (payload != nullptr) ? strlen(payload) : 0;
+ return publish(topic,(const uint8_t*)payload,plength,retained);
}
boolean PubSubClient::publish(const char* topic, const uint8_t* payload, unsigned int plength) {
@@ -366,12 +392,12 @@ boolean PubSubClient::publish(const char* topic, const uint8_t* payload, unsigne
boolean PubSubClient::publish(const char* topic, const uint8_t* payload, unsigned int plength, boolean retained) {
if (connected()) {
- if (MQTT_MAX_PACKET_SIZE < 5 + 2+strlen(topic) + plength) {
+ if (MQTT_MAX_PACKET_SIZE < MQTT_MAX_HEADER_SIZE + 2+strlen(topic) + plength) {
// Too long
return false;
}
// Leave room in the buffer for header and variable length field
- uint16_t length = 5;
+ uint16_t length = MQTT_MAX_HEADER_SIZE;
length = writeString(topic,buffer,length);
uint16_t i;
for (i=0;iwrite(buffer+(MQTT_MAX_HEADER_SIZE-hlen),length-(MQTT_MAX_HEADER_SIZE-hlen));
+ lastOutActivity = millis();
+ return (rc == (length-(MQTT_MAX_HEADER_SIZE-hlen)));
+ }
+ return false;
+}
+
+int PubSubClient::endPublish() {
+ return 1;
+}
+
+size_t PubSubClient::write(uint8_t data) {
+ lastOutActivity = millis();
+ if (_client == nullptr) {
+ return 0;
+ }
+ return _client->write(data);
+}
+
+size_t PubSubClient::write(const uint8_t *buffer, size_t size) {
+ lastOutActivity = millis();
+ if (_client == nullptr) {
+ return 0;
+ }
+ return _client->write(buffer,size);
+}
+
+size_t PubSubClient::buildHeader(uint8_t header, uint8_t* buf, uint16_t length) {
uint8_t lenBuf[4];
uint8_t llen = 0;
uint8_t digit;
uint8_t pos = 0;
- uint16_t rc;
uint16_t len = length;
do {
digit = len % 128;
@@ -450,15 +519,22 @@ boolean PubSubClient::write(uint8_t header, uint8_t* buf, uint16_t length) {
buf[4-llen] = header;
for (int i=0;i 0) && result) {
+ delay(0); // Prevent watchdog crashes
bytesToWrite = (bytesRemaining > MQTT_MAX_TRANSFER_SIZE)?MQTT_MAX_TRANSFER_SIZE:bytesRemaining;
rc = _client->write(writeBuf,bytesToWrite);
result = (rc == bytesToWrite);
@@ -467,9 +543,9 @@ boolean PubSubClient::write(uint8_t header, uint8_t* buf, uint16_t length) {
}
return result;
#else
- rc = _client->write(buf+(4-llen),length+1+llen);
+ rc = _client->write(buf+(MQTT_MAX_HEADER_SIZE-hlen),length+hlen);
lastOutActivity = millis();
- return (rc == 1+llen+length);
+ return (rc == hlen+length);
#endif
}
@@ -487,7 +563,7 @@ boolean PubSubClient::subscribe(const char* topic, uint8_t qos) {
}
if (connected()) {
// Leave room in the buffer for header and variable length field
- uint16_t length = 5;
+ uint16_t length = MQTT_MAX_HEADER_SIZE;
nextMsgId++;
if (nextMsgId == 0) {
nextMsgId = 1;
@@ -496,7 +572,7 @@ boolean PubSubClient::subscribe(const char* topic, uint8_t qos) {
buffer[length++] = (nextMsgId & 0xFF);
length = writeString((char*)topic, buffer,length);
buffer[length++] = qos;
- return write(MQTTSUBSCRIBE|MQTTQOS1,buffer,length-5);
+ return write(MQTTSUBSCRIBE|MQTTQOS1,buffer,length-MQTT_MAX_HEADER_SIZE);
}
return false;
}
@@ -507,7 +583,7 @@ boolean PubSubClient::unsubscribe(const char* topic) {
return false;
}
if (connected()) {
- uint16_t length = 5;
+ uint16_t length = MQTT_MAX_HEADER_SIZE;
nextMsgId++;
if (nextMsgId == 0) {
nextMsgId = 1;
@@ -515,7 +591,7 @@ boolean PubSubClient::unsubscribe(const char* topic) {
buffer[length++] = (nextMsgId >> 8);
buffer[length++] = (nextMsgId & 0xFF);
length = writeString(topic, buffer,length);
- return write(MQTTUNSUBSCRIBE|MQTTQOS1,buffer,length-5);
+ return write(MQTTUNSUBSCRIBE|MQTTQOS1,buffer,length-MQTT_MAX_HEADER_SIZE);
}
return false;
}
@@ -523,7 +599,7 @@ boolean PubSubClient::unsubscribe(const char* topic) {
void PubSubClient::disconnect() {
buffer[0] = MQTTDISCONNECT;
buffer[1] = 0;
- if (_client != NULL) {
+ if (_client != nullptr) {
_client->write(buffer,2);
_client->flush();
_client->stop();
@@ -558,6 +634,8 @@ boolean PubSubClient::connected() {
_client->flush();
_client->stop();
}
+ } else {
+ return this->_state == MQTT_CONNECTED;
}
}
return rc;
diff --git a/lib/PubSubClient-EspEasy-2.6.09/src/PubSubClient.h b/lib/PubSubClient-EspEasy-2.7.12/src/PubSubClient.h
similarity index 75%
rename from lib/PubSubClient-EspEasy-2.6.09/src/PubSubClient.h
rename to lib/PubSubClient-EspEasy-2.7.12/src/PubSubClient.h
index 003df770e..aa2080ed1 100644
--- a/lib/PubSubClient-EspEasy-2.6.09/src/PubSubClient.h
+++ b/lib/PubSubClient-EspEasy-2.7.12/src/PubSubClient.h
@@ -30,7 +30,8 @@
// MQTT_KEEPALIVE : keepAlive interval in Seconds
// Keepalive timeout for default MQTT Broker is 10s
#ifndef MQTT_KEEPALIVE
-#define MQTT_KEEPALIVE 10
+//#define MQTT_KEEPALIVE 10
+#define MQTT_KEEPALIVE 30 // Tasmota v6.5.0.14 enabling AWS-iot
#endif
// MQTT_SOCKET_TIMEOUT: socket timeout interval in Seconds
@@ -75,6 +76,9 @@
#define MQTTQOS1 (1 << 1)
#define MQTTQOS2 (2 << 1)
+// Maximum size of fixed header and variable length size header
+#define MQTT_MAX_HEADER_SIZE 5
+
#if defined(ESP8266) || defined(ESP32)
#include
#define MQTT_CALLBACK_SIGNATURE std::function callback
@@ -82,7 +86,9 @@
#define MQTT_CALLBACK_SIGNATURE void (*callback)(char*, uint8_t*, unsigned int)
#endif
-class PubSubClient {
+#define CHECK_STRING_LENGTH(l,s) if (l+2+strlen(s) > MQTT_MAX_PACKET_SIZE) {_client->stop();return false;}
+
+class PubSubClient : public Print {
private:
Client* _client;
uint8_t buffer[MQTT_MAX_PACKET_SIZE];
@@ -96,6 +102,11 @@ private:
boolean readByte(uint8_t * result, uint16_t * index);
boolean write(uint8_t header, uint8_t* buf, uint16_t length);
uint16_t writeString(const char* string, uint8_t* buf, uint16_t pos);
+ // Build up the header ready to send
+ // Returns the size of the header
+ // Note: the header is built at the end of the first MQTT_MAX_HEADER_SIZE bytes, so will start
+ // (MQTT_MAX_HEADER_SIZE - ) bytes into the buffer
+ size_t buildHeader(uint8_t header, uint8_t* buf, uint16_t length);
IPAddress ip;
String domain;
uint16_t port;
@@ -129,12 +140,31 @@ public:
boolean connect(const char* id, const char* user, const char* pass);
boolean connect(const char* id, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage);
boolean connect(const char* id, const char* user, const char* pass, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage);
+ boolean connect(const char* id, const char* user, const char* pass, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage, boolean cleanSession);
void disconnect();
boolean publish(const char* topic, const char* payload);
boolean publish(const char* topic, const char* payload, boolean retained);
boolean publish(const char* topic, const uint8_t * payload, unsigned int plength);
boolean publish(const char* topic, const uint8_t * payload, unsigned int plength, boolean retained);
+ boolean publish_P(const char* topic, const char* payload, boolean retained);
boolean publish_P(const char* topic, const uint8_t * payload, unsigned int plength, boolean retained);
+ // Start to publish a message.
+ // This API:
+ // beginPublish(...)
+ // one or more calls to write(...)
+ // endPublish()
+ // Allows for arbitrarily large payloads to be sent without them having to be copied into
+ // a new buffer and held in memory at one time
+ // Returns 1 if the message was started successfully, 0 if there was an error
+ boolean beginPublish(const char* topic, unsigned int plength, boolean retained);
+ // Finish off this publish message (started with beginPublish)
+ // Returns 1 if the packet was sent successfully, 0 if there was an error
+ int endPublish();
+ // Write a single byte of payload (only to be used with beginPublish/endPublish)
+ virtual size_t write(uint8_t);
+ // Write size bytes from buffer into the payload (only to be used with beginPublish/endPublish)
+ // Returns the number of bytes written
+ virtual size_t write(const uint8_t *buffer, size_t size);
boolean subscribe(const char* topic);
boolean subscribe(const char* topic, uint8_t qos);
boolean unsubscribe(const char* topic);
diff --git a/lib/PubSubClient-EspEasy-2.6.09/tests/.gitignore b/lib/PubSubClient-EspEasy-2.7.12/tests/.gitignore
similarity index 100%
rename from lib/PubSubClient-EspEasy-2.6.09/tests/.gitignore
rename to lib/PubSubClient-EspEasy-2.7.12/tests/.gitignore
diff --git a/lib/PubSubClient-EspEasy-2.6.09/tests/Makefile b/lib/PubSubClient-EspEasy-2.7.12/tests/Makefile
similarity index 100%
rename from lib/PubSubClient-EspEasy-2.6.09/tests/Makefile
rename to lib/PubSubClient-EspEasy-2.7.12/tests/Makefile
diff --git a/lib/PubSubClient-EspEasy-2.6.09/tests/README.md b/lib/PubSubClient-EspEasy-2.7.12/tests/README.md
similarity index 100%
rename from lib/PubSubClient-EspEasy-2.6.09/tests/README.md
rename to lib/PubSubClient-EspEasy-2.7.12/tests/README.md
diff --git a/lib/PubSubClient-EspEasy-2.6.09/tests/src/connect_spec.cpp b/lib/PubSubClient-EspEasy-2.7.12/tests/src/connect_spec.cpp
similarity index 83%
rename from lib/PubSubClient-EspEasy-2.6.09/tests/src/connect_spec.cpp
rename to lib/PubSubClient-EspEasy-2.7.12/tests/src/connect_spec.cpp
index 69f18646f..e27a1f59f 100644
--- a/lib/PubSubClient-EspEasy-2.6.09/tests/src/connect_spec.cpp
+++ b/lib/PubSubClient-EspEasy-2.7.12/tests/src/connect_spec.cpp
@@ -98,6 +98,33 @@ int test_connect_fails_on_bad_rc() {
END_IT
}
+int test_connect_non_clean_session() {
+ IT("sends a properly formatted non-clean session connect packet and succeeds");
+ ShimClient shimClient;
+
+ shimClient.setAllowConnect(true);
+ byte expectServer[] = { 172, 16, 0, 2 };
+ shimClient.expectConnect(expectServer,1883);
+ byte connect[] = {0x10,0x18,0x0,0x4,0x4d,0x51,0x54,0x54,0x4,0x0,0x0,0xf,0x0,0xc,0x63,0x6c,0x69,0x65,0x6e,0x74,0x5f,0x74,0x65,0x73,0x74,0x31};
+ byte connack[] = { 0x20, 0x02, 0x00, 0x00 };
+
+ shimClient.expect(connect,26);
+ shimClient.respond(connack,4);
+
+ PubSubClient client(server, 1883, callback, shimClient);
+ int state = client.state();
+ IS_TRUE(state == MQTT_DISCONNECTED);
+
+ int rc = client.connect((char*)"client_test1",0,0,0,0,0,0,0);
+ IS_TRUE(rc);
+ IS_FALSE(shimClient.error());
+
+ state = client.state();
+ IS_TRUE(state == MQTT_CONNECTED);
+
+ END_IT
+}
+
int test_connect_accepts_username_password() {
IT("accepts a username and password");
ShimClient shimClient;
@@ -133,6 +160,23 @@ int test_connect_accepts_username_no_password() {
END_IT
}
+int test_connect_accepts_username_blank_password() {
+ IT("accepts a username and blank password");
+ ShimClient shimClient;
+ shimClient.setAllowConnect(true);
+
+ byte connect[] = { 0x10,0x20,0x0,0x4,0x4d,0x51,0x54,0x54,0x4,0xc2,0x0,0xf,0x0,0xc,0x63,0x6c,0x69,0x65,0x6e,0x74,0x5f,0x74,0x65,0x73,0x74,0x31,0x0,0x4,0x75,0x73,0x65,0x72,0x0,0x0};
+ byte connack[] = { 0x20, 0x02, 0x00, 0x00 };
+ shimClient.expect(connect,0x26);
+ shimClient.respond(connack,4);
+
+ PubSubClient client(server, 1883, callback, shimClient);
+ int rc = client.connect((char*)"client_test1",(char*)"user",(char*)"pass");
+ IS_TRUE(rc);
+ IS_FALSE(shimClient.error());
+
+ END_IT
+}
int test_connect_ignores_password_no_username() {
IT("ignores a password but no username");
@@ -239,10 +283,12 @@ int test_connect_disconnect_connect() {
int main()
{
SUITE("Connect");
+
test_connect_fails_no_network();
test_connect_fails_on_no_response();
test_connect_properly_formatted();
+ test_connect_non_clean_session();
test_connect_accepts_username_password();
test_connect_fails_on_bad_rc();
test_connect_properly_formatted_hostname();
diff --git a/lib/PubSubClient-EspEasy-2.6.09/tests/src/keepalive_spec.cpp b/lib/PubSubClient-EspEasy-2.7.12/tests/src/keepalive_spec.cpp
similarity index 100%
rename from lib/PubSubClient-EspEasy-2.6.09/tests/src/keepalive_spec.cpp
rename to lib/PubSubClient-EspEasy-2.7.12/tests/src/keepalive_spec.cpp
diff --git a/lib/PubSubClient-EspEasy-2.6.09/tests/src/lib/Arduino.h b/lib/PubSubClient-EspEasy-2.7.12/tests/src/lib/Arduino.h
similarity index 90%
rename from lib/PubSubClient-EspEasy-2.6.09/tests/src/lib/Arduino.h
rename to lib/PubSubClient-EspEasy-2.7.12/tests/src/lib/Arduino.h
index c6752801a..2a00f24bc 100644
--- a/lib/PubSubClient-EspEasy-2.6.09/tests/src/lib/Arduino.h
+++ b/lib/PubSubClient-EspEasy-2.7.12/tests/src/lib/Arduino.h
@@ -5,6 +5,7 @@
#include
#include
#include
+#include "Print.h"
extern "C"{
@@ -20,4 +21,6 @@ extern "C"{
#define PROGMEM
#define pgm_read_byte_near(x) *(x)
+#define yield(x) {}
+
#endif // Arduino_h
diff --git a/lib/PubSubClient-EspEasy-2.6.09/tests/src/lib/BDDTest.cpp b/lib/PubSubClient-EspEasy-2.7.12/tests/src/lib/BDDTest.cpp
similarity index 100%
rename from lib/PubSubClient-EspEasy-2.6.09/tests/src/lib/BDDTest.cpp
rename to lib/PubSubClient-EspEasy-2.7.12/tests/src/lib/BDDTest.cpp
diff --git a/lib/PubSubClient-EspEasy-2.6.09/tests/src/lib/BDDTest.h b/lib/PubSubClient-EspEasy-2.7.12/tests/src/lib/BDDTest.h
similarity index 100%
rename from lib/PubSubClient-EspEasy-2.6.09/tests/src/lib/BDDTest.h
rename to lib/PubSubClient-EspEasy-2.7.12/tests/src/lib/BDDTest.h
diff --git a/lib/PubSubClient-EspEasy-2.6.09/tests/src/lib/Buffer.cpp b/lib/PubSubClient-EspEasy-2.7.12/tests/src/lib/Buffer.cpp
similarity index 86%
rename from lib/PubSubClient-EspEasy-2.6.09/tests/src/lib/Buffer.cpp
rename to lib/PubSubClient-EspEasy-2.7.12/tests/src/lib/Buffer.cpp
index 59a2fbbbd..f07759a3a 100644
--- a/lib/PubSubClient-EspEasy-2.6.09/tests/src/lib/Buffer.cpp
+++ b/lib/PubSubClient-EspEasy-2.7.12/tests/src/lib/Buffer.cpp
@@ -2,9 +2,13 @@
#include "Arduino.h"
Buffer::Buffer() {
+ this->pos = 0;
+ this->length = 0;
}
Buffer::Buffer(uint8_t* buf, size_t size) {
+ this->pos = 0;
+ this->length = 0;
this->add(buf,size);
}
bool Buffer::available() {
diff --git a/lib/PubSubClient-EspEasy-2.6.09/tests/src/lib/Buffer.h b/lib/PubSubClient-EspEasy-2.7.12/tests/src/lib/Buffer.h
similarity index 100%
rename from lib/PubSubClient-EspEasy-2.6.09/tests/src/lib/Buffer.h
rename to lib/PubSubClient-EspEasy-2.7.12/tests/src/lib/Buffer.h
diff --git a/lib/PubSubClient-EspEasy-2.6.09/tests/src/lib/Client.h b/lib/PubSubClient-EspEasy-2.7.12/tests/src/lib/Client.h
similarity index 100%
rename from lib/PubSubClient-EspEasy-2.6.09/tests/src/lib/Client.h
rename to lib/PubSubClient-EspEasy-2.7.12/tests/src/lib/Client.h
diff --git a/lib/PubSubClient-EspEasy-2.6.09/tests/src/lib/IPAddress.cpp b/lib/PubSubClient-EspEasy-2.7.12/tests/src/lib/IPAddress.cpp
similarity index 100%
rename from lib/PubSubClient-EspEasy-2.6.09/tests/src/lib/IPAddress.cpp
rename to lib/PubSubClient-EspEasy-2.7.12/tests/src/lib/IPAddress.cpp
diff --git a/lib/PubSubClient-EspEasy-2.6.09/tests/src/lib/IPAddress.h b/lib/PubSubClient-EspEasy-2.7.12/tests/src/lib/IPAddress.h
similarity index 100%
rename from lib/PubSubClient-EspEasy-2.6.09/tests/src/lib/IPAddress.h
rename to lib/PubSubClient-EspEasy-2.7.12/tests/src/lib/IPAddress.h
diff --git a/lib/PubSubClient-EspEasy-2.7.12/tests/src/lib/Print.h b/lib/PubSubClient-EspEasy-2.7.12/tests/src/lib/Print.h
new file mode 100644
index 000000000..02ef77c2c
--- /dev/null
+++ b/lib/PubSubClient-EspEasy-2.7.12/tests/src/lib/Print.h
@@ -0,0 +1,28 @@
+/*
+ Print.h - Base class that provides print() and println()
+ Copyright (c) 2008 David A. Mellis. All right reserved.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef Print_h
+#define Print_h
+
+class Print {
+ public:
+ virtual size_t write(uint8_t) = 0;
+};
+
+#endif
diff --git a/lib/PubSubClient-EspEasy-2.6.09/tests/src/lib/ShimClient.cpp b/lib/PubSubClient-EspEasy-2.7.12/tests/src/lib/ShimClient.cpp
similarity index 100%
rename from lib/PubSubClient-EspEasy-2.6.09/tests/src/lib/ShimClient.cpp
rename to lib/PubSubClient-EspEasy-2.7.12/tests/src/lib/ShimClient.cpp
diff --git a/lib/PubSubClient-EspEasy-2.6.09/tests/src/lib/ShimClient.h b/lib/PubSubClient-EspEasy-2.7.12/tests/src/lib/ShimClient.h
similarity index 100%
rename from lib/PubSubClient-EspEasy-2.6.09/tests/src/lib/ShimClient.h
rename to lib/PubSubClient-EspEasy-2.7.12/tests/src/lib/ShimClient.h
diff --git a/lib/PubSubClient-EspEasy-2.6.09/tests/src/lib/Stream.cpp b/lib/PubSubClient-EspEasy-2.7.12/tests/src/lib/Stream.cpp
similarity index 100%
rename from lib/PubSubClient-EspEasy-2.6.09/tests/src/lib/Stream.cpp
rename to lib/PubSubClient-EspEasy-2.7.12/tests/src/lib/Stream.cpp
diff --git a/lib/PubSubClient-EspEasy-2.6.09/tests/src/lib/Stream.h b/lib/PubSubClient-EspEasy-2.7.12/tests/src/lib/Stream.h
similarity index 100%
rename from lib/PubSubClient-EspEasy-2.6.09/tests/src/lib/Stream.h
rename to lib/PubSubClient-EspEasy-2.7.12/tests/src/lib/Stream.h
diff --git a/lib/PubSubClient-EspEasy-2.6.09/tests/src/lib/trace.h b/lib/PubSubClient-EspEasy-2.7.12/tests/src/lib/trace.h
similarity index 100%
rename from lib/PubSubClient-EspEasy-2.6.09/tests/src/lib/trace.h
rename to lib/PubSubClient-EspEasy-2.7.12/tests/src/lib/trace.h
diff --git a/lib/PubSubClient-EspEasy-2.6.09/tests/src/publish_spec.cpp b/lib/PubSubClient-EspEasy-2.7.12/tests/src/publish_spec.cpp
similarity index 100%
rename from lib/PubSubClient-EspEasy-2.6.09/tests/src/publish_spec.cpp
rename to lib/PubSubClient-EspEasy-2.7.12/tests/src/publish_spec.cpp
diff --git a/lib/PubSubClient-EspEasy-2.6.09/tests/src/receive_spec.cpp b/lib/PubSubClient-EspEasy-2.7.12/tests/src/receive_spec.cpp
similarity index 89%
rename from lib/PubSubClient-EspEasy-2.6.09/tests/src/receive_spec.cpp
rename to lib/PubSubClient-EspEasy-2.7.12/tests/src/receive_spec.cpp
index 54a62ee5c..9a18af042 100644
--- a/lib/PubSubClient-EspEasy-2.6.09/tests/src/receive_spec.cpp
+++ b/lib/PubSubClient-EspEasy-2.7.12/tests/src/receive_spec.cpp
@@ -160,6 +160,35 @@ int test_receive_oversized_message() {
END_IT
}
+int test_drop_invalid_remaining_length_message() {
+ IT("drops invalid remaining length message");
+ reset_callback();
+
+ ShimClient shimClient;
+ shimClient.setAllowConnect(true);
+
+ byte connack[] = { 0x20, 0x02, 0x00, 0x00 };
+ shimClient.respond(connack,4);
+
+ PubSubClient client(server, 1883, callback, shimClient);
+ int rc = client.connect((char*)"client_test1");
+ IS_TRUE(rc);
+
+ byte publish[] = {0x30,0x92,0x92,0x92,0x92,0x01,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x70,0x61,0x79,0x6c,0x6f,0x61,0x64};
+ shimClient.respond(publish,20);
+
+ rc = client.loop();
+
+ IS_FALSE(rc);
+
+ IS_FALSE(callback_called);
+
+ IS_FALSE(shimClient.error());
+
+ END_IT
+}
+
+
int test_receive_oversized_stream_message() {
IT("drops an oversized message");
reset_callback();
@@ -241,6 +270,7 @@ int main()
test_receive_callback();
test_receive_stream();
test_receive_max_sized_message();
+ test_drop_invalid_remaining_length_message();
test_receive_oversized_message();
test_receive_oversized_stream_message();
test_receive_qos1();
diff --git a/lib/PubSubClient-EspEasy-2.6.09/tests/src/subscribe_spec.cpp b/lib/PubSubClient-EspEasy-2.7.12/tests/src/subscribe_spec.cpp
similarity index 100%
rename from lib/PubSubClient-EspEasy-2.6.09/tests/src/subscribe_spec.cpp
rename to lib/PubSubClient-EspEasy-2.7.12/tests/src/subscribe_spec.cpp
diff --git a/lib/PubSubClient-EspEasy-2.6.09/tests/testcases/__init__.py b/lib/PubSubClient-EspEasy-2.7.12/tests/testcases/__init__.py
similarity index 100%
rename from lib/PubSubClient-EspEasy-2.6.09/tests/testcases/__init__.py
rename to lib/PubSubClient-EspEasy-2.7.12/tests/testcases/__init__.py
diff --git a/lib/PubSubClient-EspEasy-2.7.12/tests/testcases/mqtt_basic.py b/lib/PubSubClient-EspEasy-2.7.12/tests/testcases/mqtt_basic.py
new file mode 100644
index 000000000..f23ef71c1
--- /dev/null
+++ b/lib/PubSubClient-EspEasy-2.7.12/tests/testcases/mqtt_basic.py
@@ -0,0 +1,39 @@
+import unittest
+import settings
+import time
+import mosquitto
+
+
+def on_message(mosq, obj, msg):
+ obj.message_queue.append(msg)
+
+
+class mqtt_basic(unittest.TestCase):
+
+ message_queue = []
+
+ @classmethod
+ def setUpClass(self):
+ self.client = mosquitto.Mosquitto("pubsubclient_ut", clean_session=True, obj=self)
+ self.client.connect(settings.server_ip)
+ self.client.on_message = on_message
+ self.client.subscribe("outTopic", 0)
+
+ @classmethod
+ def tearDownClass(self):
+ self.client.disconnect()
+
+ def test_one(self):
+ i = 30
+ while len(self.message_queue) == 0 and i > 0:
+ self.client.loop()
+ time.sleep(0.5)
+ i -= 1
+ self.assertTrue(i > 0, "message receive timed-out")
+ self.assertEqual(len(self.message_queue), 1, "unexpected number of messages received")
+ msg = self.message_queue[0]
+ self.assertEqual(msg.mid, 0, "message id not 0")
+ self.assertEqual(msg.topic, "outTopic", "message topic incorrect")
+ self.assertEqual(msg.payload, "hello world")
+ self.assertEqual(msg.qos, 0, "message qos not 0")
+ self.assertEqual(msg.retain, False, "message retain flag incorrect")
diff --git a/lib/PubSubClient-EspEasy-2.7.12/tests/testcases/mqtt_publish_in_callback.py b/lib/PubSubClient-EspEasy-2.7.12/tests/testcases/mqtt_publish_in_callback.py
new file mode 100644
index 000000000..45b0a8515
--- /dev/null
+++ b/lib/PubSubClient-EspEasy-2.7.12/tests/testcases/mqtt_publish_in_callback.py
@@ -0,0 +1,59 @@
+import unittest
+import settings
+import time
+import mosquitto
+
+
+def on_message(mosq, obj, msg):
+ obj.message_queue.append(msg)
+
+
+class mqtt_publish_in_callback(unittest.TestCase):
+
+ message_queue = []
+
+ @classmethod
+ def setUpClass(self):
+ self.client = mosquitto.Mosquitto("pubsubclient_ut", clean_session=True, obj=self)
+ self.client.connect(settings.server_ip)
+ self.client.on_message = on_message
+ self.client.subscribe("outTopic", 0)
+
+ @classmethod
+ def tearDownClass(self):
+ self.client.disconnect()
+
+ def test_connect(self):
+ i = 30
+ while len(self.message_queue) == 0 and i > 0:
+ self.client.loop()
+ time.sleep(0.5)
+ i -= 1
+ self.assertTrue(i > 0, "message receive timed-out")
+ self.assertEqual(len(self.message_queue), 1, "unexpected number of messages received")
+ msg = self.message_queue.pop(0)
+ self.assertEqual(msg.mid, 0, "message id not 0")
+ self.assertEqual(msg.topic, "outTopic", "message topic incorrect")
+ self.assertEqual(msg.payload, "hello world")
+ self.assertEqual(msg.qos, 0, "message qos not 0")
+ self.assertEqual(msg.retain, False, "message retain flag incorrect")
+
+ def test_publish(self):
+ self.assertEqual(len(self.message_queue), 0, "message queue not empty")
+ payload = "abcdefghij"
+ self.client.publish("inTopic", payload)
+
+ i = 30
+ while len(self.message_queue) == 0 and i > 0:
+ self.client.loop()
+ time.sleep(0.5)
+ i -= 1
+
+ self.assertTrue(i > 0, "message receive timed-out")
+ self.assertEqual(len(self.message_queue), 1, "unexpected number of messages received")
+ msg = self.message_queue.pop(0)
+ self.assertEqual(msg.mid, 0, "message id not 0")
+ self.assertEqual(msg.topic, "outTopic", "message topic incorrect")
+ self.assertEqual(msg.payload, payload)
+ self.assertEqual(msg.qos, 0, "message qos not 0")
+ self.assertEqual(msg.retain, False, "message retain flag incorrect")
diff --git a/lib/PubSubClient-EspEasy-2.6.09/tests/testcases/settings.py b/lib/PubSubClient-EspEasy-2.7.12/tests/testcases/settings.py
similarity index 100%
rename from lib/PubSubClient-EspEasy-2.6.09/tests/testcases/settings.py
rename to lib/PubSubClient-EspEasy-2.7.12/tests/testcases/settings.py
diff --git a/lib/PubSubClient-EspEasy-2.7.12/tests/testsuite.py b/lib/PubSubClient-EspEasy-2.7.12/tests/testsuite.py
new file mode 100644
index 000000000..788fc5d97
--- /dev/null
+++ b/lib/PubSubClient-EspEasy-2.7.12/tests/testsuite.py
@@ -0,0 +1,181 @@
+#!/usr/bin/env python
+import os
+import os.path
+import sys
+import shutil
+from subprocess import call
+import importlib
+import unittest
+import re
+
+from testcases import settings
+
+
+class Workspace(object):
+
+ def __init__(self):
+ self.root_dir = os.getcwd()
+ self.build_dir = os.path.join(self.root_dir, "tmpbin")
+ self.log_dir = os.path.join(self.root_dir, "logs")
+ self.tests_dir = os.path.join(self.root_dir, "testcases")
+ self.examples_dir = os.path.join(self.root_dir, "../PubSubClient/examples")
+ self.examples = []
+ self.tests = []
+ if not os.path.isdir("../PubSubClient"):
+ raise Exception("Cannot find PubSubClient library")
+ try:
+ return __import__('ino')
+ except ImportError:
+ raise Exception("ino tool not installed")
+
+ def init(self):
+ if os.path.isdir(self.build_dir):
+ shutil.rmtree(self.build_dir)
+ os.mkdir(self.build_dir)
+ if os.path.isdir(self.log_dir):
+ shutil.rmtree(self.log_dir)
+ os.mkdir(self.log_dir)
+
+ os.chdir(self.build_dir)
+ call(["ino", "init"])
+
+ shutil.copytree("../../PubSubClient", "lib/PubSubClient")
+
+ filenames = []
+ for root, dirs, files in os.walk(self.examples_dir):
+ filenames += [os.path.join(root, f) for f in files if f.endswith(".ino")]
+ filenames.sort()
+ for e in filenames:
+ self.examples.append(Sketch(self, e))
+
+ filenames = []
+ for root, dirs, files in os.walk(self.tests_dir):
+ filenames += [os.path.join(root, f) for f in files if f.endswith(".ino")]
+ filenames.sort()
+ for e in filenames:
+ self.tests.append(Sketch(self, e))
+
+ def clean(self):
+ shutil.rmtree(self.build_dir)
+
+
+class Sketch(object):
+ def __init__(self, wksp, fn):
+ self.w = wksp
+ self.filename = fn
+ self.basename = os.path.basename(self.filename)
+ self.build_log = os.path.join(self.w.log_dir, "%s.log" % (os.path.basename(self.filename),))
+ self.build_err_log = os.path.join(self.w.log_dir, "%s.err.log" % (os.path.basename(self.filename),))
+ self.build_upload_log = os.path.join(self.w.log_dir, "%s.upload.log" % (os.path.basename(self.filename),))
+
+ def build(self):
+ sys.stdout.write(" Build: ")
+ sys.stdout.flush()
+
+ # Copy sketch over, replacing IP addresses as necessary
+ fin = open(self.filename, "r")
+ lines = fin.readlines()
+ fin.close()
+ fout = open(os.path.join(self.w.build_dir, "src", "sketch.ino"), "w")
+ for l in lines:
+ if re.match(r"^byte server\[\] = {", l):
+ fout.write("byte server[] = { %s };\n" % (settings.server_ip.replace(".", ", "),))
+ elif re.match(r"^byte ip\[\] = {", l):
+ fout.write("byte ip[] = { %s };\n" % (settings.arduino_ip.replace(".", ", "),))
+ else:
+ fout.write(l)
+ fout.flush()
+ fout.close()
+
+ # Run build
+ fout = open(self.build_log, "w")
+ ferr = open(self.build_err_log, "w")
+ rc = call(["ino", "build"], stdout=fout, stderr=ferr)
+ fout.close()
+ ferr.close()
+ if rc == 0:
+ sys.stdout.write("pass")
+ sys.stdout.write("\n")
+ return True
+ else:
+ sys.stdout.write("fail")
+ sys.stdout.write("\n")
+ with open(self.build_err_log) as f:
+ for line in f:
+ print(" " + line)
+ return False
+
+ def upload(self):
+ sys.stdout.write(" Upload: ")
+ sys.stdout.flush()
+ fout = open(self.build_upload_log, "w")
+ rc = call(["ino", "upload"], stdout=fout, stderr=fout)
+ fout.close()
+ if rc == 0:
+ sys.stdout.write("pass")
+ sys.stdout.write("\n")
+ return True
+ else:
+ sys.stdout.write("fail")
+ sys.stdout.write("\n")
+ with open(self.build_upload_log) as f:
+ for line in f:
+ print(" " + line)
+ return False
+
+ def test(self):
+ # import the matching test case, if it exists
+ try:
+ basename = os.path.basename(self.filename)[:-4]
+ i = importlib.import_module("testcases." + basename)
+ except:
+ sys.stdout.write(" Test: no tests found")
+ sys.stdout.write("\n")
+ return
+ c = getattr(i, basename)
+
+ testmethods = [m for m in dir(c) if m.startswith("test_")]
+ testmethods.sort()
+ tests = []
+ for m in testmethods:
+ tests.append(c(m))
+
+ result = unittest.TestResult()
+ c.setUpClass()
+ if self.upload():
+ sys.stdout.write(" Test: ")
+ sys.stdout.flush()
+ for t in tests:
+ t.run(result)
+ print(str(result.testsRun - len(result.failures) - len(result.errors)) + "/" + str(result.testsRun))
+ if not result.wasSuccessful():
+ if len(result.failures) > 0:
+ for f in result.failures:
+ print("-- " + str(f[0]))
+ print(f[1])
+ if len(result.errors) > 0:
+ print(" Errors:")
+ for f in result.errors:
+ print("-- " + str(f[0]))
+ print(f[1])
+ c.tearDownClass()
+
+
+if __name__ == '__main__':
+ run_tests = True
+
+ w = Workspace()
+ w.init()
+
+ for e in w.examples:
+ print("--------------------------------------")
+ print("[" + e.basename + "]")
+ if e.build() and run_tests:
+ e.test()
+ for e in w.tests:
+ print("--------------------------------------")
+ print("[" + e.basename + "]")
+ if e.build() and run_tests:
+ e.test()
+
+ w.clean()
diff --git a/lib/TasmotaSerial-2.3.0/README.md b/lib/TasmotaSerial-2.3.1/README.md
similarity index 100%
rename from lib/TasmotaSerial-2.3.0/README.md
rename to lib/TasmotaSerial-2.3.1/README.md
diff --git a/lib/TasmotaSerial-2.3.0/examples/swsertest/swsertest.ino b/lib/TasmotaSerial-2.3.1/examples/swsertest/swsertest.ino
similarity index 100%
rename from lib/TasmotaSerial-2.3.0/examples/swsertest/swsertest.ino
rename to lib/TasmotaSerial-2.3.1/examples/swsertest/swsertest.ino
diff --git a/lib/TasmotaSerial-2.3.0/keywords.txt b/lib/TasmotaSerial-2.3.1/keywords.txt
similarity index 100%
rename from lib/TasmotaSerial-2.3.0/keywords.txt
rename to lib/TasmotaSerial-2.3.1/keywords.txt
diff --git a/lib/TasmotaSerial-2.3.0/library.json b/lib/TasmotaSerial-2.3.1/library.json
similarity index 100%
rename from lib/TasmotaSerial-2.3.0/library.json
rename to lib/TasmotaSerial-2.3.1/library.json
diff --git a/lib/TasmotaSerial-2.3.0/library.properties b/lib/TasmotaSerial-2.3.1/library.properties
similarity index 100%
rename from lib/TasmotaSerial-2.3.0/library.properties
rename to lib/TasmotaSerial-2.3.1/library.properties
diff --git a/lib/TasmotaSerial-2.3.0/src/TasmotaSerial.cpp b/lib/TasmotaSerial-2.3.1/src/TasmotaSerial.cpp
similarity index 97%
rename from lib/TasmotaSerial-2.3.0/src/TasmotaSerial.cpp
rename to lib/TasmotaSerial-2.3.1/src/TasmotaSerial.cpp
index eecdeb124..d99137edc 100644
--- a/lib/TasmotaSerial-2.3.0/src/TasmotaSerial.cpp
+++ b/lib/TasmotaSerial-2.3.1/src/TasmotaSerial.cpp
@@ -100,7 +100,7 @@ TasmotaSerial::TasmotaSerial(int receive_pin, int transmit_pin, int hardware_fal
m_buffer = (uint8_t*)malloc(TM_SERIAL_BUFFER_SIZE);
if (m_buffer == NULL) return;
// Use getCycleCount() loop to get as exact timing as possible
- m_bit_time = F_CPU / TM_SERIAL_BAUDRATE;
+ m_bit_time = ESP.getCpuFreqMHz() * 1000000 / TM_SERIAL_BAUDRATE;
pinMode(m_rx_pin, INPUT);
tms_obj_list[m_rx_pin] = this;
attachInterrupt(m_rx_pin, ISRList[m_rx_pin], FALLING);
@@ -145,8 +145,8 @@ bool TasmotaSerial::begin(long speed, int stop_bits) {
}
} else {
// Use getCycleCount() loop to get as exact timing as possible
- m_bit_time = F_CPU / speed;
- m_high_speed = (speed > 9600);
+ m_bit_time = ESP.getCpuFreqMHz() * 1000000 / speed;
+ m_high_speed = (speed >= 9600);
}
return m_valid;
}
diff --git a/lib/TasmotaSerial-2.3.0/src/TasmotaSerial.h b/lib/TasmotaSerial-2.3.1/src/TasmotaSerial.h
similarity index 100%
rename from lib/TasmotaSerial-2.3.0/src/TasmotaSerial.h
rename to lib/TasmotaSerial-2.3.1/src/TasmotaSerial.h
diff --git a/lib/bearssl-esp8266/bearssl_esp8266-customized.txt b/lib/bearssl-esp8266/bearssl_esp8266-customized.txt
new file mode 100644
index 000000000..265204558
--- /dev/null
+++ b/lib/bearssl-esp8266/bearssl_esp8266-customized.txt
@@ -0,0 +1,13 @@
+This library is adapted from bearssl-esp8266 to avoid conflict with the
+BearSSL headers in Arduino Core.
+
+To recreate, copy all original 'src/' and 'inc/' into 'src/' lib.
+
+Then rename the following:
+ - "bearssl with "t_bearssl
+ - "inner with "t_inner
+ - "config with "t_config
+
+Add the customized files in src/:
+ - t_bearssl_tasmota_config.h
+ - pgmspace_bearssl.h
diff --git a/lib/bearssl-esp8266/conf/esp8266.mk b/lib/bearssl-esp8266/conf/esp8266.mk
new file mode 100644
index 000000000..5c409b8be
--- /dev/null
+++ b/lib/bearssl-esp8266/conf/esp8266.mk
@@ -0,0 +1,21 @@
+# Configuration for compiling to an ESP8266 from a UNIX system
+
+# We are on a Unix system so we assume a Single Unix compatible 'make'
+# utility, and Unix defaults.
+include conf/Unix.mk
+
+# We override the build directory.
+BUILD = esp8266
+
+# C compiler, linker, and static library builder.
+TOOLCHAIN_PREFIX := xtensa-lx106-elf-
+CC := $(TOOLCHAIN_PREFIX)gcc
+CFLAGS = -W -Wall -g -O2 -Wpointer-arith -Wl,-EL -nostdlib -mlongcalls -mno-text-section-literals -ffunction-sections -fdata-sections -Werror
+CFLAGS += -D__ets__ -DICACHE_FLASH -DESP8266 -DBR_SLOW_MUL15=1
+LD := $(TOOLCHAIN_PREFIX)ld
+AR := $(TOOLCHAIN_PREFIX)ar
+
+# We compile only the static library.
+DLL = no
+TOOLS = no
+TESTS = no
diff --git a/lib/bearssl-esp8266/library.properties b/lib/bearssl-esp8266/library.properties
new file mode 100644
index 000000000..1d936cb88
--- /dev/null
+++ b/lib/bearssl-esp8266/library.properties
@@ -0,0 +1,9 @@
+name=BearSSL
+version=0.6
+author=Thomas Pornin
+maintainer=Earle F. Philhower, III
+sentence=BearSSL implementation of the SSL/TLS protocol optimized for ESP8266 by Earle F. Philhower, optimized for Tamota by Stephan Hadinger
+paragraph=
+category=Other
+url=https://github.com/earlephilhower/bearssl-esp8266.git
+architectures=esp8266
diff --git a/lib/bearssl-esp8266/src/aead/ccm.c b/lib/bearssl-esp8266/src/aead/ccm.c
new file mode 100644
index 000000000..427d1becc
--- /dev/null
+++ b/lib/bearssl-esp8266/src/aead/ccm.c
@@ -0,0 +1,346 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "t_inner.h"
+
+/*
+ * Implementation Notes
+ * ====================
+ *
+ * The combined CTR + CBC-MAC functions can only handle full blocks,
+ * so some buffering is necessary.
+ *
+ * - 'ptr' contains a value from 0 to 15, which is the number of bytes
+ * accumulated in buf[] that still needs to be processed with the
+ * current CBC-MAC computation.
+ *
+ * - When processing the message itself, CTR encryption/decryption is
+ * also done at the same time. The first 'ptr' bytes of buf[] then
+ * contains the plaintext bytes, while the last '16 - ptr' bytes of
+ * buf[] are the remnants of the stream block, to be used against
+ * the next input bytes, when available. When 'ptr' is 0, the
+ * contents of buf[] are to be ignored.
+ *
+ * - The current counter and running CBC-MAC values are kept in 'ctr'
+ * and 'cbcmac', respectively.
+ */
+
+/* see bearssl_block.h */
+void
+br_ccm_init(br_ccm_context *ctx, const br_block_ctrcbc_class **bctx)
+{
+ ctx->bctx = bctx;
+}
+
+/* see bearssl_block.h */
+int
+br_ccm_reset(br_ccm_context *ctx, const void *nonce, size_t nonce_len,
+ uint64_t aad_len, uint64_t data_len, size_t tag_len)
+{
+ unsigned char tmp[16];
+ unsigned u, q;
+
+ if (nonce_len < 7 || nonce_len > 13) {
+ return 0;
+ }
+ if (tag_len < 4 || tag_len > 16 || (tag_len & 1) != 0) {
+ return 0;
+ }
+ q = 15 - (unsigned)nonce_len;
+ ctx->tag_len = tag_len;
+
+ /*
+ * Block B0, to start CBC-MAC.
+ */
+ tmp[0] = (aad_len > 0 ? 0x40 : 0x00)
+ | (((unsigned)tag_len - 2) << 2)
+ | (q - 1);
+ memcpy(tmp + 1, nonce, nonce_len);
+ for (u = 0; u < q; u ++) {
+ tmp[15 - u] = (unsigned char)data_len;
+ data_len >>= 8;
+ }
+ if (data_len != 0) {
+ /*
+ * If the data length was not entirely consumed in the
+ * loop above, then it exceeds the maximum limit of
+ * q bytes (when encoded).
+ */
+ return 0;
+ }
+
+ /*
+ * Start CBC-MAC.
+ */
+ memset(ctx->cbcmac, 0, sizeof ctx->cbcmac);
+ (*ctx->bctx)->mac(ctx->bctx, ctx->cbcmac, tmp, sizeof tmp);
+
+ /*
+ * Assemble AAD length header.
+ */
+ if ((aad_len >> 32) != 0) {
+ ctx->buf[0] = 0xFF;
+ ctx->buf[1] = 0xFF;
+ br_enc64be(ctx->buf + 2, aad_len);
+ ctx->ptr = 10;
+ } else if (aad_len >= 0xFF00) {
+ ctx->buf[0] = 0xFF;
+ ctx->buf[1] = 0xFE;
+ br_enc32be(ctx->buf + 2, (uint32_t)aad_len);
+ ctx->ptr = 6;
+ } else if (aad_len > 0) {
+ br_enc16be(ctx->buf, (unsigned)aad_len);
+ ctx->ptr = 2;
+ } else {
+ ctx->ptr = 0;
+ }
+
+ /*
+ * Make initial counter value and compute tag mask.
+ */
+ ctx->ctr[0] = q - 1;
+ memcpy(ctx->ctr + 1, nonce, nonce_len);
+ memset(ctx->ctr + 1 + nonce_len, 0, q);
+ memset(ctx->tagmask, 0, sizeof ctx->tagmask);
+ (*ctx->bctx)->ctr(ctx->bctx, ctx->ctr,
+ ctx->tagmask, sizeof ctx->tagmask);
+
+ return 1;
+}
+
+/* see bearssl_block.h */
+void
+br_ccm_aad_inject(br_ccm_context *ctx, const void *data, size_t len)
+{
+ const unsigned char *dbuf;
+ size_t ptr;
+
+ dbuf = data;
+
+ /*
+ * Complete partial block, if needed.
+ */
+ ptr = ctx->ptr;
+ if (ptr != 0) {
+ size_t clen;
+
+ clen = (sizeof ctx->buf) - ptr;
+ if (clen > len) {
+ memcpy(ctx->buf + ptr, dbuf, len);
+ ctx->ptr = ptr + len;
+ return;
+ }
+ memcpy(ctx->buf + ptr, dbuf, clen);
+ dbuf += clen;
+ len -= clen;
+ (*ctx->bctx)->mac(ctx->bctx, ctx->cbcmac,
+ ctx->buf, sizeof ctx->buf);
+ }
+
+ /*
+ * Process complete blocks.
+ */
+ ptr = len & 15;
+ len -= ptr;
+ (*ctx->bctx)->mac(ctx->bctx, ctx->cbcmac, dbuf, len);
+ dbuf += len;
+
+ /*
+ * Copy last partial block in the context buffer.
+ */
+ memcpy(ctx->buf, dbuf, ptr);
+ ctx->ptr = ptr;
+}
+
+/* see bearssl_block.h */
+void
+br_ccm_flip(br_ccm_context *ctx)
+{
+ size_t ptr;
+
+ /*
+ * Complete AAD partial block with zeros, if necessary.
+ */
+ ptr = ctx->ptr;
+ if (ptr != 0) {
+ memset(ctx->buf + ptr, 0, (sizeof ctx->buf) - ptr);
+ (*ctx->bctx)->mac(ctx->bctx, ctx->cbcmac,
+ ctx->buf, sizeof ctx->buf);
+ ctx->ptr = 0;
+ }
+
+ /*
+ * Counter was already set by br_ccm_reset().
+ */
+}
+
+/* see bearssl_block.h */
+void
+br_ccm_run(br_ccm_context *ctx, int encrypt, void *data, size_t len)
+{
+ unsigned char *dbuf;
+ size_t ptr;
+
+ dbuf = data;
+
+ /*
+ * Complete a partial block, if any: ctx->buf[] contains
+ * ctx->ptr plaintext bytes (already reported), and the other
+ * bytes are CTR stream output.
+ */
+ ptr = ctx->ptr;
+ if (ptr != 0) {
+ size_t clen;
+ size_t u;
+
+ clen = (sizeof ctx->buf) - ptr;
+ if (clen > len) {
+ clen = len;
+ }
+ if (encrypt) {
+ for (u = 0; u < clen; u ++) {
+ unsigned w, x;
+
+ w = ctx->buf[ptr + u];
+ x = dbuf[u];
+ ctx->buf[ptr + u] = x;
+ dbuf[u] = w ^ x;
+ }
+ } else {
+ for (u = 0; u < clen; u ++) {
+ unsigned w;
+
+ w = ctx->buf[ptr + u] ^ dbuf[u];
+ dbuf[u] = w;
+ ctx->buf[ptr + u] = w;
+ }
+ }
+ dbuf += clen;
+ len -= clen;
+ ptr += clen;
+ if (ptr < sizeof ctx->buf) {
+ ctx->ptr = ptr;
+ return;
+ }
+ (*ctx->bctx)->mac(ctx->bctx,
+ ctx->cbcmac, ctx->buf, sizeof ctx->buf);
+ }
+
+ /*
+ * Process all complete blocks. Note that the ctrcbc API is for
+ * encrypt-then-MAC (CBC-MAC is computed over the encrypted
+ * blocks) while CCM uses MAC-and-encrypt (CBC-MAC is computed
+ * over the plaintext blocks). Therefore, we need to use the
+ * _decryption_ function for encryption, and the encryption
+ * function for decryption (this works because CTR encryption
+ * and decryption are identical, so the choice really is about
+ * computing the CBC-MAC before or after XORing with the CTR
+ * stream).
+ */
+ ptr = len & 15;
+ len -= ptr;
+ if (encrypt) {
+ (*ctx->bctx)->decrypt(ctx->bctx, ctx->ctr, ctx->cbcmac,
+ dbuf, len);
+ } else {
+ (*ctx->bctx)->encrypt(ctx->bctx, ctx->ctr, ctx->cbcmac,
+ dbuf, len);
+ }
+ dbuf += len;
+
+ /*
+ * If there is some remaining data, then we need to compute an
+ * extra block of CTR stream.
+ */
+ if (ptr != 0) {
+ size_t u;
+
+ memset(ctx->buf, 0, sizeof ctx->buf);
+ (*ctx->bctx)->ctr(ctx->bctx, ctx->ctr,
+ ctx->buf, sizeof ctx->buf);
+ if (encrypt) {
+ for (u = 0; u < ptr; u ++) {
+ unsigned w, x;
+
+ w = ctx->buf[u];
+ x = dbuf[u];
+ ctx->buf[u] = x;
+ dbuf[u] = w ^ x;
+ }
+ } else {
+ for (u = 0; u < ptr; u ++) {
+ unsigned w;
+
+ w = ctx->buf[u] ^ dbuf[u];
+ dbuf[u] = w;
+ ctx->buf[u] = w;
+ }
+ }
+ }
+ ctx->ptr = ptr;
+}
+
+/* see bearssl_block.h */
+size_t
+br_ccm_get_tag(br_ccm_context *ctx, void *tag)
+{
+ size_t ptr;
+ size_t u;
+
+ /*
+ * If there is some buffered data, then we need to pad it with
+ * zeros and finish up CBC-MAC.
+ */
+ ptr = ctx->ptr;
+ if (ptr != 0) {
+ memset(ctx->buf + ptr, 0, (sizeof ctx->buf) - ptr);
+ (*ctx->bctx)->mac(ctx->bctx, ctx->cbcmac,
+ ctx->buf, sizeof ctx->buf);
+ }
+
+ /*
+ * XOR the tag mask into the CBC-MAC output.
+ */
+ for (u = 0; u < ctx->tag_len; u ++) {
+ ctx->cbcmac[u] ^= ctx->tagmask[u];
+ }
+ memcpy(tag, ctx->cbcmac, ctx->tag_len);
+ return ctx->tag_len;
+}
+
+/* see bearssl_block.h */
+uint32_t
+br_ccm_check_tag(br_ccm_context *ctx, const void *tag)
+{
+ unsigned char tmp[16];
+ size_t u, tag_len;
+ uint32_t z;
+
+ tag_len = br_ccm_get_tag(ctx, tmp);
+ z = 0;
+ for (u = 0; u < tag_len; u ++) {
+ z |= tmp[u] ^ ((const unsigned char *)tag)[u];
+ }
+ return EQ0(z);
+}
diff --git a/lib/bearssl-esp8266/src/aead/eax.c b/lib/bearssl-esp8266/src/aead/eax.c
new file mode 100644
index 000000000..9e0b3230b
--- /dev/null
+++ b/lib/bearssl-esp8266/src/aead/eax.c
@@ -0,0 +1,525 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "t_inner.h"
+
+/*
+ * Implementation Notes
+ * ====================
+ *
+ * The combined CTR + CBC-MAC functions can only handle full blocks,
+ * so some buffering is necessary. Moreover, EAX has a special padding
+ * rule for CBC-MAC, which implies that we cannot compute the MAC over
+ * the last received full block until we know whether we are at the
+ * end of the data or not.
+ *
+ * - 'ptr' contains a value from 1 to 16, which is the number of bytes
+ * accumulated in buf[] that still needs to be processed with the
+ * current OMAC computation. Beware that this can go to 16: a
+ * complete block cannot be processed until it is known whether it
+ * is the last block or not. However, it can never be 0, because
+ * OMAC^t works on an input that is at least one-block long.
+ *
+ * - When processing the message itself, CTR encryption/decryption is
+ * also done at the same time. The first 'ptr' bytes of buf[] then
+ * contains the encrypted bytes, while the last '16 - ptr' bytes of
+ * buf[] are the remnants of the stream block, to be used against
+ * the next input bytes, when available.
+ *
+ * - The current counter and running CBC-MAC values are kept in 'ctr'
+ * and 'cbcmac', respectively.
+ *
+ * - The derived keys for padding are kept in L2 and L4 (double and
+ * quadruple of Enc_K(0^n), in GF(2^128), respectively).
+ */
+
+/*
+ * Start an OMAC computation; the first block is the big-endian
+ * representation of the provided value ('val' must fit on one byte).
+ * We make it a delayed block because it may also be the last one,
+ */
+static void
+omac_start(br_eax_context *ctx, unsigned val)
+{
+ memset(ctx->cbcmac, 0, sizeof ctx->cbcmac);
+ memset(ctx->buf, 0, sizeof ctx->buf);
+ ctx->buf[15] = val;
+ ctx->ptr = 16;
+}
+
+/*
+ * Double a value in finite field GF(2^128), defined with modulus
+ * X^128+X^7+X^2+X+1.
+ */
+static void
+double_gf128(unsigned char *dst, const unsigned char *src)
+{
+ unsigned cc;
+ int i;
+
+ cc = 0x87 & -((unsigned)src[0] >> 7);
+ for (i = 15; i >= 0; i --) {
+ unsigned z;
+
+ z = (src[i] << 1) ^ cc;
+ cc = z >> 8;
+ dst[i] = (unsigned char)z;
+ }
+}
+
+/*
+ * Apply padding to the last block, currently in ctx->buf (with
+ * ctx->ptr bytes), and finalize OMAC computation.
+ */
+static void
+do_pad(br_eax_context *ctx)
+{
+ unsigned char *pad;
+ size_t ptr, u;
+
+ ptr = ctx->ptr;
+ if (ptr == 16) {
+ pad = ctx->L2;
+ } else {
+ ctx->buf[ptr ++] = 0x80;
+ memset(ctx->buf + ptr, 0x00, 16 - ptr);
+ pad = ctx->L4;
+ }
+ for (u = 0; u < sizeof ctx->buf; u ++) {
+ ctx->buf[u] ^= pad[u];
+ }
+ (*ctx->bctx)->mac(ctx->bctx, ctx->cbcmac, ctx->buf, sizeof ctx->buf);
+}
+
+/*
+ * Apply CBC-MAC on the provided data, with buffering management.
+ *
+ * Upon entry, two situations are acceptable:
+ *
+ * ctx->ptr == 0: there is no data to process in ctx->buf
+ * ctx->ptr == 16: there is a full block of unprocessed data in ctx->buf
+ *
+ * Upon exit, ctx->ptr may be zero only if it was already zero on entry,
+ * and len == 0. In all other situations, ctx->ptr will be non-zero on
+ * exit (and may have value 16).
+ */
+static void
+do_cbcmac_chunk(br_eax_context *ctx, const void *data, size_t len)
+{
+ size_t ptr;
+
+ if (len == 0) {
+ return;
+ }
+ ptr = len & (size_t)15;
+ if (ptr == 0) {
+ len -= 16;
+ ptr = 16;
+ } else {
+ len -= ptr;
+ }
+ if (ctx->ptr == 16) {
+ (*ctx->bctx)->mac(ctx->bctx, ctx->cbcmac,
+ ctx->buf, sizeof ctx->buf);
+ }
+ (*ctx->bctx)->mac(ctx->bctx, ctx->cbcmac, data, len);
+ memcpy(ctx->buf, (const unsigned char *)data + len, ptr);
+ ctx->ptr = ptr;
+}
+
+/* see bearssl_aead.h */
+void
+br_eax_init(br_eax_context *ctx, const br_block_ctrcbc_class **bctx)
+{
+ unsigned char tmp[16], iv[16];
+
+ ctx->vtable = &br_eax_vtable;
+ ctx->bctx = bctx;
+
+ /*
+ * Encrypt a whole-zero block to compute L2 and L4.
+ */
+ memset(tmp, 0, sizeof tmp);
+ memset(iv, 0, sizeof iv);
+ (*bctx)->ctr(bctx, iv, tmp, sizeof tmp);
+ double_gf128(ctx->L2, tmp);
+ double_gf128(ctx->L4, ctx->L2);
+}
+
+/* see bearssl_aead.h */
+void
+br_eax_capture(const br_eax_context *ctx, br_eax_state *st)
+{
+ /*
+ * We capture the three OMAC* states _after_ processing the
+ * initial block (assuming that nonce, message and AAD are
+ * all non-empty).
+ */
+ int i;
+
+ memset(st->st, 0, sizeof st->st);
+ for (i = 0; i < 3; i ++) {
+ unsigned char tmp[16];
+
+ memset(tmp, 0, sizeof tmp);
+ tmp[15] = (unsigned char)i;
+ (*ctx->bctx)->mac(ctx->bctx, st->st[i], tmp, sizeof tmp);
+ }
+}
+
+/* see bearssl_aead.h */
+void
+br_eax_reset(br_eax_context *ctx, const void *nonce, size_t len)
+{
+ /*
+ * Process nonce with OMAC^0.
+ */
+ omac_start(ctx, 0);
+ do_cbcmac_chunk(ctx, nonce, len);
+ do_pad(ctx);
+ memcpy(ctx->nonce, ctx->cbcmac, sizeof ctx->cbcmac);
+
+ /*
+ * Start OMAC^1 for the AAD ("header" in the EAX specification).
+ */
+ omac_start(ctx, 1);
+
+ /*
+ * We use ctx->head[0] as temporary flag to mark that we are
+ * using a "normal" reset().
+ */
+ ctx->head[0] = 0;
+}
+
+/* see bearssl_aead.h */
+void
+br_eax_reset_pre_aad(br_eax_context *ctx, const br_eax_state *st,
+ const void *nonce, size_t len)
+{
+ if (len == 0) {
+ omac_start(ctx, 0);
+ } else {
+ memcpy(ctx->cbcmac, st->st[0], sizeof ctx->cbcmac);
+ ctx->ptr = 0;
+ do_cbcmac_chunk(ctx, nonce, len);
+ }
+ do_pad(ctx);
+ memcpy(ctx->nonce, ctx->cbcmac, sizeof ctx->cbcmac);
+
+ memcpy(ctx->cbcmac, st->st[1], sizeof ctx->cbcmac);
+ ctx->ptr = 0;
+
+ memcpy(ctx->ctr, st->st[2], sizeof ctx->ctr);
+
+ /*
+ * We use ctx->head[0] as a flag to indicate that we use a
+ * a recorded state, with ctx->ctr containing the preprocessed
+ * first block for OMAC^2.
+ */
+ ctx->head[0] = 1;
+}
+
+/* see bearssl_aead.h */
+void
+br_eax_reset_post_aad(br_eax_context *ctx, const br_eax_state *st,
+ const void *nonce, size_t len)
+{
+ if (len == 0) {
+ omac_start(ctx, 0);
+ } else {
+ memcpy(ctx->cbcmac, st->st[0], sizeof ctx->cbcmac);
+ ctx->ptr = 0;
+ do_cbcmac_chunk(ctx, nonce, len);
+ }
+ do_pad(ctx);
+ memcpy(ctx->nonce, ctx->cbcmac, sizeof ctx->cbcmac);
+ memcpy(ctx->ctr, ctx->nonce, sizeof ctx->nonce);
+
+ memcpy(ctx->head, st->st[1], sizeof ctx->head);
+
+ memcpy(ctx->cbcmac, st->st[2], sizeof ctx->cbcmac);
+ ctx->ptr = 0;
+}
+
+/* see bearssl_aead.h */
+void
+br_eax_aad_inject(br_eax_context *ctx, const void *data, size_t len)
+{
+ size_t ptr;
+
+ ptr = ctx->ptr;
+
+ /*
+ * If there is a partial block, first complete it.
+ */
+ if (ptr < 16) {
+ size_t clen;
+
+ clen = 16 - ptr;
+ if (len <= clen) {
+ memcpy(ctx->buf + ptr, data, len);
+ ctx->ptr = ptr + len;
+ return;
+ }
+ memcpy(ctx->buf + ptr, data, clen);
+ data = (const unsigned char *)data + clen;
+ len -= clen;
+ }
+
+ /*
+ * We now have a full block in buf[], and this is not the last
+ * block.
+ */
+ do_cbcmac_chunk(ctx, data, len);
+}
+
+/* see bearssl_aead.h */
+void
+br_eax_flip(br_eax_context *ctx)
+{
+ int from_capture;
+
+ /*
+ * ctx->head[0] may be non-zero if the context was reset with
+ * a pre-AAD captured state. In that case, ctx->ctr[] contains
+ * the state for OMAC^2 _after_ processing the first block.
+ */
+ from_capture = ctx->head[0];
+
+ /*
+ * Complete the OMAC computation on the AAD.
+ */
+ do_pad(ctx);
+ memcpy(ctx->head, ctx->cbcmac, sizeof ctx->cbcmac);
+
+ /*
+ * Start OMAC^2 for the encrypted data.
+ * If the context was initialized from a captured state, then
+ * the OMAC^2 value is in the ctr[] array.
+ */
+ if (from_capture) {
+ memcpy(ctx->cbcmac, ctx->ctr, sizeof ctx->cbcmac);
+ ctx->ptr = 0;
+ } else {
+ omac_start(ctx, 2);
+ }
+
+ /*
+ * Initial counter value for CTR is the processed nonce.
+ */
+ memcpy(ctx->ctr, ctx->nonce, sizeof ctx->nonce);
+}
+
+/* see bearssl_aead.h */
+void
+br_eax_run(br_eax_context *ctx, int encrypt, void *data, size_t len)
+{
+ unsigned char *dbuf;
+ size_t ptr;
+
+ /*
+ * Ensure that there is actual data to process.
+ */
+ if (len == 0) {
+ return;
+ }
+
+ dbuf = data;
+ ptr = ctx->ptr;
+
+ /*
+ * We may have ptr == 0 here if we initialized from a captured
+ * state. In that case, there is no partially consumed block
+ * or unprocessed data.
+ */
+ if (ptr != 0 && ptr != 16) {
+ /*
+ * We have a partially consumed block.
+ */
+ size_t u, clen;
+
+ clen = 16 - ptr;
+ if (len <= clen) {
+ clen = len;
+ }
+ if (encrypt) {
+ for (u = 0; u < clen; u ++) {
+ ctx->buf[ptr + u] ^= dbuf[u];
+ }
+ memcpy(dbuf, ctx->buf + ptr, clen);
+ } else {
+ for (u = 0; u < clen; u ++) {
+ unsigned dx, sx;
+
+ sx = ctx->buf[ptr + u];
+ dx = dbuf[u];
+ ctx->buf[ptr + u] = dx;
+ dbuf[u] = sx ^ dx;
+ }
+ }
+
+ if (len <= clen) {
+ ctx->ptr = ptr + clen;
+ return;
+ }
+ dbuf += clen;
+ len -= clen;
+ }
+
+ /*
+ * We now have a complete encrypted block in buf[] that must still
+ * be processed with OMAC, and this is not the final buf.
+ * Exception: when ptr == 0, no block has been produced yet.
+ */
+ if (ptr != 0) {
+ (*ctx->bctx)->mac(ctx->bctx, ctx->cbcmac,
+ ctx->buf, sizeof ctx->buf);
+ }
+
+ /*
+ * Do CTR encryption or decryption and CBC-MAC for all full blocks
+ * except the last.
+ */
+ ptr = len & (size_t)15;
+ if (ptr == 0) {
+ len -= 16;
+ ptr = 16;
+ } else {
+ len -= ptr;
+ }
+ if (encrypt) {
+ (*ctx->bctx)->encrypt(ctx->bctx, ctx->ctr, ctx->cbcmac,
+ dbuf, len);
+ } else {
+ (*ctx->bctx)->decrypt(ctx->bctx, ctx->ctr, ctx->cbcmac,
+ dbuf, len);
+ }
+ dbuf += len;
+
+ /*
+ * Compute next block of CTR stream, and use it to finish
+ * encrypting or decrypting the data.
+ */
+ memset(ctx->buf, 0, sizeof ctx->buf);
+ (*ctx->bctx)->ctr(ctx->bctx, ctx->ctr, ctx->buf, sizeof ctx->buf);
+ if (encrypt) {
+ size_t u;
+
+ for (u = 0; u < ptr; u ++) {
+ ctx->buf[u] ^= dbuf[u];
+ }
+ memcpy(dbuf, ctx->buf, ptr);
+ } else {
+ size_t u;
+
+ for (u = 0; u < ptr; u ++) {
+ unsigned dx, sx;
+
+ sx = ctx->buf[u];
+ dx = dbuf[u];
+ ctx->buf[u] = dx;
+ dbuf[u] = sx ^ dx;
+ }
+ }
+ ctx->ptr = ptr;
+}
+
+/*
+ * Complete tag computation. The final tag is written in ctx->cbcmac.
+ */
+static void
+do_final(br_eax_context *ctx)
+{
+ size_t u;
+
+ do_pad(ctx);
+
+ /*
+ * Authentication tag is the XOR of the three OMAC outputs for
+ * the nonce, AAD and encrypted data.
+ */
+ for (u = 0; u < 16; u ++) {
+ ctx->cbcmac[u] ^= ctx->nonce[u] ^ ctx->head[u];
+ }
+}
+
+/* see bearssl_aead.h */
+void
+br_eax_get_tag(br_eax_context *ctx, void *tag)
+{
+ do_final(ctx);
+ memcpy(tag, ctx->cbcmac, sizeof ctx->cbcmac);
+}
+
+/* see bearssl_aead.h */
+void
+br_eax_get_tag_trunc(br_eax_context *ctx, void *tag, size_t len)
+{
+ do_final(ctx);
+ memcpy(tag, ctx->cbcmac, len);
+}
+
+/* see bearssl_aead.h */
+uint32_t
+br_eax_check_tag_trunc(br_eax_context *ctx, const void *tag, size_t len)
+{
+ unsigned char tmp[16];
+ size_t u;
+ int x;
+
+ br_eax_get_tag(ctx, tmp);
+ x = 0;
+ for (u = 0; u < len; u ++) {
+ x |= tmp[u] ^ ((const unsigned char *)tag)[u];
+ }
+ return EQ0(x);
+}
+
+/* see bearssl_aead.h */
+uint32_t
+br_eax_check_tag(br_eax_context *ctx, const void *tag)
+{
+ return br_eax_check_tag_trunc(ctx, tag, 16);
+}
+
+/* see bearssl_aead.h */
+const br_aead_class br_eax_vtable PROGMEM = {
+ 16,
+ (void (*)(const br_aead_class **, const void *, size_t))
+ &br_eax_reset,
+ (void (*)(const br_aead_class **, const void *, size_t))
+ &br_eax_aad_inject,
+ (void (*)(const br_aead_class **))
+ &br_eax_flip,
+ (void (*)(const br_aead_class **, int, void *, size_t))
+ &br_eax_run,
+ (void (*)(const br_aead_class **, void *))
+ &br_eax_get_tag,
+ (uint32_t (*)(const br_aead_class **, const void *))
+ &br_eax_check_tag,
+ (void (*)(const br_aead_class **, void *, size_t))
+ &br_eax_get_tag_trunc,
+ (uint32_t (*)(const br_aead_class **, const void *, size_t))
+ &br_eax_check_tag_trunc
+};
diff --git a/lib/bearssl-esp8266/src/aead/gcm.c b/lib/bearssl-esp8266/src/aead/gcm.c
new file mode 100644
index 000000000..40084ed65
--- /dev/null
+++ b/lib/bearssl-esp8266/src/aead/gcm.c
@@ -0,0 +1,318 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "t_inner.h"
+
+/*
+ * Implementation Notes
+ * ====================
+ *
+ * Since CTR and GHASH implementations can handle only full blocks, a
+ * 16-byte buffer (buf[]) is maintained in the context:
+ *
+ * - When processing AAD, buf[] contains the 0-15 unprocessed bytes.
+ *
+ * - When doing CTR encryption / decryption, buf[] contains the AES output
+ * for the last partial block, to be used with the next few bytes of
+ * data, as well as the already encrypted bytes. For instance, if the
+ * processed data length so far is 21 bytes, then buf[0..4] contains
+ * the five last encrypted bytes, and buf[5..15] contains the next 11
+ * AES output bytes to be XORed with the next 11 bytes of input.
+ *
+ * The recorded AES output bytes are used to complete the block when
+ * the corresponding bytes are obtained. Note that buf[] always
+ * contains the _encrypted_ bytes, whether we apply encryption or
+ * decryption: these bytes are used as input to GHASH when the block
+ * is complete.
+ *
+ * In both cases, the low bits of the data length counters (count_aad,
+ * count_ctr) are used to work out the current situation.
+ */
+
+/* see bearssl_aead.h */
+void
+br_gcm_init(br_gcm_context *ctx, const br_block_ctr_class **bctx, br_ghash gh)
+{
+ unsigned char iv[12];
+
+ ctx->vtable = &br_gcm_vtable;
+ ctx->bctx = bctx;
+ ctx->gh = gh;
+
+ /*
+ * The GHASH key h[] is the raw encryption of the all-zero
+ * block. Since we only have a CTR implementation, we use it
+ * with an all-zero IV and a zero counter, to CTR-encrypt an
+ * all-zero block.
+ */
+ memset(ctx->h, 0, sizeof ctx->h);
+ memset(iv, 0, sizeof iv);
+ (*bctx)->run(bctx, iv, 0, ctx->h, sizeof ctx->h);
+}
+
+/* see bearssl_aead.h */
+void
+br_gcm_reset(br_gcm_context *ctx, const void *iv, size_t len)
+{
+ /*
+ * If the provided nonce is 12 bytes, then this is the initial
+ * IV for CTR mode; it will be used with a counter that starts
+ * at 2 (value 1 is for encrypting the GHASH output into the tag).
+ *
+ * If the provided nonce has any other length, then it is hashed
+ * (with GHASH) into a 16-byte value that will be the IV for CTR
+ * (both 12-byte IV and 32-bit counter).
+ */
+ if (len == 12) {
+ memcpy(ctx->j0_1, iv, 12);
+ ctx->j0_2 = 1;
+ } else {
+ unsigned char ty[16], tmp[16];
+
+ memset(ty, 0, sizeof ty);
+ ctx->gh(ty, ctx->h, iv, len);
+ memset(tmp, 0, 8);
+ br_enc64be(tmp + 8, (uint64_t)len << 3);
+ ctx->gh(ty, ctx->h, tmp, 16);
+ memcpy(ctx->j0_1, ty, 12);
+ ctx->j0_2 = br_dec32be(ty + 12);
+ }
+ ctx->jc = ctx->j0_2 + 1;
+ memset(ctx->y, 0, sizeof ctx->y);
+ ctx->count_aad = 0;
+ ctx->count_ctr = 0;
+}
+
+/* see bearssl_aead.h */
+void
+br_gcm_aad_inject(br_gcm_context *ctx, const void *data, size_t len)
+{
+ size_t ptr, dlen;
+
+ ptr = (size_t)ctx->count_aad & (size_t)15;
+ if (ptr != 0) {
+ /*
+ * If there is a partial block, then we first try to
+ * complete it.
+ */
+ size_t clen;
+
+ clen = 16 - ptr;
+ if (len < clen) {
+ memcpy(ctx->buf + ptr, data, len);
+ ctx->count_aad += (uint64_t)len;
+ return;
+ }
+ memcpy(ctx->buf + ptr, data, clen);
+ ctx->gh(ctx->y, ctx->h, ctx->buf, 16);
+ data = (const unsigned char *)data + clen;
+ len -= clen;
+ ctx->count_aad += (uint64_t)clen;
+ }
+
+ /*
+ * Now AAD is aligned on a 16-byte block (with regards to GHASH).
+ * We process all complete blocks, and save the last partial
+ * block.
+ */
+ dlen = len & ~(size_t)15;
+ ctx->gh(ctx->y, ctx->h, data, dlen);
+ memcpy(ctx->buf, (const unsigned char *)data + dlen, len - dlen);
+ ctx->count_aad += (uint64_t)len;
+}
+
+/* see bearssl_aead.h */
+void
+br_gcm_flip(br_gcm_context *ctx)
+{
+ /*
+ * We complete the GHASH computation if there is a partial block.
+ * The GHASH implementation automatically applies padding with
+ * zeros.
+ */
+ size_t ptr;
+
+ ptr = (size_t)ctx->count_aad & (size_t)15;
+ if (ptr != 0) {
+ ctx->gh(ctx->y, ctx->h, ctx->buf, ptr);
+ }
+}
+
+/* see bearssl_aead.h */
+void
+br_gcm_run(br_gcm_context *ctx, int encrypt, void *data, size_t len)
+{
+ unsigned char *buf;
+ size_t ptr, dlen;
+
+ buf = data;
+ ptr = (size_t)ctx->count_ctr & (size_t)15;
+ if (ptr != 0) {
+ /*
+ * If we have a partial block, then we try to complete it.
+ */
+ size_t u, clen;
+
+ clen = 16 - ptr;
+ if (len < clen) {
+ clen = len;
+ }
+ for (u = 0; u < clen; u ++) {
+ unsigned x, y;
+
+ x = buf[u];
+ y = x ^ ctx->buf[ptr + u];
+ ctx->buf[ptr + u] = encrypt ? y : x;
+ buf[u] = y;
+ }
+ ctx->count_ctr += (uint64_t)clen;
+ buf += clen;
+ len -= clen;
+ if (ptr + clen < 16) {
+ return;
+ }
+ ctx->gh(ctx->y, ctx->h, ctx->buf, 16);
+ }
+
+ /*
+ * Process full blocks.
+ */
+ dlen = len & ~(size_t)15;
+ if (!encrypt) {
+ ctx->gh(ctx->y, ctx->h, buf, dlen);
+ }
+ ctx->jc = (*ctx->bctx)->run(ctx->bctx, ctx->j0_1, ctx->jc, buf, dlen);
+ if (encrypt) {
+ ctx->gh(ctx->y, ctx->h, buf, dlen);
+ }
+ buf += dlen;
+ len -= dlen;
+ ctx->count_ctr += (uint64_t)dlen;
+
+ if (len > 0) {
+ /*
+ * There is a partial block.
+ */
+ size_t u;
+
+ memset(ctx->buf, 0, sizeof ctx->buf);
+ ctx->jc = (*ctx->bctx)->run(ctx->bctx, ctx->j0_1,
+ ctx->jc, ctx->buf, 16);
+ for (u = 0; u < len; u ++) {
+ unsigned x, y;
+
+ x = buf[u];
+ y = x ^ ctx->buf[u];
+ ctx->buf[u] = encrypt ? y : x;
+ buf[u] = y;
+ }
+ ctx->count_ctr += (uint64_t)len;
+ }
+}
+
+/* see bearssl_aead.h */
+void
+br_gcm_get_tag(br_gcm_context *ctx, void *tag)
+{
+ size_t ptr;
+ unsigned char tmp[16];
+
+ ptr = (size_t)ctx->count_ctr & (size_t)15;
+ if (ptr > 0) {
+ /*
+ * There is a partial block: encrypted/decrypted data has
+ * been produced, but the encrypted bytes must still be
+ * processed by GHASH.
+ */
+ ctx->gh(ctx->y, ctx->h, ctx->buf, ptr);
+ }
+
+ /*
+ * Final block for GHASH: the AAD and plaintext lengths (in bits).
+ */
+ br_enc64be(tmp, ctx->count_aad << 3);
+ br_enc64be(tmp + 8, ctx->count_ctr << 3);
+ ctx->gh(ctx->y, ctx->h, tmp, 16);
+
+ /*
+ * Tag is the GHASH output XORed with the encryption of the
+ * nonce with the initial counter value.
+ */
+ memcpy(tag, ctx->y, 16);
+ (*ctx->bctx)->run(ctx->bctx, ctx->j0_1, ctx->j0_2, tag, 16);
+}
+
+/* see bearssl_aead.h */
+void
+br_gcm_get_tag_trunc(br_gcm_context *ctx, void *tag, size_t len)
+{
+ unsigned char tmp[16];
+
+ br_gcm_get_tag(ctx, tmp);
+ memcpy(tag, tmp, len);
+}
+
+/* see bearssl_aead.h */
+uint32_t
+br_gcm_check_tag_trunc(br_gcm_context *ctx, const void *tag, size_t len)
+{
+ unsigned char tmp[16];
+ size_t u;
+ int x;
+
+ br_gcm_get_tag(ctx, tmp);
+ x = 0;
+ for (u = 0; u < len; u ++) {
+ x |= tmp[u] ^ ((const unsigned char *)tag)[u];
+ }
+ return EQ0(x);
+}
+
+/* see bearssl_aead.h */
+uint32_t
+br_gcm_check_tag(br_gcm_context *ctx, const void *tag)
+{
+ return br_gcm_check_tag_trunc(ctx, tag, 16);
+}
+
+/* see bearssl_aead.h */
+const br_aead_class br_gcm_vtable PROGMEM = {
+ 16,
+ (void (*)(const br_aead_class **, const void *, size_t))
+ &br_gcm_reset,
+ (void (*)(const br_aead_class **, const void *, size_t))
+ &br_gcm_aad_inject,
+ (void (*)(const br_aead_class **))
+ &br_gcm_flip,
+ (void (*)(const br_aead_class **, int, void *, size_t))
+ &br_gcm_run,
+ (void (*)(const br_aead_class **, void *))
+ &br_gcm_get_tag,
+ (uint32_t (*)(const br_aead_class **, const void *))
+ &br_gcm_check_tag,
+ (void (*)(const br_aead_class **, void *, size_t))
+ &br_gcm_get_tag_trunc,
+ (uint32_t (*)(const br_aead_class **, const void *, size_t))
+ &br_gcm_check_tag_trunc
+};
diff --git a/lib/bearssl-esp8266/src/codec/ccopy.c b/lib/bearssl-esp8266/src/codec/ccopy.c
new file mode 100644
index 000000000..33f4b1a49
--- /dev/null
+++ b/lib/bearssl-esp8266/src/codec/ccopy.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "t_inner.h"
+
+/* see inner.h */
+void
+br_ccopy(uint32_t ctl, void *dst, const void *src, size_t len)
+{
+ unsigned char *d;
+ const unsigned char *s;
+
+ d = dst;
+ s = src;
+ while (len -- > 0) {
+ uint32_t x, y;
+
+ x = *s ++;
+ y = *d;
+ *d = MUX(ctl, x, y);
+ d ++;
+ }
+}
diff --git a/lib/bearssl-esp8266/src/codec/dec16be.c b/lib/bearssl-esp8266/src/codec/dec16be.c
new file mode 100644
index 000000000..af7b48074
--- /dev/null
+++ b/lib/bearssl-esp8266/src/codec/dec16be.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "t_inner.h"
+
+/* see inner.h */
+void
+br_range_dec16be(uint16_t *v, size_t num, const void *src)
+{
+ const unsigned char *buf;
+
+ buf = src;
+ while (num -- > 0) {
+ *v ++ = br_dec16be(buf);
+ buf += 2;
+ }
+}
diff --git a/lib/bearssl-esp8266/src/codec/dec16le.c b/lib/bearssl-esp8266/src/codec/dec16le.c
new file mode 100644
index 000000000..4bf0174b9
--- /dev/null
+++ b/lib/bearssl-esp8266/src/codec/dec16le.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "t_inner.h"
+
+/* see inner.h */
+void
+br_range_dec16le(uint16_t *v, size_t num, const void *src)
+{
+ const unsigned char *buf;
+
+ buf = src;
+ while (num -- > 0) {
+ *v ++ = br_dec16le(buf);
+ buf += 2;
+ }
+}
diff --git a/lib/bearssl-esp8266/src/codec/dec32be.c b/lib/bearssl-esp8266/src/codec/dec32be.c
new file mode 100644
index 000000000..51016e5b9
--- /dev/null
+++ b/lib/bearssl-esp8266/src/codec/dec32be.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "t_inner.h"
+
+/* see inner.h */
+void
+br_range_dec32be(uint32_t *v, size_t num, const void *src)
+{
+ const unsigned char *buf;
+
+ buf = src;
+ while (num -- > 0) {
+ *v ++ = br_dec32be(buf);
+ buf += 4;
+ }
+}
diff --git a/lib/bearssl-esp8266/src/codec/dec32le.c b/lib/bearssl-esp8266/src/codec/dec32le.c
new file mode 100644
index 000000000..22b2c01a8
--- /dev/null
+++ b/lib/bearssl-esp8266/src/codec/dec32le.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "t_inner.h"
+
+/* see inner.h */
+void
+br_range_dec32le(uint32_t *v, size_t num, const void *src)
+{
+ const unsigned char *buf;
+
+ buf = src;
+ while (num -- > 0) {
+ *v ++ = br_dec32le(buf);
+ buf += 4;
+ }
+}
diff --git a/lib/bearssl-esp8266/src/codec/dec64be.c b/lib/bearssl-esp8266/src/codec/dec64be.c
new file mode 100644
index 000000000..55632e4a5
--- /dev/null
+++ b/lib/bearssl-esp8266/src/codec/dec64be.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "t_inner.h"
+
+/* see inner.h */
+void
+br_range_dec64be(uint64_t *v, size_t num, const void *src)
+{
+ const unsigned char *buf;
+
+ buf = src;
+ while (num -- > 0) {
+ *v ++ = br_dec64be(buf);
+ buf += 8;
+ }
+}
diff --git a/lib/bearssl-esp8266/src/codec/dec64le.c b/lib/bearssl-esp8266/src/codec/dec64le.c
new file mode 100644
index 000000000..e77614a5c
--- /dev/null
+++ b/lib/bearssl-esp8266/src/codec/dec64le.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "t_inner.h"
+
+/* see inner.h */
+void
+br_range_dec64le(uint64_t *v, size_t num, const void *src)
+{
+ const unsigned char *buf;
+
+ buf = src;
+ while (num -- > 0) {
+ *v ++ = br_dec64le(buf);
+ buf += 8;
+ }
+}
diff --git a/lib/bearssl-esp8266/src/codec/enc16be.c b/lib/bearssl-esp8266/src/codec/enc16be.c
new file mode 100644
index 000000000..be29cd6e9
--- /dev/null
+++ b/lib/bearssl-esp8266/src/codec/enc16be.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "t_inner.h"
+
+/* see inner.h */
+void
+br_range_enc16be(void *dst, const uint16_t *v, size_t num)
+{
+ unsigned char *buf;
+
+ buf = dst;
+ while (num -- > 0) {
+ br_enc16be(buf, *v ++);
+ buf += 2;
+ }
+}
diff --git a/lib/bearssl-esp8266/src/codec/enc16le.c b/lib/bearssl-esp8266/src/codec/enc16le.c
new file mode 100644
index 000000000..d5f6f7ea0
--- /dev/null
+++ b/lib/bearssl-esp8266/src/codec/enc16le.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "t_inner.h"
+
+/* see inner.h */
+void
+br_range_enc16le(void *dst, const uint16_t *v, size_t num)
+{
+ unsigned char *buf;
+
+ buf = dst;
+ while (num -- > 0) {
+ br_enc16le(buf, *v ++);
+ buf += 2;
+ }
+}
diff --git a/lib/bearssl-esp8266/src/codec/enc32be.c b/lib/bearssl-esp8266/src/codec/enc32be.c
new file mode 100644
index 000000000..89fad30d6
--- /dev/null
+++ b/lib/bearssl-esp8266/src/codec/enc32be.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "t_inner.h"
+
+/* see inner.h */
+void
+br_range_enc32be(void *dst, const uint32_t *v, size_t num)
+{
+ unsigned char *buf;
+
+ buf = dst;
+ while (num -- > 0) {
+ br_enc32be(buf, *v ++);
+ buf += 4;
+ }
+}
diff --git a/lib/bearssl-esp8266/src/codec/enc32le.c b/lib/bearssl-esp8266/src/codec/enc32le.c
new file mode 100644
index 000000000..4fae44774
--- /dev/null
+++ b/lib/bearssl-esp8266/src/codec/enc32le.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "t_inner.h"
+
+/* see inner.h */
+void
+br_range_enc32le(void *dst, const uint32_t *v, size_t num)
+{
+ unsigned char *buf;
+
+ buf = dst;
+ while (num -- > 0) {
+ br_enc32le(buf, *v ++);
+ buf += 4;
+ }
+}
diff --git a/lib/bearssl-esp8266/src/codec/enc64be.c b/lib/bearssl-esp8266/src/codec/enc64be.c
new file mode 100644
index 000000000..d06ffebbd
--- /dev/null
+++ b/lib/bearssl-esp8266/src/codec/enc64be.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "t_inner.h"
+
+/* see inner.h */
+void
+br_range_enc64be(void *dst, const uint64_t *v, size_t num)
+{
+ unsigned char *buf;
+
+ buf = dst;
+ while (num -- > 0) {
+ br_enc64be(buf, *v ++);
+ buf += 8;
+ }
+}
diff --git a/lib/bearssl-esp8266/src/codec/enc64le.c b/lib/bearssl-esp8266/src/codec/enc64le.c
new file mode 100644
index 000000000..8e2f8e887
--- /dev/null
+++ b/lib/bearssl-esp8266/src/codec/enc64le.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "t_inner.h"
+
+/* see inner.h */
+void
+br_range_enc64le(void *dst, const uint64_t *v, size_t num)
+{
+ unsigned char *buf;
+
+ buf = dst;
+ while (num -- > 0) {
+ br_enc64le(buf, *v ++);
+ buf += 8;
+ }
+}
diff --git a/lib/bearssl-esp8266/src/codec/pemdec.c b/lib/bearssl-esp8266/src/codec/pemdec.c
new file mode 100644
index 000000000..0de8d3414
--- /dev/null
+++ b/lib/bearssl-esp8266/src/codec/pemdec.c
@@ -0,0 +1,536 @@
+/* Automatically generated code; do not modify directly. */
+
+#include
+#include
+#include
+
+typedef struct {
+ uint32_t *dp;
+ uint32_t *rp;
+ const unsigned char *ip;
+} t0_context;
+
+static uint32_t
+t0_parse7E_unsigned(const unsigned char **p)
+{
+ uint32_t x;
+
+ x = 0;
+ for (;;) {
+ unsigned y;
+
+ y = pgm_read_byte((*p)++);
+ x = (x << 7) | (uint32_t)(y & 0x7F);
+ if (y < 0x80) {
+ return x;
+ }
+ }
+}
+
+static int32_t
+t0_parse7E_signed(const unsigned char **p)
+{
+ int neg;
+ uint32_t x;
+
+ neg = (pgm_read_byte(*p) >> 6) & 1;
+ x = (uint32_t)-neg;
+ for (;;) {
+ unsigned y;
+
+ y = pgm_read_byte((*p)++);
+ x = (x << 7) | (uint32_t)(y & 0x7F);
+ if (y < 0x80) {
+ if (neg) {
+ return -(int32_t)~x - 1;
+ } else {
+ return (int32_t)x;
+ }
+ }
+ }
+}
+
+#define T0_VBYTE(x, n) (unsigned char)((((uint32_t)(x) >> (n)) & 0x7F) | 0x80)
+#define T0_FBYTE(x, n) (unsigned char)(((uint32_t)(x) >> (n)) & 0x7F)
+#define T0_SBYTE(x) (unsigned char)((((uint32_t)(x) >> 28) + 0xF8) ^ 0xF8)
+#define T0_INT1(x) T0_FBYTE(x, 0)
+#define T0_INT2(x) T0_VBYTE(x, 7), T0_FBYTE(x, 0)
+#define T0_INT3(x) T0_VBYTE(x, 14), T0_VBYTE(x, 7), T0_FBYTE(x, 0)
+#define T0_INT4(x) T0_VBYTE(x, 21), T0_VBYTE(x, 14), T0_VBYTE(x, 7), T0_FBYTE(x, 0)
+#define T0_INT5(x) T0_SBYTE(x), T0_VBYTE(x, 21), T0_VBYTE(x, 14), T0_VBYTE(x, 7), T0_FBYTE(x, 0)
+
+/* static const unsigned char t0_datablock[]; */
+
+
+void br_pem_decoder_init_main(void *t0ctx);
+
+void br_pem_decoder_run(void *t0ctx);
+
+
+
+#include "t_inner.h"
+
+#define CTX ((br_pem_decoder_context *)(void *)((unsigned char *)t0ctx - offsetof(br_pem_decoder_context, cpu)))
+
+/* see bearssl_pem.h */
+void
+br_pem_decoder_init(br_pem_decoder_context *ctx)
+{
+ memset(ctx, 0, sizeof *ctx);
+ ctx->cpu.dp = &ctx->dp_stack[0];
+ ctx->cpu.rp = &ctx->rp_stack[0];
+ br_pem_decoder_init_main(&ctx->cpu);
+ br_pem_decoder_run(&ctx->cpu);
+}
+
+/* see bearssl_pem.h */
+size_t
+br_pem_decoder_push(br_pem_decoder_context *ctx,
+ const void *data, size_t len)
+{
+ if (ctx->event) {
+ return 0;
+ }
+ ctx->hbuf = data;
+ ctx->hlen = len;
+ br_pem_decoder_run(&ctx->cpu);
+ return len - ctx->hlen;
+}
+
+/* see bearssl_pem.h */
+int
+br_pem_decoder_event(br_pem_decoder_context *ctx)
+{
+ int event;
+
+ event = ctx->event;
+ ctx->event = 0;
+ return event;
+}
+
+
+
+static const unsigned char t0_datablock[] PROGMEM = {
+
+ 0x00, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x42, 0x45, 0x47, 0x49, 0x4E, 0x20,
+ 0x00, 0x2D, 0x2D, 0x2D, 0x2D, 0x45, 0x4E, 0x44, 0x20, 0x00
+};
+
+static const unsigned char t0_codeblock[] PROGMEM = {
+
+ 0x00, 0x01, 0x00, 0x09, 0x00, 0x00, 0x01, 0x01, 0x07, 0x00, 0x00, 0x01,
+ 0x01, 0x08, 0x00, 0x00, 0x13, 0x13, 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(br_pem_decoder_context, event)), 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(br_pem_decoder_context, name)), 0x00, 0x00, 0x05,
+ 0x14, 0x2C, 0x14, 0x01, 0x0A, 0x0D, 0x06, 0x03, 0x13, 0x04, 0x76, 0x01,
+ 0x2D, 0x0C, 0x06, 0x05, 0x2E, 0x01, 0x03, 0x2D, 0x00, 0x01, 0x0D, 0x27,
+ 0x05, 0x04, 0x01, 0x03, 0x2D, 0x00, 0x15, 0x2E, 0x01, 0x02, 0x2D, 0x00,
+ 0x01, 0x01, 0x7F, 0x03, 0x00, 0x25, 0x01, 0x00, 0x18, 0x0D, 0x06, 0x03,
+ 0x13, 0x04, 0x3C, 0x01, 0x7F, 0x18, 0x0D, 0x06, 0x13, 0x13, 0x02, 0x00,
+ 0x05, 0x06, 0x2E, 0x01, 0x03, 0x2D, 0x04, 0x03, 0x01, 0x7F, 0x23, 0x01,
+ 0x00, 0x00, 0x04, 0x23, 0x01, 0x01, 0x18, 0x0D, 0x06, 0x09, 0x13, 0x01,
+ 0x00, 0x23, 0x01, 0x00, 0x00, 0x04, 0x14, 0x01, 0x02, 0x18, 0x0D, 0x06,
+ 0x06, 0x13, 0x01, 0x7F, 0x00, 0x04, 0x08, 0x13, 0x01, 0x03, 0x2D, 0x01,
+ 0x00, 0x00, 0x13, 0x01, 0x00, 0x03, 0x00, 0x04, 0xFF, 0x33, 0x01, 0x2C,
+ 0x14, 0x01, 0x2D, 0x0D, 0x06, 0x04, 0x13, 0x01, 0x7F, 0x00, 0x14, 0x31,
+ 0x06, 0x02, 0x13, 0x29, 0x14, 0x01, 0x0A, 0x0D, 0x06, 0x04, 0x13, 0x01,
+ 0x02, 0x00, 0x16, 0x14, 0x1D, 0x06, 0x05, 0x13, 0x2E, 0x01, 0x03, 0x00,
+ 0x03, 0x00, 0x29, 0x14, 0x01, 0x0A, 0x0D, 0x06, 0x04, 0x13, 0x01, 0x03,
+ 0x00, 0x16, 0x14, 0x1D, 0x06, 0x05, 0x13, 0x2E, 0x01, 0x03, 0x00, 0x02,
+ 0x00, 0x01, 0x06, 0x0A, 0x07, 0x03, 0x00, 0x29, 0x14, 0x01, 0x0A, 0x0D,
+ 0x06, 0x04, 0x13, 0x01, 0x03, 0x00, 0x14, 0x01, 0x3D, 0x0D, 0x06, 0x2E,
+ 0x13, 0x29, 0x14, 0x01, 0x0A, 0x0D, 0x06, 0x04, 0x13, 0x01, 0x03, 0x00,
+ 0x2F, 0x05, 0x04, 0x13, 0x01, 0x03, 0x00, 0x01, 0x3D, 0x0C, 0x06, 0x03,
+ 0x01, 0x03, 0x00, 0x02, 0x00, 0x01, 0x0F, 0x10, 0x06, 0x03, 0x01, 0x03,
+ 0x00, 0x02, 0x00, 0x01, 0x04, 0x0F, 0x1C, 0x01, 0x01, 0x00, 0x16, 0x14,
+ 0x1D, 0x06, 0x05, 0x13, 0x2E, 0x01, 0x03, 0x00, 0x02, 0x00, 0x01, 0x06,
+ 0x0A, 0x07, 0x03, 0x00, 0x29, 0x14, 0x01, 0x0A, 0x0D, 0x06, 0x04, 0x13,
+ 0x01, 0x03, 0x00, 0x14, 0x01, 0x3D, 0x0D, 0x06, 0x20, 0x13, 0x2F, 0x05,
+ 0x03, 0x01, 0x03, 0x00, 0x02, 0x00, 0x01, 0x03, 0x10, 0x06, 0x03, 0x01,
+ 0x03, 0x00, 0x02, 0x00, 0x01, 0x0A, 0x0F, 0x1C, 0x02, 0x00, 0x01, 0x02,
+ 0x0F, 0x1C, 0x01, 0x01, 0x00, 0x16, 0x14, 0x1D, 0x06, 0x05, 0x13, 0x2E,
+ 0x01, 0x03, 0x00, 0x02, 0x00, 0x01, 0x06, 0x0A, 0x07, 0x03, 0x00, 0x02,
+ 0x00, 0x01, 0x10, 0x0F, 0x1C, 0x02, 0x00, 0x01, 0x08, 0x0F, 0x1C, 0x02,
+ 0x00, 0x1C, 0x01, 0x00, 0x00, 0x00, 0x28, 0x01, 0x01, 0x2D, 0x24, 0x06,
+ 0x02, 0x04, 0x7B, 0x04, 0x75, 0x00, 0x14, 0x12, 0x2A, 0x14, 0x05, 0x04,
+ 0x20, 0x01, 0x7F, 0x00, 0x2C, 0x2A, 0x14, 0x01, 0x0A, 0x0D, 0x06, 0x05,
+ 0x13, 0x20, 0x01, 0x00, 0x00, 0x0D, 0x05, 0x05, 0x13, 0x2E, 0x01, 0x00,
+ 0x00, 0x1E, 0x04, 0x5E, 0x00, 0x01, 0x01, 0x27, 0x06, 0x0B, 0x22, 0x01,
+ 0x80, 0x7F, 0x2B, 0x14, 0x06, 0x02, 0x30, 0x00, 0x13, 0x04, 0x6E, 0x00,
+ 0x2C, 0x14, 0x31, 0x05, 0x01, 0x00, 0x13, 0x04, 0x77, 0x00, 0x14, 0x14,
+ 0x01, 0x80, 0x61, 0x0E, 0x1B, 0x01, 0x80, 0x7A, 0x0B, 0x10, 0x06, 0x03,
+ 0x01, 0x20, 0x08, 0x00, 0x01, 0x14, 0x03, 0x00, 0x1B, 0x18, 0x05, 0x05,
+ 0x20, 0x2E, 0x01, 0x00, 0x00, 0x2C, 0x14, 0x01, 0x0A, 0x0D, 0x06, 0x06,
+ 0x20, 0x02, 0x00, 0x1B, 0x08, 0x00, 0x14, 0x01, 0x0D, 0x0D, 0x06, 0x03,
+ 0x13, 0x04, 0x03, 0x2A, 0x18, 0x1A, 0x1E, 0x1B, 0x1F, 0x1B, 0x04, 0x59,
+ 0x00, 0x19, 0x14, 0x1D, 0x05, 0x01, 0x00, 0x13, 0x11, 0x04, 0x76, 0x00,
+ 0x21, 0x1A, 0x11, 0x00, 0x00, 0x2C, 0x01, 0x0A, 0x0C, 0x06, 0x02, 0x04,
+ 0x78, 0x00, 0x01, 0x01, 0x7F, 0x03, 0x00, 0x2C, 0x14, 0x01, 0x0A, 0x0C,
+ 0x06, 0x09, 0x31, 0x05, 0x04, 0x01, 0x00, 0x03, 0x00, 0x04, 0x70, 0x13,
+ 0x02, 0x00, 0x00, 0x00, 0x14, 0x06, 0x14, 0x1F, 0x14, 0x22, 0x07, 0x17,
+ 0x01, 0x2D, 0x0C, 0x06, 0x08, 0x22, 0x07, 0x1E, 0x01, 0x00, 0x1B, 0x1A,
+ 0x00, 0x04, 0x69, 0x22, 0x1A, 0x00, 0x00, 0x14, 0x01, 0x0A, 0x0C, 0x1B,
+ 0x01, 0x20, 0x0B, 0x10, 0x00
+};
+
+static const uint16_t t0_caddr[] PROGMEM = {
+
+ 0,
+ 5,
+ 10,
+ 15,
+ 19,
+ 24,
+ 29,
+ 67,
+ 149,
+ 384,
+ 396,
+ 431,
+ 450,
+ 460,
+ 479,
+ 523,
+ 534,
+ 539,
+ 549,
+ 574,
+ 601
+};
+
+#define T0_INTERPRETED 29
+
+#define T0_ENTER(ip, rp, slot) do { \
+ const unsigned char *t0_newip; \
+ uint32_t t0_lnum; \
+ t0_newip = &t0_codeblock[pgm_read_word(&t0_caddr[(slot) - T0_INTERPRETED])]; \
+ t0_lnum = t0_parse7E_unsigned(&t0_newip); \
+ (rp) += t0_lnum; \
+ *((rp) ++) = (uint32_t)((ip) - &t0_codeblock[0]) + (t0_lnum << 16); \
+ (ip) = t0_newip; \
+ } while (0)
+
+#define T0_DEFENTRY(name, slot) \
+void \
+name(void *ctx) \
+{ \
+ t0_context *t0ctx = ctx; \
+ t0ctx->ip = &t0_codeblock[0]; \
+ T0_ENTER(t0ctx->ip, t0ctx->rp, slot); \
+}
+
+T0_DEFENTRY(br_pem_decoder_init_main, 38)
+
+#define T0_NEXT(t0ipp) (pgm_read_byte((*t0ipp)++))
+
+void
+br_pem_decoder_run(void *t0ctx)
+{
+ uint32_t *dp, *rp;
+ const unsigned char *ip;
+
+#define T0_LOCAL(x) (*(rp - 2 - (x)))
+#define T0_POP() (*-- dp)
+#define T0_POPi() (*(int32_t *)(-- dp))
+#define T0_PEEK(x) (*(dp - 1 - (x)))
+#define T0_PEEKi(x) (*(int32_t *)(dp - 1 - (x)))
+#define T0_PUSH(v) do { *dp = (v); dp ++; } while (0)
+#define T0_PUSHi(v) do { *(int32_t *)dp = (v); dp ++; } while (0)
+#define T0_RPOP() (*-- rp)
+#define T0_RPOPi() (*(int32_t *)(-- rp))
+#define T0_RPUSH(v) do { *rp = (v); rp ++; } while (0)
+#define T0_RPUSHi(v) do { *(int32_t *)rp = (v); rp ++; } while (0)
+#define T0_ROLL(x) do { \
+ size_t t0len = (size_t)(x); \
+ uint32_t t0tmp = *(dp - 1 - t0len); \
+ memmove(dp - t0len - 1, dp - t0len, t0len * sizeof *dp); \
+ *(dp - 1) = t0tmp; \
+} while (0)
+#define T0_SWAP() do { \
+ uint32_t t0tmp = *(dp - 2); \
+ *(dp - 2) = *(dp - 1); \
+ *(dp - 1) = t0tmp; \
+} while (0)
+#define T0_ROT() do { \
+ uint32_t t0tmp = *(dp - 3); \
+ *(dp - 3) = *(dp - 2); \
+ *(dp - 2) = *(dp - 1); \
+ *(dp - 1) = t0tmp; \
+} while (0)
+#define T0_NROT() do { \
+ uint32_t t0tmp = *(dp - 1); \
+ *(dp - 1) = *(dp - 2); \
+ *(dp - 2) = *(dp - 3); \
+ *(dp - 3) = t0tmp; \
+} while (0)
+#define T0_PICK(x) do { \
+ uint32_t t0depth = (x); \
+ T0_PUSH(T0_PEEK(t0depth)); \
+} while (0)
+#define T0_CO() do { \
+ goto t0_exit; \
+} while (0)
+#define T0_RET() goto t0_next
+
+ dp = ((t0_context *)t0ctx)->dp;
+ rp = ((t0_context *)t0ctx)->rp;
+ ip = ((t0_context *)t0ctx)->ip;
+ goto t0_next;
+ for (;;) {
+ uint32_t t0x;
+
+ t0_next:
+ t0x = T0_NEXT(&ip);
+ if (t0x < T0_INTERPRETED) {
+ switch (t0x) {
+ int32_t t0off;
+
+ case 0: /* ret */
+ t0x = T0_RPOP();
+ rp -= (t0x >> 16);
+ t0x &= 0xFFFF;
+ if (t0x == 0) {
+ ip = NULL;
+ goto t0_exit;
+ }
+ ip = &t0_codeblock[t0x];
+ break;
+ case 1: /* literal constant */
+ T0_PUSHi(t0_parse7E_signed(&ip));
+ break;
+ case 2: /* read local */
+ T0_PUSH(T0_LOCAL(t0_parse7E_unsigned(&ip)));
+ break;
+ case 3: /* write local */
+ T0_LOCAL(t0_parse7E_unsigned(&ip)) = T0_POP();
+ break;
+ case 4: /* jump */
+ t0off = t0_parse7E_signed(&ip);
+ ip += t0off;
+ break;
+ case 5: /* jump if */
+ t0off = t0_parse7E_signed(&ip);
+ if (T0_POP()) {
+ ip += t0off;
+ }
+ break;
+ case 6: /* jump if not */
+ t0off = t0_parse7E_signed(&ip);
+ if (!T0_POP()) {
+ ip += t0off;
+ }
+ break;
+ case 7: {
+ /* + */
+
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(a + b);
+
+ }
+ break;
+ case 8: {
+ /* - */
+
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(a - b);
+
+ }
+ break;
+ case 9: {
+ /* < */
+
+ int32_t b = T0_POPi();
+ int32_t a = T0_POPi();
+ T0_PUSH(-(uint32_t)(a < b));
+
+ }
+ break;
+ case 10: {
+ /* << */
+
+ int c = (int)T0_POPi();
+ uint32_t x = T0_POP();
+ T0_PUSH(x << c);
+
+ }
+ break;
+ case 11: {
+ /* <= */
+
+ int32_t b = T0_POPi();
+ int32_t a = T0_POPi();
+ T0_PUSH(-(uint32_t)(a <= b));
+
+ }
+ break;
+ case 12: {
+ /* <> */
+
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(-(uint32_t)(a != b));
+
+ }
+ break;
+ case 13: {
+ /* = */
+
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(-(uint32_t)(a == b));
+
+ }
+ break;
+ case 14: {
+ /* >= */
+
+ int32_t b = T0_POPi();
+ int32_t a = T0_POPi();
+ T0_PUSH(-(uint32_t)(a >= b));
+
+ }
+ break;
+ case 15: {
+ /* >> */
+
+ int c = (int)T0_POPi();
+ int32_t x = T0_POPi();
+ T0_PUSHi(x >> c);
+
+ }
+ break;
+ case 16: {
+ /* and */
+
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(a & b);
+
+ }
+ break;
+ case 17: {
+ /* co */
+ T0_CO();
+ }
+ break;
+ case 18: {
+ /* data-get8 */
+
+ size_t addr = T0_POP();
+ T0_PUSH(pgm_read_byte(&t0_datablock[addr]));
+
+ }
+ break;
+ case 19: {
+ /* drop */
+ (void)T0_POP();
+ }
+ break;
+ case 20: {
+ /* dup */
+ T0_PUSH(T0_PEEK(0));
+ }
+ break;
+ case 21: {
+ /* flush-buf */
+
+ if (CTX->ptr > 0) {
+ if (CTX->dest) {
+ CTX->dest(CTX->dest_ctx, CTX->buf, CTX->ptr);
+ }
+ CTX->ptr = 0;
+ }
+
+ }
+ break;
+ case 22: {
+ /* from-base64 */
+
+ uint32_t c = T0_POP();
+ uint32_t p, q, r, z;
+ p = c - 0x41;
+ q = c - 0x61;
+ r = c - 0x30;
+
+ z = ((p + 2) & -LT(p, 26))
+ | ((q + 28) & -LT(q, 26))
+ | ((r + 54) & -LT(r, 10))
+ | (64 & -EQ(c, 0x2B))
+ | (65 & -EQ(c, 0x2F))
+ | EQ(c, 0x3D);
+ T0_PUSHi((int32_t)z - 2);
+
+ }
+ break;
+ case 23: {
+ /* get8 */
+
+ size_t addr = T0_POP();
+ T0_PUSH(*((unsigned char *)CTX + addr));
+
+ }
+ break;
+ case 24: {
+ /* over */
+ T0_PUSH(T0_PEEK(1));
+ }
+ break;
+ case 25: {
+ /* read8-native */
+
+ do {
+ if (CTX->hlen > 0) {
+ uint8_t ch = pgm_read_byte(CTX->hbuf ++);
+ CTX->hlen --;
+ if (ch == '\r') continue; // skip \rs
+ T0_PUSH(ch);
+ break;
+ } else {
+ T0_PUSHi(-1);
+ break;
+ }
+ } while (1);
+
+ }
+ break;
+ case 26: {
+ /* set8 */
+
+ size_t addr = T0_POP();
+ unsigned x = T0_POP();
+ *((unsigned char *)CTX + addr) = x;
+
+ }
+ break;
+ case 27: {
+ /* swap */
+ T0_SWAP();
+ }
+ break;
+ case 28: {
+ /* write8 */
+
+ unsigned char x = (unsigned char)T0_POP();
+ CTX->buf[CTX->ptr ++] = x;
+ if (CTX->ptr == sizeof CTX->buf) {
+ if (CTX->dest) {
+ CTX->dest(CTX->dest_ctx, CTX->buf, sizeof CTX->buf);
+ }
+ CTX->ptr = 0;
+ }
+
+ }
+ break;
+ }
+
+ } else {
+ T0_ENTER(ip, rp, t0x);
+ }
+ }
+t0_exit:
+ ((t0_context *)t0ctx)->dp = dp;
+ ((t0_context *)t0ctx)->rp = rp;
+ ((t0_context *)t0ctx)->ip = ip;
+}
diff --git a/lib/bearssl-esp8266/src/codec/pemenc.c b/lib/bearssl-esp8266/src/codec/pemenc.c
new file mode 100644
index 000000000..b6475cd68
--- /dev/null
+++ b/lib/bearssl-esp8266/src/codec/pemenc.c
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2018 Thomas Pornin
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "t_inner.h"
+
+/*
+ * Get the appropriate Base64 character for a numeric value in the
+ * 0..63 range. This is constant-time.
+ */
+static char
+b64char(uint32_t x)
+{
+ /*
+ * Values 0 to 25 map to 0x41..0x5A ('A' to 'Z')
+ * Values 26 to 51 map to 0x61..0x7A ('a' to 'z')
+ * Values 52 to 61 map to 0x30..0x39 ('0' to '9')
+ * Value 62 maps to 0x2B ('+')
+ * Value 63 maps to 0x2F ('/')
+ */
+ uint32_t a, b, c;
+
+ a = x - 26;
+ b = x - 52;
+ c = x - 62;
+
+ /*
+ * Looking at bits 8..15 of values a, b and c:
+ *
+ * x a b c
+ * ---------------------
+ * 0..25 FF FF FF
+ * 26..51 00 FF FF
+ * 52..61 00 00 FF
+ * 62..63 00 00 00
+ */
+ return (char)(((x + 0x41) & ((a & b & c) >> 8))
+ | ((x + (0x61 - 26)) & ((~a & b & c) >> 8))
+ | ((x - (52 - 0x30)) & ((~a & ~b & c) >> 8))
+ | ((0x2B + ((x & 1) << 2)) & (~(a | b | c) >> 8)));
+}
+
+/* see bearssl_pem.h */
+size_t
+br_pem_encode(void *dest, const void *data, size_t len,
+ const char *banner, unsigned flags)
+{
+ size_t dlen, banner_len, lines;
+ char *d;
+ unsigned char *buf;
+ size_t u;
+ int off, lim;
+
+ banner_len = strlen(banner);
+ /* FIXME: try to avoid divisions here, as they may pull
+ an extra libc function. */
+ if ((flags & BR_PEM_LINE64) != 0) {
+ lines = (len + 47) / 48;
+ } else {
+ lines = (len + 56) / 57;
+ }
+ dlen = (banner_len << 1) + 30 + (((len + 2) / 3) << 2)
+ + lines + 2;
+ if ((flags & BR_PEM_CRLF) != 0) {
+ dlen += lines + 2;
+ }
+
+ if (dest == NULL) {
+ return dlen;
+ }
+
+ d = dest;
+
+ /*
+ * We always move the source data to the end of output buffer;
+ * the encoding process never "catches up" except at the very
+ * end. This also handles all conditions of partial or total
+ * overlap.
+ */
+ buf = (unsigned char *)d + dlen - len;
+ memmove(buf, data, len);
+
+ memcpy(d, "-----BEGIN ", 11);
+ d += 11;
+ memcpy(d, banner, banner_len);
+ d += banner_len;
+ memcpy(d, "-----", 5);
+ d += 5;
+ if ((flags & BR_PEM_CRLF) != 0) {
+ *d ++ = 0x0D;
+ }
+ *d ++ = 0x0A;
+
+ off = 0;
+ lim = (flags & BR_PEM_LINE64) != 0 ? 16 : 19;
+ for (u = 0; (u + 2) < len; u += 3) {
+ uint32_t w;
+
+ w = ((uint32_t)buf[u] << 16)
+ | ((uint32_t)buf[u + 1] << 8)
+ | (uint32_t)buf[u + 2];
+ *d ++ = b64char(w >> 18);
+ *d ++ = b64char((w >> 12) & 0x3F);
+ *d ++ = b64char((w >> 6) & 0x3F);
+ *d ++ = b64char(w & 0x3F);
+ if (++ off == lim) {
+ off = 0;
+ if ((flags & BR_PEM_CRLF) != 0) {
+ *d ++ = 0x0D;
+ }
+ *d ++ = 0x0A;
+ }
+ }
+ if (u < len) {
+ uint32_t w;
+
+ w = (uint32_t)buf[u] << 16;
+ if (u + 1 < len) {
+ w |= (uint32_t)buf[u + 1] << 8;
+ }
+ *d ++ = b64char(w >> 18);
+ *d ++ = b64char((w >> 12) & 0x3F);
+ if (u + 1 < len) {
+ *d ++ = b64char((w >> 6) & 0x3F);
+ } else {
+ *d ++ = 0x3D;
+ }
+ *d ++ = 0x3D;
+ off ++;
+ }
+ if (off != 0) {
+ if ((flags & BR_PEM_CRLF) != 0) {
+ *d ++ = 0x0D;
+ }
+ *d ++ = 0x0A;
+ }
+
+ memcpy(d, "-----END ", 9);
+ d += 9;
+ memcpy(d, banner, banner_len);
+ d += banner_len;
+ memcpy(d, "-----", 5);
+ d += 5;
+ if ((flags & BR_PEM_CRLF) != 0) {
+ *d ++ = 0x0D;
+ }
+ *d ++ = 0x0A;
+
+ /* Final zero, not counted in returned length. */
+ *d ++ = 0x00;
+
+ return dlen;
+}
diff --git a/lib/bearssl-esp8266/src/ec/ec_all_m15.c b/lib/bearssl-esp8266/src/ec/ec_all_m15.c
new file mode 100644
index 000000000..a8708dd91
--- /dev/null
+++ b/lib/bearssl-esp8266/src/ec/ec_all_m15.c
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "t_inner.h"
+
+static const unsigned char *
+api_generator(int curve, size_t *len)
+{
+ switch (curve) {
+ case BR_EC_secp256r1:
+ return br_ec_p256_m15.generator(curve, len);
+ case BR_EC_curve25519:
+ return br_ec_c25519_m15.generator(curve, len);
+ default:
+ return br_ec_prime_i15.generator(curve, len);
+ }
+}
+
+static const unsigned char *
+api_order(int curve, size_t *len)
+{
+ switch (curve) {
+ case BR_EC_secp256r1:
+ return br_ec_p256_m15.order(curve, len);
+ case BR_EC_curve25519:
+ return br_ec_c25519_m15.order(curve, len);
+ default:
+ return br_ec_prime_i15.order(curve, len);
+ }
+}
+
+static size_t
+api_xoff(int curve, size_t *len)
+{
+ switch (curve) {
+ case BR_EC_secp256r1:
+ return br_ec_p256_m15.xoff(curve, len);
+ case BR_EC_curve25519:
+ return br_ec_c25519_m15.xoff(curve, len);
+ default:
+ return br_ec_prime_i15.xoff(curve, len);
+ }
+}
+
+static uint32_t
+api_mul(unsigned char *G, size_t Glen,
+ const unsigned char *kb, size_t kblen, int curve)
+{
+ switch (curve) {
+ case BR_EC_secp256r1:
+ return br_ec_p256_m15.mul(G, Glen, kb, kblen, curve);
+ case BR_EC_curve25519:
+ return br_ec_c25519_m15.mul(G, Glen, kb, kblen, curve);
+ default:
+ return br_ec_prime_i15.mul(G, Glen, kb, kblen, curve);
+ }
+}
+
+static size_t
+api_mulgen(unsigned char *R,
+ const unsigned char *x, size_t xlen, int curve)
+{
+ switch (curve) {
+ case BR_EC_secp256r1:
+ return br_ec_p256_m15.mulgen(R, x, xlen, curve);
+ case BR_EC_curve25519:
+ return br_ec_c25519_m15.mulgen(R, x, xlen, curve);
+ default:
+ return br_ec_prime_i15.mulgen(R, x, xlen, curve);
+ }
+}
+
+static uint32_t
+api_muladd(unsigned char *A, const unsigned char *B, size_t len,
+ const unsigned char *x, size_t xlen,
+ const unsigned char *y, size_t ylen, int curve)
+{
+ switch (curve) {
+ case BR_EC_secp256r1:
+ return br_ec_p256_m15.muladd(A, B, len,
+ x, xlen, y, ylen, curve);
+ case BR_EC_curve25519:
+ return br_ec_c25519_m15.muladd(A, B, len,
+ x, xlen, y, ylen, curve);
+ default:
+ return br_ec_prime_i15.muladd(A, B, len,
+ x, xlen, y, ylen, curve);
+ }
+}
+
+/* see bearssl_ec.h */
+const br_ec_impl br_ec_all_m15 PROGMEM = {
+ (uint32_t)0x23800000,
+ &api_generator,
+ &api_order,
+ &api_xoff,
+ &api_mul,
+ &api_mulgen,
+ &api_muladd
+};
diff --git a/lib/bearssl-esp8266/src/ec/ec_c25519_i15.c b/lib/bearssl-esp8266/src/ec/ec_c25519_i15.c
new file mode 100644
index 000000000..cea8091d8
--- /dev/null
+++ b/lib/bearssl-esp8266/src/ec/ec_c25519_i15.c
@@ -0,0 +1,398 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "t_inner.h"
+
+/*
+ * Parameters for the field:
+ * - field modulus p = 2^255-19
+ * - R^2 mod p (R = 2^(15k) for the smallest k such that R >= p)
+ */
+
+static const uint16_t C255_P[] = {
+ 0x0110,
+ 0x7FED, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF,
+ 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF,
+ 0x7FFF
+};
+
+#define P0I 0x4A1B
+
+static const uint16_t C255_R2[] = {
+ 0x0110,
+ 0x0169, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000
+};
+
+/* obsolete
+#include
+#include
+static void
+print_int_mont(const char *name, const uint16_t *x)
+{
+ uint16_t y[18];
+ unsigned char tmp[32];
+ size_t u;
+
+ printf("%s = ", name);
+ memcpy(y, x, sizeof y);
+ br_i15_from_monty(y, C255_P, P0I);
+ br_i15_encode(tmp, sizeof tmp, y);
+ for (u = 0; u < sizeof tmp; u ++) {
+ printf("%02X", tmp[u]);
+ }
+ printf("\n");
+}
+*/
+
+static const uint16_t C255_A24[] = {
+ 0x0110,
+ 0x45D3, 0x0046, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000
+};
+
+static const unsigned char GEN[] PROGMEM = {
+ 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static const unsigned char ORDER[] PROGMEM = {
+ 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+};
+
+static const unsigned char *
+api_generator(int curve, size_t *len)
+{
+ (void)curve;
+ *len = 32;
+ return GEN;
+}
+
+static const unsigned char *
+api_order(int curve, size_t *len)
+{
+ (void)curve;
+ *len = 32;
+ return ORDER;
+}
+
+static size_t
+api_xoff(int curve, size_t *len)
+{
+ (void)curve;
+ *len = 32;
+ return 0;
+}
+
+static void
+cswap(uint16_t *a, uint16_t *b, uint32_t ctl)
+{
+ int i;
+
+ ctl = -ctl;
+ for (i = 0; i < 18; i ++) {
+ uint32_t aw, bw, tw;
+
+ aw = a[i];
+ bw = b[i];
+ tw = ctl & (aw ^ bw);
+ a[i] = aw ^ tw;
+ b[i] = bw ^ tw;
+ }
+}
+
+static void
+c255_add(uint16_t *d, const uint16_t *a, const uint16_t *b)
+{
+ uint32_t ctl;
+ uint16_t t[18];
+
+ memcpy_P(t, a, sizeof t);
+ ctl = br_i15_add(t, b, 1);
+ ctl |= NOT(br_i15_sub(t, C255_P, 0));
+ br_i15_sub(t, C255_P, ctl);
+ memcpy(d, t, sizeof t);
+}
+
+static void
+c255_sub(uint16_t *d, const uint16_t *a, const uint16_t *b)
+{
+ uint16_t t[18];
+
+ memcpy_P(t, a, sizeof t);
+ br_i15_add(t, C255_P, br_i15_sub(t, b, 1));
+ memcpy(d, t, sizeof t);
+}
+
+static void
+c255_mul(uint16_t *d, const uint16_t *a, const uint16_t *b)
+{
+ uint16_t t[18];
+
+ br_i15_montymul(t, a, b, C255_P, P0I);
+ memcpy(d, t, sizeof t);
+}
+
+static void
+byteswap(unsigned char *G)
+{
+ int i;
+
+ for (i = 0; i < 16; i ++) {
+ unsigned char t;
+
+ t = G[i];
+ G[i] = G[31 - i];
+ G[31 - i] = t;
+ }
+}
+
+static uint32_t
+api_mul(unsigned char *G, size_t Glen,
+ const unsigned char *kb, size_t kblen, int curve)
+{
+#define ILEN (18 * sizeof(uint16_t))
+
+ /*
+ * The a[] and b[] arrays have an extra word to allow for
+ * decoding without using br_i15_decode_reduce().
+ */
+ uint16_t x1[18], x2[18], x3[18], z2[18], z3[18];
+ uint16_t a[19], aa[18], b[19], bb[18];
+ uint16_t c[18], d[18], e[18], da[18], cb[18];
+ unsigned char k[32];
+ uint32_t swap;
+ int i;
+
+ (void)curve;
+
+ /*
+ * Points are encoded over exactly 32 bytes. Multipliers must fit
+ * in 32 bytes as well.
+ * RFC 7748 mandates that the high bit of the last point byte must
+ * be ignored/cleared.
+ */
+ if (Glen != 32 || kblen > 32) {
+ return 0;
+ }
+ G[31] &= 0x7F;
+
+ /*
+ * Byteswap the point encoding, because it uses little-endian, and
+ * the generic decoding routine uses big-endian.
+ */
+ byteswap(G);
+
+ /*
+ * Decode the point ('u' coordinate). This should be reduced
+ * modulo p, but we prefer to avoid the dependency on
+ * br_i15_decode_reduce(). Instead, we use br_i15_decode_mod()
+ * with a synthetic modulus of value 2^255 (this must work
+ * since G was truncated to 255 bits), then use a conditional
+ * subtraction. We use br_i15_decode_mod() and not
+ * br_i15_decode(), because the ec_prime_i15 implementation uses
+ * the former but not the latter.
+ * br_i15_decode_reduce(a, G, 32, C255_P);
+ */
+ br_i15_zero(b, 0x111);
+ b[18] = 1;
+ br_i15_decode_mod(a, G, 32, b);
+ a[0] = 0x110;
+ br_i15_sub(a, C255_P, NOT(br_i15_sub(a, C255_P, 0)));
+
+ /*
+ * Initialise variables x1, x2, z2, x3 and z3. We set all of them
+ * into Montgomery representation.
+ */
+ br_i15_montymul(x1, a, C255_R2, C255_P, P0I);
+ memcpy(x3, x1, ILEN);
+ br_i15_zero(z2, C255_P[0]);
+ memcpy(x2, z2, ILEN);
+ x2[1] = 19;
+ memcpy(z3, x2, ILEN);
+
+ memset(k, 0, (sizeof k) - kblen);
+ memcpy_P(k + (sizeof k) - kblen, kb, kblen);
+ k[31] &= 0xF8;
+ k[0] &= 0x7F;
+ k[0] |= 0x40;
+
+ /* obsolete
+ print_int_mont("x1", x1);
+ */
+
+ swap = 0;
+ for (i = 254; i >= 0; i --) {
+ uint32_t kt;
+
+ kt = (k[31 - (i >> 3)] >> (i & 7)) & 1;
+ swap ^= kt;
+ cswap(x2, x3, swap);
+ cswap(z2, z3, swap);
+ swap = kt;
+
+ /* obsolete
+ print_int_mont("x2", x2);
+ print_int_mont("z2", z2);
+ print_int_mont("x3", x3);
+ print_int_mont("z3", z3);
+ */
+
+ c255_add(a, x2, z2);
+ c255_mul(aa, a, a);
+ c255_sub(b, x2, z2);
+ c255_mul(bb, b, b);
+ c255_sub(e, aa, bb);
+ c255_add(c, x3, z3);
+ c255_sub(d, x3, z3);
+ c255_mul(da, d, a);
+ c255_mul(cb, c, b);
+
+ /* obsolete
+ print_int_mont("a ", a);
+ print_int_mont("aa", aa);
+ print_int_mont("b ", b);
+ print_int_mont("bb", bb);
+ print_int_mont("e ", e);
+ print_int_mont("c ", c);
+ print_int_mont("d ", d);
+ print_int_mont("da", da);
+ print_int_mont("cb", cb);
+ */
+
+ c255_add(x3, da, cb);
+ c255_mul(x3, x3, x3);
+ c255_sub(z3, da, cb);
+ c255_mul(z3, z3, z3);
+ c255_mul(z3, z3, x1);
+ c255_mul(x2, aa, bb);
+ c255_mul(z2, C255_A24, e);
+ c255_add(z2, z2, aa);
+ c255_mul(z2, e, z2);
+
+ /* obsolete
+ print_int_mont("x2", x2);
+ print_int_mont("z2", z2);
+ print_int_mont("x3", x3);
+ print_int_mont("z3", z3);
+ */
+ }
+ cswap(x2, x3, swap);
+ cswap(z2, z3, swap);
+
+ /*
+ * Inverse z2 with a modular exponentiation. This is a simple
+ * square-and-multiply algorithm; we mutualise most non-squarings
+ * since the exponent contains almost only ones.
+ */
+ memcpy(a, z2, ILEN);
+ for (i = 0; i < 15; i ++) {
+ c255_mul(a, a, a);
+ c255_mul(a, a, z2);
+ }
+ memcpy(b, a, ILEN);
+ for (i = 0; i < 14; i ++) {
+ int j;
+
+ for (j = 0; j < 16; j ++) {
+ c255_mul(b, b, b);
+ }
+ c255_mul(b, b, a);
+ }
+ for (i = 14; i >= 0; i --) {
+ c255_mul(b, b, b);
+ if ((0xFFEB >> i) & 1) {
+ c255_mul(b, z2, b);
+ }
+ }
+ c255_mul(b, x2, b);
+
+ /*
+ * To avoid a dependency on br_i15_from_monty(), we use a
+ * Montgomery multiplication with 1.
+ * memcpy(x2, b, ILEN);
+ * br_i15_from_monty(x2, C255_P, P0I);
+ */
+ br_i15_zero(a, C255_P[0]);
+ a[1] = 1;
+ br_i15_montymul(x2, a, b, C255_P, P0I);
+
+ br_i15_encode(G, 32, x2);
+ byteswap(G);
+ return 1;
+
+#undef ILEN
+}
+
+static size_t
+api_mulgen(unsigned char *R,
+ const unsigned char *x, size_t xlen, int curve)
+{
+ const unsigned char *G;
+ size_t Glen;
+
+ G = api_generator(curve, &Glen);
+ memcpy(R, G, Glen);
+ api_mul(R, Glen, x, xlen, curve);
+ return Glen;
+}
+
+static uint32_t
+api_muladd(unsigned char *A, const unsigned char *B, size_t len,
+ const unsigned char *x, size_t xlen,
+ const unsigned char *y, size_t ylen, int curve)
+{
+ /*
+ * We don't implement this method, since it is used for ECDSA
+ * only, and there is no ECDSA over Curve25519 (which instead
+ * uses EdDSA).
+ */
+ (void)A;
+ (void)B;
+ (void)len;
+ (void)x;
+ (void)xlen;
+ (void)y;
+ (void)ylen;
+ (void)curve;
+ return 0;
+}
+
+/* see bearssl_ec.h */
+const br_ec_impl br_ec_c25519_i15 PROGMEM = {
+ (uint32_t)0x20000000,
+ &api_generator,
+ &api_order,
+ &api_xoff,
+ &api_mul,
+ &api_mulgen,
+ &api_muladd
+};
diff --git a/lib/bearssl-esp8266/src/ec/ec_curve25519.c b/lib/bearssl-esp8266/src/ec/ec_curve25519.c
new file mode 100644
index 000000000..a475035a1
--- /dev/null
+++ b/lib/bearssl-esp8266/src/ec/ec_curve25519.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "t_inner.h"
+
+static const unsigned char GEN[] PROGMEM = {
+ 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static const unsigned char ORDER[] PROGMEM = {
+ 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+};
+
+/* see inner.h */
+const br_ec_curve_def br_curve25519 = {
+ BR_EC_curve25519,
+ ORDER, sizeof ORDER,
+ GEN, sizeof GEN
+};
diff --git a/lib/bearssl-esp8266/src/ec/ec_default.c b/lib/bearssl-esp8266/src/ec/ec_default.c
new file mode 100644
index 000000000..b29d68e33
--- /dev/null
+++ b/lib/bearssl-esp8266/src/ec/ec_default.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "t_inner.h"
+
+/* see bearssl_ec.h */
+const br_ec_impl *
+br_ec_get_default(void)
+{
+#if BR_LOMUL
+ return &br_ec_all_m15;
+#else
+ return &br_ec_all_m31;
+#endif
+}
diff --git a/lib/bearssl-esp8266/src/ec/ec_keygen.c b/lib/bearssl-esp8266/src/ec/ec_keygen.c
new file mode 100644
index 000000000..2c9069d66
--- /dev/null
+++ b/lib/bearssl-esp8266/src/ec/ec_keygen.c
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2018 Thomas Pornin
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "t_inner.h"
+
+/* see bearssl_ec.h */
+size_t
+br_ec_keygen(const br_prng_class **rng_ctx,
+ const br_ec_impl *impl, br_ec_private_key *sk,
+ void *kbuf, int curve)
+{
+ const unsigned char *order;
+ unsigned char *buf;
+ size_t len;
+ unsigned mask;
+
+ if (curve < 0 || curve >= 32
+ || ((impl->supported_curves >> curve) & 1) == 0)
+ {
+ return 0;
+ }
+ order = impl->order(curve, &len);
+ while (len > 0 && *order == 0) {
+ order ++;
+ len --;
+ }
+ if (kbuf == NULL || len == 0) {
+ return len;
+ }
+ mask = order[0];
+ mask |= (mask >> 1);
+ mask |= (mask >> 2);
+ mask |= (mask >> 4);
+
+ /*
+ * We generate sequences of random bits of the right size, until
+ * the value is strictly lower than the curve order (we also
+ * check for all-zero values, which are invalid).
+ */
+ buf = kbuf;
+ for (;;) {
+ size_t u;
+ unsigned cc, zz;
+
+ (*rng_ctx)->generate(rng_ctx, buf, len);
+ buf[0] &= mask;
+ cc = 0;
+ u = len;
+ zz = 0;
+ while (u -- > 0) {
+ cc = ((unsigned)(buf[u] - order[u] - cc) >> 8) & 1;
+ zz |= buf[u];
+ }
+ if (cc != 0 && zz != 0) {
+ break;
+ }
+ }
+
+ if (sk != NULL) {
+ sk->curve = curve;
+ sk->x = buf;
+ sk->xlen = len;
+ }
+ return len;
+}
diff --git a/lib/bearssl-esp8266/src/ec/ec_p256_m15.c b/lib/bearssl-esp8266/src/ec/ec_p256_m15.c
new file mode 100644
index 000000000..e5d76c6b4
--- /dev/null
+++ b/lib/bearssl-esp8266/src/ec/ec_p256_m15.c
@@ -0,0 +1,2117 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "t_inner.h"
+
+/*
+ * If BR_NO_ARITH_SHIFT is undefined, or defined to 0, then we _assume_
+ * that right-shifting a signed negative integer copies the sign bit
+ * (arithmetic right-shift). This is "implementation-defined behaviour",
+ * i.e. it is not undefined, but it may differ between compilers. Each
+ * compiler is supposed to document its behaviour in that respect. GCC
+ * explicitly defines that an arithmetic right shift is used. We expect
+ * all other compilers to do the same, because underlying CPU offer an
+ * arithmetic right shift opcode that could not be used otherwise.
+ */
+#if BR_NO_ARITH_SHIFT
+#define ARSH(x, n) (((uint32_t)(x) >> (n)) \
+ | ((-((uint32_t)(x) >> 31)) << (32 - (n))))
+#else
+#define ARSH(x, n) ((*(int32_t *)&(x)) >> (n))
+#endif
+
+/*
+ * Convert an integer from unsigned big-endian encoding to a sequence of
+ * 13-bit words in little-endian order. The final "partial" word is
+ * returned.
+ */
+static uint32_t
+be8_to_le13(uint32_t *dst, const unsigned char *src, size_t len)
+{
+ uint32_t acc;
+ int acc_len;
+
+ acc = 0;
+ acc_len = 0;
+ while (len -- > 0) {
+ acc |= (uint32_t)src[len] << acc_len;
+ acc_len += 8;
+ if (acc_len >= 13) {
+ *dst ++ = acc & 0x1FFF;
+ acc >>= 13;
+ acc_len -= 13;
+ }
+ }
+ return acc;
+}
+
+/*
+ * Convert an integer (13-bit words, little-endian) to unsigned
+ * big-endian encoding. The total encoding length is provided; all
+ * the destination bytes will be filled.
+ */
+static void
+le13_to_be8(unsigned char *dst, size_t len, const uint32_t *src)
+{
+ uint32_t acc;
+ int acc_len;
+
+ acc = 0;
+ acc_len = 0;
+ while (len -- > 0) {
+ if (acc_len < 8) {
+ acc |= (*src ++) << acc_len;
+ acc_len += 13;
+ }
+ dst[len] = (unsigned char)acc;
+ acc >>= 8;
+ acc_len -= 8;
+ }
+}
+
+/*
+ * Normalise an array of words to a strict 13 bits per word. Returned
+ * value is the resulting carry. The source (w) and destination (d)
+ * arrays may be identical, but shall not overlap partially.
+ */
+static inline uint32_t
+norm13(uint32_t *d, const uint32_t *w, size_t len)
+{
+ size_t u;
+ uint32_t cc;
+
+ cc = 0;
+ for (u = 0; u < len; u ++) {
+ int32_t z;
+
+ z = w[u] + cc;
+ d[u] = z & 0x1FFF;
+ cc = ARSH(z, 13);
+ }
+ return cc;
+}
+
+/*
+ * mul20() multiplies two 260-bit integers together. Each word must fit
+ * on 13 bits; source operands use 20 words, destination operand
+ * receives 40 words. All overlaps allowed.
+ *
+ * square20() computes the square of a 260-bit integer. Each word must
+ * fit on 13 bits; source operand uses 20 words, destination operand
+ * receives 40 words. All overlaps allowed.
+ */
+
+#if BR_SLOW_MUL15
+
+static void
+mul20(uint32_t *d, const uint32_t *a, const uint32_t *b)
+{
+ /*
+ * Two-level Karatsuba: turns a 20x20 multiplication into
+ * nine 5x5 multiplications. We use 13-bit words but do not
+ * propagate carries immediately, so words may expand:
+ *
+ * - First Karatsuba decomposition turns the 20x20 mul on
+ * 13-bit words into three 10x10 muls, two on 13-bit words
+ * and one on 14-bit words.
+ *
+ * - Second Karatsuba decomposition further splits these into:
+ *
+ * * four 5x5 muls on 13-bit words
+ * * four 5x5 muls on 14-bit words
+ * * one 5x5 mul on 15-bit words
+ *
+ * Highest word value is 8191, 16382 or 32764, for 13-bit, 14-bit
+ * or 15-bit words, respectively.
+ */
+ uint32_t u[45], v[45], w[90];
+ uint32_t cc;
+ int i;
+
+#define ZADD(dw, d_off, s1w, s1_off, s2w, s2_off) do { \
+ (dw)[5 * (d_off) + 0] = (s1w)[5 * (s1_off) + 0] \
+ + (s2w)[5 * (s2_off) + 0]; \
+ (dw)[5 * (d_off) + 1] = (s1w)[5 * (s1_off) + 1] \
+ + (s2w)[5 * (s2_off) + 1]; \
+ (dw)[5 * (d_off) + 2] = (s1w)[5 * (s1_off) + 2] \
+ + (s2w)[5 * (s2_off) + 2]; \
+ (dw)[5 * (d_off) + 3] = (s1w)[5 * (s1_off) + 3] \
+ + (s2w)[5 * (s2_off) + 3]; \
+ (dw)[5 * (d_off) + 4] = (s1w)[5 * (s1_off) + 4] \
+ + (s2w)[5 * (s2_off) + 4]; \
+ } while (0)
+
+#define ZADDT(dw, d_off, sw, s_off) do { \
+ (dw)[5 * (d_off) + 0] += (sw)[5 * (s_off) + 0]; \
+ (dw)[5 * (d_off) + 1] += (sw)[5 * (s_off) + 1]; \
+ (dw)[5 * (d_off) + 2] += (sw)[5 * (s_off) + 2]; \
+ (dw)[5 * (d_off) + 3] += (sw)[5 * (s_off) + 3]; \
+ (dw)[5 * (d_off) + 4] += (sw)[5 * (s_off) + 4]; \
+ } while (0)
+
+#define ZSUB2F(dw, d_off, s1w, s1_off, s2w, s2_off) do { \
+ (dw)[5 * (d_off) + 0] -= (s1w)[5 * (s1_off) + 0] \
+ + (s2w)[5 * (s2_off) + 0]; \
+ (dw)[5 * (d_off) + 1] -= (s1w)[5 * (s1_off) + 1] \
+ + (s2w)[5 * (s2_off) + 1]; \
+ (dw)[5 * (d_off) + 2] -= (s1w)[5 * (s1_off) + 2] \
+ + (s2w)[5 * (s2_off) + 2]; \
+ (dw)[5 * (d_off) + 3] -= (s1w)[5 * (s1_off) + 3] \
+ + (s2w)[5 * (s2_off) + 3]; \
+ (dw)[5 * (d_off) + 4] -= (s1w)[5 * (s1_off) + 4] \
+ + (s2w)[5 * (s2_off) + 4]; \
+ } while (0)
+
+#define CPR1(w, cprcc) do { \
+ uint32_t cprz = (w) + cprcc; \
+ (w) = cprz & 0x1FFF; \
+ cprcc = cprz >> 13; \
+ } while (0)
+
+#define CPR(dw, d_off) do { \
+ uint32_t cprcc; \
+ cprcc = 0; \
+ CPR1((dw)[(d_off) + 0], cprcc); \
+ CPR1((dw)[(d_off) + 1], cprcc); \
+ CPR1((dw)[(d_off) + 2], cprcc); \
+ CPR1((dw)[(d_off) + 3], cprcc); \
+ CPR1((dw)[(d_off) + 4], cprcc); \
+ CPR1((dw)[(d_off) + 5], cprcc); \
+ CPR1((dw)[(d_off) + 6], cprcc); \
+ CPR1((dw)[(d_off) + 7], cprcc); \
+ CPR1((dw)[(d_off) + 8], cprcc); \
+ (dw)[(d_off) + 9] = cprcc; \
+ } while (0)
+
+ memcpy(u, a, 20 * sizeof *a);
+ ZADD(u, 4, a, 0, a, 1);
+ ZADD(u, 5, a, 2, a, 3);
+ ZADD(u, 6, a, 0, a, 2);
+ ZADD(u, 7, a, 1, a, 3);
+ ZADD(u, 8, u, 6, u, 7);
+
+ memcpy(v, b, 20 * sizeof *b);
+ ZADD(v, 4, b, 0, b, 1);
+ ZADD(v, 5, b, 2, b, 3);
+ ZADD(v, 6, b, 0, b, 2);
+ ZADD(v, 7, b, 1, b, 3);
+ ZADD(v, 8, v, 6, v, 7);
+
+ /*
+ * Do the eight first 8x8 muls. Source words are at most 16382
+ * each, so we can add product results together "as is" in 32-bit
+ * words.
+ */
+ for (i = 0; i < 40; i += 5) {
+ w[(i << 1) + 0] = MUL15(u[i + 0], v[i + 0]);
+ w[(i << 1) + 1] = MUL15(u[i + 0], v[i + 1])
+ + MUL15(u[i + 1], v[i + 0]);
+ w[(i << 1) + 2] = MUL15(u[i + 0], v[i + 2])
+ + MUL15(u[i + 1], v[i + 1])
+ + MUL15(u[i + 2], v[i + 0]);
+ w[(i << 1) + 3] = MUL15(u[i + 0], v[i + 3])
+ + MUL15(u[i + 1], v[i + 2])
+ + MUL15(u[i + 2], v[i + 1])
+ + MUL15(u[i + 3], v[i + 0]);
+ w[(i << 1) + 4] = MUL15(u[i + 0], v[i + 4])
+ + MUL15(u[i + 1], v[i + 3])
+ + MUL15(u[i + 2], v[i + 2])
+ + MUL15(u[i + 3], v[i + 1])
+ + MUL15(u[i + 4], v[i + 0]);
+ w[(i << 1) + 5] = MUL15(u[i + 1], v[i + 4])
+ + MUL15(u[i + 2], v[i + 3])
+ + MUL15(u[i + 3], v[i + 2])
+ + MUL15(u[i + 4], v[i + 1]);
+ w[(i << 1) + 6] = MUL15(u[i + 2], v[i + 4])
+ + MUL15(u[i + 3], v[i + 3])
+ + MUL15(u[i + 4], v[i + 2]);
+ w[(i << 1) + 7] = MUL15(u[i + 3], v[i + 4])
+ + MUL15(u[i + 4], v[i + 3]);
+ w[(i << 1) + 8] = MUL15(u[i + 4], v[i + 4]);
+ w[(i << 1) + 9] = 0;
+ }
+
+ /*
+ * For the 9th multiplication, source words are up to 32764,
+ * so we must do some carry propagation. If we add up to
+ * 4 products and the carry is no more than 524224, then the
+ * result fits in 32 bits, and the next carry will be no more
+ * than 524224 (because 4*(32764^2)+524224 < 8192*524225).
+ *
+ * We thus just skip one of the products in the middle word,
+ * then do a carry propagation (this reduces words to 13 bits
+ * each, except possibly the last, which may use up to 17 bits
+ * or so), then add the missing product.
+ */
+ w[80 + 0] = MUL15(u[40 + 0], v[40 + 0]);
+ w[80 + 1] = MUL15(u[40 + 0], v[40 + 1])
+ + MUL15(u[40 + 1], v[40 + 0]);
+ w[80 + 2] = MUL15(u[40 + 0], v[40 + 2])
+ + MUL15(u[40 + 1], v[40 + 1])
+ + MUL15(u[40 + 2], v[40 + 0]);
+ w[80 + 3] = MUL15(u[40 + 0], v[40 + 3])
+ + MUL15(u[40 + 1], v[40 + 2])
+ + MUL15(u[40 + 2], v[40 + 1])
+ + MUL15(u[40 + 3], v[40 + 0]);
+ w[80 + 4] = MUL15(u[40 + 0], v[40 + 4])
+ + MUL15(u[40 + 1], v[40 + 3])
+ + MUL15(u[40 + 2], v[40 + 2])
+ + MUL15(u[40 + 3], v[40 + 1]);
+ /* + MUL15(u[40 + 4], v[40 + 0]) */
+ w[80 + 5] = MUL15(u[40 + 1], v[40 + 4])
+ + MUL15(u[40 + 2], v[40 + 3])
+ + MUL15(u[40 + 3], v[40 + 2])
+ + MUL15(u[40 + 4], v[40 + 1]);
+ w[80 + 6] = MUL15(u[40 + 2], v[40 + 4])
+ + MUL15(u[40 + 3], v[40 + 3])
+ + MUL15(u[40 + 4], v[40 + 2]);
+ w[80 + 7] = MUL15(u[40 + 3], v[40 + 4])
+ + MUL15(u[40 + 4], v[40 + 3]);
+ w[80 + 8] = MUL15(u[40 + 4], v[40 + 4]);
+
+ CPR(w, 80);
+
+ w[80 + 4] += MUL15(u[40 + 4], v[40 + 0]);
+
+ /*
+ * The products on 14-bit words in slots 6 and 7 yield values
+ * up to 5*(16382^2) each, and we need to subtract two such
+ * values from the higher word. We need the subtraction to fit
+ * in a _signed_ 32-bit integer, i.e. 31 bits + a sign bit.
+ * However, 10*(16382^2) does not fit. So we must perform a
+ * bit of reduction here.
+ */
+ CPR(w, 60);
+ CPR(w, 70);
+
+ /*
+ * Recompose results.
+ */
+
+ /* 0..1*0..1 into 0..3 */
+ ZSUB2F(w, 8, w, 0, w, 2);
+ ZSUB2F(w, 9, w, 1, w, 3);
+ ZADDT(w, 1, w, 8);
+ ZADDT(w, 2, w, 9);
+
+ /* 2..3*2..3 into 4..7 */
+ ZSUB2F(w, 10, w, 4, w, 6);
+ ZSUB2F(w, 11, w, 5, w, 7);
+ ZADDT(w, 5, w, 10);
+ ZADDT(w, 6, w, 11);
+
+ /* (0..1+2..3)*(0..1+2..3) into 12..15 */
+ ZSUB2F(w, 16, w, 12, w, 14);
+ ZSUB2F(w, 17, w, 13, w, 15);
+ ZADDT(w, 13, w, 16);
+ ZADDT(w, 14, w, 17);
+
+ /* first-level recomposition */
+ ZSUB2F(w, 12, w, 0, w, 4);
+ ZSUB2F(w, 13, w, 1, w, 5);
+ ZSUB2F(w, 14, w, 2, w, 6);
+ ZSUB2F(w, 15, w, 3, w, 7);
+ ZADDT(w, 2, w, 12);
+ ZADDT(w, 3, w, 13);
+ ZADDT(w, 4, w, 14);
+ ZADDT(w, 5, w, 15);
+
+ /*
+ * Perform carry propagation to bring all words down to 13 bits.
+ */
+ cc = norm13(d, w, 40);
+ d[39] += (cc << 13);
+
+#undef ZADD
+#undef ZADDT
+#undef ZSUB2F
+#undef CPR1
+#undef CPR
+}
+
+static inline void
+square20(uint32_t *d, const uint32_t *a)
+{
+ mul20(d, a, a);
+}
+
+#else
+extern void mul20(uint32_t *d, const uint32_t *a, const uint32_t *b);
+extern void square20(uint32_t *d, const uint32_t *a);
+
+#if 0
+static void
+mul20(uint32_t *d, const uint32_t *a, const uint32_t *b)
+{
+ uint32_t t[39];
+
+ t[ 0] = MUL15(a[ 0], b[ 0]);
+ t[ 1] = MUL15(a[ 0], b[ 1])
+ + MUL15(a[ 1], b[ 0]);
+ t[ 2] = MUL15(a[ 0], b[ 2])
+ + MUL15(a[ 1], b[ 1])
+ + MUL15(a[ 2], b[ 0]);
+ t[ 3] = MUL15(a[ 0], b[ 3])
+ + MUL15(a[ 1], b[ 2])
+ + MUL15(a[ 2], b[ 1])
+ + MUL15(a[ 3], b[ 0]);
+ t[ 4] = MUL15(a[ 0], b[ 4])
+ + MUL15(a[ 1], b[ 3])
+ + MUL15(a[ 2], b[ 2])
+ + MUL15(a[ 3], b[ 1])
+ + MUL15(a[ 4], b[ 0]);
+ t[ 5] = MUL15(a[ 0], b[ 5])
+ + MUL15(a[ 1], b[ 4])
+ + MUL15(a[ 2], b[ 3])
+ + MUL15(a[ 3], b[ 2])
+ + MUL15(a[ 4], b[ 1])
+ + MUL15(a[ 5], b[ 0]);
+ t[ 6] = MUL15(a[ 0], b[ 6])
+ + MUL15(a[ 1], b[ 5])
+ + MUL15(a[ 2], b[ 4])
+ + MUL15(a[ 3], b[ 3])
+ + MUL15(a[ 4], b[ 2])
+ + MUL15(a[ 5], b[ 1])
+ + MUL15(a[ 6], b[ 0]);
+ t[ 7] = MUL15(a[ 0], b[ 7])
+ + MUL15(a[ 1], b[ 6])
+ + MUL15(a[ 2], b[ 5])
+ + MUL15(a[ 3], b[ 4])
+ + MUL15(a[ 4], b[ 3])
+ + MUL15(a[ 5], b[ 2])
+ + MUL15(a[ 6], b[ 1])
+ + MUL15(a[ 7], b[ 0]);
+ t[ 8] = MUL15(a[ 0], b[ 8])
+ + MUL15(a[ 1], b[ 7])
+ + MUL15(a[ 2], b[ 6])
+ + MUL15(a[ 3], b[ 5])
+ + MUL15(a[ 4], b[ 4])
+ + MUL15(a[ 5], b[ 3])
+ + MUL15(a[ 6], b[ 2])
+ + MUL15(a[ 7], b[ 1])
+ + MUL15(a[ 8], b[ 0]);
+ t[ 9] = MUL15(a[ 0], b[ 9])
+ + MUL15(a[ 1], b[ 8])
+ + MUL15(a[ 2], b[ 7])
+ + MUL15(a[ 3], b[ 6])
+ + MUL15(a[ 4], b[ 5])
+ + MUL15(a[ 5], b[ 4])
+ + MUL15(a[ 6], b[ 3])
+ + MUL15(a[ 7], b[ 2])
+ + MUL15(a[ 8], b[ 1])
+ + MUL15(a[ 9], b[ 0]);
+ t[10] = MUL15(a[ 0], b[10])
+ + MUL15(a[ 1], b[ 9])
+ + MUL15(a[ 2], b[ 8])
+ + MUL15(a[ 3], b[ 7])
+ + MUL15(a[ 4], b[ 6])
+ + MUL15(a[ 5], b[ 5])
+ + MUL15(a[ 6], b[ 4])
+ + MUL15(a[ 7], b[ 3])
+ + MUL15(a[ 8], b[ 2])
+ + MUL15(a[ 9], b[ 1])
+ + MUL15(a[10], b[ 0]);
+ t[11] = MUL15(a[ 0], b[11])
+ + MUL15(a[ 1], b[10])
+ + MUL15(a[ 2], b[ 9])
+ + MUL15(a[ 3], b[ 8])
+ + MUL15(a[ 4], b[ 7])
+ + MUL15(a[ 5], b[ 6])
+ + MUL15(a[ 6], b[ 5])
+ + MUL15(a[ 7], b[ 4])
+ + MUL15(a[ 8], b[ 3])
+ + MUL15(a[ 9], b[ 2])
+ + MUL15(a[10], b[ 1])
+ + MUL15(a[11], b[ 0]);
+ t[12] = MUL15(a[ 0], b[12])
+ + MUL15(a[ 1], b[11])
+ + MUL15(a[ 2], b[10])
+ + MUL15(a[ 3], b[ 9])
+ + MUL15(a[ 4], b[ 8])
+ + MUL15(a[ 5], b[ 7])
+ + MUL15(a[ 6], b[ 6])
+ + MUL15(a[ 7], b[ 5])
+ + MUL15(a[ 8], b[ 4])
+ + MUL15(a[ 9], b[ 3])
+ + MUL15(a[10], b[ 2])
+ + MUL15(a[11], b[ 1])
+ + MUL15(a[12], b[ 0]);
+ t[13] = MUL15(a[ 0], b[13])
+ + MUL15(a[ 1], b[12])
+ + MUL15(a[ 2], b[11])
+ + MUL15(a[ 3], b[10])
+ + MUL15(a[ 4], b[ 9])
+ + MUL15(a[ 5], b[ 8])
+ + MUL15(a[ 6], b[ 7])
+ + MUL15(a[ 7], b[ 6])
+ + MUL15(a[ 8], b[ 5])
+ + MUL15(a[ 9], b[ 4])
+ + MUL15(a[10], b[ 3])
+ + MUL15(a[11], b[ 2])
+ + MUL15(a[12], b[ 1])
+ + MUL15(a[13], b[ 0]);
+ t[14] = MUL15(a[ 0], b[14])
+ + MUL15(a[ 1], b[13])
+ + MUL15(a[ 2], b[12])
+ + MUL15(a[ 3], b[11])
+ + MUL15(a[ 4], b[10])
+ + MUL15(a[ 5], b[ 9])
+ + MUL15(a[ 6], b[ 8])
+ + MUL15(a[ 7], b[ 7])
+ + MUL15(a[ 8], b[ 6])
+ + MUL15(a[ 9], b[ 5])
+ + MUL15(a[10], b[ 4])
+ + MUL15(a[11], b[ 3])
+ + MUL15(a[12], b[ 2])
+ + MUL15(a[13], b[ 1])
+ + MUL15(a[14], b[ 0]);
+ t[15] = MUL15(a[ 0], b[15])
+ + MUL15(a[ 1], b[14])
+ + MUL15(a[ 2], b[13])
+ + MUL15(a[ 3], b[12])
+ + MUL15(a[ 4], b[11])
+ + MUL15(a[ 5], b[10])
+ + MUL15(a[ 6], b[ 9])
+ + MUL15(a[ 7], b[ 8])
+ + MUL15(a[ 8], b[ 7])
+ + MUL15(a[ 9], b[ 6])
+ + MUL15(a[10], b[ 5])
+ + MUL15(a[11], b[ 4])
+ + MUL15(a[12], b[ 3])
+ + MUL15(a[13], b[ 2])
+ + MUL15(a[14], b[ 1])
+ + MUL15(a[15], b[ 0]);
+ t[16] = MUL15(a[ 0], b[16])
+ + MUL15(a[ 1], b[15])
+ + MUL15(a[ 2], b[14])
+ + MUL15(a[ 3], b[13])
+ + MUL15(a[ 4], b[12])
+ + MUL15(a[ 5], b[11])
+ + MUL15(a[ 6], b[10])
+ + MUL15(a[ 7], b[ 9])
+ + MUL15(a[ 8], b[ 8])
+ + MUL15(a[ 9], b[ 7])
+ + MUL15(a[10], b[ 6])
+ + MUL15(a[11], b[ 5])
+ + MUL15(a[12], b[ 4])
+ + MUL15(a[13], b[ 3])
+ + MUL15(a[14], b[ 2])
+ + MUL15(a[15], b[ 1])
+ + MUL15(a[16], b[ 0]);
+ t[17] = MUL15(a[ 0], b[17])
+ + MUL15(a[ 1], b[16])
+ + MUL15(a[ 2], b[15])
+ + MUL15(a[ 3], b[14])
+ + MUL15(a[ 4], b[13])
+ + MUL15(a[ 5], b[12])
+ + MUL15(a[ 6], b[11])
+ + MUL15(a[ 7], b[10])
+ + MUL15(a[ 8], b[ 9])
+ + MUL15(a[ 9], b[ 8])
+ + MUL15(a[10], b[ 7])
+ + MUL15(a[11], b[ 6])
+ + MUL15(a[12], b[ 5])
+ + MUL15(a[13], b[ 4])
+ + MUL15(a[14], b[ 3])
+ + MUL15(a[15], b[ 2])
+ + MUL15(a[16], b[ 1])
+ + MUL15(a[17], b[ 0]);
+ t[18] = MUL15(a[ 0], b[18])
+ + MUL15(a[ 1], b[17])
+ + MUL15(a[ 2], b[16])
+ + MUL15(a[ 3], b[15])
+ + MUL15(a[ 4], b[14])
+ + MUL15(a[ 5], b[13])
+ + MUL15(a[ 6], b[12])
+ + MUL15(a[ 7], b[11])
+ + MUL15(a[ 8], b[10])
+ + MUL15(a[ 9], b[ 9])
+ + MUL15(a[10], b[ 8])
+ + MUL15(a[11], b[ 7])
+ + MUL15(a[12], b[ 6])
+ + MUL15(a[13], b[ 5])
+ + MUL15(a[14], b[ 4])
+ + MUL15(a[15], b[ 3])
+ + MUL15(a[16], b[ 2])
+ + MUL15(a[17], b[ 1])
+ + MUL15(a[18], b[ 0]);
+ t[19] = MUL15(a[ 0], b[19])
+ + MUL15(a[ 1], b[18])
+ + MUL15(a[ 2], b[17])
+ + MUL15(a[ 3], b[16])
+ + MUL15(a[ 4], b[15])
+ + MUL15(a[ 5], b[14])
+ + MUL15(a[ 6], b[13])
+ + MUL15(a[ 7], b[12])
+ + MUL15(a[ 8], b[11])
+ + MUL15(a[ 9], b[10])
+ + MUL15(a[10], b[ 9])
+ + MUL15(a[11], b[ 8])
+ + MUL15(a[12], b[ 7])
+ + MUL15(a[13], b[ 6])
+ + MUL15(a[14], b[ 5])
+ + MUL15(a[15], b[ 4])
+ + MUL15(a[16], b[ 3])
+ + MUL15(a[17], b[ 2])
+ + MUL15(a[18], b[ 1])
+ + MUL15(a[19], b[ 0]);
+ t[20] = MUL15(a[ 1], b[19])
+ + MUL15(a[ 2], b[18])
+ + MUL15(a[ 3], b[17])
+ + MUL15(a[ 4], b[16])
+ + MUL15(a[ 5], b[15])
+ + MUL15(a[ 6], b[14])
+ + MUL15(a[ 7], b[13])
+ + MUL15(a[ 8], b[12])
+ + MUL15(a[ 9], b[11])
+ + MUL15(a[10], b[10])
+ + MUL15(a[11], b[ 9])
+ + MUL15(a[12], b[ 8])
+ + MUL15(a[13], b[ 7])
+ + MUL15(a[14], b[ 6])
+ + MUL15(a[15], b[ 5])
+ + MUL15(a[16], b[ 4])
+ + MUL15(a[17], b[ 3])
+ + MUL15(a[18], b[ 2])
+ + MUL15(a[19], b[ 1]);
+ t[21] = MUL15(a[ 2], b[19])
+ + MUL15(a[ 3], b[18])
+ + MUL15(a[ 4], b[17])
+ + MUL15(a[ 5], b[16])
+ + MUL15(a[ 6], b[15])
+ + MUL15(a[ 7], b[14])
+ + MUL15(a[ 8], b[13])
+ + MUL15(a[ 9], b[12])
+ + MUL15(a[10], b[11])
+ + MUL15(a[11], b[10])
+ + MUL15(a[12], b[ 9])
+ + MUL15(a[13], b[ 8])
+ + MUL15(a[14], b[ 7])
+ + MUL15(a[15], b[ 6])
+ + MUL15(a[16], b[ 5])
+ + MUL15(a[17], b[ 4])
+ + MUL15(a[18], b[ 3])
+ + MUL15(a[19], b[ 2]);
+ t[22] = MUL15(a[ 3], b[19])
+ + MUL15(a[ 4], b[18])
+ + MUL15(a[ 5], b[17])
+ + MUL15(a[ 6], b[16])
+ + MUL15(a[ 7], b[15])
+ + MUL15(a[ 8], b[14])
+ + MUL15(a[ 9], b[13])
+ + MUL15(a[10], b[12])
+ + MUL15(a[11], b[11])
+ + MUL15(a[12], b[10])
+ + MUL15(a[13], b[ 9])
+ + MUL15(a[14], b[ 8])
+ + MUL15(a[15], b[ 7])
+ + MUL15(a[16], b[ 6])
+ + MUL15(a[17], b[ 5])
+ + MUL15(a[18], b[ 4])
+ + MUL15(a[19], b[ 3]);
+ t[23] = MUL15(a[ 4], b[19])
+ + MUL15(a[ 5], b[18])
+ + MUL15(a[ 6], b[17])
+ + MUL15(a[ 7], b[16])
+ + MUL15(a[ 8], b[15])
+ + MUL15(a[ 9], b[14])
+ + MUL15(a[10], b[13])
+ + MUL15(a[11], b[12])
+ + MUL15(a[12], b[11])
+ + MUL15(a[13], b[10])
+ + MUL15(a[14], b[ 9])
+ + MUL15(a[15], b[ 8])
+ + MUL15(a[16], b[ 7])
+ + MUL15(a[17], b[ 6])
+ + MUL15(a[18], b[ 5])
+ + MUL15(a[19], b[ 4]);
+ t[24] = MUL15(a[ 5], b[19])
+ + MUL15(a[ 6], b[18])
+ + MUL15(a[ 7], b[17])
+ + MUL15(a[ 8], b[16])
+ + MUL15(a[ 9], b[15])
+ + MUL15(a[10], b[14])
+ + MUL15(a[11], b[13])
+ + MUL15(a[12], b[12])
+ + MUL15(a[13], b[11])
+ + MUL15(a[14], b[10])
+ + MUL15(a[15], b[ 9])
+ + MUL15(a[16], b[ 8])
+ + MUL15(a[17], b[ 7])
+ + MUL15(a[18], b[ 6])
+ + MUL15(a[19], b[ 5]);
+ t[25] = MUL15(a[ 6], b[19])
+ + MUL15(a[ 7], b[18])
+ + MUL15(a[ 8], b[17])
+ + MUL15(a[ 9], b[16])
+ + MUL15(a[10], b[15])
+ + MUL15(a[11], b[14])
+ + MUL15(a[12], b[13])
+ + MUL15(a[13], b[12])
+ + MUL15(a[14], b[11])
+ + MUL15(a[15], b[10])
+ + MUL15(a[16], b[ 9])
+ + MUL15(a[17], b[ 8])
+ + MUL15(a[18], b[ 7])
+ + MUL15(a[19], b[ 6]);
+ t[26] = MUL15(a[ 7], b[19])
+ + MUL15(a[ 8], b[18])
+ + MUL15(a[ 9], b[17])
+ + MUL15(a[10], b[16])
+ + MUL15(a[11], b[15])
+ + MUL15(a[12], b[14])
+ + MUL15(a[13], b[13])
+ + MUL15(a[14], b[12])
+ + MUL15(a[15], b[11])
+ + MUL15(a[16], b[10])
+ + MUL15(a[17], b[ 9])
+ + MUL15(a[18], b[ 8])
+ + MUL15(a[19], b[ 7]);
+ t[27] = MUL15(a[ 8], b[19])
+ + MUL15(a[ 9], b[18])
+ + MUL15(a[10], b[17])
+ + MUL15(a[11], b[16])
+ + MUL15(a[12], b[15])
+ + MUL15(a[13], b[14])
+ + MUL15(a[14], b[13])
+ + MUL15(a[15], b[12])
+ + MUL15(a[16], b[11])
+ + MUL15(a[17], b[10])
+ + MUL15(a[18], b[ 9])
+ + MUL15(a[19], b[ 8]);
+ t[28] = MUL15(a[ 9], b[19])
+ + MUL15(a[10], b[18])
+ + MUL15(a[11], b[17])
+ + MUL15(a[12], b[16])
+ + MUL15(a[13], b[15])
+ + MUL15(a[14], b[14])
+ + MUL15(a[15], b[13])
+ + MUL15(a[16], b[12])
+ + MUL15(a[17], b[11])
+ + MUL15(a[18], b[10])
+ + MUL15(a[19], b[ 9]);
+ t[29] = MUL15(a[10], b[19])
+ + MUL15(a[11], b[18])
+ + MUL15(a[12], b[17])
+ + MUL15(a[13], b[16])
+ + MUL15(a[14], b[15])
+ + MUL15(a[15], b[14])
+ + MUL15(a[16], b[13])
+ + MUL15(a[17], b[12])
+ + MUL15(a[18], b[11])
+ + MUL15(a[19], b[10]);
+ t[30] = MUL15(a[11], b[19])
+ + MUL15(a[12], b[18])
+ + MUL15(a[13], b[17])
+ + MUL15(a[14], b[16])
+ + MUL15(a[15], b[15])
+ + MUL15(a[16], b[14])
+ + MUL15(a[17], b[13])
+ + MUL15(a[18], b[12])
+ + MUL15(a[19], b[11]);
+ t[31] = MUL15(a[12], b[19])
+ + MUL15(a[13], b[18])
+ + MUL15(a[14], b[17])
+ + MUL15(a[15], b[16])
+ + MUL15(a[16], b[15])
+ + MUL15(a[17], b[14])
+ + MUL15(a[18], b[13])
+ + MUL15(a[19], b[12]);
+ t[32] = MUL15(a[13], b[19])
+ + MUL15(a[14], b[18])
+ + MUL15(a[15], b[17])
+ + MUL15(a[16], b[16])
+ + MUL15(a[17], b[15])
+ + MUL15(a[18], b[14])
+ + MUL15(a[19], b[13]);
+ t[33] = MUL15(a[14], b[19])
+ + MUL15(a[15], b[18])
+ + MUL15(a[16], b[17])
+ + MUL15(a[17], b[16])
+ + MUL15(a[18], b[15])
+ + MUL15(a[19], b[14]);
+ t[34] = MUL15(a[15], b[19])
+ + MUL15(a[16], b[18])
+ + MUL15(a[17], b[17])
+ + MUL15(a[18], b[16])
+ + MUL15(a[19], b[15]);
+ t[35] = MUL15(a[16], b[19])
+ + MUL15(a[17], b[18])
+ + MUL15(a[18], b[17])
+ + MUL15(a[19], b[16]);
+ t[36] = MUL15(a[17], b[19])
+ + MUL15(a[18], b[18])
+ + MUL15(a[19], b[17]);
+ t[37] = MUL15(a[18], b[19])
+ + MUL15(a[19], b[18]);
+ t[38] = MUL15(a[19], b[19]);
+ d[39] = norm13(d, t, 39);
+}
+
+static void
+square20(uint32_t *d, const uint32_t *a)
+{
+ uint32_t t[39];
+
+ t[ 0] = MUL15(a[ 0], a[ 0]);
+ t[ 1] = ((MUL15(a[ 0], a[ 1])) << 1);
+ t[ 2] = MUL15(a[ 1], a[ 1])
+ + ((MUL15(a[ 0], a[ 2])) << 1);
+ t[ 3] = ((MUL15(a[ 0], a[ 3])
+ + MUL15(a[ 1], a[ 2])) << 1);
+ t[ 4] = MUL15(a[ 2], a[ 2])
+ + ((MUL15(a[ 0], a[ 4])
+ + MUL15(a[ 1], a[ 3])) << 1);
+ t[ 5] = ((MUL15(a[ 0], a[ 5])
+ + MUL15(a[ 1], a[ 4])
+ + MUL15(a[ 2], a[ 3])) << 1);
+ t[ 6] = MUL15(a[ 3], a[ 3])
+ + ((MUL15(a[ 0], a[ 6])
+ + MUL15(a[ 1], a[ 5])
+ + MUL15(a[ 2], a[ 4])) << 1);
+ t[ 7] = ((MUL15(a[ 0], a[ 7])
+ + MUL15(a[ 1], a[ 6])
+ + MUL15(a[ 2], a[ 5])
+ + MUL15(a[ 3], a[ 4])) << 1);
+ t[ 8] = MUL15(a[ 4], a[ 4])
+ + ((MUL15(a[ 0], a[ 8])
+ + MUL15(a[ 1], a[ 7])
+ + MUL15(a[ 2], a[ 6])
+ + MUL15(a[ 3], a[ 5])) << 1);
+ t[ 9] = ((MUL15(a[ 0], a[ 9])
+ + MUL15(a[ 1], a[ 8])
+ + MUL15(a[ 2], a[ 7])
+ + MUL15(a[ 3], a[ 6])
+ + MUL15(a[ 4], a[ 5])) << 1);
+ t[10] = MUL15(a[ 5], a[ 5])
+ + ((MUL15(a[ 0], a[10])
+ + MUL15(a[ 1], a[ 9])
+ + MUL15(a[ 2], a[ 8])
+ + MUL15(a[ 3], a[ 7])
+ + MUL15(a[ 4], a[ 6])) << 1);
+ t[11] = ((MUL15(a[ 0], a[11])
+ + MUL15(a[ 1], a[10])
+ + MUL15(a[ 2], a[ 9])
+ + MUL15(a[ 3], a[ 8])
+ + MUL15(a[ 4], a[ 7])
+ + MUL15(a[ 5], a[ 6])) << 1);
+ t[12] = MUL15(a[ 6], a[ 6])
+ + ((MUL15(a[ 0], a[12])
+ + MUL15(a[ 1], a[11])
+ + MUL15(a[ 2], a[10])
+ + MUL15(a[ 3], a[ 9])
+ + MUL15(a[ 4], a[ 8])
+ + MUL15(a[ 5], a[ 7])) << 1);
+ t[13] = ((MUL15(a[ 0], a[13])
+ + MUL15(a[ 1], a[12])
+ + MUL15(a[ 2], a[11])
+ + MUL15(a[ 3], a[10])
+ + MUL15(a[ 4], a[ 9])
+ + MUL15(a[ 5], a[ 8])
+ + MUL15(a[ 6], a[ 7])) << 1);
+ t[14] = MUL15(a[ 7], a[ 7])
+ + ((MUL15(a[ 0], a[14])
+ + MUL15(a[ 1], a[13])
+ + MUL15(a[ 2], a[12])
+ + MUL15(a[ 3], a[11])
+ + MUL15(a[ 4], a[10])
+ + MUL15(a[ 5], a[ 9])
+ + MUL15(a[ 6], a[ 8])) << 1);
+ t[15] = ((MUL15(a[ 0], a[15])
+ + MUL15(a[ 1], a[14])
+ + MUL15(a[ 2], a[13])
+ + MUL15(a[ 3], a[12])
+ + MUL15(a[ 4], a[11])
+ + MUL15(a[ 5], a[10])
+ + MUL15(a[ 6], a[ 9])
+ + MUL15(a[ 7], a[ 8])) << 1);
+ t[16] = MUL15(a[ 8], a[ 8])
+ + ((MUL15(a[ 0], a[16])
+ + MUL15(a[ 1], a[15])
+ + MUL15(a[ 2], a[14])
+ + MUL15(a[ 3], a[13])
+ + MUL15(a[ 4], a[12])
+ + MUL15(a[ 5], a[11])
+ + MUL15(a[ 6], a[10])
+ + MUL15(a[ 7], a[ 9])) << 1);
+ t[17] = ((MUL15(a[ 0], a[17])
+ + MUL15(a[ 1], a[16])
+ + MUL15(a[ 2], a[15])
+ + MUL15(a[ 3], a[14])
+ + MUL15(a[ 4], a[13])
+ + MUL15(a[ 5], a[12])
+ + MUL15(a[ 6], a[11])
+ + MUL15(a[ 7], a[10])
+ + MUL15(a[ 8], a[ 9])) << 1);
+ t[18] = MUL15(a[ 9], a[ 9])
+ + ((MUL15(a[ 0], a[18])
+ + MUL15(a[ 1], a[17])
+ + MUL15(a[ 2], a[16])
+ + MUL15(a[ 3], a[15])
+ + MUL15(a[ 4], a[14])
+ + MUL15(a[ 5], a[13])
+ + MUL15(a[ 6], a[12])
+ + MUL15(a[ 7], a[11])
+ + MUL15(a[ 8], a[10])) << 1);
+ t[19] = ((MUL15(a[ 0], a[19])
+ + MUL15(a[ 1], a[18])
+ + MUL15(a[ 2], a[17])
+ + MUL15(a[ 3], a[16])
+ + MUL15(a[ 4], a[15])
+ + MUL15(a[ 5], a[14])
+ + MUL15(a[ 6], a[13])
+ + MUL15(a[ 7], a[12])
+ + MUL15(a[ 8], a[11])
+ + MUL15(a[ 9], a[10])) << 1);
+ t[20] = MUL15(a[10], a[10])
+ + ((MUL15(a[ 1], a[19])
+ + MUL15(a[ 2], a[18])
+ + MUL15(a[ 3], a[17])
+ + MUL15(a[ 4], a[16])
+ + MUL15(a[ 5], a[15])
+ + MUL15(a[ 6], a[14])
+ + MUL15(a[ 7], a[13])
+ + MUL15(a[ 8], a[12])
+ + MUL15(a[ 9], a[11])) << 1);
+ t[21] = ((MUL15(a[ 2], a[19])
+ + MUL15(a[ 3], a[18])
+ + MUL15(a[ 4], a[17])
+ + MUL15(a[ 5], a[16])
+ + MUL15(a[ 6], a[15])
+ + MUL15(a[ 7], a[14])
+ + MUL15(a[ 8], a[13])
+ + MUL15(a[ 9], a[12])
+ + MUL15(a[10], a[11])) << 1);
+ t[22] = MUL15(a[11], a[11])
+ + ((MUL15(a[ 3], a[19])
+ + MUL15(a[ 4], a[18])
+ + MUL15(a[ 5], a[17])
+ + MUL15(a[ 6], a[16])
+ + MUL15(a[ 7], a[15])
+ + MUL15(a[ 8], a[14])
+ + MUL15(a[ 9], a[13])
+ + MUL15(a[10], a[12])) << 1);
+ t[23] = ((MUL15(a[ 4], a[19])
+ + MUL15(a[ 5], a[18])
+ + MUL15(a[ 6], a[17])
+ + MUL15(a[ 7], a[16])
+ + MUL15(a[ 8], a[15])
+ + MUL15(a[ 9], a[14])
+ + MUL15(a[10], a[13])
+ + MUL15(a[11], a[12])) << 1);
+ t[24] = MUL15(a[12], a[12])
+ + ((MUL15(a[ 5], a[19])
+ + MUL15(a[ 6], a[18])
+ + MUL15(a[ 7], a[17])
+ + MUL15(a[ 8], a[16])
+ + MUL15(a[ 9], a[15])
+ + MUL15(a[10], a[14])
+ + MUL15(a[11], a[13])) << 1);
+ t[25] = ((MUL15(a[ 6], a[19])
+ + MUL15(a[ 7], a[18])
+ + MUL15(a[ 8], a[17])
+ + MUL15(a[ 9], a[16])
+ + MUL15(a[10], a[15])
+ + MUL15(a[11], a[14])
+ + MUL15(a[12], a[13])) << 1);
+ t[26] = MUL15(a[13], a[13])
+ + ((MUL15(a[ 7], a[19])
+ + MUL15(a[ 8], a[18])
+ + MUL15(a[ 9], a[17])
+ + MUL15(a[10], a[16])
+ + MUL15(a[11], a[15])
+ + MUL15(a[12], a[14])) << 1);
+ t[27] = ((MUL15(a[ 8], a[19])
+ + MUL15(a[ 9], a[18])
+ + MUL15(a[10], a[17])
+ + MUL15(a[11], a[16])
+ + MUL15(a[12], a[15])
+ + MUL15(a[13], a[14])) << 1);
+ t[28] = MUL15(a[14], a[14])
+ + ((MUL15(a[ 9], a[19])
+ + MUL15(a[10], a[18])
+ + MUL15(a[11], a[17])
+ + MUL15(a[12], a[16])
+ + MUL15(a[13], a[15])) << 1);
+ t[29] = ((MUL15(a[10], a[19])
+ + MUL15(a[11], a[18])
+ + MUL15(a[12], a[17])
+ + MUL15(a[13], a[16])
+ + MUL15(a[14], a[15])) << 1);
+ t[30] = MUL15(a[15], a[15])
+ + ((MUL15(a[11], a[19])
+ + MUL15(a[12], a[18])
+ + MUL15(a[13], a[17])
+ + MUL15(a[14], a[16])) << 1);
+ t[31] = ((MUL15(a[12], a[19])
+ + MUL15(a[13], a[18])
+ + MUL15(a[14], a[17])
+ + MUL15(a[15], a[16])) << 1);
+ t[32] = MUL15(a[16], a[16])
+ + ((MUL15(a[13], a[19])
+ + MUL15(a[14], a[18])
+ + MUL15(a[15], a[17])) << 1);
+ t[33] = ((MUL15(a[14], a[19])
+ + MUL15(a[15], a[18])
+ + MUL15(a[16], a[17])) << 1);
+ t[34] = MUL15(a[17], a[17])
+ + ((MUL15(a[15], a[19])
+ + MUL15(a[16], a[18])) << 1);
+ t[35] = ((MUL15(a[16], a[19])
+ + MUL15(a[17], a[18])) << 1);
+ t[36] = MUL15(a[18], a[18])
+ + ((MUL15(a[17], a[19])) << 1);
+ t[37] = ((MUL15(a[18], a[19])) << 1);
+ t[38] = MUL15(a[19], a[19]);
+ d[39] = norm13(d, t, 39);
+}
+#endif
+
+#endif
+
+/*
+ * Modulus for field F256 (field for point coordinates in curve P-256).
+ */
+static const uint32_t F256[] PROGMEM = {
+ 0x1FFF, 0x1FFF, 0x1FFF, 0x1FFF, 0x1FFF, 0x1FFF, 0x1FFF, 0x001F,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0400, 0x0000,
+ 0x0000, 0x1FF8, 0x1FFF, 0x01FF
+};
+
+/*
+ * The 'b' curve equation coefficient for P-256.
+ */
+static const uint32_t P256_B[] PROGMEM = {
+ 0x004B, 0x1E93, 0x0F89, 0x1C78, 0x03BC, 0x187B, 0x114E, 0x1619,
+ 0x1D06, 0x0328, 0x01AF, 0x0D31, 0x1557, 0x15DE, 0x1ECF, 0x127C,
+ 0x0A3A, 0x0EC5, 0x118D, 0x00B5
+};
+
+/*
+ * Perform a "short reduction" in field F256 (field for curve P-256).
+ * The source value should be less than 262 bits; on output, it will
+ * be at most 257 bits, and less than twice the modulus.
+ */
+static void
+reduce_f256(uint32_t *d)
+{
+ uint32_t x;
+
+ x = d[19] >> 9;
+ d[19] &= 0x01FF;
+ d[17] += x << 3;
+ d[14] -= x << 10;
+ d[7] -= x << 5;
+ d[0] += x;
+ norm13(d, d, 20);
+}
+
+/*
+ * Perform a "final reduction" in field F256 (field for curve P-256).
+ * The source value must be less than twice the modulus. If the value
+ * is not lower than the modulus, then the modulus is subtracted and
+ * this function returns 1; otherwise, it leaves it untouched and it
+ * returns 0.
+ */
+static uint32_t
+reduce_final_f256(uint32_t *d)
+{
+ uint32_t t[20];
+ uint32_t cc;
+ int i;
+
+ memcpy(t, d, sizeof t);
+ cc = 0;
+ for (i = 0; i < 20; i ++) {
+ uint32_t w;
+
+ w = t[i] - F256[i] - cc;
+ cc = w >> 31;
+ t[i] = w & 0x1FFF;
+ }
+ cc ^= 1;
+ CCOPY(cc, d, t, sizeof t);
+ return cc;
+}
+
+/*
+ * Perform a multiplication of two integers modulo
+ * 2^256-2^224+2^192+2^96-1 (for NIST curve P-256). Operands are arrays
+ * of 20 words, each containing 13 bits of data, in little-endian order.
+ * On input, upper word may be up to 13 bits (hence value up to 2^260-1);
+ * on output, value fits on 257 bits and is lower than twice the modulus.
+ */
+static void
+mul_f256(uint32_t *d, const uint32_t *a, const uint32_t *b)
+{
+ uint32_t t[40], cc;
+ int i;
+
+ /*
+ * Compute raw multiplication. All result words fit in 13 bits
+ * each.
+ */
+ mul20(t, a, b);
+
+ /*
+ * Modular reduction: each high word in added/subtracted where
+ * necessary.
+ *
+ * The modulus is:
+ * p = 2^256 - 2^224 + 2^192 + 2^96 - 1
+ * Therefore:
+ * 2^256 = 2^224 - 2^192 - 2^96 + 1 mod p
+ *
+ * For a word x at bit offset n (n >= 256), we have:
+ * x*2^n = x*2^(n-32) - x*2^(n-64)
+ * - x*2^(n - 160) + x*2^(n-256) mod p
+ *
+ * Thus, we can nullify the high word if we reinject it at some
+ * proper emplacements.
+ */
+ for (i = 39; i >= 20; i --) {
+ uint32_t x;
+
+ x = t[i];
+ t[i - 2] += ARSH(x, 6);
+ t[i - 3] += (x << 7) & 0x1FFF;
+ t[i - 4] -= ARSH(x, 12);
+ t[i - 5] -= (x << 1) & 0x1FFF;
+ t[i - 12] -= ARSH(x, 4);
+ t[i - 13] -= (x << 9) & 0x1FFF;
+ t[i - 19] += ARSH(x, 9);
+ t[i - 20] += (x << 4) & 0x1FFF;
+ }
+
+ /*
+ * Propagate carries. This is a signed propagation, and the
+ * result may be negative. The loop above may enlarge values,
+ * but not two much: worst case is the chain involving t[i - 3],
+ * in which a value may be added to itself up to 7 times. Since
+ * starting values are 13-bit each, all words fit on 20 bits
+ * (21 to account for the sign bit).
+ */
+ cc = norm13(t, t, 20);
+
+ /*
+ * Perform modular reduction again for the bits beyond 256 (the carry
+ * and the bits 256..259). Since the largest shift below is by 10
+ * bits, and the values fit on 21 bits, values fit in 32-bit words,
+ * thereby allowing injecting full word values.
+ */
+ cc = (cc << 4) | (t[19] >> 9);
+ t[19] &= 0x01FF;
+ t[17] += cc << 3;
+ t[14] -= cc << 10;
+ t[7] -= cc << 5;
+ t[0] += cc;
+
+ /*
+ * If the carry is negative, then after carry propagation, we may
+ * end up with a value which is negative, and we don't want that.
+ * Thus, in that case, we add the modulus. Note that the subtraction
+ * result, when the carry is negative, is always smaller than the
+ * modulus, so the extra addition will not make the value exceed
+ * twice the modulus.
+ */
+ cc >>= 31;
+ t[0] -= cc;
+ t[7] += cc << 5;
+ t[14] += cc << 10;
+ t[17] -= cc << 3;
+ t[19] += cc << 9;
+
+ norm13(d, t, 20);
+}
+
+/*
+ * Square an integer modulo 2^256-2^224+2^192+2^96-1 (for NIST curve
+ * P-256). Operand is an array of 20 words, each containing 13 bits of
+ * data, in little-endian order. On input, upper word may be up to 13
+ * bits (hence value up to 2^260-1); on output, value fits on 257 bits
+ * and is lower than twice the modulus.
+ */
+static void
+square_f256(uint32_t *d, const uint32_t *a)
+{
+ uint32_t t[40], cc;
+ int i;
+
+ /*
+ * Compute raw square. All result words fit in 13 bits each.
+ */
+ square20(t, a);
+
+ /*
+ * Modular reduction: each high word in added/subtracted where
+ * necessary.
+ *
+ * The modulus is:
+ * p = 2^256 - 2^224 + 2^192 + 2^96 - 1
+ * Therefore:
+ * 2^256 = 2^224 - 2^192 - 2^96 + 1 mod p
+ *
+ * For a word x at bit offset n (n >= 256), we have:
+ * x*2^n = x*2^(n-32) - x*2^(n-64)
+ * - x*2^(n - 160) + x*2^(n-256) mod p
+ *
+ * Thus, we can nullify the high word if we reinject it at some
+ * proper emplacements.
+ */
+ for (i = 39; i >= 20; i --) {
+ uint32_t x;
+
+ x = t[i];
+ t[i - 2] += ARSH(x, 6);
+ t[i - 3] += (x << 7) & 0x1FFF;
+ t[i - 4] -= ARSH(x, 12);
+ t[i - 5] -= (x << 1) & 0x1FFF;
+ t[i - 12] -= ARSH(x, 4);
+ t[i - 13] -= (x << 9) & 0x1FFF;
+ t[i - 19] += ARSH(x, 9);
+ t[i - 20] += (x << 4) & 0x1FFF;
+ }
+
+ /*
+ * Propagate carries. This is a signed propagation, and the
+ * result may be negative. The loop above may enlarge values,
+ * but not two much: worst case is the chain involving t[i - 3],
+ * in which a value may be added to itself up to 7 times. Since
+ * starting values are 13-bit each, all words fit on 20 bits
+ * (21 to account for the sign bit).
+ */
+ cc = norm13(t, t, 20);
+
+ /*
+ * Perform modular reduction again for the bits beyond 256 (the carry
+ * and the bits 256..259). Since the largest shift below is by 10
+ * bits, and the values fit on 21 bits, values fit in 32-bit words,
+ * thereby allowing injecting full word values.
+ */
+ cc = (cc << 4) | (t[19] >> 9);
+ t[19] &= 0x01FF;
+ t[17] += cc << 3;
+ t[14] -= cc << 10;
+ t[7] -= cc << 5;
+ t[0] += cc;
+
+ /*
+ * If the carry is negative, then after carry propagation, we may
+ * end up with a value which is negative, and we don't want that.
+ * Thus, in that case, we add the modulus. Note that the subtraction
+ * result, when the carry is negative, is always smaller than the
+ * modulus, so the extra addition will not make the value exceed
+ * twice the modulus.
+ */
+ cc >>= 31;
+ t[0] -= cc;
+ t[7] += cc << 5;
+ t[14] += cc << 10;
+ t[17] -= cc << 3;
+ t[19] += cc << 9;
+
+ norm13(d, t, 20);
+}
+
+/*
+ * Jacobian coordinates for a point in P-256: affine coordinates (X,Y)
+ * are such that:
+ * X = x / z^2
+ * Y = y / z^3
+ * For the point at infinity, z = 0.
+ * Each point thus admits many possible representations.
+ *
+ * Coordinates are represented in arrays of 32-bit integers, each holding
+ * 13 bits of data. Values may also be slightly greater than the modulus,
+ * but they will always be lower than twice the modulus.
+ */
+typedef struct {
+ uint32_t x[20];
+ uint32_t y[20];
+ uint32_t z[20];
+} p256_jacobian;
+
+/*
+ * Convert a point to affine coordinates:
+ * - If the point is the point at infinity, then all three coordinates
+ * are set to 0.
+ * - Otherwise, the 'z' coordinate is set to 1, and the 'x' and 'y'
+ * coordinates are the 'X' and 'Y' affine coordinates.
+ * The coordinates are guaranteed to be lower than the modulus.
+ */
+static void
+p256_to_affine(p256_jacobian *P)
+{
+ uint32_t t1[20], t2[20];
+ int i;
+
+ /*
+ * Invert z with a modular exponentiation: the modulus is
+ * p = 2^256 - 2^224 + 2^192 + 2^96 - 1, and the exponent is
+ * p-2. Exponent bit pattern (from high to low) is:
+ * - 32 bits of value 1
+ * - 31 bits of value 0
+ * - 1 bit of value 1
+ * - 96 bits of value 0
+ * - 94 bits of value 1
+ * - 1 bit of value 0
+ * - 1 bit of value 1
+ * Thus, we precompute z^(2^31-1) to speed things up.
+ *
+ * If z = 0 (point at infinity) then the modular exponentiation
+ * will yield 0, which leads to the expected result (all three
+ * coordinates set to 0).
+ */
+
+ /*
+ * A simple square-and-multiply for z^(2^31-1). We could save about
+ * two dozen multiplications here with an addition chain, but
+ * this would require a bit more code, and extra stack buffers.
+ */
+ memcpy(t1, P->z, sizeof P->z);
+ for (i = 0; i < 30; i ++) {
+ square_f256(t1, t1);
+ mul_f256(t1, t1, P->z);
+ }
+
+ /*
+ * Square-and-multiply. Apart from the squarings, we have a few
+ * multiplications to set bits to 1; we multiply by the original z
+ * for setting 1 bit, and by t1 for setting 31 bits.
+ */
+ memcpy(t2, P->z, sizeof P->z);
+ for (i = 1; i < 256; i ++) {
+ square_f256(t2, t2);
+ switch (i) {
+ case 31:
+ case 190:
+ case 221:
+ case 252:
+ mul_f256(t2, t2, t1);
+ break;
+ case 63:
+ case 253:
+ case 255:
+ mul_f256(t2, t2, P->z);
+ break;
+ }
+ }
+
+ /*
+ * Now that we have 1/z, multiply x by 1/z^2 and y by 1/z^3.
+ */
+ mul_f256(t1, t2, t2);
+ mul_f256(P->x, t1, P->x);
+ mul_f256(t1, t1, t2);
+ mul_f256(P->y, t1, P->y);
+ reduce_final_f256(P->x);
+ reduce_final_f256(P->y);
+
+ /*
+ * Multiply z by 1/z. If z = 0, then this will yield 0, otherwise
+ * this will set z to 1.
+ */
+ mul_f256(P->z, P->z, t2);
+ reduce_final_f256(P->z);
+}
+
+/*
+ * Double a point in P-256. This function works for all valid points,
+ * including the point at infinity.
+ */
+static void
+p256_double(p256_jacobian *Q)
+{
+ /*
+ * Doubling formulas are:
+ *
+ * s = 4*x*y^2
+ * m = 3*(x + z^2)*(x - z^2)
+ * x' = m^2 - 2*s
+ * y' = m*(s - x') - 8*y^4
+ * z' = 2*y*z
+ *
+ * These formulas work for all points, including points of order 2
+ * and points at infinity:
+ * - If y = 0 then z' = 0. But there is no such point in P-256
+ * anyway.
+ * - If z = 0 then z' = 0.
+ */
+ uint32_t t1[20], t2[20], t3[20], t4[20];
+ int i;
+
+ /*
+ * Compute z^2 in t1.
+ */
+ square_f256(t1, Q->z);
+
+ /*
+ * Compute x-z^2 in t2 and x+z^2 in t1.
+ */
+ for (i = 0; i < 20; i ++) {
+ t2[i] = (F256[i] << 1) + Q->x[i] - t1[i];
+ t1[i] += Q->x[i];
+ }
+ norm13(t1, t1, 20);
+ norm13(t2, t2, 20);
+
+ /*
+ * Compute 3*(x+z^2)*(x-z^2) in t1.
+ */
+ mul_f256(t3, t1, t2);
+ for (i = 0; i < 20; i ++) {
+ t1[i] = MUL15(3, t3[i]);
+ }
+ norm13(t1, t1, 20);
+
+ /*
+ * Compute 4*x*y^2 (in t2) and 2*y^2 (in t3).
+ */
+ square_f256(t3, Q->y);
+ for (i = 0; i < 20; i ++) {
+ t3[i] <<= 1;
+ }
+ norm13(t3, t3, 20);
+ mul_f256(t2, Q->x, t3);
+ for (i = 0; i < 20; i ++) {
+ t2[i] <<= 1;
+ }
+ norm13(t2, t2, 20);
+ reduce_f256(t2);
+
+ /*
+ * Compute x' = m^2 - 2*s.
+ */
+ square_f256(Q->x, t1);
+ for (i = 0; i < 20; i ++) {
+ Q->x[i] += (F256[i] << 2) - (t2[i] << 1);
+ }
+ norm13(Q->x, Q->x, 20);
+ reduce_f256(Q->x);
+
+ /*
+ * Compute z' = 2*y*z.
+ */
+ mul_f256(t4, Q->y, Q->z);
+ for (i = 0; i < 20; i ++) {
+ Q->z[i] = t4[i] << 1;
+ }
+ norm13(Q->z, Q->z, 20);
+ reduce_f256(Q->z);
+
+ /*
+ * Compute y' = m*(s - x') - 8*y^4. Note that we already have
+ * 2*y^2 in t3.
+ */
+ for (i = 0; i < 20; i ++) {
+ t2[i] += (F256[i] << 1) - Q->x[i];
+ }
+ norm13(t2, t2, 20);
+ mul_f256(Q->y, t1, t2);
+ square_f256(t4, t3);
+ for (i = 0; i < 20; i ++) {
+ Q->y[i] += (F256[i] << 2) - (t4[i] << 1);
+ }
+ norm13(Q->y, Q->y, 20);
+ reduce_f256(Q->y);
+}
+
+/*
+ * Add point P2 to point P1.
+ *
+ * This function computes the wrong result in the following cases:
+ *
+ * - If P1 == 0 but P2 != 0
+ * - If P1 != 0 but P2 == 0
+ * - If P1 == P2
+ *
+ * In all three cases, P1 is set to the point at infinity.
+ *
+ * Returned value is 0 if one of the following occurs:
+ *
+ * - P1 and P2 have the same Y coordinate
+ * - P1 == 0 and P2 == 0
+ * - The Y coordinate of one of the points is 0 and the other point is
+ * the point at infinity.
+ *
+ * The third case cannot actually happen with valid points, since a point
+ * with Y == 0 is a point of order 2, and there is no point of order 2 on
+ * curve P-256.
+ *
+ * Therefore, assuming that P1 != 0 and P2 != 0 on input, then the caller
+ * can apply the following:
+ *
+ * - If the result is not the point at infinity, then it is correct.
+ * - Otherwise, if the returned value is 1, then this is a case of
+ * P1+P2 == 0, so the result is indeed the point at infinity.
+ * - Otherwise, P1 == P2, so a "double" operation should have been
+ * performed.
+ */
+static uint32_t
+p256_add(p256_jacobian *P1, const p256_jacobian *P2)
+{
+ /*
+ * Addtions formulas are:
+ *
+ * u1 = x1 * z2^2
+ * u2 = x2 * z1^2
+ * s1 = y1 * z2^3
+ * s2 = y2 * z1^3
+ * h = u2 - u1
+ * r = s2 - s1
+ * x3 = r^2 - h^3 - 2 * u1 * h^2
+ * y3 = r * (u1 * h^2 - x3) - s1 * h^3
+ * z3 = h * z1 * z2
+ */
+ uint32_t t1[20], t2[20], t3[20], t4[20], t5[20], t6[20], t7[20];
+ uint32_t ret;
+ int i;
+
+ /*
+ * Compute u1 = x1*z2^2 (in t1) and s1 = y1*z2^3 (in t3).
+ */
+ square_f256(t3, P2->z);
+ mul_f256(t1, P1->x, t3);
+ mul_f256(t4, P2->z, t3);
+ mul_f256(t3, P1->y, t4);
+
+ /*
+ * Compute u2 = x2*z1^2 (in t2) and s2 = y2*z1^3 (in t4).
+ */
+ square_f256(t4, P1->z);
+ mul_f256(t2, P2->x, t4);
+ mul_f256(t5, P1->z, t4);
+ mul_f256(t4, P2->y, t5);
+
+ /*
+ * Compute h = h2 - u1 (in t2) and r = s2 - s1 (in t4).
+ * We need to test whether r is zero, so we will do some extra
+ * reduce.
+ */
+ for (i = 0; i < 20; i ++) {
+ t2[i] += (F256[i] << 1) - t1[i];
+ t4[i] += (F256[i] << 1) - t3[i];
+ }
+ norm13(t2, t2, 20);
+ norm13(t4, t4, 20);
+ reduce_f256(t4);
+ reduce_final_f256(t4);
+ ret = 0;
+ for (i = 0; i < 20; i ++) {
+ ret |= t4[i];
+ }
+ ret = (ret | -ret) >> 31;
+
+ /*
+ * Compute u1*h^2 (in t6) and h^3 (in t5);
+ */
+ square_f256(t7, t2);
+ mul_f256(t6, t1, t7);
+ mul_f256(t5, t7, t2);
+
+ /*
+ * Compute x3 = r^2 - h^3 - 2*u1*h^2.
+ */
+ square_f256(P1->x, t4);
+ for (i = 0; i < 20; i ++) {
+ P1->x[i] += (F256[i] << 3) - t5[i] - (t6[i] << 1);
+ }
+ norm13(P1->x, P1->x, 20);
+ reduce_f256(P1->x);
+
+ /*
+ * Compute y3 = r*(u1*h^2 - x3) - s1*h^3.
+ */
+ for (i = 0; i < 20; i ++) {
+ t6[i] += (F256[i] << 1) - P1->x[i];
+ }
+ norm13(t6, t6, 20);
+ mul_f256(P1->y, t4, t6);
+ mul_f256(t1, t5, t3);
+ for (i = 0; i < 20; i ++) {
+ P1->y[i] += (F256[i] << 1) - t1[i];
+ }
+ norm13(P1->y, P1->y, 20);
+ reduce_f256(P1->y);
+
+ /*
+ * Compute z3 = h*z1*z2.
+ */
+ mul_f256(t1, P1->z, P2->z);
+ mul_f256(P1->z, t1, t2);
+
+ return ret;
+}
+
+/*
+ * Add point P2 to point P1. This is a specialised function for the
+ * case when P2 is a non-zero point in affine coordinate.
+ *
+ * This function computes the wrong result in the following cases:
+ *
+ * - If P1 == 0
+ * - If P1 == P2
+ *
+ * In both cases, P1 is set to the point at infinity.
+ *
+ * Returned value is 0 if one of the following occurs:
+ *
+ * - P1 and P2 have the same Y coordinate
+ * - The Y coordinate of P2 is 0 and P1 is the point at infinity.
+ *
+ * The second case cannot actually happen with valid points, since a point
+ * with Y == 0 is a point of order 2, and there is no point of order 2 on
+ * curve P-256.
+ *
+ * Therefore, assuming that P1 != 0 on input, then the caller
+ * can apply the following:
+ *
+ * - If the result is not the point at infinity, then it is correct.
+ * - Otherwise, if the returned value is 1, then this is a case of
+ * P1+P2 == 0, so the result is indeed the point at infinity.
+ * - Otherwise, P1 == P2, so a "double" operation should have been
+ * performed.
+ */
+static uint32_t
+p256_add_mixed(p256_jacobian *P1, const p256_jacobian *P2)
+{
+ /*
+ * Addtions formulas are:
+ *
+ * u1 = x1
+ * u2 = x2 * z1^2
+ * s1 = y1
+ * s2 = y2 * z1^3
+ * h = u2 - u1
+ * r = s2 - s1
+ * x3 = r^2 - h^3 - 2 * u1 * h^2
+ * y3 = r * (u1 * h^2 - x3) - s1 * h^3
+ * z3 = h * z1
+ */
+ uint32_t t1[20], t2[20], t3[20], t4[20], t5[20], t6[20], t7[20];
+ uint32_t ret;
+ int i;
+
+ /*
+ * Compute u1 = x1 (in t1) and s1 = y1 (in t3).
+ */
+ memcpy(t1, P1->x, sizeof t1);
+ memcpy(t3, P1->y, sizeof t3);
+
+ /*
+ * Compute u2 = x2*z1^2 (in t2) and s2 = y2*z1^3 (in t4).
+ */
+ square_f256(t4, P1->z);
+ mul_f256(t2, P2->x, t4);
+ mul_f256(t5, P1->z, t4);
+ mul_f256(t4, P2->y, t5);
+
+ /*
+ * Compute h = h2 - u1 (in t2) and r = s2 - s1 (in t4).
+ * We need to test whether r is zero, so we will do some extra
+ * reduce.
+ */
+ for (i = 0; i < 20; i ++) {
+ t2[i] += (F256[i] << 1) - t1[i];
+ t4[i] += (F256[i] << 1) - t3[i];
+ }
+ norm13(t2, t2, 20);
+ norm13(t4, t4, 20);
+ reduce_f256(t4);
+ reduce_final_f256(t4);
+ ret = 0;
+ for (i = 0; i < 20; i ++) {
+ ret |= t4[i];
+ }
+ ret = (ret | -ret) >> 31;
+
+ /*
+ * Compute u1*h^2 (in t6) and h^3 (in t5);
+ */
+ square_f256(t7, t2);
+ mul_f256(t6, t1, t7);
+ mul_f256(t5, t7, t2);
+
+ /*
+ * Compute x3 = r^2 - h^3 - 2*u1*h^2.
+ */
+ square_f256(P1->x, t4);
+ for (i = 0; i < 20; i ++) {
+ P1->x[i] += (F256[i] << 3) - t5[i] - (t6[i] << 1);
+ }
+ norm13(P1->x, P1->x, 20);
+ reduce_f256(P1->x);
+
+ /*
+ * Compute y3 = r*(u1*h^2 - x3) - s1*h^3.
+ */
+ for (i = 0; i < 20; i ++) {
+ t6[i] += (F256[i] << 1) - P1->x[i];
+ }
+ norm13(t6, t6, 20);
+ mul_f256(P1->y, t4, t6);
+ mul_f256(t1, t5, t3);
+ for (i = 0; i < 20; i ++) {
+ P1->y[i] += (F256[i] << 1) - t1[i];
+ }
+ norm13(P1->y, P1->y, 20);
+ reduce_f256(P1->y);
+
+ /*
+ * Compute z3 = h*z1*z2.
+ */
+ mul_f256(P1->z, P1->z, t2);
+
+ return ret;
+}
+
+/*
+ * Decode a P-256 point. This function does not support the point at
+ * infinity. Returned value is 0 if the point is invalid, 1 otherwise.
+ */
+static uint32_t
+p256_decode(p256_jacobian *P, const void *src, size_t len)
+{
+ const unsigned char *buf;
+ uint32_t tx[20], ty[20], t1[20], t2[20];
+ uint32_t bad;
+ int i;
+
+ if (len != 65) {
+ return 0;
+ }
+ buf = src;
+
+ /*
+ * First byte must be 0x04 (uncompressed format). We could support
+ * "hybrid format" (first byte is 0x06 or 0x07, and encodes the
+ * least significant bit of the Y coordinate), but it is explicitly
+ * forbidden by RFC 5480 (section 2.2).
+ */
+ bad = NEQ(buf[0], 0x04);
+
+ /*
+ * Decode the coordinates, and check that they are both lower
+ * than the modulus.
+ */
+ tx[19] = be8_to_le13(tx, buf + 1, 32);
+ ty[19] = be8_to_le13(ty, buf + 33, 32);
+ bad |= reduce_final_f256(tx);
+ bad |= reduce_final_f256(ty);
+
+ /*
+ * Check curve equation.
+ */
+ square_f256(t1, tx);
+ mul_f256(t1, tx, t1);
+ square_f256(t2, ty);
+ for (i = 0; i < 20; i ++) {
+ t1[i] += (F256[i] << 3) - MUL15(3, tx[i]) + P256_B[i] - t2[i];
+ }
+ norm13(t1, t1, 20);
+ reduce_f256(t1);
+ reduce_final_f256(t1);
+ for (i = 0; i < 20; i ++) {
+ bad |= t1[i];
+ }
+
+ /*
+ * Copy coordinates to the point structure.
+ */
+ memcpy(P->x, tx, sizeof tx);
+ memcpy(P->y, ty, sizeof ty);
+ memset(P->z, 0, sizeof P->z);
+ P->z[0] = 1;
+ return EQ(bad, 0);
+}
+
+/*
+ * Encode a point into a buffer. This function assumes that the point is
+ * valid, in affine coordinates, and not the point at infinity.
+ */
+static void
+p256_encode(void *dst, const p256_jacobian *P)
+{
+ unsigned char *buf;
+
+ buf = dst;
+ buf[0] = 0x04;
+ le13_to_be8(buf + 1, 32, P->x);
+ le13_to_be8(buf + 33, 32, P->y);
+}
+
+/*
+ * Multiply a curve point by an integer. The integer is assumed to be
+ * lower than the curve order, and the base point must not be the point
+ * at infinity.
+ */
+static void
+p256_mul(p256_jacobian *P, const unsigned char *x, size_t xlen)
+{
+ /*
+ * qz is a flag that is initially 1, and remains equal to 1
+ * as long as the point is the point at infinity.
+ *
+ * We use a 2-bit window to handle multiplier bits by pairs.
+ * The precomputed window really is the points P2 and P3.
+ */
+ uint32_t qz;
+ p256_jacobian P2, P3, Q, T, U;
+
+ /*
+ * Compute window values.
+ */
+ P2 = *P;
+ p256_double(&P2);
+ P3 = *P;
+ p256_add(&P3, &P2);
+
+ /*
+ * We start with Q = 0. We process multiplier bits 2 by 2.
+ */
+ memset(&Q, 0, sizeof Q);
+ qz = 1;
+ while (xlen -- > 0) {
+ int k;
+
+ for (k = 6; k >= 0; k -= 2) {
+ uint32_t bits;
+ uint32_t bnz;
+
+ p256_double(&Q);
+ p256_double(&Q);
+ T = *P;
+ U = Q;
+ bits = (*x >> k) & (uint32_t)3;
+ bnz = NEQ(bits, 0);
+ CCOPY(EQ(bits, 2), &T, &P2, sizeof T);
+ CCOPY(EQ(bits, 3), &T, &P3, sizeof T);
+ p256_add(&U, &T);
+ CCOPY(bnz & qz, &Q, &T, sizeof Q);
+ CCOPY(bnz & ~qz, &Q, &U, sizeof Q);
+ qz &= ~bnz;
+ }
+ x ++;
+ }
+ *P = Q;
+}
+
+/*
+ * Precomputed window: k*G points, where G is the curve generator, and k
+ * is an integer from 1 to 15 (inclusive). The X and Y coordinates of
+ * the point are encoded as 20 words of 13 bits each (little-endian
+ * order); 13-bit words are then grouped 2-by-2 into 32-bit words
+ * (little-endian order within each word).
+ */
+static const uint32_t Gwin[15][20] PROGMEM = {
+
+ { 0x04C60296, 0x02721176, 0x19D00F4A, 0x102517AC,
+ 0x13B8037D, 0x0748103C, 0x1E730E56, 0x08481FE2,
+ 0x0F97012C, 0x00D605F4, 0x1DFA11F5, 0x0C801A0D,
+ 0x0F670CBB, 0x0AED0CC5, 0x115E0E33, 0x181F0785,
+ 0x13F514A7, 0x0FF30E3B, 0x17171E1A, 0x009F18D0 },
+
+ { 0x1B341978, 0x16911F11, 0x0D9A1A60, 0x1C4E1FC8,
+ 0x1E040969, 0x096A06B0, 0x091C0030, 0x09EF1A29,
+ 0x18C40D03, 0x00F91C9E, 0x13C313D1, 0x096F0748,
+ 0x011419E0, 0x1CC713A6, 0x1DD31DAD, 0x1EE80C36,
+ 0x1ECD0C69, 0x1A0800A4, 0x08861B8E, 0x000E1DD5 },
+
+ { 0x173F1D6C, 0x02CC06F1, 0x14C21FB4, 0x043D1EB6,
+ 0x0F3606B7, 0x1A971C59, 0x1BF71951, 0x01481323,
+ 0x068D0633, 0x00BD12F9, 0x13EA1032, 0x136209E8,
+ 0x1C1E19A7, 0x06C7013E, 0x06C10AB0, 0x14C908BB,
+ 0x05830CE1, 0x1FEF18DD, 0x00620998, 0x010E0D19 },
+
+ { 0x18180852, 0x0604111A, 0x0B771509, 0x1B6F0156,
+ 0x00181FE2, 0x1DCC0AF4, 0x16EF0659, 0x11F70E80,
+ 0x11A912D0, 0x01C414D2, 0x027618C6, 0x05840FC6,
+ 0x100215C4, 0x187E0C3B, 0x12771C96, 0x150C0B5D,
+ 0x0FF705FD, 0x07981C67, 0x1AD20C63, 0x01C11C55 },
+
+ { 0x1E8113ED, 0x0A940370, 0x12920215, 0x1FA31D6F,
+ 0x1F7C0C82, 0x10CD03F7, 0x02640560, 0x081A0B5E,
+ 0x1BD21151, 0x00A21642, 0x0D0B0DA4, 0x0176113F,
+ 0x04440D1D, 0x001A1360, 0x1068012F, 0x1F141E49,
+ 0x10DF136B, 0x0E4F162B, 0x0D44104A, 0x01C1105F },
+
+ { 0x011411A9, 0x01551A4F, 0x0ADA0C6B, 0x01BD0EC8,
+ 0x18120C74, 0x112F1778, 0x099202CB, 0x0C05124B,
+ 0x195316A4, 0x01600685, 0x1E3B1FE2, 0x189014E3,
+ 0x0B5E1FD7, 0x0E0311F8, 0x08E000F7, 0x174E00DE,
+ 0x160702DF, 0x1B5A15BF, 0x03A11237, 0x01D01704 },
+
+ { 0x0C3D12A3, 0x0C501C0C, 0x17AD1300, 0x1715003F,
+ 0x03F719F8, 0x18031ED8, 0x1D980667, 0x0F681896,
+ 0x1B7D00BF, 0x011C14CE, 0x0FA000B4, 0x1C3501B0,
+ 0x0D901C55, 0x06790C10, 0x029E0736, 0x0DEB0400,
+ 0x034F183A, 0x030619B4, 0x0DEF0033, 0x00E71AC7 },
+
+ { 0x1B7D1393, 0x1B3B1076, 0x0BED1B4D, 0x13011F3A,
+ 0x0E0E1238, 0x156A132B, 0x013A02D3, 0x160A0D01,
+ 0x1CED1EE9, 0x00C5165D, 0x184C157E, 0x08141A83,
+ 0x153C0DA5, 0x1ED70F9D, 0x05170D51, 0x02CF13B8,
+ 0x18AE1771, 0x1B04113F, 0x05EC11E9, 0x015A16B3 },
+
+ { 0x04A41EE0, 0x1D1412E4, 0x1C591D79, 0x118511B7,
+ 0x14F00ACB, 0x1AE31E1C, 0x049C0D51, 0x016E061E,
+ 0x1DB71EDF, 0x01D41A35, 0x0E8208FA, 0x14441293,
+ 0x011F1E85, 0x1D54137A, 0x026B114F, 0x151D0832,
+ 0x00A50964, 0x1F9C1E1C, 0x064B12C9, 0x005409D1 },
+
+ { 0x062B123F, 0x0C0D0501, 0x183704C3, 0x08E31120,
+ 0x0A2E0A6C, 0x14440FED, 0x090A0D1E, 0x13271964,
+ 0x0B590A3A, 0x019D1D9B, 0x05780773, 0x09770A91,
+ 0x0F770CA3, 0x053F19D4, 0x02C80DED, 0x1A761304,
+ 0x091E0DD9, 0x15D201B8, 0x151109AA, 0x010F0198 },
+
+ { 0x05E101D1, 0x072314DD, 0x045F1433, 0x1A041541,
+ 0x10B3142E, 0x01840736, 0x1C1B19DB, 0x098B0418,
+ 0x1DBC083B, 0x007D1444, 0x01511740, 0x11DD1F3A,
+ 0x04ED0E2F, 0x1B4B1A62, 0x10480D04, 0x09E911A2,
+ 0x04211AFA, 0x19140893, 0x04D60CC4, 0x01210648 },
+
+ { 0x112703C4, 0x018B1BA1, 0x164C1D50, 0x05160BE0,
+ 0x0BCC1830, 0x01CB1554, 0x13291732, 0x1B2B1918,
+ 0x0DED0817, 0x00E80775, 0x0A2401D3, 0x0BFE08B3,
+ 0x0E531199, 0x058616E9, 0x04770B91, 0x110F0C55,
+ 0x19C11554, 0x0BFB1159, 0x03541C38, 0x000E1C2D },
+
+ { 0x10390C01, 0x02BB0751, 0x0AC5098E, 0x096C17AB,
+ 0x03C90E28, 0x10BD18BF, 0x002E1F2D, 0x092B0986,
+ 0x1BD700AC, 0x002E1F20, 0x1E3D1FD8, 0x077718BB,
+ 0x06F919C4, 0x187407ED, 0x11370E14, 0x081E139C,
+ 0x00481ADB, 0x14AB0289, 0x066A0EBE, 0x00C70ED6 },
+
+ { 0x0694120B, 0x124E1CC9, 0x0E2F0570, 0x17CF081A,
+ 0x078906AC, 0x066D17CF, 0x1B3207F4, 0x0C5705E9,
+ 0x10001C38, 0x00A919DE, 0x06851375, 0x0F900BD8,
+ 0x080401BA, 0x0EEE0D42, 0x1B8B11EA, 0x0B4519F0,
+ 0x090F18C0, 0x062E1508, 0x0DD909F4, 0x01EB067C },
+
+ { 0x0CDC1D5F, 0x0D1818F9, 0x07781636, 0x125B18E8,
+ 0x0D7003AF, 0x13110099, 0x1D9B1899, 0x175C1EB7,
+ 0x0E34171A, 0x01E01153, 0x081A0F36, 0x0B391783,
+ 0x1D1F147E, 0x19CE16D7, 0x11511B21, 0x1F2C10F9,
+ 0x12CA0E51, 0x05A31D39, 0x171A192E, 0x016B0E4F }
+};
+
+/*
+ * Lookup one of the Gwin[] values, by index. This is constant-time.
+ */
+static void
+lookup_Gwin(p256_jacobian *T, uint32_t idx)
+{
+ uint32_t xy[20];
+ uint32_t k;
+ size_t u;
+
+ memset(xy, 0, sizeof xy);
+ for (k = 0; k < 15; k ++) {
+ uint32_t m;
+
+ m = -EQ(idx, k + 1);
+ for (u = 0; u < 20; u ++) {
+ xy[u] |= m & Gwin[k][u];
+ }
+ }
+ for (u = 0; u < 10; u ++) {
+ T->x[(u << 1) + 0] = xy[u] & 0xFFFF;
+ T->x[(u << 1) + 1] = xy[u] >> 16;
+ T->y[(u << 1) + 0] = xy[u + 10] & 0xFFFF;
+ T->y[(u << 1) + 1] = xy[u + 10] >> 16;
+ }
+ memset(T->z, 0, sizeof T->z);
+ T->z[0] = 1;
+}
+
+/*
+ * Multiply the generator by an integer. The integer is assumed non-zero
+ * and lower than the curve order.
+ */
+static void
+p256_mulgen(p256_jacobian *P, const unsigned char *x, size_t xlen)
+{
+ /*
+ * qz is a flag that is initially 1, and remains equal to 1
+ * as long as the point is the point at infinity.
+ *
+ * We use a 4-bit window to handle multiplier bits by groups
+ * of 4. The precomputed window is constant static data, with
+ * points in affine coordinates; we use a constant-time lookup.
+ */
+ p256_jacobian Q;
+ uint32_t qz;
+
+ memset(&Q, 0, sizeof Q);
+ qz = 1;
+ while (xlen -- > 0) {
+ int k;
+ unsigned bx;
+
+ bx = *x ++;
+ for (k = 0; k < 2; k ++) {
+ uint32_t bits;
+ uint32_t bnz;
+ p256_jacobian T, U;
+
+ p256_double(&Q);
+ p256_double(&Q);
+ p256_double(&Q);
+ p256_double(&Q);
+ bits = (bx >> 4) & 0x0F;
+ bnz = NEQ(bits, 0);
+ lookup_Gwin(&T, bits);
+ U = Q;
+ p256_add_mixed(&U, &T);
+ CCOPY(bnz & qz, &Q, &T, sizeof Q);
+ CCOPY(bnz & ~qz, &Q, &U, sizeof Q);
+ qz &= ~bnz;
+ bx <<= 4;
+ }
+ }
+ *P = Q;
+}
+
+static const unsigned char *
+api_generator(int curve, size_t *len)
+{
+ (void)curve;
+ *len = br_secp256r1.generator_len;
+ return br_secp256r1.generator;
+}
+
+static const unsigned char *
+api_order(int curve, size_t *len)
+{
+ (void)curve;
+ *len = br_secp256r1.order_len;
+ return br_secp256r1.order;
+}
+
+static size_t
+api_xoff(int curve, size_t *len)
+{
+ (void)curve;
+ *len = 32;
+ return 1;
+}
+
+static uint32_t
+api_mul(unsigned char *G, size_t Glen,
+ const unsigned char *x, size_t xlen, int curve)
+{
+ uint32_t r;
+ p256_jacobian P;
+
+ (void)curve;
+ r = p256_decode(&P, G, Glen);
+ p256_mul(&P, x, xlen);
+ if (Glen >= 65) {
+ p256_to_affine(&P);
+ p256_encode(G, &P);
+ }
+ return r;
+}
+
+static size_t
+api_mulgen(unsigned char *R,
+ const unsigned char *x, size_t xlen, int curve)
+{
+ p256_jacobian P;
+
+ (void)curve;
+ p256_mulgen(&P, x, xlen);
+ p256_to_affine(&P);
+ p256_encode(R, &P);
+ return 65;
+
+ /*
+ const unsigned char *G;
+ size_t Glen;
+
+ G = api_generator(curve, &Glen);
+ memcpy(R, G, Glen);
+ api_mul(R, Glen, x, xlen, curve);
+ return Glen;
+ */
+}
+
+static uint32_t
+api_muladd(unsigned char *A, const unsigned char *B, size_t len,
+ const unsigned char *x, size_t xlen,
+ const unsigned char *y, size_t ylen, int curve)
+{
+ p256_jacobian P, Q;
+ uint32_t r, t, z;
+ int i;
+
+ (void)curve;
+ r = p256_decode(&P, A, len);
+ p256_mul(&P, x, xlen);
+ if (B == NULL) {
+ p256_mulgen(&Q, y, ylen);
+ } else {
+ r &= p256_decode(&Q, B, len);
+ p256_mul(&Q, y, ylen);
+ }
+
+ /*
+ * The final addition may fail in case both points are equal.
+ */
+ t = p256_add(&P, &Q);
+ reduce_final_f256(P.z);
+ z = 0;
+ for (i = 0; i < 20; i ++) {
+ z |= P.z[i];
+ }
+ z = EQ(z, 0);
+ p256_double(&Q);
+
+ /*
+ * If z is 1 then either P+Q = 0 (t = 1) or P = Q (t = 0). So we
+ * have the following:
+ *
+ * z = 0, t = 0 return P (normal addition)
+ * z = 0, t = 1 return P (normal addition)
+ * z = 1, t = 0 return Q (a 'double' case)
+ * z = 1, t = 1 report an error (P+Q = 0)
+ */
+ CCOPY(z & ~t, &P, &Q, sizeof Q);
+ p256_to_affine(&P);
+ p256_encode(A, &P);
+ r &= ~(z & t);
+ return r;
+}
+
+/* see bearssl_ec.h */
+const br_ec_impl br_ec_p256_m15 PROGMEM = {
+ (uint32_t)0x00800000,
+ &api_generator,
+ &api_order,
+ &api_xoff,
+ &api_mul,
+ &api_mulgen,
+ &api_muladd
+};
diff --git a/lib/bearssl-esp8266/src/ec/ec_prime_i15.c b/lib/bearssl-esp8266/src/ec/ec_prime_i15.c
new file mode 100644
index 000000000..1bed22aa4
--- /dev/null
+++ b/lib/bearssl-esp8266/src/ec/ec_prime_i15.c
@@ -0,0 +1,822 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "t_inner.h"
+
+/*
+ * Parameters for supported curves:
+ * - field modulus p
+ * - R^2 mod p (R = 2^(15k) for the smallest k such that R >= p)
+ * - b*R mod p (b is the second curve equation parameter)
+ */
+
+static const uint16_t P256_P[] PROGMEM = {
+ 0x0111,
+ 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x003F, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x1000, 0x0000, 0x4000, 0x7FFF,
+ 0x7FFF, 0x0001
+};
+
+static const uint16_t P256_R2[] PROGMEM = {
+ 0x0111,
+ 0x0000, 0x6000, 0x0000, 0x0000, 0x0000, 0x0000, 0x7FFC, 0x7FFF,
+ 0x7FBF, 0x7FFF, 0x7FBF, 0x7FFF, 0x7FFF, 0x7FFF, 0x77FF, 0x7FFF,
+ 0x4FFF, 0x0000
+};
+
+static const uint16_t P256_B[] PROGMEM = {
+ 0x0111,
+ 0x770C, 0x5EEF, 0x29C4, 0x3EC4, 0x6273, 0x0486, 0x4543, 0x3993,
+ 0x3C01, 0x6B56, 0x212E, 0x57EE, 0x4882, 0x204B, 0x7483, 0x3C16,
+ 0x0187, 0x0000
+};
+
+static const uint16_t P384_P[] PROGMEM = {
+ 0x0199,
+ 0x7FFF, 0x7FFF, 0x0003, 0x0000, 0x0000, 0x0000, 0x7FC0, 0x7FFF,
+ 0x7EFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF,
+ 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF,
+ 0x7FFF, 0x01FF
+};
+
+static const uint16_t P384_R2[] PROGMEM = {
+ 0x0199,
+ 0x1000, 0x0000, 0x0000, 0x7FFF, 0x7FFF, 0x0001, 0x0000, 0x0010,
+ 0x0000, 0x0000, 0x0000, 0x7F00, 0x7FFF, 0x01FF, 0x0000, 0x1000,
+ 0x0000, 0x2000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000
+};
+
+static const uint16_t P384_B[] PROGMEM = {
+ 0x0199,
+ 0x7333, 0x2096, 0x70D1, 0x2310, 0x3020, 0x6197, 0x1464, 0x35BB,
+ 0x70CA, 0x0117, 0x1920, 0x4136, 0x5FC8, 0x5713, 0x4938, 0x7DD2,
+ 0x4DD2, 0x4A71, 0x0220, 0x683E, 0x2C87, 0x4DB1, 0x7BFF, 0x6C09,
+ 0x0452, 0x0084
+};
+
+static const uint16_t P521_P[] PROGMEM = {
+ 0x022B,
+ 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF,
+ 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF,
+ 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF,
+ 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF,
+ 0x7FFF, 0x7FFF, 0x07FF
+};
+
+static const uint16_t P521_R2[] PROGMEM = {
+ 0x022B,
+ 0x0100, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000
+};
+
+static const uint16_t P521_B[] PROGMEM = {
+ 0x022B,
+ 0x7002, 0x6A07, 0x751A, 0x228F, 0x71EF, 0x5869, 0x20F4, 0x1EFC,
+ 0x7357, 0x37E0, 0x4EEC, 0x605E, 0x1652, 0x26F6, 0x31FA, 0x4A8F,
+ 0x6193, 0x3C2A, 0x3C42, 0x48C7, 0x3489, 0x6771, 0x4C57, 0x5CCD,
+ 0x2725, 0x545B, 0x503B, 0x5B42, 0x21A0, 0x2534, 0x687E, 0x70E4,
+ 0x1618, 0x27D7, 0x0465
+};
+
+typedef struct {
+ const uint16_t *p;
+ const uint16_t *b;
+ const uint16_t *R2;
+ uint16_t p0i;
+ size_t point_len;
+} curve_params;
+
+static inline const curve_params *
+id_to_curve(int curve)
+{
+ static const curve_params pp[] = {
+ { P256_P, P256_B, P256_R2, 0x0001, 65 },
+ { P384_P, P384_B, P384_R2, 0x0001, 97 },
+ { P521_P, P521_B, P521_R2, 0x0001, 133 }
+ };
+
+ return &pp[curve - BR_EC_secp256r1];
+}
+
+#define I15_LEN ((BR_MAX_EC_SIZE + 29) / 15)
+
+/*
+ * Type for a point in Jacobian coordinates:
+ * -- three values, x, y and z, in Montgomery representation
+ * -- affine coordinates are X = x / z^2 and Y = y / z^3
+ * -- for the point at infinity, z = 0
+ */
+typedef struct {
+ uint16_t c[3][I15_LEN];
+} jacobian;
+
+/*
+ * We use a custom interpreter that uses a dozen registers, and
+ * only six operations:
+ * MSET(d, a) copy a into d
+ * MADD(d, a) d = d+a (modular)
+ * MSUB(d, a) d = d-a (modular)
+ * MMUL(d, a, b) d = a*b (Montgomery multiplication)
+ * MINV(d, a, b) invert d modulo p; a and b are used as scratch registers
+ * MTZ(d) clear return value if d = 0
+ * Destination of MMUL (d) must be distinct from operands (a and b).
+ * There is no such constraint for MSUB and MADD.
+ *
+ * Registers include the operand coordinates, and temporaries.
+ */
+#define MSET(d, a) (0x0000 + ((d) << 8) + ((a) << 4))
+#define MADD(d, a) (0x1000 + ((d) << 8) + ((a) << 4))
+#define MSUB(d, a) (0x2000 + ((d) << 8) + ((a) << 4))
+#define MMUL(d, a, b) (0x3000 + ((d) << 8) + ((a) << 4) + (b))
+#define MINV(d, a, b) (0x4000 + ((d) << 8) + ((a) << 4) + (b))
+#define MTZ(d) (0x5000 + ((d) << 8))
+#define ENDCODE 0
+
+/*
+ * Registers for the input operands.
+ */
+#define P1x 0
+#define P1y 1
+#define P1z 2
+#define P2x 3
+#define P2y 4
+#define P2z 5
+
+/*
+ * Alternate names for the first input operand.
+ */
+#define Px 0
+#define Py 1
+#define Pz 2
+
+/*
+ * Temporaries.
+ */
+#define t1 6
+#define t2 7
+#define t3 8
+#define t4 9
+#define t5 10
+#define t6 11
+#define t7 12
+
+/*
+ * Extra scratch registers available when there is no second operand (e.g.
+ * for "double" and "affine").
+ */
+#define t8 3
+#define t9 4
+#define t10 5
+
+/*
+ * Doubling formulas are:
+ *
+ * s = 4*x*y^2
+ * m = 3*(x + z^2)*(x - z^2)
+ * x' = m^2 - 2*s
+ * y' = m*(s - x') - 8*y^4
+ * z' = 2*y*z
+ *
+ * If y = 0 (P has order 2) then this yields infinity (z' = 0), as it
+ * should. This case should not happen anyway, because our curves have
+ * prime order, and thus do not contain any point of order 2.
+ *
+ * If P is infinity (z = 0), then again the formulas yield infinity,
+ * which is correct. Thus, this code works for all points.
+ *
+ * Cost: 8 multiplications
+ */
+static const uint16_t code_double[] PROGMEM = {
+ /*
+ * Compute z^2 (in t1).
+ */
+ MMUL(t1, Pz, Pz),
+
+ /*
+ * Compute x-z^2 (in t2) and then x+z^2 (in t1).
+ */
+ MSET(t2, Px),
+ MSUB(t2, t1),
+ MADD(t1, Px),
+
+ /*
+ * Compute m = 3*(x+z^2)*(x-z^2) (in t1).
+ */
+ MMUL(t3, t1, t2),
+ MSET(t1, t3),
+ MADD(t1, t3),
+ MADD(t1, t3),
+
+ /*
+ * Compute s = 4*x*y^2 (in t2) and 2*y^2 (in t3).
+ */
+ MMUL(t3, Py, Py),
+ MADD(t3, t3),
+ MMUL(t2, Px, t3),
+ MADD(t2, t2),
+
+ /*
+ * Compute x' = m^2 - 2*s.
+ */
+ MMUL(Px, t1, t1),
+ MSUB(Px, t2),
+ MSUB(Px, t2),
+
+ /*
+ * Compute z' = 2*y*z.
+ */
+ MMUL(t4, Py, Pz),
+ MSET(Pz, t4),
+ MADD(Pz, t4),
+
+ /*
+ * Compute y' = m*(s - x') - 8*y^4. Note that we already have
+ * 2*y^2 in t3.
+ */
+ MSUB(t2, Px),
+ MMUL(Py, t1, t2),
+ MMUL(t4, t3, t3),
+ MSUB(Py, t4),
+ MSUB(Py, t4),
+
+ ENDCODE
+};
+
+/*
+ * Addtions formulas are:
+ *
+ * u1 = x1 * z2^2
+ * u2 = x2 * z1^2
+ * s1 = y1 * z2^3
+ * s2 = y2 * z1^3
+ * h = u2 - u1
+ * r = s2 - s1
+ * x3 = r^2 - h^3 - 2 * u1 * h^2
+ * y3 = r * (u1 * h^2 - x3) - s1 * h^3
+ * z3 = h * z1 * z2
+ *
+ * If both P1 and P2 are infinity, then z1 == 0 and z2 == 0, implying that
+ * z3 == 0, so the result is correct.
+ * If either of P1 or P2 is infinity, but not both, then z3 == 0, which is
+ * not correct.
+ * h == 0 only if u1 == u2; this happens in two cases:
+ * -- if s1 == s2 then P1 and/or P2 is infinity, or P1 == P2
+ * -- if s1 != s2 then P1 + P2 == infinity (but neither P1 or P2 is infinity)
+ *
+ * Thus, the following situations are not handled correctly:
+ * -- P1 = 0 and P2 != 0
+ * -- P1 != 0 and P2 = 0
+ * -- P1 = P2
+ * All other cases are properly computed. However, even in "incorrect"
+ * situations, the three coordinates still are properly formed field
+ * elements.
+ *
+ * The returned flag is cleared if r == 0. This happens in the following
+ * cases:
+ * -- Both points are on the same horizontal line (same Y coordinate).
+ * -- Both points are infinity.
+ * -- One point is infinity and the other is on line Y = 0.
+ * The third case cannot happen with our curves (there is no valid point
+ * on line Y = 0 since that would be a point of order 2). If the two
+ * source points are non-infinity, then remains only the case where the
+ * two points are on the same horizontal line.
+ *
+ * This allows us to detect the "P1 == P2" case, assuming that P1 != 0 and
+ * P2 != 0:
+ * -- If the returned value is not the point at infinity, then it was properly
+ * computed.
+ * -- Otherwise, if the returned flag is 1, then P1+P2 = 0, and the result
+ * is indeed the point at infinity.
+ * -- Otherwise (result is infinity, flag is 0), then P1 = P2 and we should
+ * use the 'double' code.
+ *
+ * Cost: 16 multiplications
+ */
+static const uint16_t code_add[] PROGMEM = {
+ /*
+ * Compute u1 = x1*z2^2 (in t1) and s1 = y1*z2^3 (in t3).
+ */
+ MMUL(t3, P2z, P2z),
+ MMUL(t1, P1x, t3),
+ MMUL(t4, P2z, t3),
+ MMUL(t3, P1y, t4),
+
+ /*
+ * Compute u2 = x2*z1^2 (in t2) and s2 = y2*z1^3 (in t4).
+ */
+ MMUL(t4, P1z, P1z),
+ MMUL(t2, P2x, t4),
+ MMUL(t5, P1z, t4),
+ MMUL(t4, P2y, t5),
+
+ /*
+ * Compute h = u2 - u1 (in t2) and r = s2 - s1 (in t4).
+ */
+ MSUB(t2, t1),
+ MSUB(t4, t3),
+
+ /*
+ * Report cases where r = 0 through the returned flag.
+ */
+ MTZ(t4),
+
+ /*
+ * Compute u1*h^2 (in t6) and h^3 (in t5).
+ */
+ MMUL(t7, t2, t2),
+ MMUL(t6, t1, t7),
+ MMUL(t5, t7, t2),
+
+ /*
+ * Compute x3 = r^2 - h^3 - 2*u1*h^2.
+ * t1 and t7 can be used as scratch registers.
+ */
+ MMUL(P1x, t4, t4),
+ MSUB(P1x, t5),
+ MSUB(P1x, t6),
+ MSUB(P1x, t6),
+
+ /*
+ * Compute y3 = r*(u1*h^2 - x3) - s1*h^3.
+ */
+ MSUB(t6, P1x),
+ MMUL(P1y, t4, t6),
+ MMUL(t1, t5, t3),
+ MSUB(P1y, t1),
+
+ /*
+ * Compute z3 = h*z1*z2.
+ */
+ MMUL(t1, P1z, P2z),
+ MMUL(P1z, t1, t2),
+
+ ENDCODE
+};
+
+/*
+ * Check that the point is on the curve. This code snippet assumes the
+ * following conventions:
+ * -- Coordinates x and y have been freshly decoded in P1 (but not
+ * converted to Montgomery coordinates yet).
+ * -- P2x, P2y and P2z are set to, respectively, R^2, b*R and 1.
+ */
+static const uint16_t code_check[] PROGMEM = {
+
+ /* Convert x and y to Montgomery representation. */
+ MMUL(t1, P1x, P2x),
+ MMUL(t2, P1y, P2x),
+ MSET(P1x, t1),
+ MSET(P1y, t2),
+
+ /* Compute x^3 in t1. */
+ MMUL(t2, P1x, P1x),
+ MMUL(t1, P1x, t2),
+
+ /* Subtract 3*x from t1. */
+ MSUB(t1, P1x),
+ MSUB(t1, P1x),
+ MSUB(t1, P1x),
+
+ /* Add b. */
+ MADD(t1, P2y),
+
+ /* Compute y^2 in t2. */
+ MMUL(t2, P1y, P1y),
+
+ /* Compare y^2 with x^3 - 3*x + b; they must match. */
+ MSUB(t1, t2),
+ MTZ(t1),
+
+ /* Set z to 1 (in Montgomery representation). */
+ MMUL(P1z, P2x, P2z),
+
+ ENDCODE
+};
+
+/*
+ * Conversion back to affine coordinates. This code snippet assumes that
+ * the z coordinate of P2 is set to 1 (not in Montgomery representation).
+ */
+static const uint16_t code_affine[] PROGMEM = {
+
+ /* Save z*R in t1. */
+ MSET(t1, P1z),
+
+ /* Compute z^3 in t2. */
+ MMUL(t2, P1z, P1z),
+ MMUL(t3, P1z, t2),
+ MMUL(t2, t3, P2z),
+
+ /* Invert to (1/z^3) in t2. */
+ MINV(t2, t3, t4),
+
+ /* Compute y. */
+ MSET(t3, P1y),
+ MMUL(P1y, t2, t3),
+
+ /* Compute (1/z^2) in t3. */
+ MMUL(t3, t2, t1),
+
+ /* Compute x. */
+ MSET(t2, P1x),
+ MMUL(P1x, t2, t3),
+
+ ENDCODE
+};
+
+static uint32_t
+run_code(jacobian *P1, const jacobian *P2,
+ const curve_params *cc, const uint16_t *code)
+{
+ uint32_t r;
+ uint16_t t[13][I15_LEN];
+ size_t u;
+
+ r = 1;
+
+ /*
+ * Copy the two operands in the dedicated registers.
+ */
+ memcpy(t[P1x], P1->c, 3 * I15_LEN * sizeof(uint16_t));
+ memcpy(t[P2x], P2->c, 3 * I15_LEN * sizeof(uint16_t));
+
+ optimistic_yield(10000);
+
+ /*
+ * Run formulas.
+ */
+ for (u = 0;; u ++) {
+ unsigned op, d, a, b;
+
+ op = pgm_read_word(&code[u]);
+ if (op == 0) {
+ break;
+ }
+ d = (op >> 8) & 0x0F;
+ a = (op >> 4) & 0x0F;
+ b = op & 0x0F;
+ op >>= 12;
+ switch (op) {
+ uint32_t ctl;
+ size_t plen;
+ unsigned char tp[(BR_MAX_EC_SIZE + 7) >> 3];
+
+ case 0:
+ memcpy(t[d], t[a], I15_LEN * sizeof(uint16_t));
+ break;
+ case 1:
+ ctl = br_i15_add(t[d], t[a], 1);
+ ctl |= NOT(br_i15_sub(t[d], cc->p, 0));
+ br_i15_sub(t[d], cc->p, ctl);
+ break;
+ case 2:
+ br_i15_add(t[d], cc->p, br_i15_sub(t[d], t[a], 1));
+ break;
+ case 3:
+ br_i15_montymul(t[d], t[a], t[b], cc->p, cc->p0i);
+ break;
+ case 4:
+ plen = (pgm_read_word(&cc->p[0]) - (pgm_read_word(&cc->p[0]) >> 4) + 7) >> 3;
+ br_i15_encode(tp, plen, cc->p);
+ tp[plen - 1] -= 2;
+ br_i15_modpow(t[d], tp, plen,
+ cc->p, cc->p0i, t[a], t[b]);
+ break;
+ default:
+ r &= ~br_i15_iszero(t[d]);
+ break;
+ }
+ }
+
+ /*
+ * Copy back result.
+ */
+ memcpy(P1->c, t[P1x], 3 * I15_LEN * sizeof(uint16_t));
+ return r;
+}
+
+static void
+set_one(uint16_t *x, const uint16_t *p)
+{
+ size_t plen;
+
+ plen = (pgm_read_word(&p[0]) + 31) >> 4;
+ memset(x, 0, plen * sizeof *x);
+ x[0] = pgm_read_word(&p[0]);
+ x[1] = 0x0001;
+}
+
+static void
+point_zero(jacobian *P, const curve_params *cc)
+{
+ memset(P, 0, sizeof *P);
+ P->c[0][0] = P->c[1][0] = P->c[2][0] = pgm_read_word(&cc->p[0]);
+}
+
+static inline void
+point_double(jacobian *P, const curve_params *cc)
+{
+ run_code(P, P, cc, code_double);
+}
+
+static inline uint32_t
+point_add(jacobian *P1, const jacobian *P2, const curve_params *cc)
+{
+ return run_code(P1, P2, cc, code_add);
+}
+
+static void
+point_mul(jacobian *P, const unsigned char *x, size_t xlen,
+ const curve_params *cc)
+{
+ /*
+ * We do a simple double-and-add ladder with a 2-bit window
+ * to make only one add every two doublings. We thus first
+ * precompute 2P and 3P in some local buffers.
+ *
+ * We always perform two doublings and one addition; the
+ * addition is with P, 2P and 3P and is done in a temporary
+ * array.
+ *
+ * The addition code cannot handle cases where one of the
+ * operands is infinity, which is the case at the start of the
+ * ladder. We therefore need to maintain a flag that controls
+ * this situation.
+ */
+ uint32_t qz;
+ jacobian P2, P3, Q, T, U;
+
+ memcpy(&P2, P, sizeof P2);
+ point_double(&P2, cc);
+ memcpy(&P3, P, sizeof P3);
+ point_add(&P3, &P2, cc);
+
+ point_zero(&Q, cc);
+ qz = 1;
+ while (xlen -- > 0) {
+ int k;
+
+ for (k = 6; k >= 0; k -= 2) {
+ uint32_t bits;
+ uint32_t bnz;
+
+ point_double(&Q, cc);
+ point_double(&Q, cc);
+ memcpy(&T, P, sizeof T);
+ memcpy(&U, &Q, sizeof U);
+ bits = (pgm_read_byte(&*x) >> k) & (uint32_t)3;
+ bnz = NEQ(bits, 0);
+ CCOPY(EQ(bits, 2), &T, &P2, sizeof T);
+ CCOPY(EQ(bits, 3), &T, &P3, sizeof T);
+ point_add(&U, &T, cc);
+ CCOPY(bnz & qz, &Q, &T, sizeof Q);
+ CCOPY(bnz & ~qz, &Q, &U, sizeof Q);
+ qz &= ~bnz;
+ }
+ x ++;
+ }
+ memcpy(P, &Q, sizeof Q);
+}
+
+/*
+ * Decode point into Jacobian coordinates. This function does not support
+ * the point at infinity. If the point is invalid then this returns 0, but
+ * the coordinates are still set to properly formed field elements.
+ */
+static uint32_t
+point_decode(jacobian *P, const void *src, size_t len, const curve_params *cc)
+{
+ /*
+ * Points must use uncompressed format:
+ * -- first byte is 0x04;
+ * -- coordinates X and Y use unsigned big-endian, with the same
+ * length as the field modulus.
+ *
+ * We don't support hybrid format (uncompressed, but first byte
+ * has value 0x06 or 0x07, depending on the least significant bit
+ * of Y) because it is rather useless, and explicitly forbidden
+ * by PKIX (RFC 5480, section 2.2).
+ *
+ * We don't support compressed format either, because it is not
+ * much used in practice (there are or were patent-related
+ * concerns about point compression, which explains the lack of
+ * generalised support). Also, point compression support would
+ * need a bit more code.
+ */
+ const unsigned char *buf;
+ size_t plen, zlen;
+ uint32_t r;
+ jacobian Q;
+
+ buf = src;
+ point_zero(P, cc);
+ plen = (pgm_read_word(&cc->p[0]) - (pgm_read_word(&cc->p[0]) >> 4) + 7) >> 3;
+ if (len != 1 + (plen << 1)) {
+ return 0;
+ }
+ r = br_i15_decode_mod(P->c[0], buf + 1, plen, cc->p);
+ r &= br_i15_decode_mod(P->c[1], buf + 1 + plen, plen, cc->p);
+
+ /*
+ * Check first byte.
+ */
+ r &= EQ(pgm_read_byte(&buf[0]), 0x04);
+ /* obsolete
+ r &= EQ(buf[0], 0x04) | (EQ(buf[0] & 0xFE, 0x06)
+ & ~(uint32_t)(buf[0] ^ buf[plen << 1]));
+ */
+
+ /*
+ * Convert coordinates and check that the point is valid.
+ */
+ zlen = ((pgm_read_word(&cc->p[0]) + 31) >> 4) * sizeof(uint16_t);
+ memcpy_P(Q.c[0], cc->R2, zlen);
+ memcpy_P(Q.c[1], cc->b, zlen);
+ set_one(Q.c[2], cc->p);
+ r &= ~run_code(P, &Q, cc, code_check);
+ return r;
+}
+
+/*
+ * Encode a point. This method assumes that the point is correct and is
+ * not the point at infinity. Encoded size is always 1+2*plen, where
+ * plen is the field modulus length, in bytes.
+ */
+static void
+point_encode(void *dst, const jacobian *P, const curve_params *cc)
+{
+ unsigned char *buf;
+ size_t plen;
+ jacobian Q, T;
+
+ buf = dst;
+ plen = (pgm_read_word(&cc->p[0]) - (pgm_read_word(&cc->p[0]) >> 4) + 7) >> 3;
+ buf[0] = 0x04;
+ memcpy(&Q, P, sizeof *P);
+ set_one(T.c[2], cc->p);
+ run_code(&Q, &T, cc, code_affine);
+ br_i15_encode(buf + 1, plen, Q.c[0]);
+ br_i15_encode(buf + 1 + plen, plen, Q.c[1]);
+}
+
+static const br_ec_curve_def *
+id_to_curve_def(int curve)
+{
+ switch (curve) {
+ case BR_EC_secp256r1:
+ return &br_secp256r1;
+ case BR_EC_secp384r1:
+ return &br_secp384r1;
+ case BR_EC_secp521r1:
+ return &br_secp521r1;
+ }
+ return NULL;
+}
+
+static const unsigned char *
+api_generator(int curve, size_t *len)
+{
+ const br_ec_curve_def *cd;
+
+ cd = id_to_curve_def(curve);
+ *len = cd->generator_len;
+ return cd->generator;
+}
+
+static const unsigned char *
+api_order(int curve, size_t *len)
+{
+ const br_ec_curve_def *cd;
+
+ cd = id_to_curve_def(curve);
+ *len = cd->order_len;
+ return cd->order;
+}
+
+static size_t
+api_xoff(int curve, size_t *len)
+{
+ api_generator(curve, len);
+ *len >>= 1;
+ return 1;
+}
+
+static uint32_t
+api_mul(unsigned char *G, size_t Glen,
+ const unsigned char *x, size_t xlen, int curve)
+{
+ uint32_t r;
+ const curve_params *cc;
+ jacobian P;
+
+ cc = id_to_curve(curve);
+ r = point_decode(&P, G, Glen, cc);
+ point_mul(&P, x, xlen, cc);
+ if (Glen == cc->point_len) {
+ point_encode(G, &P, cc);
+ }
+ return r;
+}
+
+static size_t
+api_mulgen(unsigned char *R,
+ const unsigned char *x, size_t xlen, int curve)
+{
+ const unsigned char *G;
+ size_t Glen;
+
+ G = api_generator(curve, &Glen);
+ memcpy_P(R, G, Glen);
+ api_mul(R, Glen, x, xlen, curve);
+ return Glen;
+}
+
+static uint32_t
+api_muladd(unsigned char *A, const unsigned char *B, size_t len,
+ const unsigned char *x, size_t xlen,
+ const unsigned char *y, size_t ylen, int curve)
+{
+ uint32_t r, t, z;
+ const curve_params *cc;
+ jacobian P, Q;
+
+ /*
+ * TODO: see about merging the two ladders. Right now, we do
+ * two independent point multiplications, which is a bit
+ * wasteful of CPU resources (but yields short code).
+ */
+
+ cc = id_to_curve(curve);
+ r = point_decode(&P, A, len, cc);
+ if (B == NULL) {
+ size_t Glen;
+
+ B = api_generator(curve, &Glen);
+ }
+ r &= point_decode(&Q, B, len, cc);
+ point_mul(&P, x, xlen, cc);
+ point_mul(&Q, y, ylen, cc);
+
+ /*
+ * We want to compute P+Q. Since the base points A and B are distinct
+ * from infinity, and the multipliers are non-zero and lower than the
+ * curve order, then we know that P and Q are non-infinity. This
+ * leaves two special situations to test for:
+ * -- If P = Q then we must use point_double().
+ * -- If P+Q = 0 then we must report an error.
+ */
+ t = point_add(&P, &Q, cc);
+ point_double(&Q, cc);
+ z = br_i15_iszero(P.c[2]);
+
+ /*
+ * If z is 1 then either P+Q = 0 (t = 1) or P = Q (t = 0). So we
+ * have the following:
+ *
+ * z = 0, t = 0 return P (normal addition)
+ * z = 0, t = 1 return P (normal addition)
+ * z = 1, t = 0 return Q (a 'double' case)
+ * z = 1, t = 1 report an error (P+Q = 0)
+ */
+ CCOPY(z & ~t, &P, &Q, sizeof Q);
+ point_encode(A, &P, cc);
+ r &= ~(z & t);
+
+ return r;
+}
+
+/* see bearssl_ec.h */
+const br_ec_impl br_ec_prime_i15 PROGMEM = {
+ (uint32_t)0x03800000,
+ &api_generator,
+ &api_order,
+ &api_xoff,
+ &api_mul,
+ &api_mulgen,
+ &api_muladd
+};
diff --git a/lib/bearssl-esp8266/src/ec/ec_pubkey.c b/lib/bearssl-esp8266/src/ec/ec_pubkey.c
new file mode 100644
index 000000000..638937f84
--- /dev/null
+++ b/lib/bearssl-esp8266/src/ec/ec_pubkey.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2018 Thomas Pornin
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "t_inner.h"
+
+static const unsigned char POINT_LEN[] PROGMEM = {
+ 0, /* 0: not a valid curve ID */
+ 43, /* sect163k1 */
+ 43, /* sect163r1 */
+ 43, /* sect163r2 */
+ 51, /* sect193r1 */
+ 51, /* sect193r2 */
+ 61, /* sect233k1 */
+ 61, /* sect233r1 */
+ 61, /* sect239k1 */
+ 73, /* sect283k1 */
+ 73, /* sect283r1 */
+ 105, /* sect409k1 */
+ 105, /* sect409r1 */
+ 145, /* sect571k1 */
+ 145, /* sect571r1 */
+ 41, /* secp160k1 */
+ 41, /* secp160r1 */
+ 41, /* secp160r2 */
+ 49, /* secp192k1 */
+ 49, /* secp192r1 */
+ 57, /* secp224k1 */
+ 57, /* secp224r1 */
+ 65, /* secp256k1 */
+ 65, /* secp256r1 */
+ 97, /* secp384r1 */
+ 133, /* secp521r1 */
+ 65, /* brainpoolP256r1 */
+ 97, /* brainpoolP384r1 */
+ 129, /* brainpoolP512r1 */
+ 32, /* curve25519 */
+ 56, /* curve448 */
+};
+
+/* see bearssl_ec.h */
+size_t
+br_ec_compute_pub(const br_ec_impl *impl, br_ec_public_key *pk,
+ void *kbuf, const br_ec_private_key *sk)
+{
+ int curve;
+ size_t len;
+
+ curve = sk->curve;
+ if (curve < 0 || curve >= 32 || curve >= (int)(sizeof POINT_LEN)
+ || ((impl->supported_curves >> curve) & 1) == 0)
+ {
+ return 0;
+ }
+ if (kbuf == NULL) {
+ return pgm_read_byte(&POINT_LEN[curve]);
+ }
+ len = impl->mulgen(kbuf, sk->x, sk->xlen, curve);
+ if (pk != NULL) {
+ pk->curve = curve;
+ pk->q = kbuf;
+ pk->qlen = len;
+ }
+ return len;
+}
diff --git a/lib/bearssl-esp8266/src/ec/ec_secp256r1.c b/lib/bearssl-esp8266/src/ec/ec_secp256r1.c
new file mode 100644
index 000000000..70c856a04
--- /dev/null
+++ b/lib/bearssl-esp8266/src/ec/ec_secp256r1.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "t_inner.h"
+
+static const unsigned char P256_N[] PROGMEM = {
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xBC, 0xE6, 0xFA, 0xAD, 0xA7, 0x17, 0x9E, 0x84,
+ 0xF3, 0xB9, 0xCA, 0xC2, 0xFC, 0x63, 0x25, 0x51
+};
+
+static const unsigned char P256_G[] PROGMEM = {
+ 0x04, 0x6B, 0x17, 0xD1, 0xF2, 0xE1, 0x2C, 0x42,
+ 0x47, 0xF8, 0xBC, 0xE6, 0xE5, 0x63, 0xA4, 0x40,
+ 0xF2, 0x77, 0x03, 0x7D, 0x81, 0x2D, 0xEB, 0x33,
+ 0xA0, 0xF4, 0xA1, 0x39, 0x45, 0xD8, 0x98, 0xC2,
+ 0x96, 0x4F, 0xE3, 0x42, 0xE2, 0xFE, 0x1A, 0x7F,
+ 0x9B, 0x8E, 0xE7, 0xEB, 0x4A, 0x7C, 0x0F, 0x9E,
+ 0x16, 0x2B, 0xCE, 0x33, 0x57, 0x6B, 0x31, 0x5E,
+ 0xCE, 0xCB, 0xB6, 0x40, 0x68, 0x37, 0xBF, 0x51,
+ 0xF5
+};
+
+/* see inner.h */
+const br_ec_curve_def br_secp256r1 PROGMEM = {
+ BR_EC_secp256r1,
+ P256_N, sizeof P256_N,
+ P256_G, sizeof P256_G
+};
diff --git a/lib/bearssl-esp8266/src/ec/ec_secp384r1.c b/lib/bearssl-esp8266/src/ec/ec_secp384r1.c
new file mode 100644
index 000000000..2e6d63709
--- /dev/null
+++ b/lib/bearssl-esp8266/src/ec/ec_secp384r1.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "t_inner.h"
+
+static const unsigned char P384_N[] PROGMEM = {
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xC7, 0x63, 0x4D, 0x81, 0xF4, 0x37, 0x2D, 0xDF,
+ 0x58, 0x1A, 0x0D, 0xB2, 0x48, 0xB0, 0xA7, 0x7A,
+ 0xEC, 0xEC, 0x19, 0x6A, 0xCC, 0xC5, 0x29, 0x73
+};
+
+static const unsigned char P384_G[] PROGMEM = {
+ 0x04, 0xAA, 0x87, 0xCA, 0x22, 0xBE, 0x8B, 0x05,
+ 0x37, 0x8E, 0xB1, 0xC7, 0x1E, 0xF3, 0x20, 0xAD,
+ 0x74, 0x6E, 0x1D, 0x3B, 0x62, 0x8B, 0xA7, 0x9B,
+ 0x98, 0x59, 0xF7, 0x41, 0xE0, 0x82, 0x54, 0x2A,
+ 0x38, 0x55, 0x02, 0xF2, 0x5D, 0xBF, 0x55, 0x29,
+ 0x6C, 0x3A, 0x54, 0x5E, 0x38, 0x72, 0x76, 0x0A,
+ 0xB7, 0x36, 0x17, 0xDE, 0x4A, 0x96, 0x26, 0x2C,
+ 0x6F, 0x5D, 0x9E, 0x98, 0xBF, 0x92, 0x92, 0xDC,
+ 0x29, 0xF8, 0xF4, 0x1D, 0xBD, 0x28, 0x9A, 0x14,
+ 0x7C, 0xE9, 0xDA, 0x31, 0x13, 0xB5, 0xF0, 0xB8,
+ 0xC0, 0x0A, 0x60, 0xB1, 0xCE, 0x1D, 0x7E, 0x81,
+ 0x9D, 0x7A, 0x43, 0x1D, 0x7C, 0x90, 0xEA, 0x0E,
+ 0x5F
+};
+
+/* see inner.h */
+const br_ec_curve_def br_secp384r1 PROGMEM = {
+ BR_EC_secp384r1,
+ P384_N, sizeof P384_N,
+ P384_G, sizeof P384_G
+};
diff --git a/lib/bearssl-esp8266/src/ec/ec_secp521r1.c b/lib/bearssl-esp8266/src/ec/ec_secp521r1.c
new file mode 100644
index 000000000..4c082481d
--- /dev/null
+++ b/lib/bearssl-esp8266/src/ec/ec_secp521r1.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "t_inner.h"
+
+static const unsigned char P521_N[] PROGMEM = {
+ 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFA, 0x51, 0x86, 0x87, 0x83, 0xBF, 0x2F,
+ 0x96, 0x6B, 0x7F, 0xCC, 0x01, 0x48, 0xF7, 0x09,
+ 0xA5, 0xD0, 0x3B, 0xB5, 0xC9, 0xB8, 0x89, 0x9C,
+ 0x47, 0xAE, 0xBB, 0x6F, 0xB7, 0x1E, 0x91, 0x38,
+ 0x64, 0x09
+};
+
+static const unsigned char P521_G[] PROGMEM = {
+ 0x04, 0x00, 0xC6, 0x85, 0x8E, 0x06, 0xB7, 0x04,
+ 0x04, 0xE9, 0xCD, 0x9E, 0x3E, 0xCB, 0x66, 0x23,
+ 0x95, 0xB4, 0x42, 0x9C, 0x64, 0x81, 0x39, 0x05,
+ 0x3F, 0xB5, 0x21, 0xF8, 0x28, 0xAF, 0x60, 0x6B,
+ 0x4D, 0x3D, 0xBA, 0xA1, 0x4B, 0x5E, 0x77, 0xEF,
+ 0xE7, 0x59, 0x28, 0xFE, 0x1D, 0xC1, 0x27, 0xA2,
+ 0xFF, 0xA8, 0xDE, 0x33, 0x48, 0xB3, 0xC1, 0x85,
+ 0x6A, 0x42, 0x9B, 0xF9, 0x7E, 0x7E, 0x31, 0xC2,
+ 0xE5, 0xBD, 0x66, 0x01, 0x18, 0x39, 0x29, 0x6A,
+ 0x78, 0x9A, 0x3B, 0xC0, 0x04, 0x5C, 0x8A, 0x5F,
+ 0xB4, 0x2C, 0x7D, 0x1B, 0xD9, 0x98, 0xF5, 0x44,
+ 0x49, 0x57, 0x9B, 0x44, 0x68, 0x17, 0xAF, 0xBD,
+ 0x17, 0x27, 0x3E, 0x66, 0x2C, 0x97, 0xEE, 0x72,
+ 0x99, 0x5E, 0xF4, 0x26, 0x40, 0xC5, 0x50, 0xB9,
+ 0x01, 0x3F, 0xAD, 0x07, 0x61, 0x35, 0x3C, 0x70,
+ 0x86, 0xA2, 0x72, 0xC2, 0x40, 0x88, 0xBE, 0x94,
+ 0x76, 0x9F, 0xD1, 0x66, 0x50
+};
+
+/* see inner.h */
+const br_ec_curve_def br_secp521r1 PROGMEM = {
+ BR_EC_secp521r1,
+ P521_N, sizeof P521_N,
+ P521_G, sizeof P521_G
+};
diff --git a/lib/bearssl-esp8266/src/ec/ecdsa_atr.c b/lib/bearssl-esp8266/src/ec/ecdsa_atr.c
new file mode 100644
index 000000000..e5b61f05d
--- /dev/null
+++ b/lib/bearssl-esp8266/src/ec/ecdsa_atr.c
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "t_inner.h"
+
+/* see bearssl_ec.h */
+size_t
+br_ecdsa_asn1_to_raw(void *sig, size_t sig_len)
+{
+ /*
+ * Note: this code is a bit lenient in that it accepts a few
+ * deviations to DER with regards to minimality of encoding of
+ * lengths and integer values. These deviations are still
+ * unambiguous.
+ *
+ * Signature format is a SEQUENCE of two INTEGER values. We
+ * support only integers of less than 127 bytes each (signed
+ * encoding) so the resulting raw signature will have length
+ * at most 254 bytes.
+ */
+
+ unsigned char *buf, *r, *s;
+ size_t zlen, rlen, slen, off;
+ unsigned char tmp[254];
+
+ buf = sig;
+ if (sig_len < 8) {
+ return 0;
+ }
+
+ /*
+ * First byte is SEQUENCE tag.
+ */
+ if (buf[0] != 0x30) {
+ return 0;
+ }
+
+ /*
+ * The SEQUENCE length will be encoded over one or two bytes. We
+ * limit the total SEQUENCE contents to 255 bytes, because it
+ * makes things simpler; this is enough for subgroup orders up
+ * to 999 bits.
+ */
+ zlen = buf[1];
+ if (zlen > 0x80) {
+ if (zlen != 0x81) {
+ return 0;
+ }
+ zlen = buf[2];
+ if (zlen != sig_len - 3) {
+ return 0;
+ }
+ off = 3;
+ } else {
+ if (zlen != sig_len - 2) {
+ return 0;
+ }
+ off = 2;
+ }
+
+ /*
+ * First INTEGER (r).
+ */
+ if (buf[off ++] != 0x02) {
+ return 0;
+ }
+ rlen = buf[off ++];
+ if (rlen >= 0x80) {
+ return 0;
+ }
+ r = buf + off;
+ off += rlen;
+
+ /*
+ * Second INTEGER (s).
+ */
+ if (off + 2 > sig_len) {
+ return 0;
+ }
+ if (buf[off ++] != 0x02) {
+ return 0;
+ }
+ slen = buf[off ++];
+ if (slen >= 0x80 || slen != sig_len - off) {
+ return 0;
+ }
+ s = buf + off;
+
+ /*
+ * Removing leading zeros from r and s.
+ */
+ while (rlen > 0 && *r == 0) {
+ rlen --;
+ r ++;
+ }
+ while (slen > 0 && *s == 0) {
+ slen --;
+ s ++;
+ }
+
+ /*
+ * Compute common length for the two integers, then copy integers
+ * into the temporary buffer, and finally copy it back over the
+ * signature buffer.
+ */
+ zlen = rlen > slen ? rlen : slen;
+ sig_len = zlen << 1;
+ memset(tmp, 0, sig_len);
+ memcpy(tmp + zlen - rlen, r, rlen);
+ memcpy(tmp + sig_len - slen, s, slen);
+ memcpy(sig, tmp, sig_len);
+ return sig_len;
+}
diff --git a/lib/bearssl-esp8266/src/ec/ecdsa_default_sign_asn1.c b/lib/bearssl-esp8266/src/ec/ecdsa_default_sign_asn1.c
new file mode 100644
index 000000000..c07ad2aff
--- /dev/null
+++ b/lib/bearssl-esp8266/src/ec/ecdsa_default_sign_asn1.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "t_inner.h"
+
+/* see bearssl_ec.h */
+br_ecdsa_sign
+br_ecdsa_sign_asn1_get_default(void)
+{
+#if BR_LOMUL
+ return &br_ecdsa_i15_sign_asn1;
+#else
+ return &br_ecdsa_i31_sign_asn1;
+#endif
+}
diff --git a/lib/bearssl-esp8266/src/ec/ecdsa_default_sign_raw.c b/lib/bearssl-esp8266/src/ec/ecdsa_default_sign_raw.c
new file mode 100644
index 000000000..cbaa9b80f
--- /dev/null
+++ b/lib/bearssl-esp8266/src/ec/ecdsa_default_sign_raw.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "t_inner.h"
+
+/* see bearssl_ec.h */
+br_ecdsa_sign
+br_ecdsa_sign_raw_get_default(void)
+{
+#if BR_LOMUL
+ return &br_ecdsa_i15_sign_raw;
+#else
+ return &br_ecdsa_i31_sign_raw;
+#endif
+}
diff --git a/lib/bearssl-esp8266/src/ec/ecdsa_default_vrfy_asn1.c b/lib/bearssl-esp8266/src/ec/ecdsa_default_vrfy_asn1.c
new file mode 100644
index 000000000..0a82bc413
--- /dev/null
+++ b/lib/bearssl-esp8266/src/ec/ecdsa_default_vrfy_asn1.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "t_inner.h"
+
+/* see bearssl_ec.h */
+br_ecdsa_vrfy
+br_ecdsa_vrfy_asn1_get_default(void)
+{
+#if BR_LOMUL
+ return &br_ecdsa_i15_vrfy_asn1;
+#else
+ return &br_ecdsa_i31_vrfy_asn1;
+#endif
+}
diff --git a/lib/bearssl-esp8266/src/ec/ecdsa_default_vrfy_raw.c b/lib/bearssl-esp8266/src/ec/ecdsa_default_vrfy_raw.c
new file mode 100644
index 000000000..833e79f16
--- /dev/null
+++ b/lib/bearssl-esp8266/src/ec/ecdsa_default_vrfy_raw.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "t_inner.h"
+
+/* see bearssl_ec.h */
+br_ecdsa_vrfy
+br_ecdsa_vrfy_raw_get_default(void)
+{
+#if BR_LOMUL
+ return &br_ecdsa_i15_vrfy_raw;
+#else
+ return &br_ecdsa_i31_vrfy_raw;
+#endif
+}
diff --git a/lib/bearssl-esp8266/src/ec/ecdsa_i15_bits.c b/lib/bearssl-esp8266/src/ec/ecdsa_i15_bits.c
new file mode 100644
index 000000000..e1e754d3f
--- /dev/null
+++ b/lib/bearssl-esp8266/src/ec/ecdsa_i15_bits.c
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin