Update Irremote lib to latest master commit ca474a6 (#24226)
This commit is contained in:
parent
a922d6609f
commit
df1aa6dc98
@ -25,7 +25,7 @@ jobs:
|
||||
JSONI=${JSONI//$'\n'}
|
||||
echo $JSONI
|
||||
# Set output
|
||||
echo "::set-output name=matrix::[${JSONI}]"
|
||||
echo "matrix=[${JSONI}]" >> $GITHUB_OUTPUT
|
||||
Build_Example:
|
||||
needs: Gen_Matrix
|
||||
runs-on: ubuntu-latest
|
||||
@ -36,19 +36,19 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Cache pip
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.cache/pip
|
||||
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pip-
|
||||
- name: Cache PlatformIO
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.platformio
|
||||
key: ${{ runner.os }}-${{ hashFiles('**/platformio.ini') }}
|
||||
- name: Cache PlatformIO build
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: .pio
|
||||
key: pio-${{ runner.os }}-${{ matrix.project }}
|
||||
@ -56,10 +56,13 @@ jobs:
|
||||
pio-${{ runner.os }}-
|
||||
pio-
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v2
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.13'
|
||||
- name: Install PlatformIO
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install --upgrade intelhex
|
||||
pip install --upgrade platformio
|
||||
- name: Build example
|
||||
env:
|
||||
|
||||
@ -42,7 +42,7 @@ jobs:
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v2
|
||||
uses: github/codeql-action/init@v3
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
@ -56,7 +56,7 @@ jobs:
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v2
|
||||
uses: github/codeql-action/autobuild@v3
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
|
||||
@ -69,4 +69,4 @@ jobs:
|
||||
# ./location_of_script_within_repo/buildscript.sh
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v2
|
||||
uses: github/codeql-action/analyze@v3
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
set noparent
|
||||
root=src
|
||||
linelength=80
|
||||
filter=-whitespace/indent_namespace
|
||||
|
||||
@ -77,6 +77,8 @@ If you want to [contribute](.github/CONTRIBUTING.md#how-can-i-contribute) to thi
|
||||
- Improve our documentation
|
||||
- [Creating issues](.github/CONTRIBUTING.md#reporting-bugs) and [pull requests](.github/CONTRIBUTING.md#pull-requests)
|
||||
- Tell other people about this library
|
||||
- Updated documentation formatting and clarified installation steps (Hacktoberfest contribution by Prerna Utage)
|
||||
|
||||
|
||||
## Contributors
|
||||
Available [here](.github/Contributors.md)
|
||||
@ -87,3 +89,6 @@ This library was originally based on Ken Shirriff's work (https://github.com/shi
|
||||
[Mark Szabo](https://github.com/crankyoldgit/IRremoteESP8266) has updated the IRsend class to work on ESP8266 and [Sebastien Warin](https://github.com/sebastienwarin/IRremoteESP8266) the receiving & decoding part (IRrecv class).
|
||||
|
||||
As of v2.0, the library was almost entirely re-written with the ESP8266's resources in mind.
|
||||
|
||||
## About This Project
|
||||
This project allows decoding and encoding of IR signals for controlling Air Conditioners and other devices using ESP8266 or ESP32 boards.
|
||||
|
||||
@ -593,7 +593,7 @@ bool mountSpiffs(void) {
|
||||
bool saveConfig(void) {
|
||||
debug("Saving the config.");
|
||||
bool success = false;
|
||||
DynamicJsonDocument json(kJsonConfigMaxSize);
|
||||
JsonDocument json;
|
||||
#if MQTT_ENABLE
|
||||
json[kMqttServerKey] = MqttServer;
|
||||
json[kMqttPortKey] = MqttPort;
|
||||
@ -611,6 +611,8 @@ bool saveConfig(void) {
|
||||
const String key = KEY_TX_GPIO + String(i);
|
||||
json[key] = static_cast<int>(txGpioTable[i]);
|
||||
}
|
||||
if (json.overflowed())
|
||||
debug("ERROR: no enough memory to store the entire json document");
|
||||
|
||||
if (mountSpiffs()) {
|
||||
File configFile = FILESYSTEM.open(kConfigFile, "w");
|
||||
@ -642,7 +644,7 @@ bool loadConfigFile(void) {
|
||||
std::unique_ptr<char[]> buf(new char[size]);
|
||||
|
||||
configFile.readBytes(buf.get(), size);
|
||||
DynamicJsonDocument json(kJsonConfigMaxSize);
|
||||
JsonDocument json;
|
||||
if (!deserializeJson(json, buf.get(), kJsonConfigMaxSize)) {
|
||||
debug("Json config file parsed ok.");
|
||||
#if MQTT_ENABLE
|
||||
@ -1659,11 +1661,13 @@ bool parseStringAndSendAirCon(IRsend *irsend, const decode_type_t irType,
|
||||
stateSize = inputLength / 2; // Every two hex chars is a byte.
|
||||
// Use at least the minimum size.
|
||||
stateSize = std::max(stateSize,
|
||||
(uint16_t) (kFujitsuAcStateLengthShort - 1));
|
||||
static_cast<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));
|
||||
stateSize = std::max(stateSize,
|
||||
static_cast<uint16_t>(kFujitsuAcStateLength - 1));
|
||||
// Lastly, it should never exceed the maximum "normal" size.
|
||||
stateSize = std::min(stateSize, kFujitsuAcStateLength);
|
||||
break;
|
||||
@ -1675,12 +1679,12 @@ bool parseStringAndSendAirCon(IRsend *irsend, const decode_type_t irType,
|
||||
stateSize = inputLength / 2; // Every two hex chars is a byte.
|
||||
// Use at least the minimum size.
|
||||
stateSize = std::max(stateSize,
|
||||
(uint16_t) (kHitachiAc3MinStateLength));
|
||||
static_cast<uint16_t>(kHitachiAc3MinStateLength));
|
||||
// If we think it isn't a "short" message.
|
||||
if (stateSize > kHitachiAc3MinStateLength)
|
||||
// Then it probably the "normal" size.
|
||||
stateSize = std::max(stateSize,
|
||||
(uint16_t) (kHitachiAc3StateLength));
|
||||
static_cast<uint16_t>(kHitachiAc3StateLength));
|
||||
// Lastly, it should never exceed the maximum "normal" size.
|
||||
stateSize = std::min(stateSize, kHitachiAc3StateLength);
|
||||
break;
|
||||
@ -1691,7 +1695,7 @@ bool parseStringAndSendAirCon(IRsend *irsend, const decode_type_t irType,
|
||||
// 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);
|
||||
stateSize = std::max(stateSize, static_cast<uint16_t>(3));
|
||||
// Cap the maximum size.
|
||||
stateSize = std::min(stateSize, kStateSizeMax);
|
||||
break;
|
||||
@ -1702,12 +1706,13 @@ bool parseStringAndSendAirCon(IRsend *irsend, const decode_type_t irType,
|
||||
// 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));
|
||||
stateSize = std::max(stateSize,
|
||||
static_cast<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));
|
||||
stateSize = std::max(
|
||||
stateSize, static_cast<uint16_t>(kSamsungAcExtendedStateLength));
|
||||
// Lastly, it should never exceed the maximum "extended" size.
|
||||
stateSize = std::min(stateSize, kSamsungAcExtendedStateLength);
|
||||
break;
|
||||
@ -2671,7 +2676,8 @@ void receivingMQTT(String const topic_name, String const callback_str) {
|
||||
switch (ircommand[0]) {
|
||||
case kPauseChar:
|
||||
{ // It's a pause. Everything after the 'P' should be a number.
|
||||
int32_t msecs = std::min((int32_t) strtoul(ircommand + 1, NULL, 10),
|
||||
int32_t msecs = std::min(static_cast<int32_t>(strtoul(ircommand + 1,
|
||||
NULL, 10)),
|
||||
kMaxPauseMs);
|
||||
delay(msecs);
|
||||
mqtt_client.publish(MqttAck.c_str(),
|
||||
@ -3142,7 +3148,7 @@ bool sendFloat(const String topic, const float_t temp, const bool retain) {
|
||||
#if MQTT_CLIMATE_JSON
|
||||
void sendJsonState(const stdAc::state_t state, const String topic,
|
||||
const bool retain, const bool ha_mode) {
|
||||
DynamicJsonDocument json(kJsonAcStateMaxSize);
|
||||
JsonDocument json;
|
||||
json[KEY_PROTOCOL] = typeToString(state.protocol);
|
||||
json[KEY_MODEL] = state.model;
|
||||
json[KEY_COMMAND] = IRac::commandToString(state.command);
|
||||
@ -3168,6 +3174,8 @@ void sendJsonState(const stdAc::state_t state, const String topic,
|
||||
json[KEY_CLEAN] = IRac::boolToString(state.clean);
|
||||
json[KEY_BEEP] = IRac::boolToString(state.beep);
|
||||
json[KEY_SLEEP] = state.sleep;
|
||||
if (json.overflowed())
|
||||
debug("ERROR: no enough memory to store the entire json document");
|
||||
|
||||
String payload = "";
|
||||
payload.reserve(200);
|
||||
@ -3175,16 +3183,16 @@ void sendJsonState(const stdAc::state_t state, const String topic,
|
||||
sendString(topic, payload, retain);
|
||||
}
|
||||
|
||||
bool validJsonStr(DynamicJsonDocument doc, const char* key) {
|
||||
bool validJsonStr(JsonDocument doc, const char* key) {
|
||||
return doc.containsKey(key) && doc[key].is<char*>();
|
||||
}
|
||||
|
||||
bool validJsonInt(DynamicJsonDocument doc, const char* key) {
|
||||
bool validJsonInt(JsonDocument doc, const char* key) {
|
||||
return doc.containsKey(key) && doc[key].is<signed int>();
|
||||
}
|
||||
|
||||
stdAc::state_t jsonToState(const stdAc::state_t current, const char *str) {
|
||||
DynamicJsonDocument json(kJsonAcStateMaxSize);
|
||||
JsonDocument json;
|
||||
if (deserializeJson(json, str, kJsonAcStateMaxSize)) {
|
||||
debug("json MQTT message did not parse. Skipping!");
|
||||
return current;
|
||||
|
||||
@ -14,7 +14,7 @@ monitor_speed = 115200
|
||||
lib_deps_builtin =
|
||||
lib_deps_external =
|
||||
PubSubClient@>=2.8.0
|
||||
ArduinoJson@>=6.0
|
||||
ArduinoJson@>=7.0
|
||||
# Uncomment the following to enable SHT-3x support.
|
||||
# https://github.com/wemos/WEMOS_SHT3x_Arduino_Library.git
|
||||
|
||||
|
||||
@ -87,7 +87,7 @@ void dump(decode_results *results) {
|
||||
Serial.print(results->rawbuf[i] * kRawTick, DEC);
|
||||
} else {
|
||||
Serial.print(", ");
|
||||
Serial.print((uint32_t) results->rawbuf[i] * kRawTick, DEC);
|
||||
Serial.print(static_cast<uint32_t>(results->rawbuf[i] * kRawTick), DEC);
|
||||
}
|
||||
}
|
||||
Serial.println("};");
|
||||
|
||||
@ -130,6 +130,8 @@ decode_results results; // Somewhere to store the results
|
||||
void setup() {
|
||||
#if defined(ESP8266)
|
||||
Serial.begin(kBaudRate, SERIAL_8N1, SERIAL_TX_ONLY);
|
||||
#elif ARDUINO_USB_CDC_ON_BOOT
|
||||
Serial.begin(kBaudRate);
|
||||
#else // ESP8266
|
||||
Serial.begin(kBaudRate, SERIAL_8N1);
|
||||
#endif // ESP8266
|
||||
|
||||
@ -138,6 +138,8 @@ void setup() {
|
||||
OTAwifi(); // start default wifi (previously saved on the ESP) for OTA
|
||||
#if defined(ESP8266)
|
||||
Serial.begin(kBaudRate, SERIAL_8N1, SERIAL_TX_ONLY);
|
||||
#elif ARDUINO_USB_CDC_ON_BOOT
|
||||
Serial.begin(kBaudRate);
|
||||
#else // ESP8266
|
||||
Serial.begin(kBaudRate, SERIAL_8N1);
|
||||
#endif // ESP8266
|
||||
|
||||
@ -46,5 +46,6 @@
|
||||
],
|
||||
"exclude": [".github", "extras", "docs", "assets"],
|
||||
"frameworks": "arduino",
|
||||
"libCompatMode": "strict",
|
||||
"platforms": ["espressif8266", "espressif32"]
|
||||
}
|
||||
|
||||
@ -13,6 +13,7 @@
|
||||
#include <string>
|
||||
#endif
|
||||
#include <cmath>
|
||||
#include <memory>
|
||||
#if __cplusplus >= 201103L && defined(_GLIBCXX_USE_C99_MATH_TR1)
|
||||
using std::roundf;
|
||||
#else
|
||||
@ -33,6 +34,7 @@
|
||||
#include "ir_Daikin.h"
|
||||
#include "ir_Ecoclim.h"
|
||||
#include "ir_Electra.h"
|
||||
#include "ir_Eurom.h"
|
||||
#include "ir_Fujitsu.h"
|
||||
#include "ir_Haier.h"
|
||||
#include "ir_Hitachi.h"
|
||||
@ -243,6 +245,9 @@ bool IRac::isProtocolSupported(const decode_type_t protocol) {
|
||||
#if SEND_ELECTRA_AC
|
||||
case decode_type_t::ELECTRA_AC:
|
||||
#endif
|
||||
#if SEND_EUROM
|
||||
case decode_type_t::EUROM:
|
||||
#endif
|
||||
#if SEND_FUJITSU_AC
|
||||
case decode_type_t::FUJITSU_AC:
|
||||
#endif
|
||||
@ -402,10 +407,8 @@ void IRac::airton(IRAirtonAc *ac,
|
||||
const int16_t sleep) {
|
||||
ac->begin();
|
||||
ac->setPower(on);
|
||||
ac->setTemp(degrees);
|
||||
// Mode needs to be set after temp as Fan-only uses a special temp.
|
||||
ac->setMode(ac->convertMode(mode));
|
||||
// Fan needs to be set after mode, as setMode can change the fan speed.
|
||||
ac->setTemp(degrees);
|
||||
ac->setFan(ac->convertFan(fan));
|
||||
ac->setSwingV(swingv != stdAc::swingv_t::kOff);
|
||||
// No Quiet setting available.
|
||||
@ -592,13 +595,19 @@ void IRac::argoWrem3_ConfigSet(IRArgoAC_WREM3 *ac, const uint8_t param,
|
||||
if (safe) {
|
||||
switch (param) {
|
||||
case 5: // temp. scale (note this is likely excess as not transmitted)
|
||||
if (value > 1) { return; /* invalid */ }
|
||||
if (value > 1) {
|
||||
return; /* invalid */
|
||||
}
|
||||
break;
|
||||
case 6: // channel (note this is likely excess as not transmitted)
|
||||
if (value > 3) { return; /* invalid */ }
|
||||
if (value > 3) {
|
||||
return; /* invalid */
|
||||
}
|
||||
break;
|
||||
case 12: // eco power limit
|
||||
if (value < 30 || value > 99) { return; /* invalid */ }
|
||||
if (value < 30 || value > 99) {
|
||||
return; /* invalid */
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return; /* invalid */
|
||||
@ -738,8 +747,10 @@ void IRac::coolix(IRCoolixAC *ac,
|
||||
ac->send();
|
||||
return;
|
||||
}
|
||||
ac->setMode(ac->convertMode(mode));
|
||||
ac->setTemp(degrees);
|
||||
// Mode needs to be set after temp as Fan-only uses a special temp.
|
||||
ac->setMode(ac->convertMode(mode));
|
||||
// Fan needs to be set after mode, as setMode can change the fan speed.
|
||||
ac->setFan(ac->convertFan(fan));
|
||||
// No Filter setting available.
|
||||
// No Beep setting available.
|
||||
@ -1169,6 +1180,7 @@ void IRac::ecoclim(IREcoclimAc *ac,
|
||||
/// @param[in] swingv The vertical swing setting.
|
||||
/// @param[in] swingh The horizontal swing setting.
|
||||
/// @param[in] iFeel Whether to enable iFeel (remote temp) mode on the A/C unit.
|
||||
/// @param[in] quiet Run the device in quiet/silent mode.
|
||||
/// @param[in] turbo Run the device in turbo/powerful mode.
|
||||
/// @param[in] lighttoggle Should we toggle the LED/Display?
|
||||
/// @param[in] clean Turn on the self-cleaning mode. e.g. Mould, dry filters etc
|
||||
@ -1177,7 +1189,8 @@ void IRac::electra(IRElectraAc *ac,
|
||||
const float degrees, const float sensorTemp,
|
||||
const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv,
|
||||
const stdAc::swingh_t swingh, const bool iFeel,
|
||||
const bool turbo, const bool lighttoggle, const bool clean) {
|
||||
const bool quiet, const bool turbo, const bool lighttoggle,
|
||||
const bool clean) {
|
||||
ac->begin();
|
||||
ac->setPower(on);
|
||||
ac->setMode(ac->convertMode(mode));
|
||||
@ -1188,7 +1201,7 @@ void IRac::electra(IRElectraAc *ac,
|
||||
ac->setFan(ac->convertFan(fan));
|
||||
ac->setSwingV(swingv != stdAc::swingv_t::kOff);
|
||||
ac->setSwingH(swingh != stdAc::swingh_t::kOff);
|
||||
// No Quiet setting available.
|
||||
ac->setQuiet(quiet);
|
||||
ac->setTurbo(turbo);
|
||||
ac->setLightToggle(lighttoggle);
|
||||
// No Econo setting available.
|
||||
@ -1202,6 +1215,31 @@ void IRac::electra(IRElectraAc *ac,
|
||||
}
|
||||
#endif // SEND_ELECTRA_AC
|
||||
|
||||
#if SEND_EUROM
|
||||
/// Send an Eurom A/C message with the supplied settings.
|
||||
/// @param[in, out] ac A Ptr to an IREuromAc object to use.
|
||||
/// @param[in] power The power setting.
|
||||
/// @param[in] mode The operation mode setting.
|
||||
/// @param[in] degrees The temperature setting in degrees, normally Celsius.
|
||||
/// @param[in] fahrenheit If the given temperature is in Fahrenheit instead.
|
||||
/// @param[in] fan The speed setting for the fan.
|
||||
/// @param[in] swingv The swing setting.
|
||||
/// @param[in] sleep The sleep mode setting.
|
||||
void IRac::eurom(IREuromAc *ac, const bool power, const stdAc::opmode_t mode,
|
||||
const float degrees, const bool fahrenheit,
|
||||
const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv,
|
||||
const bool sleep) {
|
||||
ac->begin();
|
||||
ac->setPower(power);
|
||||
ac->setMode(ac->convertMode(mode));
|
||||
ac->setTemp(degrees, fahrenheit);
|
||||
ac->setFan(ac->convertFan(fan));
|
||||
ac->setSwing(ac->convertSwing(swingv));
|
||||
ac->setSleep(sleep);
|
||||
ac->send();
|
||||
}
|
||||
#endif // SEND_EUROM
|
||||
|
||||
#if SEND_FUJITSU_AC
|
||||
/// Send a Fujitsu A/C message with the supplied settings.
|
||||
/// @param[in, out] ac A Ptr to an IRFujitsuAC object to use.
|
||||
@ -3225,11 +3263,20 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) {
|
||||
{
|
||||
IRElectraAc ac(_pin, _inverted, _modulation);
|
||||
electra(&ac, send.power, send.mode, degC, sensorTempC, send.fanspeed,
|
||||
send.swingv, send.swingh, send.iFeel, send.turbo, send.light,
|
||||
send.clean);
|
||||
send.swingv, send.swingh, send.iFeel, send.quiet, send.turbo,
|
||||
send.light, send.clean);
|
||||
break;
|
||||
}
|
||||
#endif // SEND_ELECTRA_AC
|
||||
#if SEND_EUROM
|
||||
case EUROM:
|
||||
{
|
||||
IREuromAc ac(_pin, _inverted, _modulation);
|
||||
eurom(&ac, send.power, send.mode, send.degrees, !send.celsius,
|
||||
send.fanspeed, send.swingv, send.sleep);
|
||||
break;
|
||||
}
|
||||
#endif // SEND_EUROM
|
||||
#if SEND_FUJITSU_AC
|
||||
case FUJITSU_AC:
|
||||
{
|
||||
@ -3277,8 +3324,8 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) {
|
||||
{
|
||||
IRHaierAC160 ac(_pin, _inverted, _modulation);
|
||||
haier160(&ac, send.power, send.mode, send.celsius, send.degrees,
|
||||
send.fanspeed, send.swingv, send.turbo, send.filter, send.clean,
|
||||
send.light, prev_light, send.sleep);
|
||||
send.fanspeed, send.swingv, send.turbo, send.quiet,
|
||||
send.filter, send.clean, send.light, prev_light, send.sleep);
|
||||
break;
|
||||
}
|
||||
#endif // SEND_HAIER_AC160
|
||||
@ -3288,7 +3335,8 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) {
|
||||
IRHaierAC176 ac(_pin, _inverted, _modulation);
|
||||
haier176(&ac, (haier_ac176_remote_model_t)send.model, send.power,
|
||||
send.mode, send.celsius, send.degrees, send.fanspeed,
|
||||
send.swingv, send.swingh, send.turbo, send.filter, send.sleep);
|
||||
send.swingv, send.swingh, send.turbo, send.quiet, send.filter,
|
||||
send.sleep);
|
||||
break;
|
||||
}
|
||||
#endif // SEND_HAIER_AC176
|
||||
@ -3298,7 +3346,7 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) {
|
||||
IRHaierACYRW02 ac(_pin, _inverted, _modulation);
|
||||
haierYrwo2(&ac, send.power, send.mode, send.celsius, send.degrees,
|
||||
send.fanspeed, send.swingv, send.swingh, send.turbo,
|
||||
send.filter, send.sleep);
|
||||
send.quiet, send.filter, send.sleep);
|
||||
break;
|
||||
}
|
||||
#endif // SEND_HAIER_AC_YRW02
|
||||
@ -4118,6 +4166,15 @@ namespace IRAcUtils {
|
||||
return ac.toString();
|
||||
}
|
||||
#endif // DECODE_COOLIX
|
||||
#if DECODE_COOLIX48
|
||||
case decode_type_t::COOLIX48: {
|
||||
IRCoolixAC ac(kGpioUnused);
|
||||
ac.on();
|
||||
// Coolix uses value instead of state.
|
||||
ac.setRawFromCoolix48(result->value);
|
||||
return ac.toString();
|
||||
}
|
||||
#endif // DECODE_COOLIX
|
||||
#if DECODE_CORONA_AC
|
||||
case decode_type_t::CORONA_AC: {
|
||||
IRCoronaAc ac(kGpioUnused);
|
||||
@ -4205,6 +4262,13 @@ namespace IRAcUtils {
|
||||
return ac.toString();
|
||||
}
|
||||
#endif // DECODE_ELECTRA_AC
|
||||
#if DECODE_EUROM
|
||||
case decode_type_t::EUROM: {
|
||||
IREuromAc ac(kGpioUnused);
|
||||
ac.setRaw(result->state);
|
||||
return ac.toString();
|
||||
}
|
||||
#endif // DECODE_EUROM
|
||||
#if DECODE_FUJITSU_AC
|
||||
case decode_type_t::FUJITSU_AC: {
|
||||
IRFujitsuAC ac(kGpioUnused);
|
||||
@ -4705,6 +4769,14 @@ namespace IRAcUtils {
|
||||
break;
|
||||
}
|
||||
#endif // DECODE_ELECTRA_AC
|
||||
#if DECODE_EUROM
|
||||
case decode_type_t::EUROM: {
|
||||
IREuromAc ac(kGpioUnused);
|
||||
ac.setRaw(decode->state);
|
||||
*result = ac.toCommon();
|
||||
break;
|
||||
}
|
||||
#endif // DECODE_EUROM
|
||||
#if DECODE_FUJITSU_AC
|
||||
case decode_type_t::FUJITSU_AC: {
|
||||
IRFujitsuAC ac(kGpioUnused);
|
||||
|
||||
@ -22,6 +22,7 @@
|
||||
#include "ir_Fujitsu.h"
|
||||
#include "ir_Ecoclim.h"
|
||||
#include "ir_Electra.h"
|
||||
#include "ir_Eurom.h"
|
||||
#include "ir_Goodweather.h"
|
||||
#include "ir_Gree.h"
|
||||
#include "ir_Haier.h"
|
||||
@ -264,9 +265,15 @@ void electra(IRElectraAc *ac,
|
||||
const bool on, const stdAc::opmode_t mode,
|
||||
const float degrees, const float sensorTemp,
|
||||
const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv,
|
||||
const stdAc::swingh_t swingh, const bool iFeel, const bool turbo,
|
||||
const bool lighttoggle, const bool clean);
|
||||
const stdAc::swingh_t swingh, const bool iFeel, const bool quiet,
|
||||
const bool turbo, const bool lighttoggle, const bool clean);
|
||||
#endif // SEND_ELECTRA_AC
|
||||
#if SEND_EUROM
|
||||
void eurom(IREuromAc *ac, const bool power, const stdAc::opmode_t mode,
|
||||
const float degrees, const bool fahrenheit,
|
||||
const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv,
|
||||
const bool sleep);
|
||||
#endif // SEND_EUROM
|
||||
#if SEND_FUJITSU_AC
|
||||
void fujitsu(IRFujitsuAC *ac, const fujitsu_ac_remote_model_t model,
|
||||
const bool on, const stdAc::opmode_t mode,
|
||||
|
||||
@ -13,11 +13,6 @@ extern "C" {
|
||||
}
|
||||
#endif // ESP8266
|
||||
#include <Arduino.h>
|
||||
#if defined(ESP32)
|
||||
#if ( defined(ESP_ARDUINO_VERSION_MAJOR) && (ESP_ARDUINO_VERSION_MAJOR >= 3) )
|
||||
#include <driver/gpio.h>
|
||||
#endif // ESP_ARDUINO_VERSION_MAJOR >= 3
|
||||
#endif
|
||||
#endif // UNIT_TEST
|
||||
#include <algorithm>
|
||||
#ifdef UNIT_TEST
|
||||
@ -61,20 +56,24 @@ static ETSTimer timer;
|
||||
} // namespace _IRrecv
|
||||
#endif // ESP8266
|
||||
#if defined(ESP32)
|
||||
#if ( defined(ESP_ARDUINO_VERSION) && \
|
||||
(ESP_ARDUINO_VERSION >= ESP_ARDUINO_VERSION_VAL(3, 0, 0)) )
|
||||
#define _ESP32_ARDUINO_CORE_V3PLUS
|
||||
#endif // ESP_ARDUINO_VERSION >= 3
|
||||
// We need a horrible timer hack for ESP32 Arduino framework < v2.0.0
|
||||
#if !defined(_ESP32_IRRECV_TIMER_HACK)
|
||||
#if !defined(_ESP32_ARDUINO_CORE_V2PLUS)
|
||||
// Version check
|
||||
#if ( defined(ESP_ARDUINO_VERSION_MAJOR) && (ESP_ARDUINO_VERSION_MAJOR >= 2) )
|
||||
// No need for the hack if we are running version >= 2.0.0
|
||||
#define _ESP32_IRRECV_TIMER_HACK false
|
||||
#define _ESP32_ARDUINO_CORE_V2PLUS false
|
||||
#else // Version check
|
||||
// If no ESP_ARDUINO_VERSION_MAJOR is defined, or less than 2, then we are
|
||||
// using an old ESP32 core, so we need the hack.
|
||||
#define _ESP32_IRRECV_TIMER_HACK true
|
||||
#define _ESP32_ARDUINO_CORE_V2PLUS true
|
||||
#endif // Version check
|
||||
#endif // !defined(_ESP32_IRRECV_TIMER_HACK)
|
||||
#endif // !defined(_ESP32_ARDUINO_CORE_V2PLUS)
|
||||
|
||||
#if _ESP32_IRRECV_TIMER_HACK
|
||||
#if _ESP32_ARDUINO_CORE_V2PLUS
|
||||
// Required structs/types from:
|
||||
// https://github.com/espressif/arduino-esp32/blob/6b0114366baf986c155e8173ab7c22bc0c5fcedc/cores/esp32/esp32-hal-timer.c#L28-L58
|
||||
// These are needed to be able to directly manipulate the timer registers from
|
||||
@ -136,7 +135,7 @@ typedef struct hw_timer_s {
|
||||
uint8_t timer;
|
||||
portMUX_TYPE lock;
|
||||
} hw_timer_t;
|
||||
#endif // _ESP32_IRRECV_TIMER_HACK / End of Horrible Hack.
|
||||
#endif // _ESP32_ARDUINO_CORE_V2PLUS / End of Horrible Hack.
|
||||
|
||||
namespace _IRrecv {
|
||||
static hw_timer_t *timer = NULL;
|
||||
@ -230,31 +229,31 @@ static void USE_IRAM_ATTR gpio_intr() {
|
||||
#if defined(ESP32)
|
||||
// Reset the timeout.
|
||||
//
|
||||
#if _ESP32_IRRECV_TIMER_HACK
|
||||
// The following three lines of code are the equiv of:
|
||||
#if _ESP32_ARDUINO_CORE_V2PLUS
|
||||
// The following three lines of code are the equivalent of:
|
||||
// `timerWrite(timer, 0);`
|
||||
// We can't call that routine safely from inside an ISR as that procedure
|
||||
// is not stored in IRAM. Hence, we do it manually so that it's covered by
|
||||
// USE_IRAM_ATTR in this ISR.
|
||||
// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1350
|
||||
// @see https://github.com/espressif/arduino-esp32/blob/6b0114366baf986c155e8173ab7c22bc0c5fcedc/cores/esp32/esp32-hal-timer.c#L106-L110
|
||||
timer->dev->load_high = (uint32_t) 0;
|
||||
timer->dev->load_low = (uint32_t) 0;
|
||||
timer->dev->load_high = static_cast<uint32_t>(0);
|
||||
timer->dev->load_low = static_cast<uint32_t>(0);
|
||||
timer->dev->reload = 1;
|
||||
// The next line is the same, but instead replaces:
|
||||
// `timerAlarmEnable(timer);`
|
||||
// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1350
|
||||
// @see https://github.com/espressif/arduino-esp32/blob/6b0114366baf986c155e8173ab7c22bc0c5fcedc/cores/esp32/esp32-hal-timer.c#L176-L178
|
||||
timer->dev->config.alarm_en = 1;
|
||||
#else // _ESP32_IRRECV_TIMER_HACK
|
||||
#if ( defined(ESP_ARDUINO_VERSION_MAJOR) && (ESP_ARDUINO_VERSION_MAJOR >= 3) )
|
||||
#elif defined(_ESP32_ARDUINO_CORE_V3PLUS)
|
||||
// For ESP32 core version 3.x, replace `timerAlarmEnable`
|
||||
timerWrite(timer, 0);
|
||||
timerStart(timer);
|
||||
#else // ESP_ARDUINO_VERSION_MAJOR >= 3
|
||||
uint64_t alarm_value = 50000; // Example value (50ms)
|
||||
timerAlarm(timer, alarm_value, false, 0);
|
||||
#else // !_ESP32_ARDUINO_CORE_V3PLUS
|
||||
timerWrite(timer, 0);
|
||||
timerAlarmEnable(timer);
|
||||
#endif // ESP_ARDUINO_VERSION_MAJOR >= 3
|
||||
#endif // _ESP32_IRRECV_TIMER_HACK
|
||||
#endif // _ESP32_ARDUINO_CORE_V2PLUS
|
||||
#endif // ESP32
|
||||
}
|
||||
#endif // UNIT_TEST
|
||||
@ -344,10 +343,7 @@ IRrecv::IRrecv(const uint16_t recvpin, const uint16_t bufsize,
|
||||
IRrecv::~IRrecv(void) {
|
||||
disableIRIn();
|
||||
#if defined(ESP32)
|
||||
if (timer != NULL) {
|
||||
timerEnd(timer); // Cleanup the ESP32 timeout timer.
|
||||
timer = NULL;
|
||||
}
|
||||
if (timer != NULL) timerEnd(timer); // Cleanup the ESP32 timeout timer.
|
||||
#endif // ESP32
|
||||
delete[] params.rawbuf;
|
||||
if (params_save != NULL) {
|
||||
@ -371,12 +367,15 @@ void IRrecv::enableIRIn(const bool pullup) {
|
||||
}
|
||||
#if defined(ESP32)
|
||||
// Initialise the ESP32 timer.
|
||||
#if defined(_ESP32_ARDUINO_CORE_V3PLUS)
|
||||
// Use newer timerBegin signature for ESP32 core version 3.x
|
||||
timer = timerBegin(1000000); // Initialize with 1MHz (1us per tick)
|
||||
#else // _ESP32_ARDUINO_CORE_V3PLUS
|
||||
// 80MHz / 80 = 1 uSec granularity.
|
||||
#if ( defined(ESP_ARDUINO_VERSION_MAJOR) && (ESP_ARDUINO_VERSION_MAJOR >= 3) )
|
||||
timer = timerBegin(1000000); // 1 MHz
|
||||
#else // ESP_ARDUINO_VERSION_MAJOR >= 3
|
||||
timer = timerBegin(_timer_num, 80, true); // 1 MHz : 80 MHz with divider 80
|
||||
#endif // ESP_ARDUINO_VERSION_MAJOR >= 3
|
||||
timer = timerBegin(_timer_num, 80, true);
|
||||
#endif // _ESP32_ARDUINO_CORE_V3PLUS
|
||||
|
||||
// Ensure the timer is successfully initialized
|
||||
#ifdef DEBUG
|
||||
if (timer == NULL) {
|
||||
DPRINT("FATAL: Unable enable system timer: ");
|
||||
@ -384,17 +383,17 @@ void IRrecv::enableIRIn(const bool pullup) {
|
||||
}
|
||||
#endif // DEBUG
|
||||
assert(timer != NULL); // Check we actually got the timer.
|
||||
#if ( defined(ESP_ARDUINO_VERSION_MAJOR) && (ESP_ARDUINO_VERSION_MAJOR >= 3) )
|
||||
// Set the timer so it only fires once, and set its trigger in microseconds.
|
||||
#if defined(_ESP32_ARDUINO_CORE_V3PLUS)
|
||||
timerWrite(timer, 0); // Reset the timer for ESP32 core version 3.x
|
||||
timerAttachInterrupt(timer, &read_timeout);
|
||||
timerAlarm(timer, MS_TO_USEC(params.timeout), ONCE, 0);
|
||||
#else // ESP_ARDUINO_VERSION_MAJOR >= 3
|
||||
// Set the timer so it only fires once, and set it's trigger in uSeconds.
|
||||
#else // _ESP32_ARDUINO_CORE_V3PLUS
|
||||
timerAlarmWrite(timer, MS_TO_USEC(params.timeout), ONCE);
|
||||
// Note: Interrupt needs to be attached before it can be enabled or disabled.
|
||||
// Note: EDGE (true) is not supported, use LEVEL (false). Ref: #1713
|
||||
// See: https://github.com/espressif/arduino-esp32/blob/caef4006af491130136b219c1205bdcf8f08bf2b/cores/esp32/esp32-hal-timer.c#L224-L227
|
||||
timerAttachInterrupt(timer, &read_timeout, false);
|
||||
#endif // ESP_ARDUINO_VERSION_MAJOR >= 3
|
||||
#endif // _ESP32_ARDUINO_CORE_V3PLUS
|
||||
#endif // ESP32
|
||||
|
||||
// Initialise state machine variables
|
||||
@ -418,16 +417,14 @@ void IRrecv::disableIRIn(void) {
|
||||
#ifndef UNIT_TEST
|
||||
#if defined(ESP8266)
|
||||
os_timer_disarm(&timer);
|
||||
#endif // ESP8266
|
||||
#if defined(ESP32)
|
||||
#if ( defined(ESP_ARDUINO_VERSION_MAJOR) && (ESP_ARDUINO_VERSION_MAJOR >= 3) )
|
||||
#elif defined(_ESP32_ARDUINO_CORE_V3PLUS)
|
||||
timerWrite(timer, 0); // Reset the timer
|
||||
timerDetachInterrupt(timer);
|
||||
timerEnd(timer);
|
||||
#else // ESP_ARDUINO_VERSION_MAJOR >= 3
|
||||
#elif defined(ESP32)
|
||||
timerAlarmDisable(timer);
|
||||
timerDetachInterrupt(timer);
|
||||
timerEnd(timer);
|
||||
#endif // ESP_ARDUINO_VERSION_MAJOR >= 3
|
||||
#endif // ESP32
|
||||
detachInterrupt(params.recvpin);
|
||||
#endif // UNIT_TEST
|
||||
@ -453,11 +450,13 @@ void IRrecv::resume(void) {
|
||||
params.rawlen = 0;
|
||||
params.overflow = false;
|
||||
#if defined(ESP32)
|
||||
#if ( defined(ESP_ARDUINO_VERSION_MAJOR) && (ESP_ARDUINO_VERSION_MAJOR >= 3) )
|
||||
timerStop(timer);
|
||||
#else // ESP_ARDUINO_VERSION_MAJOR >= 3
|
||||
// Check for ESP32 core version and handle timer functions differently
|
||||
#if defined(_ESP32_ARDUINO_CORE_V3PLUS)
|
||||
timerWrite(timer, 0); // Reset the timer (no need for timerAlarmDisable)
|
||||
#else // _ESP32_ARDUINO_CORE_V3PLUS
|
||||
timerAlarmDisable(timer);
|
||||
#endif // ESP_ARDUINO_VERSION_MAJOR >= 3
|
||||
#endif // _ESP32_ARDUINO_CORE_V3PLUS
|
||||
// Re-enable GPIO interrupt in both versions
|
||||
gpio_intr_enable((gpio_num_t)params.recvpin);
|
||||
#endif // ESP32
|
||||
}
|
||||
@ -1216,6 +1215,14 @@ bool IRrecv::decode(decode_results *results, irparams_t *save,
|
||||
DPRINTLN("Attempting York decode");
|
||||
if (decodeYork(results, offset, kYorkBits)) return true;
|
||||
#endif // DECODE_YORK
|
||||
#if DECODE_BLUESTARHEAVY
|
||||
DPRINTLN("Attempting BluestarHeavy decode");
|
||||
if (decodeBluestarHeavy(results, offset, kBluestarHeavyBits)) return true;
|
||||
#endif // DECODE_BLUESTARHEAVY
|
||||
#if DECODE_EUROM
|
||||
DPRINTLN("Attempting Eurom decode");
|
||||
if (decodeEurom(results, offset, kEuromBits)) return true;
|
||||
#endif // DECODE_EUROM
|
||||
// Typically new protocols are added above this line.
|
||||
}
|
||||
#if DECODE_HASH
|
||||
@ -1246,9 +1253,10 @@ uint8_t IRrecv::_validTolerance(const uint8_t percentage) {
|
||||
uint32_t IRrecv::ticksLow(const uint32_t usecs, const uint8_t tolerance,
|
||||
const uint16_t delta) {
|
||||
// max() used to ensure the result can't drop below 0 before the cast.
|
||||
return ((uint32_t)std::max(
|
||||
(int32_t)(usecs * (1.0 - _validTolerance(tolerance) / 100.0) - delta),
|
||||
(int32_t)0));
|
||||
return (static_cast<uint32_t>(std::max(
|
||||
static_cast<int32_t>(usecs * (1.0 - _validTolerance(tolerance) / 100.0) -
|
||||
delta),
|
||||
static_cast<int32_t>(0))));
|
||||
}
|
||||
|
||||
/// Calculate the upper bound of the nr. of ticks.
|
||||
@ -1258,8 +1266,8 @@ uint32_t IRrecv::ticksLow(const uint32_t usecs, const uint8_t tolerance,
|
||||
/// @return Nr. of ticks.
|
||||
uint32_t IRrecv::ticksHigh(const uint32_t usecs, const uint8_t tolerance,
|
||||
const uint16_t delta) {
|
||||
return ((uint32_t)(usecs * (1.0 + _validTolerance(tolerance) / 100.0)) + 1 +
|
||||
delta);
|
||||
return (static_cast<uint32_t>(usecs * (1.0 + _validTolerance(tolerance) /
|
||||
100.0)) + 1 + delta);
|
||||
}
|
||||
|
||||
/// Check if we match a pulse(measured) with the desired within
|
||||
@ -1310,7 +1318,8 @@ bool IRrecv::matchAtLeast(uint32_t measured, uint32_t desired,
|
||||
DPRINT(". Matching: ");
|
||||
DPRINT(measured);
|
||||
DPRINT(" >= ");
|
||||
DPRINT(ticksLow(std::min(desired, (uint32_t)MS_TO_USEC(params.timeout)),
|
||||
DPRINT(ticksLow(std::min(desired,
|
||||
static_cast<uint32_t>(MS_TO_USEC(params.timeout))),
|
||||
tolerance, delta));
|
||||
DPRINT(" [min(");
|
||||
DPRINT(ticksLow(desired, tolerance, delta));
|
||||
@ -1331,9 +1340,9 @@ bool IRrecv::matchAtLeast(uint32_t measured, uint32_t desired,
|
||||
// We really should never get a value of 0, except as the last value
|
||||
// in the buffer. If that is the case, then assume infinity and return true.
|
||||
if (measured == 0) return true;
|
||||
return measured >= ticksLow(std::min(desired,
|
||||
(uint32_t)MS_TO_USEC(params.timeout)),
|
||||
tolerance, delta);
|
||||
return measured >= ticksLow(std::min(
|
||||
desired, static_cast<uint32_t>(MS_TO_USEC(params.timeout))), tolerance,
|
||||
delta);
|
||||
}
|
||||
|
||||
/// Check if we match a mark signal(measured) with the desired within
|
||||
|
||||
@ -879,10 +879,22 @@ class IRrecv {
|
||||
#endif // DECODE_WOWWEE
|
||||
#if DECODE_YORK
|
||||
bool decodeYork(decode_results *results,
|
||||
uint16_t kStartOffset,
|
||||
const uint16_t kYorkBits,
|
||||
uint16_t offset = kStartOffset,
|
||||
const uint16_t nbits = kYorkBits,
|
||||
const bool strict = true);
|
||||
#endif // DECODE_YORK
|
||||
#if DECODE_BLUESTARHEAVY
|
||||
bool decodeBluestarHeavy(decode_results *results,
|
||||
uint16_t offset = kStartOffset,
|
||||
const uint16_t nbits = kBluestarHeavyBits,
|
||||
const bool strict = true);
|
||||
#endif // DECODE_BLUESTARHEAVY
|
||||
#if DECODE_EUROM
|
||||
bool decodeEurom(decode_results *results,
|
||||
uint16_t offset = kStartOffset,
|
||||
const uint16_t nbits = kEuromBits,
|
||||
const bool strict = true);
|
||||
#endif // DECODE_EUROM
|
||||
};
|
||||
|
||||
#endif // IRRECV_H_
|
||||
|
||||
@ -952,6 +952,20 @@
|
||||
#define SEND_YORK _IR_ENABLE_DEFAULT_
|
||||
#endif // SEND_YORK
|
||||
|
||||
#ifndef DECODE_BLUESTARHEAVY
|
||||
#define DECODE_BLUESTARHEAVY _IR_ENABLE_DEFAULT_
|
||||
#endif // DECODE_BLUESTARHEAVY
|
||||
#ifndef SEND_BLUESTARHEAVY
|
||||
#define SEND_BLUESTARHEAVY _IR_ENABLE_DEFAULT_
|
||||
#endif // SEND_BLUESTARHEAVY
|
||||
|
||||
#ifndef DECODE_EUROM
|
||||
#define DECODE_EUROM _IR_ENABLE_DEFAULT_
|
||||
#endif // DECODE_EUROM
|
||||
#ifndef SEND_EUROM
|
||||
#define SEND_EUROM _IR_ENABLE_DEFAULT_
|
||||
#endif // SEND_EUROM
|
||||
|
||||
#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 || \
|
||||
@ -970,7 +984,8 @@
|
||||
DECODE_KELON168 || DECODE_HITACHI_AC296 || DECODE_CARRIER_AC128 || \
|
||||
DECODE_DAIKIN200 || DECODE_HAIER_AC160 || DECODE_TCL96AC || \
|
||||
DECODE_BOSCH144 || DECODE_SANYO_AC152 || DECODE_DAIKIN312 || \
|
||||
DECODE_CARRIER_AC84 || DECODE_YORK || \
|
||||
DECODE_CARRIER_AC84 || DECODE_YORK || DECODE_BLUESTARHEAVY || \
|
||||
DECODE_EUROM || \
|
||||
false)
|
||||
// Add any DECODE to the above if it uses result->state (see kStateSizeMax)
|
||||
// you might also want to add the protocol to hasACState function
|
||||
@ -1137,8 +1152,10 @@ enum decode_type_t {
|
||||
WOWWEE,
|
||||
CARRIER_AC84, // 125
|
||||
YORK,
|
||||
BLUESTARHEAVY,
|
||||
EUROM,
|
||||
// Add new entries before this one, and update it to point to the last entry.
|
||||
kLastDecodeType = YORK,
|
||||
kLastDecodeType = EUROM,
|
||||
};
|
||||
|
||||
// Message lengths & required repeat values
|
||||
@ -1165,6 +1182,8 @@ const uint16_t kArgo3TimerStateLength = 9; // Bytes
|
||||
const uint16_t kArgo3ConfigStateLength = 4; // Bytes
|
||||
const uint16_t kArgoDefaultRepeat = kNoRepeat;
|
||||
const uint16_t kArrisBits = 32;
|
||||
const uint16_t kBluestarHeavyStateLength = 13;
|
||||
const uint16_t kBluestarHeavyBits = kBluestarHeavyStateLength * 8;
|
||||
const uint16_t kBosch144StateLength = 18;
|
||||
const uint16_t kBosch144Bits = kBosch144StateLength * 8;
|
||||
const uint16_t kCoolixBits = 24;
|
||||
@ -1435,7 +1454,8 @@ const uint16_t kRhossDefaultRepeat = 0;
|
||||
const uint16_t kClimaButlerBits = 52;
|
||||
const uint16_t kYorkBits = 136;
|
||||
const uint16_t kYorkStateLength = 17;
|
||||
|
||||
const uint16_t kEuromStateLength = 12;
|
||||
const uint16_t kEuromBits = kEuromStateLength * 8;
|
||||
|
||||
// Legacy defines. (Deprecated)
|
||||
#define AIWA_RC_T501_BITS kAiwaRcT501Bits
|
||||
@ -1498,12 +1518,24 @@ const uint16_t kYorkStateLength = 17;
|
||||
|
||||
#ifdef DEBUG
|
||||
#ifdef UNIT_TEST
|
||||
#define DPRINT(x) do { std::cout << x; } while (0)
|
||||
#define DPRINTLN(x) do { std::cout << x << std::endl; } while (0)
|
||||
#define DPRINT(x) do { \
|
||||
std::cout << x; \
|
||||
} \
|
||||
while (0)
|
||||
#define DPRINTLN(x) do { \
|
||||
std::cout << x << std::endl; \
|
||||
} \
|
||||
while (0)
|
||||
#endif // UNIT_TEST
|
||||
#ifdef ARDUINO
|
||||
#define DPRINT(x) do { Serial.print(x); } while (0)
|
||||
#define DPRINTLN(x) do { Serial.println(x); } while (0)
|
||||
#define DPRINT(x) do { \
|
||||
Serial.print(x); \
|
||||
} \
|
||||
while (0)
|
||||
#define DPRINTLN(x) do { \
|
||||
Serial.println(x); \
|
||||
} \
|
||||
while (0)
|
||||
#endif // ARDUINO
|
||||
#else // DEBUG
|
||||
#define DPRINT(x)
|
||||
|
||||
@ -74,9 +74,9 @@ uint32_t IRsend::calcUSecPeriod(uint32_t hz, bool use_offset) {
|
||||
(1000000UL + hz / 2) / hz; // The equiv of round(1000000/hz).
|
||||
// Apply the offset and ensure we don't result in a <= 0 value.
|
||||
if (use_offset)
|
||||
return std::max((uint32_t)1, period + periodOffset);
|
||||
return std::max(static_cast<uint32_t>(1), period + periodOffset);
|
||||
else
|
||||
return std::max((uint32_t)1, period);
|
||||
return std::max(static_cast<uint32_t>(1), period);
|
||||
}
|
||||
|
||||
/// Set the output frequency modulation and duty cycle.
|
||||
@ -174,14 +174,16 @@ uint16_t IRsend::mark(uint16_t usec) {
|
||||
ledOn();
|
||||
// Calculate how long we should pulse on for.
|
||||
// e.g. Are we to close to the end of our requested mark time (usec)?
|
||||
_delayMicroseconds(std::min((uint32_t)onTimePeriod, usec - elapsed));
|
||||
_delayMicroseconds(std::min(static_cast<uint32_t>(onTimePeriod),
|
||||
usec - elapsed));
|
||||
ledOff();
|
||||
counter++;
|
||||
if (elapsed + onTimePeriod >= usec)
|
||||
return counter; // LED is now off & we've passed our allotted time.
|
||||
// Wait for the lesser of the rest of the duty cycle, or the time remaining.
|
||||
_delayMicroseconds(
|
||||
std::min(usec - elapsed - onTimePeriod, (uint32_t)offTimePeriod));
|
||||
std::min(usec - elapsed - onTimePeriod,
|
||||
static_cast<uint32_t>(offTimePeriod)));
|
||||
elapsed = usecTimer.elapsed(); // Update & recache the actual elapsed time.
|
||||
}
|
||||
return counter;
|
||||
@ -214,7 +216,7 @@ int8_t IRsend::calibrate(uint16_t hz) {
|
||||
uint32_t timeTaken = usecTimer.elapsed(); // Record the time it took.
|
||||
// While it shouldn't be necessary, assume at least 1 pulse, to avoid a
|
||||
// divide by 0 situation.
|
||||
pulses = std::max(pulses, (uint16_t)1U);
|
||||
pulses = std::max(pulses, static_cast<uint16_t>(1U));
|
||||
uint32_t calcPeriod = calcUSecPeriod(hz); // e.g. @38kHz it should be 26us.
|
||||
// Assuming 38kHz for the example calculations:
|
||||
// In a 65535us pulse, we should have 2520.5769 pulses @ 26us periods.
|
||||
@ -719,6 +721,8 @@ uint16_t IRsend::defaultBits(const decode_type_t protocol) {
|
||||
return kDaikin64Bits;
|
||||
case ELECTRA_AC:
|
||||
return kElectraAcBits;
|
||||
case EUROM:
|
||||
return kEuromBits;
|
||||
case GREE:
|
||||
return kGreeBits;
|
||||
case HAIER_AC:
|
||||
@ -798,6 +802,8 @@ uint16_t IRsend::defaultBits(const decode_type_t protocol) {
|
||||
return kXmpBits;
|
||||
case YORK:
|
||||
return kYorkBits;
|
||||
case BLUESTARHEAVY:
|
||||
return kBluestarHeavyBits;
|
||||
// No default amount of bits.
|
||||
case FUJITSU_AC:
|
||||
case MWM:
|
||||
@ -1241,6 +1247,11 @@ bool IRsend::send(const decode_type_t type, const uint8_t *state,
|
||||
sendElectraAC(state, nbytes);
|
||||
break;
|
||||
#endif // SEND_ELECTRA_AC
|
||||
#if SEND_EUROM
|
||||
case EUROM:
|
||||
sendEurom(state, nbytes);
|
||||
break;
|
||||
#endif // SEND_EUROM
|
||||
#if SEND_FUJITSU_AC
|
||||
case FUJITSU_AC:
|
||||
sendFujitsuAC(state, nbytes);
|
||||
@ -1434,6 +1445,11 @@ bool IRsend::send(const decode_type_t type, const uint8_t *state,
|
||||
sendYork(state, nbytes);
|
||||
break;
|
||||
#endif // SEND_YORK
|
||||
#if SEND_BLUESTARHEAVY
|
||||
case BLUESTARHEAVY:
|
||||
sendBluestarHeavy(state, nbytes);
|
||||
break;
|
||||
#endif // SEND_BLUESTARHEAVY
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -228,6 +228,13 @@ enum argo_ac_remote_model_t {
|
||||
SAC_WREM3 // (2) ARGO WREM3 remote (touch buttons), bit-len vary by cmd
|
||||
};
|
||||
|
||||
/// Toshiba A/C model numbers
|
||||
enum toshiba_ac_remote_model_t {
|
||||
kToshibaGenericRemote_A = 0, // Default from existing codebase
|
||||
kToshibaGenericRemote_B = 1, // Newly discovered remote control b, applies to
|
||||
// many remote models such as WA-TH03A, WA-TH04A etc.
|
||||
};
|
||||
|
||||
// Classes
|
||||
|
||||
/// Class for sending all basic IR protocols.
|
||||
@ -619,11 +626,13 @@ class IRsend {
|
||||
uint16_t nbytes = kCarrierAc128StateLength,
|
||||
uint16_t repeat = kCarrierAc128MinRepeat);
|
||||
#endif // SEND_CARRIER_AC128
|
||||
#if (SEND_HAIER_AC || SEND_HAIER_AC_YRW02 || SEND_HAIER_AC176)
|
||||
#if (SEND_HAIER_AC || SEND_HAIER_AC_YRW02 || SEND_HAIER_AC160 || \
|
||||
SEND_HAIER_AC176)
|
||||
void sendHaierAC(const unsigned char data[],
|
||||
const uint16_t nbytes = kHaierACStateLength,
|
||||
const uint16_t repeat = kHaierAcDefaultRepeat);
|
||||
#endif // (SEND_HAIER_AC || SEND_HAIER_AC_YRW02 || SEND_HAIER_AC176)
|
||||
#endif // (SEND_HAIER_AC || SEND_HAIER_AC_YRW02 || SEND_HAIER_AC160 ||
|
||||
// SEND_HAIER_AC176)
|
||||
#if SEND_HAIER_AC_YRW02
|
||||
void sendHaierACYRW02(const unsigned char data[],
|
||||
const uint16_t nbytes = kHaierACYRW02StateLength,
|
||||
@ -885,6 +894,16 @@ class IRsend {
|
||||
const uint16_t nbytes = kYorkStateLength,
|
||||
const uint16_t repeat = kNoRepeat);
|
||||
#endif // SEND_YORK
|
||||
#if SEND_BLUESTARHEAVY
|
||||
void sendBluestarHeavy(const unsigned char data[],
|
||||
const uint16_t nbytes = kBluestarHeavyStateLength,
|
||||
const uint16_t repeat = kNoRepeat);
|
||||
#endif // SEND_BLUESTARHEAVY
|
||||
#if SEND_EUROM
|
||||
void sendEurom(const uint8_t data[],
|
||||
const uint16_t nbytes = kEuromStateLength,
|
||||
const uint16_t repeat = kNoRepeat);
|
||||
#endif // SEND_EUROM
|
||||
|
||||
protected:
|
||||
#ifdef UNIT_TEST
|
||||
|
||||
@ -295,6 +295,10 @@ IRTEXT_CONST_STRING(kDg11j104Str, D_STR_DG11J104); ///< "DG11J104"
|
||||
IRTEXT_CONST_STRING(kDg11j191Str, D_STR_DG11J191); ///< "DG11J191"
|
||||
IRTEXT_CONST_STRING(kArgoWrem2Str, D_STR_ARGO_WREM2); ///< "WREM3"
|
||||
IRTEXT_CONST_STRING(kArgoWrem3Str, D_STR_ARGO_WREM3); ///< "WREM3"
|
||||
IRTEXT_CONST_STRING(kToshibaGenericRemoteAStr, D_STR_TOSHIBAGENERICREMOTEA);
|
||||
// "TOSHIBA REMOTE A"
|
||||
IRTEXT_CONST_STRING(kToshibaGenericRemoteBStr, D_STR_TOSHIBAGENERICREMOTEB);
|
||||
// "TOSHIBA REMOTE B"
|
||||
|
||||
#define D_STR_UNSUPPORTED "?" // Unsupported protocols will be showing as
|
||||
// a question mark, check for length > 1
|
||||
@ -555,6 +559,10 @@ IRTEXT_CONST_BLOB_DECL(kAllProtocolNamesStr) {
|
||||
D_STR_CARRIER_AC84, D_STR_UNSUPPORTED) "\x0"
|
||||
COND(DECODE_YORK || SEND_YORK,
|
||||
D_STR_YORK, D_STR_UNSUPPORTED) "\x0"
|
||||
COND(DECODE_BLUESTARHEAVY || SEND_BLUESTARHEAVY,
|
||||
D_STR_BLUESTARHEAVY, D_STR_UNSUPPORTED) "\x0"
|
||||
COND(DECODE_EUROM || SEND_EUROM,
|
||||
D_STR_EUROM, D_STR_UNSUPPORTED) "\x0"
|
||||
///< New protocol (macro) strings should be added just above this line.
|
||||
"\x0" ///< This string requires double null termination.
|
||||
};
|
||||
|
||||
@ -229,6 +229,8 @@ extern IRTEXT_CONST_PTR(kSetTimerCommandStr);
|
||||
extern IRTEXT_CONST_PTR(kTimerStr);
|
||||
extern IRTEXT_CONST_PTR(kToggleStr);
|
||||
extern IRTEXT_CONST_PTR(kTopStr);
|
||||
extern IRTEXT_CONST_PTR(kToshibaGenericRemoteAStr);
|
||||
extern IRTEXT_CONST_PTR(kToshibaGenericRemoteBStr);
|
||||
extern IRTEXT_CONST_PTR(kTrueStr);
|
||||
extern IRTEXT_CONST_PTR(kTurboStr);
|
||||
extern IRTEXT_CONST_PTR(kTurboToggleStr);
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
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));
|
||||
nbits = std::min(nbits, static_cast<uint16_t>((sizeof(input) * 8)));
|
||||
uint64_t output = 0;
|
||||
for (uint16_t i = 0; i < nbits; i++) {
|
||||
output <<= 1;
|
||||
@ -169,6 +169,7 @@ bool hasACState(const decode_type_t protocol) {
|
||||
// This is kept sorted by name
|
||||
case AMCOR:
|
||||
case ARGO:
|
||||
case BLUESTARHEAVY:
|
||||
case BOSCH144:
|
||||
case CARRIER_AC84:
|
||||
case CARRIER_AC128:
|
||||
@ -183,6 +184,7 @@ bool hasACState(const decode_type_t protocol) {
|
||||
case DAIKIN216:
|
||||
case DAIKIN312:
|
||||
case ELECTRA_AC:
|
||||
case EUROM:
|
||||
case FUJITSU_AC:
|
||||
case GREE:
|
||||
case HAIER_AC:
|
||||
@ -701,6 +703,15 @@ namespace irutils {
|
||||
default: return kUnknownStr;
|
||||
}
|
||||
break;
|
||||
case decode_type_t::TOSHIBA_AC:
|
||||
switch (model) {
|
||||
case toshiba_ac_remote_model_t::kToshibaGenericRemote_A:
|
||||
return kToshibaGenericRemoteAStr;
|
||||
case toshiba_ac_remote_model_t::kToshibaGenericRemote_B:
|
||||
return kToshibaGenericRemoteBStr;
|
||||
default:
|
||||
return kUnknownStr;
|
||||
}
|
||||
default: return kUnknownStr;
|
||||
}
|
||||
}
|
||||
@ -753,7 +764,8 @@ namespace irutils {
|
||||
result += addIntToString(degrees, (isSensorTemp)?
|
||||
kSensorTempStr : kTempStr, precomma);
|
||||
// Is it a half degree?
|
||||
if (((uint16_t)(2 * degrees)) & 1) result += F(".5");
|
||||
if (static_cast<uint16_t>(2 * degrees) & 1)
|
||||
result += F(".5");
|
||||
result += celsius ? 'C' : 'F';
|
||||
return result;
|
||||
}
|
||||
@ -1282,7 +1294,7 @@ namespace irutils {
|
||||
/// @param[in] position Nr. of the bit to be changed. `0` is the LSB.
|
||||
/// @param[in] on Value to set the position'th bit to.
|
||||
void setBit(uint32_t * const data, const uint8_t position, const bool on) {
|
||||
uint32_t mask = (uint32_t)1 << position;
|
||||
uint32_t mask = static_cast<uint32_t>(1) << position;
|
||||
if (on)
|
||||
*data |= mask;
|
||||
else
|
||||
@ -1294,7 +1306,7 @@ namespace irutils {
|
||||
/// @param[in] position Nr. of the bit to be changed. `0` is the LSB.
|
||||
/// @param[in] on Value to set the position'th bit to.
|
||||
void setBit(uint64_t * const data, const uint8_t position, const bool on) {
|
||||
uint64_t mask = (uint64_t)1 << position;
|
||||
uint64_t mask = static_cast<uint64_t>(1) << position;
|
||||
if (on)
|
||||
*data |= mask;
|
||||
else
|
||||
|
||||
@ -117,21 +117,22 @@ namespace irutils {
|
||||
bool getBit(const uint64_t data, const uint8_t position,
|
||||
const uint8_t size = 64);
|
||||
bool getBit(const uint8_t data, const uint8_t position);
|
||||
#define GETBIT8(a, b) ((a) & ((uint8_t)1 << (b)))
|
||||
#define GETBIT16(a, b) ((a) & ((uint16_t)1 << (b)))
|
||||
#define GETBIT32(a, b) ((a) & ((uint32_t)1 << (b)))
|
||||
#define GETBIT64(a, b) ((a) & ((uint64_t)1 << (b)))
|
||||
#define GETBIT8(a, b) ((a) & (static_cast<uint8_t>(1) << (b)))
|
||||
#define GETBIT16(a, b) ((a) & (static_cast<uint16_t>(1) << (b)))
|
||||
#define GETBIT32(a, b) ((a) & (static_cast<uint32_t>(1) << (b)))
|
||||
#define GETBIT64(a, b) ((a) & (static_cast<uint64_t>(1) << (b)))
|
||||
#define GETBITS8(data, offset, size) \
|
||||
(((data) & (((uint8_t)UINT8_MAX >> (8 - (size))) << (offset))) >> (offset))
|
||||
(((data) & ((static_cast<uint8_t>(UINT8_MAX) >> (8 - (size))) << \
|
||||
(offset))) >> (offset))
|
||||
#define GETBITS16(data, offset, size) \
|
||||
(((data) & (((uint16_t)UINT16_MAX >> (16 - (size))) << (offset))) >> \
|
||||
(offset))
|
||||
(((data) & ((static_cast<uint16_t>(UINT16_MAX) >> (16 - (size))) << \
|
||||
(offset))) >> (offset))
|
||||
#define GETBITS32(data, offset, size) \
|
||||
(((data) & (((uint32_t)UINT32_MAX >> (32 - (size))) << (offset))) >> \
|
||||
(offset))
|
||||
(((data) & ((static_cast<uint32_t>(UINT32_MAX) >> (32 - (size))) << \
|
||||
(offset))) >> (offset))
|
||||
#define GETBITS64(data, offset, size) \
|
||||
(((data) & (((uint64_t)UINT64_MAX >> (64 - (size))) << (offset))) >> \
|
||||
(offset))
|
||||
(((data) & ((static_cast<uint64_t>(UINT64_MAX) >> (64 - (size))) << \
|
||||
(offset))) >> (offset))
|
||||
uint64_t setBit(const uint64_t data, const uint8_t position,
|
||||
const bool on = true, const uint8_t size = 64);
|
||||
uint8_t setBit(const uint8_t data, const uint8_t position,
|
||||
|
||||
@ -68,7 +68,7 @@ const uint8_t kAirtonFanHigh = 0b100; // 4
|
||||
const uint8_t kAirtonFanMax = 0b101; // 5
|
||||
|
||||
const uint8_t kAirtonMinTemp = 16; // 16C
|
||||
const uint8_t kAirtonMaxTemp = 25; // 25C
|
||||
const uint8_t kAirtonMaxTemp = 31; // 31C
|
||||
|
||||
|
||||
/// Class for handling detailed Airton 56-bit A/C messages.
|
||||
|
||||
@ -12,6 +12,8 @@
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
#include <set>
|
||||
#include <utility>
|
||||
#ifndef UNIT_TEST
|
||||
#include <Arduino.h>
|
||||
#endif // UNIT_TEST
|
||||
@ -1791,16 +1793,20 @@ bool IRArgoAC_WREM3::isValidWrem3Message(const uint8_t state[],
|
||||
|
||||
switch (messageType) {
|
||||
case argoIrMessageType_t::AC_CONTROL :
|
||||
if (stateLengthBytes != kArgo3AcControlStateLength) { return false; }
|
||||
if (stateLengthBytes != kArgo3AcControlStateLength)
|
||||
return false;
|
||||
break;
|
||||
case argoIrMessageType_t::CONFIG_PARAM_SET:
|
||||
if (stateLengthBytes != kArgo3ConfigStateLength) { return false; }
|
||||
if (stateLengthBytes != kArgo3ConfigStateLength)
|
||||
return false;
|
||||
break;
|
||||
case argoIrMessageType_t::TIMER_COMMAND:
|
||||
if (stateLengthBytes != kArgo3TimerStateLength) { return false; }
|
||||
if (stateLengthBytes != kArgo3TimerStateLength)
|
||||
return false;
|
||||
break;
|
||||
case argoIrMessageType_t::IFEEL_TEMP_REPORT:
|
||||
if (stateLengthBytes != kArgo3iFeelReportStateLength) { return false; }
|
||||
if (stateLengthBytes != kArgo3iFeelReportStateLength)
|
||||
return false;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
|
||||
@ -0,0 +1,72 @@
|
||||
// Copyright 2024 Harsh Bhosale (harshbhosale01)
|
||||
/// @file
|
||||
/// @brief Support for BluestarHeavy protocol
|
||||
|
||||
// Supports:
|
||||
// Brand: Bluestar, Model: D716LXM0535A2400313 (Remote)
|
||||
|
||||
#include "IRrecv.h"
|
||||
#include "IRsend.h"
|
||||
#include "IRutils.h"
|
||||
|
||||
const uint16_t kBluestarHeavyHdrMark = 4912;
|
||||
const uint16_t kBluestarHeavyBitMark = 465;
|
||||
const uint16_t kBluestarHeavyHdrSpace = 5058;
|
||||
const uint16_t kBluestarHeavyOneSpace = 572;
|
||||
const uint16_t kBluestarHeavyZeroSpace = 1548;
|
||||
const uint16_t kBluestarHeavyFreq = 38000;
|
||||
const uint16_t kBluestarHeavyOverhead = 3;
|
||||
|
||||
#if SEND_BLUESTARHEAVY
|
||||
/// Send a BluestarHeavy formatted message.
|
||||
/// Status: BETA / Tested.
|
||||
/// @param[in] data An array of bytes containing the IR command.
|
||||
/// It is assumed to be in MSB order for this code.
|
||||
/// e.g.
|
||||
/// @code
|
||||
/// uint8_t data[kBluestarHeavyStateLength] =
|
||||
/// {0x2A,0x00,0x20,0xD0,0x05,0xA0,0x05,0xA0,0x00,0x80,0xBA,0x02,0x23};
|
||||
/// @endcode
|
||||
/// @param[in] nbytes Nr. of bytes of data in the array.
|
||||
/// @param[in] repeat Nr. of times the message is to be repeated.
|
||||
void IRsend::sendBluestarHeavy(const uint8_t data[], const uint16_t nbytes,
|
||||
const uint16_t repeat) {
|
||||
sendGeneric(kBluestarHeavyHdrMark, kBluestarHeavyHdrSpace,
|
||||
kBluestarHeavyBitMark, kBluestarHeavyOneSpace,
|
||||
kBluestarHeavyBitMark, kBluestarHeavyZeroSpace,
|
||||
kBluestarHeavyHdrMark, kDefaultMessageGap,
|
||||
data, nbytes, // Bytes
|
||||
kBluestarHeavyFreq, true, repeat, kDutyDefault);
|
||||
}
|
||||
#endif // SEND_BLUESTARHEAVY
|
||||
|
||||
#if DECODE_BLUESTARHEAVY
|
||||
/// Decode the supplied BluestarHeavy message.
|
||||
/// Status: BETA / Tested.
|
||||
/// @param[in,out] results Ptr to the data to decode & where to store the decode
|
||||
/// @param[in] offset The starting index to use when attempting to decode the
|
||||
/// raw data. Typically/Defaults to kStartOffset.
|
||||
/// @param[in] nbits The number of data bits to expect.
|
||||
/// @param[in] strict Flag indicating if we should perform strict matching.
|
||||
/// @return A boolean. True if it can decode it, false if it can't.
|
||||
bool IRrecv::decodeBluestarHeavy(decode_results *results, uint16_t offset,
|
||||
const uint16_t nbits, const bool strict) {
|
||||
if (strict && nbits != kBluestarHeavyBits)
|
||||
return false;
|
||||
|
||||
uint16_t used = 0;
|
||||
|
||||
used = matchGeneric(results->rawbuf + offset, results->state,
|
||||
results->rawlen - offset, nbits,
|
||||
kBluestarHeavyHdrMark, kBluestarHeavyHdrSpace,
|
||||
kBluestarHeavyBitMark, kBluestarHeavyOneSpace,
|
||||
kBluestarHeavyBitMark, kBluestarHeavyZeroSpace,
|
||||
kBluestarHeavyHdrMark, kDefaultMessageGap, true);
|
||||
if (used == 0) return false; // We failed to find any data.
|
||||
|
||||
// Success
|
||||
results->decode_type = decode_type_t::BLUESTARHEAVY;
|
||||
results->bits = nbits;
|
||||
return true;
|
||||
}
|
||||
#endif // DECODE_BLUESTARHEAVY
|
||||
@ -5,6 +5,7 @@
|
||||
/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1787
|
||||
|
||||
#include "ir_Bosch.h"
|
||||
#include <algorithm>
|
||||
|
||||
#if SEND_BOSCH144
|
||||
/// Send a Bosch 144-bit / 18-byte message (96-bit message are also possible)
|
||||
|
||||
@ -99,6 +99,8 @@ void IRCoolixAC::stateReset(void) {
|
||||
cleanFlag = false;
|
||||
sleepFlag = false;
|
||||
swingFlag = false;
|
||||
tempLowF = false;
|
||||
tempHighF = false;
|
||||
}
|
||||
|
||||
/// Set up hardware to be able to send a message.
|
||||
@ -112,8 +114,34 @@ void IRCoolixAC::send(const uint16_t repeat) {
|
||||
// Typically repeat is `kCoolixDefaultRepeat` which is `1`, so this allows
|
||||
// it to be 0 normally for this command, and allows additional repeats if
|
||||
// requested rather always 0 for that command.
|
||||
_irsend.sendCOOLIX(getRaw(), kCoolixBits, repeat - (getSwingVStep() &&
|
||||
repeat > 0) ? 1 : 0);
|
||||
const uint16_t repeat_override =
|
||||
repeat - (getSwingVStep() && repeat > 0) ? 1 : 0;
|
||||
|
||||
if (tempHighF || tempLowF) {
|
||||
uint64_t coolix24_raw = getRaw();
|
||||
// We need to sneak our temperature range into a parity bit.
|
||||
uint64_t coolix48_raw = 0;
|
||||
|
||||
// First create our parity.
|
||||
uint64_t parity = getRaw() ^ UINT32_MAX;
|
||||
|
||||
// Interleave raw data and parity into output, in order.
|
||||
coolix48_raw |= ((coolix24_raw >> 16) & 0xFF) << 40;
|
||||
coolix48_raw |= ((parity >> 16) & 0xFF) << 32;
|
||||
coolix48_raw |= ((coolix24_raw >> 8) & 0xFF) << 24;
|
||||
coolix48_raw |= ((parity >> 8) & 0xFF) << 16;
|
||||
coolix48_raw |= (coolix24_raw & 0xFF) << 8;
|
||||
coolix48_raw |= parity & 0xFF;
|
||||
|
||||
// Mangle parity as necessary to represent Fahrenheit range.
|
||||
coolix48_raw |= static_cast<uint64_t>(tempLowF ? 1 : 3) << (36);
|
||||
|
||||
// Send as Coolix48.
|
||||
_irsend.sendCoolix48(coolix48_raw, kCoolix48Bits, repeat_override);
|
||||
} else {
|
||||
_irsend.sendCOOLIX(getRaw(), kCoolixBits, repeat_override);
|
||||
}
|
||||
|
||||
// make sure to remove special state from the internal state
|
||||
// after command has being transmitted.
|
||||
recoverSavedState();
|
||||
@ -140,6 +168,27 @@ void IRCoolixAC::setRaw(const uint32_t new_code) {
|
||||
_.raw = new_code;
|
||||
}
|
||||
|
||||
// Set internal state from a COOLIX48 read, handling F data hidden in parity.
|
||||
void IRCoolixAC::setRawFromCoolix48(const uint64_t data) {
|
||||
// Assume parity bits as in coolix24, let's strip them.
|
||||
CoolixProtocol coolix24;
|
||||
coolix24.raw = 0;
|
||||
coolix24.raw |= ((data >> 8) & 0xff);
|
||||
coolix24.raw |= ((data >> 24) & 0xff) << 8;
|
||||
coolix24.raw |= ((data >> 40) & 0xff) << 16;
|
||||
|
||||
// Delegate to coolix24 code.
|
||||
setRaw(coolix24.raw);
|
||||
|
||||
// Handle Fahrenheit range.
|
||||
uint8_t fRange = (data >> 36) & 3;
|
||||
if (fRange == 1) {
|
||||
setTempFRange(false);
|
||||
} else if (fRange == 3) {
|
||||
setTempFRange(true);
|
||||
}
|
||||
}
|
||||
|
||||
/// Is the current state is a special state?
|
||||
/// @return true, if it is. false if it isn't.
|
||||
bool IRCoolixAC::isSpecialState(void) const {
|
||||
@ -217,19 +266,53 @@ void IRCoolixAC::setTempRaw(const uint8_t code) { _.Temp = code; }
|
||||
/// @return The native temperature value.
|
||||
uint8_t IRCoolixAC::getTempRaw(void) const { return _.Temp; }
|
||||
|
||||
/// Set the fahrenheit temperature range.
|
||||
/// @param[in] high True if setting high F range, false if low F range.
|
||||
void IRCoolixAC::setTempFRange(const bool high) {
|
||||
tempLowF = !high;
|
||||
tempHighF = high;
|
||||
}
|
||||
|
||||
// Clear the fahrenheit temperature range bits.
|
||||
void IRCoolixAC::clearTempFRange() {
|
||||
tempLowF = false;
|
||||
tempHighF = false;
|
||||
}
|
||||
|
||||
/// Set the temperature.
|
||||
/// @param[in] desired The temperature in degrees celsius.
|
||||
void IRCoolixAC::setTemp(const uint8_t desired) {
|
||||
// Range check.
|
||||
if (desired >= kCoolixTempLowFMin &&
|
||||
desired <= kCoolixTempLowFMax) {
|
||||
setTempRaw(kCoolixTempMapLowF[desired - kCoolixTempLowFMin]);
|
||||
setTempFRange(false);
|
||||
return;
|
||||
}
|
||||
if (desired >= kCoolixTempHighFMin &&
|
||||
desired <= kCoolixTempHighFMax) {
|
||||
setTempRaw(kCoolixTempMapHighF[desired - kCoolixTempHighFMin]);
|
||||
setTempFRange(true);
|
||||
return;
|
||||
}
|
||||
uint8_t temp = std::min(desired, kCoolixTempMax);
|
||||
temp = std::max(temp, kCoolixTempMin);
|
||||
setTempRaw(kCoolixTempMap[temp - kCoolixTempMin]);
|
||||
clearTempFRange();
|
||||
}
|
||||
|
||||
/// Get the current temperature setting.
|
||||
/// @return The current setting for temp. in degrees celsius.
|
||||
uint8_t IRCoolixAC::getTemp(void) const {
|
||||
const uint8_t code = getTempRaw();
|
||||
if (tempLowF) {
|
||||
for (uint8_t i = 0; i < kCoolixTempLowFRange; i++)
|
||||
if (kCoolixTempMapLowF[i] == code) return kCoolixTempLowFMin + i;
|
||||
}
|
||||
if (tempHighF) {
|
||||
for (uint8_t i = 0; i < kCoolixTempHighFRange; i++)
|
||||
if (kCoolixTempMapHighF[i] == code) return kCoolixTempHighFMin + i;
|
||||
}
|
||||
for (uint8_t i = 0; i < kCoolixTempRange; i++)
|
||||
if (kCoolixTempMap[i] == code) return kCoolixTempMin + i;
|
||||
return kCoolixTempMax; // Not a temp we expected.
|
||||
@ -613,7 +696,9 @@ String IRCoolixAC::toString(void) const {
|
||||
}
|
||||
result += ')';
|
||||
// Fan mode doesn't have a temperature.
|
||||
if (getMode() != kCoolixFan) result += addTempToString(getTemp());
|
||||
bool celcius = true;
|
||||
if (tempHighF || tempLowF) celcius = false;
|
||||
if (getMode() != kCoolixFan) result += addTempToString(getTemp(), celcius);
|
||||
result += addBoolToString(getZoneFollow(), kZoneFollowStr);
|
||||
result += addLabeledString(
|
||||
(getSensorTemp() == kCoolixSensorTempIgnoreCode)
|
||||
|
||||
@ -15,6 +15,7 @@
|
||||
// Brand: Midea, Model: RG52D/BGE Remote
|
||||
// Brand: Midea, Model: MS12FU-10HRDN1-QRD0GW(B) A/C
|
||||
// Brand: Midea, Model: MSABAU-07HRFN1-QRD0GW A/C (circa 2016)
|
||||
// Brand: Comfee (Midea), Model: Breezy Cool Pro 2.6
|
||||
// Brand: Tokio, Model: AATOEMF17-12CHR1SW split-type RG51|50/BGE Remote
|
||||
// Brand: Airwell, Model: RC08B remote
|
||||
// Brand: Kastron, Model: RG57A7/BGEF Inverter remote
|
||||
@ -25,6 +26,7 @@
|
||||
// Brand: Toshiba, Model: WH-E1YE remote
|
||||
// Brand: Bosch, Model: RG36B4/BGE remote
|
||||
// Brand: Bosch, Model: B1ZAI2441W/B1ZAO2441W A/C
|
||||
// Brand: Fisher, Model: R51L1/BGE remote
|
||||
|
||||
#ifndef IR_COOLIX_H_
|
||||
#define IR_COOLIX_H_
|
||||
@ -78,6 +80,42 @@ const uint8_t kCoolixTempMap[kCoolixTempRange] = {
|
||||
0b1010, // 29C
|
||||
0b1011 // 30C
|
||||
};
|
||||
const uint8_t kCoolixTempLowFMin = 63;
|
||||
const uint8_t kCoolixTempLowFMax = 75;
|
||||
const uint8_t kCoolixTempLowFRange =
|
||||
kCoolixTempLowFMax - kCoolixTempLowFMin + 1;
|
||||
const uint8_t kCoolixTempHighFMin = kCoolixTempLowFMax + 1;
|
||||
const uint8_t kCoolixTempHighFMax = 86;
|
||||
const uint8_t kCoolixTempHighFRange =
|
||||
kCoolixTempHighFMax - kCoolixTempHighFMin + 1;
|
||||
const uint8_t kCoolixTempMapLowF[kCoolixTempLowFRange] = {
|
||||
0b1100, // 63F
|
||||
0b0010, // 64F
|
||||
0b1010, // 65F
|
||||
0b0110, // 66F
|
||||
0b1110, // 67F
|
||||
0b0001, // 68F
|
||||
0b1001, // 69F
|
||||
0b0101, // 70F
|
||||
0b1101, // 71F
|
||||
0b0011, // 72F
|
||||
0b1011, // 73F
|
||||
0b0111, // 74F
|
||||
0b1111 // 75F
|
||||
};
|
||||
const uint8_t kCoolixTempMapHighF[kCoolixTempHighFRange] = {
|
||||
0b0000, // 76F
|
||||
0b1000, // 77F
|
||||
0b0100, // 78F
|
||||
0b1100, // 79F
|
||||
0b0010, // 80F
|
||||
0b1010, // 81F
|
||||
0b0110, // 82F
|
||||
0b1110, // 83F
|
||||
0b0001, // 84F
|
||||
0b1001, // 85F
|
||||
0b0101 // 86F
|
||||
};
|
||||
const uint8_t kCoolixSensorTempMax = 30; // Celsius
|
||||
const uint8_t kCoolixSensorTempIgnoreCode = 0b11111; // 0x1F / 31 (DEC)
|
||||
// kCoolixSensorTempMask = 0b000000000000111100000000; // 0xF00
|
||||
@ -135,6 +173,8 @@ class IRCoolixAC {
|
||||
void off(void);
|
||||
void setPower(const bool on);
|
||||
bool getPower(void) const;
|
||||
void setTempFRange(const bool high = false);
|
||||
void clearTempFRange();
|
||||
void setTemp(const uint8_t temp);
|
||||
uint8_t getTemp(void) const;
|
||||
void setSensorTemp(const uint8_t temp);
|
||||
@ -159,6 +199,8 @@ class IRCoolixAC {
|
||||
bool getZoneFollow(void) const;
|
||||
uint32_t getRaw(void) const;
|
||||
void setRaw(const uint32_t new_code);
|
||||
// Convert from Coolix48 with Fahrenheit handling.
|
||||
void setRawFromCoolix48(const uint64_t new_code);
|
||||
static uint8_t convertMode(const stdAc::opmode_t mode);
|
||||
static uint8_t convertFan(const stdAc::fanspeed_t speed);
|
||||
static stdAc::opmode_t toCommonMode(const uint8_t mode);
|
||||
@ -185,6 +227,8 @@ class IRCoolixAC {
|
||||
bool cleanFlag;
|
||||
bool sleepFlag;
|
||||
bool swingFlag;
|
||||
bool tempLowF; // Indicates low-range F temperatures.
|
||||
bool tempHighF; // Indicates high-range F temperatures.
|
||||
uint8_t savedFan;
|
||||
|
||||
void setTempRaw(const uint8_t code);
|
||||
|
||||
@ -46,6 +46,7 @@ using irutils::addModeToString;
|
||||
using irutils::addSwingHToString;
|
||||
using irutils::addSwingVToString;
|
||||
using irutils::addTempToString;
|
||||
using irutils::addTempFloatToString;
|
||||
using irutils::addFanToString;
|
||||
using irutils::bcdToUint8;
|
||||
using irutils::minsToString;
|
||||
@ -73,7 +74,8 @@ void IRsend::sendDaikin(const unsigned char data[], const uint16_t nbytes,
|
||||
sendGeneric(0, 0, // No header for the header
|
||||
kDaikinBitMark, kDaikinOneSpace, kDaikinBitMark,
|
||||
kDaikinZeroSpace, kDaikinBitMark, kDaikinZeroSpace + kDaikinGap,
|
||||
(uint64_t)0b00000, kDaikinHeaderLength, 38, false, 0, 50);
|
||||
static_cast<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
|
||||
@ -221,15 +223,15 @@ bool IRDaikinESP::getPower(void) const {
|
||||
|
||||
/// Set the temperature.
|
||||
/// @param[in] temp The temperature in degrees celsius.
|
||||
void IRDaikinESP::setTemp(const uint8_t temp) {
|
||||
uint8_t degrees = std::max(temp, kDaikinMinTemp);
|
||||
degrees = std::min(degrees, kDaikinMaxTemp);
|
||||
_.Temp = degrees;
|
||||
void IRDaikinESP::setTemp(const float temp) {
|
||||
float degrees = std::max(temp, static_cast<float>(kDaikinMinTemp));
|
||||
degrees = std::min(degrees, static_cast<float>(kDaikinMaxTemp));
|
||||
_.Temp = degrees * 2.0f;
|
||||
}
|
||||
|
||||
/// Get the current temperature setting.
|
||||
/// @return The current setting for temp. in degrees celsius.
|
||||
uint8_t IRDaikinESP::getTemp(void) const { return _.Temp; }
|
||||
float IRDaikinESP::getTemp(void) const { return _.Temp / 2.0f; }
|
||||
|
||||
/// Set the speed of the fan.
|
||||
/// @param[in] fan The desired setting.
|
||||
@ -536,7 +538,7 @@ stdAc::state_t IRDaikinESP::toCommon(void) const {
|
||||
result.power = _.Power;
|
||||
result.mode = toCommonMode(_.Mode);
|
||||
result.celsius = true;
|
||||
result.degrees = _.Temp;
|
||||
result.degrees = getTemp();
|
||||
result.fanspeed = toCommonFanSpeed(getFan());
|
||||
result.swingv = _.SwingV ? stdAc::swingv_t::kAuto :
|
||||
stdAc::swingv_t::kOff;
|
||||
@ -563,7 +565,7 @@ String IRDaikinESP::toString(void) const {
|
||||
result += addBoolToString(_.Power, kPowerStr, false);
|
||||
result += addModeToString(_.Mode, kDaikinAuto, kDaikinCool, kDaikinHeat,
|
||||
kDaikinDry, kDaikinFan);
|
||||
result += addTempToString(_.Temp);
|
||||
result += addTempFloatToString(getTemp());
|
||||
result += addFanToString(getFan(), kDaikinFanMax, kDaikinFanMin,
|
||||
kDaikinFanAuto, kDaikinFanQuiet, kDaikinFanMed);
|
||||
result += addBoolToString(_.Powerful, kPowerfulStr);
|
||||
@ -674,7 +676,7 @@ void IRsend::sendDaikin2(const unsigned char data[], const uint16_t nbytes,
|
||||
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, 0, 0, 0, 0, 0, static_cast<uint64_t>(0), // No data payload.
|
||||
0, kDaikin2Freq, false, 0, 50);
|
||||
// Section #1
|
||||
sendGeneric(kDaikin2HdrMark, kDaikin2HdrSpace, kDaikin2BitMark,
|
||||
@ -2936,7 +2938,8 @@ bool IRrecv::decodeDaikin128(decode_results *results, uint16_t offset,
|
||||
kDaikinTolerance, kDaikinMarkExcess)) return false;
|
||||
}
|
||||
const uint16_t ksectionSize[kDaikin128Sections] = {
|
||||
kDaikin128SectionLength, (uint16_t)(nbits / 8 - kDaikin128SectionLength)};
|
||||
kDaikin128SectionLength,
|
||||
static_cast<uint16_t>(nbits / 8 - kDaikin128SectionLength)};
|
||||
// Data Sections
|
||||
uint16_t pos = 0;
|
||||
for (uint8_t section = 0; section < kDaikin128Sections; section++) {
|
||||
@ -2986,7 +2989,7 @@ void IRsend::sendDaikin152(const unsigned char data[], const uint16_t nbytes,
|
||||
sendGeneric(0, 0, kDaikin152BitMark, kDaikin152OneSpace,
|
||||
kDaikin152BitMark, kDaikin152ZeroSpace,
|
||||
kDaikin152BitMark, kDaikin152Gap,
|
||||
(uint64_t)0, kDaikin152LeaderBits,
|
||||
static_cast<uint64_t>(0), kDaikin152LeaderBits,
|
||||
kDaikin152Freq, false, 0, kDutyDefault);
|
||||
// Header + Data + Footer
|
||||
sendGeneric(kDaikin152HdrMark, kDaikin152HdrSpace, kDaikin152BitMark,
|
||||
@ -3838,7 +3841,7 @@ void IRsend::sendDaikin312(const unsigned char data[], const uint16_t nbytes,
|
||||
kDaikin312BitMark, kDaikin312OneSpace,
|
||||
kDaikin312BitMark, kDaikin312ZeroSpace,
|
||||
kDaikin312BitMark, kDaikin312HdrGap,
|
||||
(uint64_t)0b00000, kDaikinHeaderLength,
|
||||
static_cast<uint64_t>(0b00000), kDaikinHeaderLength,
|
||||
kDaikin2Freq, false, 0, kDutyDefault);
|
||||
// Section #1
|
||||
sendGeneric(kDaikin312HdrMark, kDaikin312HdrSpace, kDaikin312BitMark,
|
||||
|
||||
@ -53,6 +53,7 @@
|
||||
// Brand: Daikin, Model: BRC4M150W16 remote (DAIKIN200)
|
||||
// Brand: Daikin, Model: FTXM20R5V1B A/C (DAIKIN312)
|
||||
// Brand: Daikin, Model: ARC466A67 remote (DAIKIN312)
|
||||
// Brand: Daikin, Model: ARC443A5 remote (DAIKIN)
|
||||
|
||||
#ifndef IR_DAIKIN_H_
|
||||
#define IR_DAIKIN_H_
|
||||
@ -99,8 +100,7 @@ union DaikinESPProtocol{
|
||||
uint64_t Mode :3;
|
||||
uint64_t :1;
|
||||
// Byte 22
|
||||
uint64_t :1;
|
||||
uint64_t Temp :7; // Temp should be between 10 - 32
|
||||
uint64_t Temp :8; // Temp should be between 20 - 64 (10 C - 32 C)
|
||||
// Byte 23
|
||||
uint64_t :8;
|
||||
|
||||
@ -738,8 +738,8 @@ class IRDaikinESP {
|
||||
void off(void);
|
||||
void setPower(const bool on);
|
||||
bool getPower(void) const;
|
||||
void setTemp(const uint8_t temp);
|
||||
uint8_t getTemp(void) const;
|
||||
void setTemp(const float temp);
|
||||
float getTemp(void) const;
|
||||
void setFan(const uint8_t fan);
|
||||
uint8_t getFan(void) const;
|
||||
void setMode(const uint8_t mode);
|
||||
|
||||
@ -282,7 +282,7 @@ uint16_t IREcoclimAc::getClock(void) const { return _.Clock; }
|
||||
/// Set the clock time on the A/C unit.
|
||||
/// @param[in] nr_of_mins Nr. of minutes past midnight.
|
||||
void IREcoclimAc::setClock(const uint16_t nr_of_mins) {
|
||||
_.Clock = std::min(nr_of_mins, (uint16_t)(24 * 60 - 1));
|
||||
_.Clock = std::min(nr_of_mins, static_cast<uint16_t>(24 * 60 - 1));
|
||||
}
|
||||
|
||||
/// Get the Unit type/DIP switch settings of the remote.
|
||||
|
||||
@ -310,6 +310,18 @@ bool IRElectraAc::getTurbo(void) const {
|
||||
return _.Turbo;
|
||||
}
|
||||
|
||||
/// Set the Quiet/Silent'mode of the A/C.
|
||||
/// @param[in] on true, the setting is on. false, the setting is off.
|
||||
void IRElectraAc::setQuiet(const bool on) {
|
||||
_.Quiet = on;
|
||||
}
|
||||
|
||||
/// Get the Quiet/Silent mode of the A/C.
|
||||
/// @return true, the setting is on. false, the setting is off.
|
||||
bool IRElectraAc::getQuiet(void) const {
|
||||
return _.Quiet;
|
||||
}
|
||||
|
||||
/// Get the IFeel mode of the A/C.
|
||||
/// @return true, the setting is on. false, the setting is off.
|
||||
bool IRElectraAc::getIFeel(void) const { return _.IFeel; }
|
||||
@ -373,11 +385,11 @@ stdAc::state_t IRElectraAc::toCommon(void) const {
|
||||
: stdAc::swingh_t::kOff;
|
||||
result.light = getLightToggle();
|
||||
result.turbo = _.Turbo;
|
||||
result.quiet = _.Quiet;
|
||||
result.clean = _.Clean;
|
||||
result.iFeel = getIFeel();
|
||||
// Not supported.
|
||||
result.model = -1; // No models used.
|
||||
result.quiet = false;
|
||||
result.econo = false;
|
||||
result.filter = false;
|
||||
result.beep = false;
|
||||
@ -404,6 +416,7 @@ String IRElectraAc::toString(void) const {
|
||||
result += addToggleToString(getLightToggle(), kLightStr);
|
||||
result += addBoolToString(_.Clean, kCleanStr);
|
||||
result += addBoolToString(_.Turbo, kTurboStr);
|
||||
result += addBoolToString(_.Quiet, kQuietStr);
|
||||
result += addBoolToString(_.IFeel, kIFeelStr);
|
||||
}
|
||||
if (_.IFeel || _.SensorUpdate) {
|
||||
|
||||
@ -15,6 +15,7 @@
|
||||
// Brand: Centek, Model: YKR-P/002E remote
|
||||
// Brand: AEG, Model: Chillflex Pro AXP26U338CW A/C
|
||||
// Brand: Electrolux, Model: YKR-H/531E A/C
|
||||
// Brand: Delonghi, Modell: PAC EM90
|
||||
|
||||
#ifndef IR_ELECTRA_H_
|
||||
#define IR_ELECTRA_H_
|
||||
@ -52,7 +53,7 @@ union ElectraProtocol {
|
||||
// Byte 5
|
||||
uint8_t :6;
|
||||
uint8_t Turbo :1;
|
||||
uint8_t :1;
|
||||
uint8_t Quiet :1;
|
||||
// Byte 6
|
||||
uint8_t :3;
|
||||
uint8_t IFeel :1;
|
||||
@ -145,6 +146,8 @@ class IRElectraAc {
|
||||
bool getLightToggle(void) const;
|
||||
void setTurbo(const bool on);
|
||||
bool getTurbo(void) const;
|
||||
void setQuiet(const bool on);
|
||||
bool getQuiet(void) const;
|
||||
void setIFeel(const bool on);
|
||||
bool getIFeel(void) const;
|
||||
void setSensorUpdate(const bool on);
|
||||
|
||||
489
lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Eurom.cpp
Normal file
489
lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Eurom.cpp
Normal file
@ -0,0 +1,489 @@
|
||||
// Copyright 2025 GottemHams
|
||||
/// @file
|
||||
/// @brief Support for Eurom A/C protocols.
|
||||
/// @see https://eurom.nl/wp-content/uploads/2022/04/Polar-12C-16CH-v1.0.pdf
|
||||
|
||||
#include "ir_Eurom.h"
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
#include "IRrecv.h"
|
||||
#include "IRsend.h"
|
||||
#include "IRtext.h"
|
||||
#include "IRutils.h"
|
||||
|
||||
#if __cplusplus >= 201103L && defined(_GLIBCXX_USE_C99_MATH_TR1)
|
||||
using std::roundf;
|
||||
#else
|
||||
using ::roundf;
|
||||
#endif
|
||||
|
||||
using irutils::uint8ToBcd;
|
||||
using irutils::bcdToUint8;
|
||||
using irutils::addBoolToString;
|
||||
using irutils::addFanToString;
|
||||
using irutils::addLabeledString;
|
||||
using irutils::addModeToString;
|
||||
using irutils::addTempToString;
|
||||
using irutils::minsToString;
|
||||
|
||||
#if SEND_EUROM
|
||||
/// Send a Eurom formatted message.
|
||||
/// Status: STABLE / Confirmed Working.
|
||||
/// @param[in] data An array of bytes containing the IR command.
|
||||
/// It is assumed to be in MSB order for this code.
|
||||
/// e.g.
|
||||
/// @code
|
||||
/// unsigned char data[kEuromStateLength] =
|
||||
/// {0x18,0x27,0x31,0x80,0x00,0x00,0x00,0x80,0x00,0x80,0x10,0x1D};
|
||||
/// @endcode
|
||||
/// @param[in] nbytes The number of bytes of data in the array.
|
||||
/// @param[in] repeat The number of times the command is to be repeated.
|
||||
void IRsend::sendEurom(const uint8_t data[], const uint16_t nbytes,
|
||||
const uint16_t repeat) {
|
||||
// Check if we have enough bytes to send a proper message
|
||||
if (nbytes < kEuromStateLength)
|
||||
return;
|
||||
|
||||
sendGeneric(kEuromHdrMark, kEuromHdrSpace,
|
||||
kEuromBitMark, kEuromOneSpace,
|
||||
kEuromBitMark, kEuromZeroSpace,
|
||||
kEuromBitMark, kEuromSpaceGap,
|
||||
data, nbytes, kEuromFreq, true, repeat, kDutyDefault);
|
||||
}
|
||||
#endif // SEND_EUROM
|
||||
|
||||
#if DECODE_EUROM
|
||||
/// Decode the supplied Eurom message.
|
||||
/// Status: STABLE / Confirmed Working.
|
||||
/// @param[in,out] results PTR to the data to decode & where to store the result
|
||||
/// @param[in] offset The starting index to use when attempting to decode the
|
||||
/// raw data. Typically/Defaults to kStartOffset.
|
||||
/// @param[in] nbits The number of data bits to expect.
|
||||
/// @param[in] strict Flag indicating if we should perform strict matching.
|
||||
/// @return True if it can decode it, false if it can't.
|
||||
bool IRrecv::decodeEurom(decode_results *results, uint16_t offset,
|
||||
const uint16_t nbits, const bool strict) {
|
||||
if (results->rawlen < nbits)
|
||||
return false; // Too short a message to match
|
||||
|
||||
if (strict && nbits != kEuromBits)
|
||||
return false;
|
||||
|
||||
if (!matchGeneric(results->rawbuf + offset, results->state,
|
||||
results->rawlen - offset, nbits,
|
||||
kEuromHdrMark, kEuromHdrSpace,
|
||||
kEuromBitMark, kEuromOneSpace,
|
||||
kEuromBitMark, kEuromZeroSpace,
|
||||
kEuromBitMark, kEuromSpaceGap, true)) return false;
|
||||
|
||||
// Success
|
||||
results->bits = nbits;
|
||||
results->decode_type = EUROM;
|
||||
return true;
|
||||
}
|
||||
#endif // DECODE_EUROM
|
||||
|
||||
/// Class constructor.
|
||||
/// @param[in] pin GPIO to be used when sending.
|
||||
/// @param[in] inverted Is the output signal to be inverted?
|
||||
/// @param[in] use_modulation Is frequency modulation to be used?
|
||||
IREuromAc::IREuromAc(const uint16_t pin, const bool inverted,
|
||||
const bool use_modulation)
|
||||
: _irsend(pin, inverted, use_modulation) {
|
||||
stateReset();
|
||||
}
|
||||
|
||||
/// Combine a mode flag and temperature into a single byte for the AC.
|
||||
/// Note that validity is not checked again.
|
||||
/// @param[in] mode A valid mode flag.
|
||||
/// @param[in] celsius A valid temperature, i.e. within the proper range.
|
||||
uint8_t IREuromAc::getModeCelsiusByte(const uint8_t mode,
|
||||
const uint8_t celsius) const {
|
||||
if (celsius >= kEuromMaxTempC)
|
||||
return mode | kEuromMaxTempFlag;
|
||||
return mode | ((celsius - kEuromMinTempC) << 4);
|
||||
}
|
||||
|
||||
/// Combine sleep mode and a timer duration into a single byte for the AC.
|
||||
/// Note that validity is not checked again.
|
||||
/// @param[in] sleep Whether sleep mode should be enabled.
|
||||
/// @param[in] hours A valid duration, i.e. within the proper range.
|
||||
uint8_t IREuromAc::getSleepOnTimerByte(const bool sleep,
|
||||
const uint8_t hours) const {
|
||||
uint8_t base = sleep ? kEuromSleepEnabled : kEuromSleepOnTimerDisabled;
|
||||
return base + uint8ToBcd(hours);
|
||||
}
|
||||
|
||||
/// Reset the internals of the object to a known good state.
|
||||
void IREuromAc::stateReset(void) {
|
||||
_.Sum1 = 0x18;
|
||||
_.Sum2 = 0x27;
|
||||
// No need to call setMode() separately, is handled by setTemp()
|
||||
setTemp(state_celsius_); // 23 C
|
||||
_.Power_Swing = kEuromPowerSwingDisabled;
|
||||
setSleep(state_sleep_); // false
|
||||
// No need to call setOnTimer() separately, is handled by setSleep()
|
||||
_.Sum3 = 0x00;
|
||||
setOffTimer(0);
|
||||
_.Sum4 = 0x80;
|
||||
setFan(kEuromFanLow);
|
||||
}
|
||||
|
||||
#if SEND_EUROM
|
||||
/// Send the current internal state as an IR message.
|
||||
/// @param[in] repeat Number of times the message will be repeated. Note that
|
||||
/// the original remote sends the same signal twice, but the
|
||||
/// actual A/C works just fine if you send it once.
|
||||
void IREuromAc::send(const uint16_t repeat) {
|
||||
_irsend.sendEurom(getRaw(), kEuromStateLength, repeat);
|
||||
}
|
||||
#endif // SEND_EUROM
|
||||
|
||||
/// Set up hardware to be able to send a message.
|
||||
void IREuromAc::begin(void) {
|
||||
_irsend.begin();
|
||||
}
|
||||
|
||||
/// Calculate the checksum for the supplied state.
|
||||
/// @param[in] state The source state to generate the checksum from.
|
||||
/// @param[in] length Length of the supplied state to checksum.
|
||||
/// @return The checksum value.
|
||||
uint8_t IREuromAc::calcChecksum(const uint8_t state[], const uint16_t length) {
|
||||
uint8_t checksum = irutils::sumNibbles(state + 1, length - 2);
|
||||
checksum -= irutils::sumNibbles(state, 1);
|
||||
return checksum;
|
||||
}
|
||||
|
||||
/// Verify if the checksum is valid for a given state.
|
||||
/// @param[in] state The source state to verify the checksum of.
|
||||
/// @param[in] length The size of the supplied state.
|
||||
/// @return A boolean indicating if its checksum is valid.
|
||||
bool IREuromAc::validChecksum(const uint8_t state[], const uint16_t length) {
|
||||
return state[length - 1] == IREuromAc::calcChecksum(state, length);
|
||||
}
|
||||
|
||||
/// Update the checksum value for the current internal state.
|
||||
void IREuromAc::checksum(void) {
|
||||
_.Checksum = IREuromAc::calcChecksum(_.raw, kEuromStateLength);
|
||||
}
|
||||
|
||||
/// Set the raw state of the remote.
|
||||
/// @param[in] state The raw state from the native IR message.
|
||||
void IREuromAc::setRaw(const uint8_t state[]) {
|
||||
std::memcpy(_.raw, state, kEuromStateLength);
|
||||
}
|
||||
|
||||
/// Get the raw state of the remote, suitable to be sent with the appropriate
|
||||
/// IRsend object method.
|
||||
/// @return A PTR to the internal state.
|
||||
uint8_t *IREuromAc::getRaw(void) {
|
||||
checksum(); // Let's ensure this is updated before returning
|
||||
return _.raw;
|
||||
}
|
||||
|
||||
/// Set the internal state to powered on.
|
||||
void IREuromAc::on(void) {
|
||||
setPower(true);
|
||||
}
|
||||
|
||||
/// Set the internal state to powered off.
|
||||
void IREuromAc::off(void) {
|
||||
setPower(false);
|
||||
}
|
||||
|
||||
/// Set the internal state to use the desired power setting.
|
||||
/// @param[in] state The desired power setting.
|
||||
void IREuromAc::setPower(const bool state) {
|
||||
// We'll also have to preserve the swing state
|
||||
if (state)
|
||||
_.Power_Swing |= kEuromPowerOn;
|
||||
else
|
||||
_.Power_Swing &= kEuromSwingOn;
|
||||
}
|
||||
|
||||
/// Get the current power setting from the internal state.
|
||||
/// @return A boolean indicating the current power setting.
|
||||
bool IREuromAc::getPower(void) const {
|
||||
return (_.Power_Swing & kEuromPowerOn) == kEuromPowerOn;
|
||||
}
|
||||
|
||||
/// Set the internal state to use the desired operation mode.
|
||||
/// @param[in] mode The desired operation mode.
|
||||
void IREuromAc::setMode(const uint8_t mode) {
|
||||
switch (mode) {
|
||||
case kEuromCool:
|
||||
case kEuromHeat:
|
||||
state_mode_ = mode;
|
||||
_.Mode_Celsius = getModeCelsiusByte(mode, state_celsius_);
|
||||
break;
|
||||
case kEuromDehumidify:
|
||||
case kEuromVentilate:
|
||||
state_mode_ = mode;
|
||||
_.Mode_Celsius = mode;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the current operation mode setting from the internal state.
|
||||
/// @return The current operation mode.
|
||||
uint8_t IREuromAc::getMode(void) const {
|
||||
return state_mode_;
|
||||
}
|
||||
|
||||
/// Set the internal state to use the desired temperature.
|
||||
/// @param[in] degrees The desired temperature in degrees, normally Celsius.
|
||||
/// @param[in] fahrenheit If the given temperature is in Fahrenheit instead.
|
||||
void IREuromAc::setTemp(const uint8_t degrees, const bool fahrenheit) {
|
||||
if (state_mode_ != kEuromCool && state_mode_ != kEuromHeat)
|
||||
return;
|
||||
|
||||
uint8_t temp_c, temp_f;
|
||||
if (fahrenheit) {
|
||||
temp_f = std::max(kEuromMinTempF, degrees);
|
||||
temp_f = std::min(kEuromMaxTempF, temp_f);
|
||||
temp_c = static_cast<uint8_t>(roundf(fahrenheitToCelsius(temp_f)));
|
||||
_.Fahrenheit = kEuromFahrenheitEnabled + temp_f;
|
||||
} else {
|
||||
temp_c = degrees;
|
||||
_.Fahrenheit = kEuromFahrenheitDisabled;
|
||||
}
|
||||
|
||||
temp_c = std::max(kEuromMinTempC, temp_c);
|
||||
temp_c = std::min(kEuromMaxTempC, temp_c);
|
||||
state_celsius_ = temp_c;
|
||||
_.Mode_Celsius = getModeCelsiusByte(state_mode_, temp_c);
|
||||
}
|
||||
|
||||
/// Get the current temperature from the internal state.
|
||||
/// @return The current temperature, which can be either Celsius or Fahrenheit,
|
||||
/// depending on what was used with setTemp(). See also: getTempIsFahrenheit().
|
||||
uint8_t IREuromAc::getTemp(void) const {
|
||||
if (state_mode_ != kEuromCool && state_mode_ != kEuromHeat)
|
||||
return 0; // Not supported in other modes
|
||||
if (getTempIsFahrenheit())
|
||||
return _.Fahrenheit - kEuromFahrenheitEnabled;
|
||||
return state_celsius_;
|
||||
}
|
||||
|
||||
/// Check if Fahrenheit is currently being used by the internal state.
|
||||
/// @return A boolean indicating if the current temperature is in Fahrenheit.
|
||||
bool IREuromAc::getTempIsFahrenheit(void) const {
|
||||
return _.Fahrenheit != kEuromFahrenheitDisabled;
|
||||
}
|
||||
|
||||
/// Set the internal state to use the desired fan speed.
|
||||
/// @param[in] speed The desired fan speed.
|
||||
void IREuromAc::setFan(const uint8_t speed) {
|
||||
switch (speed) {
|
||||
case kEuromFanLow:
|
||||
case kEuromFanMed:
|
||||
case kEuromFanHigh:
|
||||
_.Fan = speed;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the current fan speed from the internal state.
|
||||
/// @return The current fan speed.
|
||||
uint8_t IREuromAc::getFan(void) const {
|
||||
return _.Fan;
|
||||
}
|
||||
|
||||
/// Set the internal state to use the desired swing setting.
|
||||
/// @param[in] state The desired swing setting.
|
||||
void IREuromAc::setSwing(const bool state) {
|
||||
if (state)
|
||||
_.Power_Swing |= kEuromSwingOn;
|
||||
else
|
||||
_.Power_Swing &= kEuromPowerOn;
|
||||
}
|
||||
|
||||
/// Get the current swing setting from the internal state.
|
||||
/// @return A boolean indicating the current swing setting.
|
||||
bool IREuromAc::getSwing(void) const {
|
||||
return (_.Power_Swing & kEuromSwingOn) == kEuromSwingOn;
|
||||
}
|
||||
|
||||
/// Set the internal state to use the desired sleep setting.
|
||||
/// @param[in] state The desired sleep setting.
|
||||
void IREuromAc::setSleep(const bool state) {
|
||||
state_sleep_ = state;
|
||||
_.Sleep_OnTimer = getSleepOnTimerByte(state, state_on_timer_);
|
||||
}
|
||||
|
||||
/// Get the current sleep setting from the internal state.
|
||||
/// @return A boolean indicating the current sleep setting.
|
||||
bool IREuromAc::getSleep(void) const {
|
||||
return state_sleep_;
|
||||
}
|
||||
|
||||
/// Set the internal state to use the desired "off timer" duration.
|
||||
/// @param[in] duration The desired duration, in hours.
|
||||
void IREuromAc::setOffTimer(const uint8_t duration) {
|
||||
uint8_t hours = std::max(kEuromTimerMin, duration);
|
||||
hours = std::min(kEuromTimerMax, hours);
|
||||
_.OffTimer = kEuromOffTimer + uint8ToBcd(hours);
|
||||
_.OffTimerEnabled = hours ? kEuromOffTimer : kEuromOffTimerDisabled;
|
||||
}
|
||||
|
||||
/// Get the current "off timer" duration from the internal state.
|
||||
/// @return The current duration, in hours.
|
||||
uint8_t IREuromAc::getOffTimer(void) const {
|
||||
return bcdToUint8(_.OffTimer - kEuromOffTimer);
|
||||
}
|
||||
|
||||
/// Set the internal state to use the desired "on timer" duration.
|
||||
/// @param[in] duration The desired duration, in hours.
|
||||
void IREuromAc::setOnTimer(const uint8_t duration) {
|
||||
uint8_t hours = std::max(kEuromTimerMin, duration);
|
||||
hours = std::min(kEuromTimerMax, hours);
|
||||
state_on_timer_ = hours;
|
||||
_.Sleep_OnTimer = getSleepOnTimerByte(state_sleep_, hours);
|
||||
}
|
||||
|
||||
/// Get the current "on timer" duration from the internal state.
|
||||
/// @return The current duration, in hours.
|
||||
uint8_t IREuromAc::getOnTimer(void) const {
|
||||
return state_on_timer_;
|
||||
}
|
||||
|
||||
/// Convert a stdAc::opmode_t enum into its native operation mode.
|
||||
/// @param[in] mode The enum to be converted.
|
||||
/// @return The native equivalent of the enum.
|
||||
uint8_t IREuromAc::convertMode(const stdAc::opmode_t mode) {
|
||||
// This particular A/C doesn't actually have an 'Auto' mode, so we'll just use
|
||||
// the normal fan mode instead
|
||||
switch (mode) {
|
||||
case stdAc::opmode_t::kCool:
|
||||
return kEuromCool;
|
||||
case stdAc::opmode_t::kHeat:
|
||||
return kEuromHeat;
|
||||
case stdAc::opmode_t::kDry:
|
||||
return kEuromDehumidify;
|
||||
default:
|
||||
return kEuromVentilate;
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert a stdAc::fanspeed_t enum into its native speed.
|
||||
/// @param[in] speed The enum to be converted.
|
||||
/// @return The native equivalent of the enum.
|
||||
uint8_t IREuromAc::convertFan(const stdAc::fanspeed_t speed) {
|
||||
// This particular A/C doesn't actually have an 'Auto' mode, so we'll just use
|
||||
// the lowest fan speed instead
|
||||
switch (speed) {
|
||||
case stdAc::fanspeed_t::kHigh:
|
||||
case stdAc::fanspeed_t::kMax:
|
||||
return kEuromFanHigh;
|
||||
case stdAc::fanspeed_t::kMedium:
|
||||
return kEuromFanMed;
|
||||
default:
|
||||
return kEuromFanLow;
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert a stdAc::swingv_t enum into its native swing.
|
||||
/// @param[in] swing The enum to be converted.
|
||||
/// @return The native equivalent of the enum.
|
||||
bool IREuromAc::convertSwing(const stdAc::swingv_t swing) {
|
||||
// The only choice is on or off, so let's just treat the former as auto mode
|
||||
switch (swing) {
|
||||
case stdAc::swingv_t::kAuto:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert a native operation mode into its stdAc enum equivalent.
|
||||
/// @param[in] mode The native operation mode setting to be converted.
|
||||
/// @return The stdAc enum equivalent of the native setting.
|
||||
stdAc::opmode_t IREuromAc::toCommonMode(const uint8_t mode) {
|
||||
// This particular A/C doesn't actually have an 'Auto' mode, so we'll just use
|
||||
// the normal fan mode instead. To make this more clear, 'kEuromVentilate' is
|
||||
// explicitly included in the switch (instead of being omitted and implicitly
|
||||
// handled via the default case).
|
||||
switch (mode) {
|
||||
case kEuromCool:
|
||||
return stdAc::opmode_t::kCool;
|
||||
case kEuromHeat:
|
||||
return stdAc::opmode_t::kHeat;
|
||||
case kEuromDehumidify:
|
||||
return stdAc::opmode_t::kDry;
|
||||
case kEuromVentilate:
|
||||
default:
|
||||
return stdAc::opmode_t::kFan;
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert a native fan speed into its stdAc enum equivalent.
|
||||
/// @param[in] speed The native speed setting to be converted.
|
||||
/// @return The stdAc enum equivalent of the native setting.
|
||||
stdAc::fanspeed_t IREuromAc::toCommonFanSpeed(const uint8_t speed) {
|
||||
// This particular A/C doesn't actually have an 'Auto' mode, so we'll just use
|
||||
// the lowest speed instead. To make this more clear, 'kEuromFanLow' is
|
||||
// explicitly included in the switch (instead of being omitted and implicitly
|
||||
// handled via the default case).
|
||||
switch (speed) {
|
||||
case kEuromFanHigh:
|
||||
return stdAc::fanspeed_t::kMax;
|
||||
case kEuromFanMed:
|
||||
return stdAc::fanspeed_t::kMedium;
|
||||
case kEuromFanLow:
|
||||
default:
|
||||
return stdAc::fanspeed_t::kMin;
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert a native swing setting into its stdAc enum equivalent.
|
||||
/// @param[in] swing The native swing setting to be converted.
|
||||
/// @return The stdAc enum equivalent of the native setting.
|
||||
stdAc::swingv_t IREuromAc::toCommonSwing(const bool swing) {
|
||||
// The only choice is on or off, so let's just treat the former as auto mode
|
||||
return swing ? stdAc::swingv_t::kAuto : stdAc::swingv_t::kOff;
|
||||
}
|
||||
|
||||
/// Convert the current internal state into its stdAc::state_t equivalent.
|
||||
/// @return The stdAc struct equivalent of the native settings.
|
||||
stdAc::state_t IREuromAc::toCommon(void) const {
|
||||
stdAc::state_t result{};
|
||||
result.protocol = EUROM;
|
||||
result.power = getPower();
|
||||
result.mode = toCommonMode(getMode());
|
||||
result.degrees = getTemp();
|
||||
result.celsius = !getTempIsFahrenheit();
|
||||
result.fanspeed = toCommonFanSpeed(getFan());
|
||||
result.swingv = toCommonSwing(getSwing());
|
||||
result.sleep = getSleep();
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Convert the current internal state into a human-readable string.
|
||||
/// @return A human-readable string.
|
||||
String IREuromAc::toString(void) const {
|
||||
String result = "";
|
||||
result.reserve(70); // Reserve some heap for the string to reduce fragging
|
||||
result += addBoolToString(getPower(), kPowerStr, false);
|
||||
result += addModeToString(getMode(), 0xFF, kEuromCool,
|
||||
kEuromHeat, kEuromDehumidify, kEuromVentilate);
|
||||
result += addTempToString(getTemp(), !getTempIsFahrenheit());
|
||||
result += addFanToString(getFan(), kEuromFanHigh, kEuromFanLow,
|
||||
0xFF, 0xFF,
|
||||
kEuromFanMed);
|
||||
|
||||
result += addBoolToString(getSwing(), kSwingVStr);
|
||||
result += addBoolToString(getSleep(), kSleepStr);
|
||||
|
||||
uint8_t off_timer_min = getOffTimer() * 60;
|
||||
uint8_t on_timer_min = getOnTimer() * 60;
|
||||
String off_timer_str = off_timer_min ? minsToString(off_timer_min) : kOffStr;
|
||||
String on_timer_str = on_timer_min ? minsToString(on_timer_min) : kOffStr;
|
||||
result += addLabeledString(off_timer_str, kOffTimerStr);
|
||||
result += addLabeledString(on_timer_str, kOnTimerStr);
|
||||
return result;
|
||||
}
|
||||
244
lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Eurom.h
Normal file
244
lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Eurom.h
Normal file
@ -0,0 +1,244 @@
|
||||
// Copyright 2025 GottemHams
|
||||
/// @file
|
||||
/// @brief Support for Eurom A/C protocols.
|
||||
/// @see https://eurom.nl/wp-content/uploads/2022/04/Polar-12C-16CH-v1.0.pdf
|
||||
|
||||
// Supports:
|
||||
// Brand: Eurom, Model: Polar 16CH
|
||||
|
||||
#ifndef IR_EUROM_H_
|
||||
#define IR_EUROM_H_
|
||||
|
||||
#define __STDC_LIMIT_MACROS
|
||||
#include <stdint.h>
|
||||
#ifndef UNIT_TEST
|
||||
#include <Arduino.h>
|
||||
#endif
|
||||
#include "IRremoteESP8266.h"
|
||||
#include "IRsend.h"
|
||||
#ifdef UNIT_TEST
|
||||
#include "IRsend_test.h"
|
||||
#endif
|
||||
|
||||
/// Native representation of a Eurom message.
|
||||
union EuromProtocol {
|
||||
uint8_t raw[kEuromStateLength]; // The state of the IR remote
|
||||
struct {
|
||||
// Byte 0 is used as a negative offset for the checksum and is always 0x18
|
||||
uint8_t Sum1 :8;
|
||||
|
||||
// Byte 1 is used as part of the checksum only and is always 0x27
|
||||
uint8_t Sum2 :8;
|
||||
|
||||
// Byte 2 combines 2 functions and has some considerations:
|
||||
// 1. Cooling mode almost always has the lower nibble set to 0x1,
|
||||
// e.g. 0x01 = 16 C, 0x11 = 17 C, 0xF1 = 31 C.
|
||||
// Exception: 0x09 means 32 C (max temperature).
|
||||
// 2. Dehumidification doesn't support temperatures, so this is always 0x72.
|
||||
// 3. Same goes for fan mode, which is always 0x73.
|
||||
// 4. Heating mode almost always has the lower nibble set to 0x4,
|
||||
// e.g. 0x04 = 16 C, 0x14 = 17 C, 0xF4 = 31 C.
|
||||
// Exception: 0x0C means 32 C (max temperature).
|
||||
uint8_t Mode_Celsius :8;
|
||||
|
||||
// Byte 3 also combines 2 functions, with the values being OR'ed together:
|
||||
// 1. 0x00 means power off, swing off
|
||||
// 2. 0x40 means power off, swing on
|
||||
// 3. 0x80 means power on, swing off
|
||||
// 3. 0xC0 means power on, swing on
|
||||
uint8_t Power_Swing :8;
|
||||
|
||||
// Byte 4 is to track Fahrenheit separately, but note that it will always
|
||||
// reset to 0x00 if Celsius is used. On the other hand, Celsius moves along
|
||||
// with this, i.e. a change of +1/-1 C for roughly every 3 F. The base value
|
||||
// is 0x41 which corresponds to 61 F and increases by 0x01 for every degree.
|
||||
// This gives it a range of 0x41 - 0x5E (inclusive).
|
||||
uint8_t Fahrenheit :8;
|
||||
|
||||
// Byte 5 yet again combines functions:
|
||||
// 1. 0x00 for sleep mode disabled, 0x40 for enabled
|
||||
// 2. The timer duration is simply encoded as BCD and added to this, with a
|
||||
// maximum of 24 hours
|
||||
uint8_t Sleep_OnTimer :8;
|
||||
|
||||
// Byte 6 seems to be truly unused, since it's always 0x00. We'll still
|
||||
// always use it in checksums though.
|
||||
uint8_t Sum3 :8;
|
||||
|
||||
// Byte 7 is always at least 0x80, with the hours also being added as BCD,
|
||||
// e.g. 0x80 = 0 hours, 0x81 = 1 h, 0xA4 = 24 h.
|
||||
uint8_t OffTimer :8;
|
||||
|
||||
// Byte 8 doesn't really seem to matter, but it should be 0x00 or 0x80 for
|
||||
// off and on respectively. Apparently setting the **duration** alone is
|
||||
// already enough to set the timer?
|
||||
uint8_t OffTimerEnabled :8;
|
||||
|
||||
// Byte 9 is used as part of the checksum only and is slways 0x80
|
||||
uint8_t Sum4 :8;
|
||||
|
||||
// Byte 10 is simple: 0x10, 0x20, 0x40 for low, medium and high respectively
|
||||
uint8_t Fan :8;
|
||||
|
||||
// Byte 11 holds a funny checksum. =]
|
||||
// Add all nibbles beyond the first byte (excluding the checksum of course),
|
||||
// then subtract the first byte. The second byte should always be larger, so
|
||||
// this never results in sudden signedness (i.e. underflowing). It might be
|
||||
// pure coincidence that the first byte is always 0x18 and they could have
|
||||
// hardcoded that value elsewhere/otherwise.
|
||||
uint8_t Checksum :8;
|
||||
};
|
||||
};
|
||||
|
||||
// Constants
|
||||
|
||||
// IR signal information
|
||||
const uint16_t kEuromHdrMark = 3257;
|
||||
const uint16_t kEuromBitMark = 454;
|
||||
const uint16_t kEuromHdrSpace = 3187;
|
||||
const uint16_t kEuromOneSpace = 1162;
|
||||
const uint16_t kEuromZeroSpace = 355;
|
||||
const uint16_t kEuromSpaceGap = 50058;
|
||||
const uint16_t kEuromFreq = 38000;
|
||||
|
||||
// Modes
|
||||
const uint8_t kEuromCool = 0x01; // Lowest possible value, 16 C
|
||||
const uint8_t kEuromDehumidify = 0x72;
|
||||
const uint8_t kEuromVentilate = 0x73;
|
||||
const uint8_t kEuromHeat = 0x04; // Also 16 C
|
||||
|
||||
// Reaching the highest temperature breaks the formula that is used otherwise,
|
||||
// because we should basically just OR this flag to the above mode byte. It
|
||||
// seems more like it indicates "max temp" instead of "32 C".
|
||||
const uint8_t kEuromMaxTempFlag = 0x08;
|
||||
|
||||
// Temperatures
|
||||
const uint8_t kEuromMinTempC = 16;
|
||||
const uint8_t kEuromMaxTempC = 32;
|
||||
|
||||
const uint8_t kEuromMinTempF = 61;
|
||||
const uint8_t kEuromMaxTempF = 90;
|
||||
|
||||
// The enabled flag will simply be added to chosen temperature
|
||||
const uint8_t kEuromFahrenheitDisabled = 0x00;
|
||||
const uint8_t kEuromFahrenheitEnabled = 0x04;
|
||||
|
||||
// Power and swing
|
||||
const uint8_t kEuromPowerSwingDisabled = 0x00;
|
||||
const uint8_t kEuromPowerOn = 0x80;
|
||||
const uint8_t kEuromSwingOn = 0x40;
|
||||
|
||||
// Sleep mode and the "on timer"
|
||||
const uint8_t kEuromSleepOnTimerDisabled = 0x00;
|
||||
const uint8_t kEuromSleepEnabled = 0x40;
|
||||
|
||||
// The "off timer"
|
||||
const uint8_t kEuromOffTimerDisabled = 0x00;
|
||||
const uint8_t kEuromOffTimerEnabled = 0x80;
|
||||
const uint8_t kEuromOffTimer = kEuromOffTimerEnabled; // Corresponds to 0 hours
|
||||
|
||||
// Stuff for all timers
|
||||
const uint8_t kEuromTimerMin = 0;
|
||||
const uint8_t kEuromTimerMax = 24;
|
||||
|
||||
// Fan speeds
|
||||
const uint8_t kEuromFanLow = 0x10;
|
||||
const uint8_t kEuromFanMed = 0x20;
|
||||
const uint8_t kEuromFanHigh = 0x40;
|
||||
|
||||
// Classes
|
||||
|
||||
/// Class for handling detailed Eurom A/C messages.
|
||||
class IREuromAc {
|
||||
public:
|
||||
explicit IREuromAc(const uint16_t pin, const bool inverted = false,
|
||||
const bool use_modulation = true);
|
||||
|
||||
void stateReset();
|
||||
#if SEND_EUROM
|
||||
void send(const uint16_t repeat = kNoRepeat);
|
||||
/// Run the calibration to calculate uSec timing offsets for this platform.
|
||||
/// @return The uSec timing offset needed per modulation of the IR Led.
|
||||
/// @note This will produce a 65 ms IR signal pulse at 38 kHz.
|
||||
/// Only ever needs to be run once per object instantiation, if at all.
|
||||
int8_t calibrate(void) {
|
||||
return _irsend.calibrate();
|
||||
}
|
||||
#endif // SEND_EUROM
|
||||
|
||||
void begin(void);
|
||||
static uint8_t calcChecksum(const uint8_t state[],
|
||||
const uint16_t length = kEuromStateLength);
|
||||
static bool validChecksum(const uint8_t state[],
|
||||
const uint16_t length = kEuromStateLength);
|
||||
|
||||
void setRaw(const uint8_t state[]);
|
||||
uint8_t *getRaw(void);
|
||||
|
||||
void on(void);
|
||||
void off(void);
|
||||
|
||||
void setPower(const bool state);
|
||||
bool getPower(void) const;
|
||||
|
||||
void setMode(const uint8_t mode);
|
||||
uint8_t getMode(void) const;
|
||||
|
||||
void setTemp(const uint8_t degrees, const bool fahrenheit = false);
|
||||
uint8_t getTemp(void) const;
|
||||
bool getTempIsFahrenheit(void) const;
|
||||
|
||||
void setFan(const uint8_t speed);
|
||||
uint8_t getFan(void) const;
|
||||
|
||||
void setSwing(const bool state);
|
||||
bool getSwing(void) const;
|
||||
|
||||
void setSleep(const bool state);
|
||||
bool getSleep(void) const;
|
||||
|
||||
void setOffTimer(const uint8_t duration);
|
||||
uint8_t getOffTimer(void) const;
|
||||
|
||||
void setOnTimer(const uint8_t duration);
|
||||
uint8_t getOnTimer(void) const;
|
||||
|
||||
static uint8_t convertMode(const stdAc::opmode_t mode);
|
||||
static uint8_t convertFan(const stdAc::fanspeed_t speed);
|
||||
static bool convertSwing(const stdAc::swingv_t swing);
|
||||
|
||||
static stdAc::opmode_t toCommonMode(const uint8_t mode);
|
||||
static stdAc::fanspeed_t toCommonFanSpeed(const uint8_t speed);
|
||||
static stdAc::swingv_t toCommonSwing(const bool swing);
|
||||
|
||||
stdAc::state_t toCommon(void) const;
|
||||
String toString(void) const;
|
||||
#ifndef UNIT_TEST
|
||||
|
||||
private:
|
||||
IRsend _irsend;
|
||||
#else
|
||||
/// @cond IGNORE
|
||||
IRsendTest _irsend;
|
||||
/// @endcond
|
||||
#endif
|
||||
EuromProtocol _;
|
||||
|
||||
// Due to some bytes combining multiple functions, we'll need to keep track of
|
||||
// some of the original values ourselves. Otherwise we wouldn't really be able
|
||||
// to e.g. return the current mode or temperature, or changing the sleep mode
|
||||
// without also messing with the timer hours.
|
||||
uint8_t state_mode_ = kEuromCool;
|
||||
uint8_t state_celsius_ = 23;
|
||||
bool state_sleep_ = false;
|
||||
uint8_t state_on_timer_ = kEuromTimerMin;
|
||||
|
||||
// Some helper functions for reusing the above state variables depending on
|
||||
// context and returning the byte expected by the AC.
|
||||
uint8_t getModeCelsiusByte(const uint8_t mode, const uint8_t celsius) const;
|
||||
uint8_t getSleepOnTimerByte(const bool sleep, const uint8_t hours) const;
|
||||
|
||||
void checksum(void);
|
||||
};
|
||||
|
||||
#endif // IR_EUROM_H_
|
||||
@ -41,6 +41,7 @@
|
||||
// Brand: Fujitsu, Model: AR-REG1U remote (ARRAH2E)
|
||||
// Brand: OGeneral, Model: AR-RCL1E remote (ARRAH2E)
|
||||
// Brand: Fujitsu General, Model: AR-JW17 remote (ARDB1)
|
||||
// Brand: Fujitsu General, Model: AR-JW19 remote (ARDB1)
|
||||
|
||||
#ifndef IR_FUJITSU_H_
|
||||
#define IR_FUJITSU_H_
|
||||
|
||||
@ -37,7 +37,8 @@ void IRsend::sendGC(uint16_t buf[], uint16_t len) {
|
||||
enableIROut(hz);
|
||||
uint32_t periodic_time = calcUSecPeriod(hz, false);
|
||||
uint8_t emits =
|
||||
std::min(buf[kGlobalCacheRptIndex], (uint16_t)kGlobalCacheMaxRepeat);
|
||||
std::min(buf[kGlobalCacheRptIndex],
|
||||
static_cast<uint16_t>(kGlobalCacheMaxRepeat));
|
||||
// Repeat
|
||||
for (uint8_t repeat = 0; repeat < emits; repeat++) {
|
||||
// First time through, start at the beginning (kGlobalCacheStartIndex),
|
||||
|
||||
@ -471,7 +471,7 @@ bool IRrecv::decodeGoodweather(decode_results* results, uint16_t offset,
|
||||
DPRINT("DEBUG: inverted = ");
|
||||
DPRINTLN((uint16_t)inverted);
|
||||
if (data != (inverted ^ 0xFF)) return false; // Data integrity failed.
|
||||
dataSoFar |= (uint64_t)data << dataBitsSoFar;
|
||||
dataSoFar |= static_cast<uint64_t>(data) << dataBitsSoFar;
|
||||
}
|
||||
|
||||
// Footer.
|
||||
|
||||
@ -375,6 +375,7 @@ void IRGreeAC::setSwingVertical(const bool automatic, const uint8_t position) {
|
||||
uint8_t new_position = position;
|
||||
if (!automatic) {
|
||||
switch (position) {
|
||||
case kGreeSwingLastPos:
|
||||
case kGreeSwingUp:
|
||||
case kGreeSwingMiddleUp:
|
||||
case kGreeSwingMiddle:
|
||||
@ -503,6 +504,7 @@ uint8_t IRGreeAC::convertFan(const stdAc::fanspeed_t speed) {
|
||||
/// @return The native equivalent of the enum.
|
||||
uint8_t IRGreeAC::convertSwingV(const stdAc::swingv_t swingv) {
|
||||
switch (swingv) {
|
||||
case stdAc::swingv_t::kOff: return kGreeSwingLastPos;
|
||||
case stdAc::swingv_t::kHighest: return kGreeSwingUp;
|
||||
case stdAc::swingv_t::kHigh: return kGreeSwingMiddleUp;
|
||||
case stdAc::swingv_t::kMiddle: return kGreeSwingMiddle;
|
||||
@ -562,7 +564,7 @@ stdAc::swingv_t IRGreeAC::toCommonSwingV(const uint8_t pos) {
|
||||
case kGreeSwingMiddle: return stdAc::swingv_t::kMiddle;
|
||||
case kGreeSwingMiddleDown: return stdAc::swingv_t::kLow;
|
||||
case kGreeSwingDown: return stdAc::swingv_t::kLowest;
|
||||
default: return stdAc::swingv_t::kAuto;
|
||||
default: return stdAc::swingv_t::kOff;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -723,8 +723,10 @@ void IRHaierAC176::setTemp(const uint8_t degree, const bool fahrenheit) {
|
||||
temp = kHaierAcYrw02MinTempF;
|
||||
else if (temp > kHaierAcYrw02MaxTempF)
|
||||
temp = kHaierAcYrw02MaxTempF;
|
||||
if (degree >= 77) { temp++; }
|
||||
if (degree >= 79) { temp++; }
|
||||
if (degree >= 77)
|
||||
temp++;
|
||||
if (degree >= 79)
|
||||
temp++;
|
||||
// See at IRHaierAC176::getTemp() comments for clarification
|
||||
_.ExtraDegreeF = temp % 2;
|
||||
_.Temp = (temp - kHaierAcYrw02MinTempF -_.ExtraDegreeF) >> 1;
|
||||
@ -741,7 +743,8 @@ void IRHaierAC176::setTemp(const uint8_t degree, const bool fahrenheit) {
|
||||
/// The unit of temperature is specified by UseFahrenheit value.
|
||||
/// @return The current setting for temperature.
|
||||
uint8_t IRHaierAC176::getTemp(void) const {
|
||||
if (!_.UseFahrenheit) { return _.Temp + kHaierAcYrw02MinTempC; }
|
||||
if (!_.UseFahrenheit)
|
||||
return _.Temp + kHaierAcYrw02MinTempC;
|
||||
uint8_t degree = _.Temp*2 + kHaierAcYrw02MinTempF + _.ExtraDegreeF;
|
||||
// The way of coding the temperature in degree Fahrenheit is
|
||||
// kHaierAcYrw02MinTempF + Temp*2 + ExtraDegreeF, for example
|
||||
@ -778,8 +781,10 @@ uint8_t IRHaierAC176::getTemp(void) const {
|
||||
// | 84F | 0b1101 | 0b0 |
|
||||
// | 86F | 0b1110 | 0b0 |
|
||||
// | 85F | 0b1101 | 0b1 |
|
||||
if (degree >= 77) { degree--; }
|
||||
if (degree >= 79) { degree--; }
|
||||
if (degree >= 77)
|
||||
degree--;
|
||||
if (degree >= 79)
|
||||
degree--;
|
||||
return degree;
|
||||
}
|
||||
|
||||
@ -958,7 +963,7 @@ uint8_t IRHaierAC176::getTimerMode(void) const { return _.TimerMode; }
|
||||
/// Set the number of minutes of the On Timer setting.
|
||||
/// @param[in] mins Nr. of Minutes for the Timer. `0` means disable the timer.
|
||||
void IRHaierAC176::setOnTimer(const uint16_t mins) {
|
||||
const uint16_t nr_mins = std::min((uint16_t)(23 * 60 + 59), mins);
|
||||
const uint16_t nr_mins = std::min(static_cast<uint16_t>(23 * 60 + 59), mins);
|
||||
_.OnTimerHrs = nr_mins / 60;
|
||||
_.OnTimerMins = nr_mins % 60;
|
||||
|
||||
@ -988,7 +993,7 @@ uint16_t IRHaierAC176::getOnTimer(void) const {
|
||||
/// Set the number of minutes of the Off Timer setting.
|
||||
/// @param[in] mins Nr. of Minutes for the Timer. `0` means disable the timer.
|
||||
void IRHaierAC176::setOffTimer(const uint16_t mins) {
|
||||
const uint16_t nr_mins = std::min((uint16_t)(23 * 60 + 59), mins);
|
||||
const uint16_t nr_mins = std::min(static_cast<uint16_t>(23 * 60 + 59), mins);
|
||||
_.OffTimerHrs = nr_mins / 60;
|
||||
_.OffTimerMins = nr_mins % 60;
|
||||
|
||||
@ -1617,8 +1622,10 @@ void IRHaierAC160::setTemp(const uint8_t degree, const bool fahrenheit) {
|
||||
temp = kHaierAcYrw02MinTempF;
|
||||
else if (temp > kHaierAcYrw02MaxTempF)
|
||||
temp = kHaierAcYrw02MaxTempF;
|
||||
if (degree >= 77) { temp++; }
|
||||
if (degree >= 79) { temp++; }
|
||||
if (degree >= 77)
|
||||
temp++;
|
||||
if (degree >= 79)
|
||||
temp++;
|
||||
// See at IRHaierAC160::getTemp() comments for clarification
|
||||
_.ExtraDegreeF = temp % 2;
|
||||
_.Temp = (temp - kHaierAcYrw02MinTempF -_.ExtraDegreeF) >> 1;
|
||||
@ -1635,7 +1642,8 @@ void IRHaierAC160::setTemp(const uint8_t degree, const bool fahrenheit) {
|
||||
/// The unit of temperature is specified by UseFahrenheit value.
|
||||
/// @return The current setting for temperature.
|
||||
uint8_t IRHaierAC160::getTemp(void) const {
|
||||
if (!_.UseFahrenheit) { return _.Temp + kHaierAcYrw02MinTempC; }
|
||||
if (!_.UseFahrenheit)
|
||||
return _.Temp + kHaierAcYrw02MinTempC;
|
||||
uint8_t degree = _.Temp*2 + kHaierAcYrw02MinTempF + _.ExtraDegreeF;
|
||||
// The way of coding the temperature in degree Fahrenheit is
|
||||
// kHaierAcYrw02MinTempF + Temp*2 + ExtraDegreeF, for example
|
||||
@ -1672,8 +1680,10 @@ uint8_t IRHaierAC160::getTemp(void) const {
|
||||
// | 84F | 0b1101 | 0b0 |
|
||||
// | 86F | 0b1110 | 0b0 |
|
||||
// | 85F | 0b1101 | 0b1 |
|
||||
if (degree >= 77) { degree--; }
|
||||
if (degree >= 79) { degree--; }
|
||||
if (degree >= 77)
|
||||
degree--;
|
||||
if (degree >= 79)
|
||||
degree--;
|
||||
return degree;
|
||||
}
|
||||
|
||||
@ -1854,7 +1864,7 @@ uint8_t IRHaierAC160::getTimerMode(void) const { return _.TimerMode; }
|
||||
/// Set the number of minutes of the On Timer setting.
|
||||
/// @param[in] mins Nr. of Minutes for the Timer. `0` means disable the timer.
|
||||
void IRHaierAC160::setOnTimer(const uint16_t mins) {
|
||||
const uint16_t nr_mins = std::min((uint16_t)(23 * 60 + 59), mins);
|
||||
const uint16_t nr_mins = std::min(static_cast<uint16_t>(23 * 60 + 59), mins);
|
||||
_.OnTimerHrs = nr_mins / 60;
|
||||
_.OnTimerMins = nr_mins % 60;
|
||||
|
||||
@ -1884,7 +1894,7 @@ uint16_t IRHaierAC160::getOnTimer(void) const {
|
||||
/// Set the number of minutes of the Off Timer setting.
|
||||
/// @param[in] mins Nr. of Minutes for the Timer. `0` means disable the timer.
|
||||
void IRHaierAC160::setOffTimer(const uint16_t mins) {
|
||||
const uint16_t nr_mins = std::min((uint16_t)(23 * 60 + 59), mins);
|
||||
const uint16_t nr_mins = std::min(static_cast<uint16_t>(23 * 60 + 59), mins);
|
||||
_.OffTimerHrs = nr_mins / 60;
|
||||
_.OffTimerMins = nr_mins % 60;
|
||||
|
||||
|
||||
@ -318,8 +318,9 @@ void IRKelonAc::setTimer(uint16_t mins) {
|
||||
/// @return The timer set minutes
|
||||
uint16_t IRKelonAc::getTimer() const {
|
||||
if (_.TimerHours >= 10)
|
||||
return ((uint16_t) ((_.TimerHours << 1) | _.TimerHalfHour) - 10) * 60;
|
||||
return (((uint16_t) _.TimerHours) * 60) + (_.TimerHalfHour ? 30 : 0);
|
||||
return (static_cast<uint16_t>((_.TimerHours << 1) | _.TimerHalfHour) -
|
||||
10) * 60;
|
||||
return static_cast<uint16_t>(_.TimerHours) * 60 + (_.TimerHalfHour ? 30 : 0);
|
||||
}
|
||||
|
||||
/// Enable or disable the timer. Note that in order to enable the timer the
|
||||
|
||||
@ -38,7 +38,7 @@ void IRsend::sendLegoPf(const uint64_t data, const uint16_t nbits,
|
||||
// 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++) {
|
||||
for (uint16_t r = 0; r < std::max(repeat, static_cast<uint16_t>(5)); r++) {
|
||||
// Lego has a special repeat mode which repeats a message with varying
|
||||
// start to start times.
|
||||
sendGeneric(kLegoPfBitMark, kLegoPfHdrSpace,
|
||||
|
||||
@ -96,7 +96,7 @@ bool IRrecv::decodeLutron(decode_results *results, uint16_t offset,
|
||||
break; // We've likely reached the end of a message.
|
||||
}
|
||||
// Remove a bit length from the current entry.
|
||||
entry = std::max(entry, (uint16_t)(kLutronTick / kRawTick)) -
|
||||
entry = std::max(entry, static_cast<uint16_t>(kLutronTick / kRawTick)) -
|
||||
kLutronTick / kRawTick;
|
||||
}
|
||||
if (offset % 2 && !match(entry, kLutronDelta, 0, kLutronDelta)) {
|
||||
|
||||
@ -566,7 +566,7 @@ uint16_t IRMideaAC::getOnTimer(void) const {
|
||||
/// Setting it will disable that mode/settings.
|
||||
void IRMideaAC::setOnTimer(const uint16_t mins) {
|
||||
setEnableSensorTemp(false);
|
||||
uint8_t halfhours = std::min((uint16_t)(24 * 60), mins) / 30;
|
||||
uint8_t halfhours = std::min(static_cast<uint16_t>(24 * 60), mins) / 30;
|
||||
if (halfhours)
|
||||
_.SensorTemp = ((halfhours - 1) << 1) | 1;
|
||||
else
|
||||
@ -589,7 +589,7 @@ uint16_t IRMideaAC::getOffTimer(void) const { return _.OffTimer * 30 + 30; }
|
||||
/// of the actual device/protocol.
|
||||
/// @note A value of less than 30 will disable the Timer.
|
||||
void IRMideaAC::setOffTimer(const uint16_t mins) {
|
||||
uint8_t halfhours = std::min((uint16_t)(24 * 60), mins) / 30;
|
||||
uint8_t halfhours = std::min(static_cast<uint16_t>(24 * 60), mins) / 30;
|
||||
if (halfhours)
|
||||
_.OffTimer = halfhours - 1;
|
||||
else
|
||||
|
||||
@ -389,8 +389,9 @@ void IRMirageAc::setClock(const uint32_t nr_of_seconds) {
|
||||
_.Minutes = _.Seconds = 0; // No clock setting. Clear it just in case.
|
||||
break;
|
||||
default:
|
||||
// Limit to 23:59:59
|
||||
uint32_t remaining = std::min(
|
||||
nr_of_seconds, (uint32_t)(24 * 60 * 60 - 1)); // Limit to 23:59:59.
|
||||
nr_of_seconds, static_cast<uint32_t>(24 * 60 * 60 - 1));
|
||||
_.Seconds = uint8ToBcd(remaining % 60);
|
||||
remaining /= 60;
|
||||
_.Minutes = uint8ToBcd(remaining % 60);
|
||||
@ -586,7 +587,7 @@ uint16_t IRMirageAc::getOnTimer(void) const {
|
||||
/// Set the number of minutes for the On Timer.
|
||||
/// @param[in] nr_of_mins How long to set the timer for. 0 disables the timer.
|
||||
void IRMirageAc::setOnTimer(const uint16_t nr_of_mins) {
|
||||
uint16_t mins = std::min(nr_of_mins, (uint16_t)(24 * 60));
|
||||
uint16_t mins = std::min(nr_of_mins, static_cast<uint16_t>(24 * 60));
|
||||
switch (_model) {
|
||||
case mirage_ac_remote_model_t::KKG29AC1:
|
||||
_.OnTimerEnable = (mins > 0);
|
||||
@ -612,7 +613,7 @@ uint16_t IRMirageAc::getOffTimer(void) const {
|
||||
/// Set the number of minutes for the Off Timer.
|
||||
/// @param[in] nr_of_mins How long to set the timer for. 0 disables the timer.
|
||||
void IRMirageAc::setOffTimer(const uint16_t nr_of_mins) {
|
||||
uint16_t mins = std::min(nr_of_mins, (uint16_t)(24 * 60));
|
||||
uint16_t mins = std::min(nr_of_mins, static_cast<uint16_t>(24 * 60));
|
||||
switch (_model) {
|
||||
case mirage_ac_remote_model_t::KKG29AC1:
|
||||
_.OffTimerEnable = (mins > 0);
|
||||
|
||||
@ -88,7 +88,8 @@ void IRsend::sendPanasonic64(const uint64_t data, const uint16_t nbits,
|
||||
/// @note This protocol is a modified version of Kaseikyo.
|
||||
void IRsend::sendPanasonic(const uint16_t address, const uint32_t data,
|
||||
const uint16_t nbits, const uint16_t repeat) {
|
||||
sendPanasonic64(((uint64_t)address << 32) | (uint64_t)data, nbits, repeat);
|
||||
sendPanasonic64(static_cast<uint64_t>(address) << 32 |
|
||||
static_cast<uint64_t>(data), nbits, repeat);
|
||||
}
|
||||
|
||||
/// Calculate the raw Panasonic data based on device, subdevice, & function.
|
||||
@ -105,8 +106,10 @@ uint64_t IRsend::encodePanasonic(const uint16_t manufacturer,
|
||||
const uint8_t subdevice,
|
||||
const uint8_t function) {
|
||||
uint8_t checksum = device ^ subdevice ^ function;
|
||||
return (((uint64_t)manufacturer << 32) | ((uint64_t)device << 24) |
|
||||
((uint64_t)subdevice << 16) | ((uint64_t)function << 8) | checksum);
|
||||
return ((static_cast<uint64_t>(manufacturer) << 32) |
|
||||
(static_cast<uint64_t>(device) << 24) |
|
||||
(static_cast<uint64_t>(subdevice) << 16) |
|
||||
(static_cast<uint64_t>(function) << 8) | checksum);
|
||||
}
|
||||
#endif // (SEND_PANASONIC || SEND_DENON)
|
||||
|
||||
|
||||
@ -20,9 +20,11 @@
|
||||
// Brand: Panasonic, Model: CS-Z9RKR A/C (PANASONIC_AC RKR/6)
|
||||
// Brand: Panasonic, Model: CS-Z24RKR A/C (PANASONIC_AC RKR/6)
|
||||
// Brand: Panasonic, Model: CS-YW9MKD A/C (PANASONIC_AC JKE/4)
|
||||
// Brand: Panasonic, Model: CS-E12QKEW A/C (PANASONIC_AC DKE/3)
|
||||
// Brand: Panasonic, Model: A75C2311 remote (PANASONIC_AC CKP/5)
|
||||
// Brand: Panasonic, Model: A75C2616-1 remote (PANASONIC_AC DKE/3)
|
||||
// Brand: Panasonic, Model: A75C3704 remote (PANASONIC_AC DKE/3)
|
||||
// Brand: Panasonic, Model: PN1122V remote (PANASONIC_AC DKE/3)
|
||||
// Brand: Panasonic, Model: A75C3747 remote (PANASONIC_AC JKE/4)
|
||||
// Brand: Panasonic, Model: CS-E9CKP series A/C (PANASONIC_AC32)
|
||||
// Brand: Panasonic, Model: A75C2295 remote (PANASONIC_AC32)
|
||||
|
||||
@ -80,7 +80,7 @@ void IRsend::sendPioneer(const uint64_t data, const uint16_t nbits,
|
||||
/// `irsend.sendPioneer(irsend.encodePioneer(0xAA1C, 0xAA1C), 64, 0);`
|
||||
/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1749#issuecomment-1028122645
|
||||
uint64_t IRsend::encodePioneer(const uint16_t address, const uint16_t command) {
|
||||
return (((uint64_t)encodeNEC(address >> 8, address & 0xFF)) << 32) |
|
||||
return static_cast<uint64_t>(encodeNEC(address >> 8, address & 0xFF)) << 32 |
|
||||
encodeNEC(command >> 8, command & 0xFF);
|
||||
}
|
||||
#endif // SEND_PIONEER
|
||||
|
||||
@ -62,7 +62,8 @@ void IRsend::sendPronto(uint16_t data[], uint16_t len, uint16_t repeat) {
|
||||
|
||||
// Pronto frequency is in Hz.
|
||||
uint16_t hz =
|
||||
(uint16_t)(1000000U / (data[kProntoFreqOffset] * kProntoFreqFactor));
|
||||
static_cast<uint16_t>(1000000U / (data[kProntoFreqOffset] *
|
||||
kProntoFreqFactor));
|
||||
enableIROut(hz);
|
||||
|
||||
// Grab the length of the two sequences.
|
||||
|
||||
@ -129,7 +129,7 @@ uint16_t IRsend::encodeRC5X(const uint8_t address, const uint8_t command,
|
||||
// The 2nd start/field bit (MSB of the return value) is the value of the 7th
|
||||
// command bit.
|
||||
bool s2 = (command >> 6) & 1;
|
||||
return ((uint16_t)s2 << (kRC5XBits - 1)) |
|
||||
return (static_cast<uint16_t>(s2) << (kRC5XBits - 1)) |
|
||||
encodeRC5(address, command, key_released);
|
||||
}
|
||||
|
||||
@ -174,7 +174,8 @@ uint64_t IRsend::encodeRC6(const uint32_t address, const uint8_t command,
|
||||
case kRC6Mode0Bits:
|
||||
return ((address & 0xFFF) << 8) | (command & 0xFF);
|
||||
case kRC6_36Bits:
|
||||
return ((uint64_t)(address & 0xFFFFFFF) << 8) | (command & 0xFF);
|
||||
return (static_cast<uint64_t>(address & 0xFFFFFFF) << 8) |
|
||||
(command & 0xFF);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
@ -360,7 +361,7 @@ bool IRrecv::decodeRC5(decode_results *results, uint16_t offset,
|
||||
results->repeat = false;
|
||||
if (is_rc5x) {
|
||||
results->decode_type = RC5X;
|
||||
results->command |= ((uint32_t)is_rc5x) << 6;
|
||||
results->command |= (static_cast<uint32_t>(is_rc5x)) << 6;
|
||||
} else {
|
||||
results->decode_type = RC5;
|
||||
actual_bits--; // RC5 doesn't count the field bit as data.
|
||||
|
||||
@ -35,7 +35,6 @@ const uint16_t kRcmmMinGapTicks = 120;
|
||||
const uint32_t kRcmmMinGap = 3360;
|
||||
// Use a tolerance of +/-10% when matching some data spaces.
|
||||
const uint8_t kRcmmTolerance = 10;
|
||||
const uint16_t kRcmmExcess = 50;
|
||||
|
||||
#if SEND_RCMM
|
||||
/// Send a Philips RC-MM packet.
|
||||
@ -102,13 +101,15 @@ bool IRrecv::decodeRCMM(decode_results *results, uint16_t offset,
|
||||
|
||||
// Calc the maximum size in bits, the message can be, or that we can accept.
|
||||
int16_t maxBitSize =
|
||||
std::min((uint16_t)results->rawlen - 5, (uint16_t)sizeof(data) * 8);
|
||||
std::min(static_cast<uint16_t>(results->rawlen) - 5,
|
||||
static_cast<uint16_t>(sizeof(data)) * 8);
|
||||
// Compliance
|
||||
if (strict) {
|
||||
// Technically the spec says bit sizes should be 12 xor 24. however
|
||||
// 32 bits has been seen from a device. We are going to assume
|
||||
// 12 <= bits <= 32 is the 'required' bit length for the spec.
|
||||
if (maxBitSize < 12 || maxBitSize > 32) return false;
|
||||
if (maxBitSize < 12 || maxBitSize > 32)
|
||||
return false;
|
||||
if (maxBitSize < nbits)
|
||||
return false; // Short cut, we can never reach the expected nr. of bits.
|
||||
}
|
||||
|
||||
@ -775,7 +775,7 @@ uint16_t IRSamsungAc::getSleepTimer(void) const {
|
||||
}
|
||||
|
||||
#define TIMER_RESOLUTION(mins) \
|
||||
(((std::min((mins), (uint16_t)(24 * 60))) / 10) * 10)
|
||||
(((std::min((mins), static_cast<uint16_t>(24 * 60))) / 10) * 10)
|
||||
|
||||
/// Set the On Timer value of the A/C.
|
||||
/// @param[in] nr_of_mins The number of minutes the timer should be.
|
||||
|
||||
@ -892,7 +892,8 @@ uint16_t IRSanyoAc88::getClock(void) const {
|
||||
/// Set the current clock time.
|
||||
/// @param[in] mins_since_midnight The time as nr. of minutes past midnight.
|
||||
void IRSanyoAc88::setClock(const uint16_t mins_since_midnight) {
|
||||
uint16_t mins = std::min(mins_since_midnight, (uint16_t)(23 * 60 + 59));
|
||||
uint16_t mins = std::min(mins_since_midnight,
|
||||
static_cast<uint16_t>(23 * 60 + 59));
|
||||
_.ClockMins = mins % 60;
|
||||
_.ClockHrs = mins / 60;
|
||||
_.ClockSecs = 0;
|
||||
|
||||
@ -35,9 +35,11 @@ const uint16_t kSharpGapTicks = 1677;
|
||||
const uint16_t kSharpGap = kSharpGapTicks * kSharpTick;
|
||||
// Address(5) + Command(8) + Expansion(1) + Check(1)
|
||||
const uint64_t kSharpToggleMask =
|
||||
((uint64_t)1 << (kSharpBits - kSharpAddressBits)) - 1;
|
||||
const uint64_t kSharpAddressMask = ((uint64_t)1 << kSharpAddressBits) - 1;
|
||||
const uint64_t kSharpCommandMask = ((uint64_t)1 << kSharpCommandBits) - 1;
|
||||
(static_cast<uint64_t>(1) << (kSharpBits - kSharpAddressBits)) - 1;
|
||||
const uint64_t kSharpAddressMask = (static_cast<uint64_t>(1) <<
|
||||
kSharpAddressBits) - 1;
|
||||
const uint64_t kSharpCommandMask = (static_cast<uint64_t>(1) <<
|
||||
kSharpCommandBits) - 1;
|
||||
|
||||
using irutils::addBoolToString;
|
||||
using irutils::addFanToString;
|
||||
|
||||
@ -19,6 +19,7 @@
|
||||
/// @note Sherwood remote codes appear to be NEC codes with a mandatory repeat
|
||||
/// code. i.e. repeat should be >= kSherwoodMinRepeat (1).
|
||||
void IRsend::sendSherwood(uint64_t data, uint16_t nbits, uint16_t repeat) {
|
||||
sendNEC(data, nbits, std::max((uint16_t)kSherwoodMinRepeat, repeat));
|
||||
sendNEC(data, nbits,
|
||||
std::max(static_cast<uint16_t>(kSherwoodMinRepeat), repeat));
|
||||
}
|
||||
#endif // SEND_SHERWOOD
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
// Brand: Daewoo, Model: DSB-F0934ELH-V A/C
|
||||
// Brand: Daewoo, Model: GYKQ-52E remote
|
||||
// Brand: TCL, Model: GYKQ-58(XM) remote (TCL96AC)
|
||||
// Brand: Electrolux, Model: EACM CL/N3 series remote
|
||||
|
||||
#ifndef IR_TCL_H_
|
||||
#define IR_TCL_H_
|
||||
|
||||
@ -231,7 +231,8 @@ uint16_t IRTecoAc::getTimer(void) const {
|
||||
/// `0` will clear the timer. Max is 24 hrs.
|
||||
/// @note Time is stored internally in increments of 30 mins.
|
||||
void IRTecoAc::setTimer(const uint16_t nr_mins) {
|
||||
uint16_t mins = std::min(nr_mins, (uint16_t)(24 * 60)); // Limit to 24 hrs.
|
||||
// Limit to 24 hrs
|
||||
uint16_t mins = std::min(nr_mins, static_cast<uint16_t>(24 * 60));
|
||||
uint8_t hours = mins / 60;
|
||||
_.TimerOn = mins > 0; // Set the timer flag.
|
||||
_.HalfHour = (mins % 60) >= 30;
|
||||
|
||||
@ -40,6 +40,7 @@ using irutils::addModeToString;
|
||||
using irutils::addTempToString;
|
||||
using irutils::checkInvertedBytePairs;
|
||||
using irutils::invertBytePairs;
|
||||
using irutils::addModelToString;
|
||||
|
||||
#if SEND_TOSHIBA_AC
|
||||
/// Send a Toshiba A/C message.
|
||||
@ -104,8 +105,9 @@ void IRToshibaAC::send(const uint16_t repeat) {
|
||||
uint16_t IRToshibaAC::getInternalStateLength(const uint8_t state[],
|
||||
const uint16_t size) {
|
||||
if (size < kToshibaAcLengthByte) return 0;
|
||||
return std::min((uint16_t)(state[kToshibaAcLengthByte] + kToshibaAcMinLength),
|
||||
kToshibaACStateLengthLong);
|
||||
// Fix: Extract the last 4 bits instead
|
||||
return std::min(static_cast<uint16_t>((state[kToshibaAcLengthByte] & 0xF)
|
||||
+ kToshibaAcMinLength), kToshibaACStateLengthLong);
|
||||
}
|
||||
|
||||
/// Get the length of the current internal state per the protocol structure.
|
||||
@ -462,7 +464,8 @@ stdAc::state_t IRToshibaAC::toCommon(const stdAc::state_t *prev) const {
|
||||
String IRToshibaAC::toString(void) const {
|
||||
String result = "";
|
||||
result.reserve(95);
|
||||
result += addTempToString(getTemp(), true, false);
|
||||
result += addModelToString(decode_type_t::TOSHIBA_AC, getModel(), false);
|
||||
result += addTempToString(getTemp(), true);
|
||||
switch (getStateLength()) {
|
||||
case kToshibaACStateLengthShort:
|
||||
result += addIntToString(getSwing(true), kSwingVStr);
|
||||
@ -493,6 +496,30 @@ String IRToshibaAC::toString(void) const {
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Get the model information currently known.
|
||||
/// @return The known model number.
|
||||
toshiba_ac_remote_model_t IRToshibaAC::getModel(void) const {
|
||||
switch (_.Model) {
|
||||
case kToshibaAcRemoteB:
|
||||
return toshiba_ac_remote_model_t::kToshibaGenericRemote_B;
|
||||
default:
|
||||
return toshiba_ac_remote_model_t::kToshibaGenericRemote_A;
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the current model for the remote.
|
||||
/// @param[in] model The model number.
|
||||
void IRToshibaAC::setModel(const toshiba_ac_remote_model_t model) {
|
||||
switch (model) {
|
||||
case toshiba_ac_remote_model_t::kToshibaGenericRemote_B:
|
||||
_.Model = kToshibaAcRemoteB;
|
||||
break;
|
||||
default:
|
||||
_.Model = kToshibaAcRemoteA;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#if DECODE_TOSHIBA_AC
|
||||
/// Decode the supplied Toshiba A/C message.
|
||||
/// Status: STABLE / Working.
|
||||
|
||||
@ -53,7 +53,11 @@ union ToshibaProtocol{
|
||||
///< 1 (56 bit message)
|
||||
///< 3 (72 bit message)
|
||||
///< 4 (80 bit message)
|
||||
uint8_t Length :8;
|
||||
uint8_t Length :4;
|
||||
// Toshiba remote type
|
||||
// 0 - Remote control A
|
||||
// 1 - Remote control B
|
||||
uint8_t Model :4;
|
||||
// Byte[3] - The bit-inverted value of the "length" byte.
|
||||
uint8_t :8;
|
||||
// Byte[4]
|
||||
@ -111,6 +115,9 @@ const uint8_t kToshibaAcFanMax = 5; // 0b101
|
||||
const uint8_t kToshibaAcTurboOn = 1; // 0b01
|
||||
const uint8_t kToshibaAcEconoOn = 3; // 0b11
|
||||
|
||||
const uint8_t kToshibaAcRemoteA = 0; // 0b0000
|
||||
const uint8_t kToshibaAcRemoteB = 1; // 0b0001
|
||||
|
||||
// Legacy defines. (Deprecated)
|
||||
#define TOSHIBA_AC_AUTO kToshibaAcAuto
|
||||
#define TOSHIBA_AC_COOL kToshibaAcCool
|
||||
@ -140,6 +147,8 @@ class IRToshibaAC {
|
||||
void begin(void);
|
||||
void on(void);
|
||||
void off(void);
|
||||
void setModel(const toshiba_ac_remote_model_t model);
|
||||
toshiba_ac_remote_model_t getModel() const;
|
||||
void setPower(const bool on);
|
||||
bool getPower(void) const;
|
||||
void setTemp(const uint8_t degrees);
|
||||
|
||||
@ -422,7 +422,7 @@ uint16_t IRVoltas::getOnTime(void) const {
|
||||
/// 0 disables the timer. Max is 23 hrs & 59 mins (1439 mins)
|
||||
void IRVoltas::setOnTime(const uint16_t nr_of_mins) {
|
||||
// Cap the total number of mins.
|
||||
uint16_t mins = std::min(nr_of_mins, (uint16_t)(23 * 60 + 59));
|
||||
uint16_t mins = std::min(nr_of_mins, static_cast<uint16_t>(23 * 60 + 59));
|
||||
uint16_t hrs = (mins / 60) + 1;
|
||||
_.OnTimerMins = mins % 60;
|
||||
_.OnTimer12Hr = hrs / 12;
|
||||
@ -442,7 +442,7 @@ uint16_t IRVoltas::getOffTime(void) const {
|
||||
/// 0 disables the timer. Max is 23 hrs & 59 mins (1439 mins)
|
||||
void IRVoltas::setOffTime(const uint16_t nr_of_mins) {
|
||||
// Cap the total number of mins.
|
||||
uint16_t mins = std::min(nr_of_mins, (uint16_t)(23 * 60 + 59));
|
||||
uint16_t mins = std::min(nr_of_mins, static_cast<uint16_t>(23 * 60 + 59));
|
||||
uint16_t hrs = (mins / 60) + 1;
|
||||
_.OffTimerMins = mins % 60;
|
||||
_.OffTimer12Hr = hrs / 12;
|
||||
|
||||
@ -126,7 +126,8 @@ void IRsend::sendXmp(const uint64_t data, const uint16_t nbits,
|
||||
uint64_t send_data = data;
|
||||
for (uint16_t r = 0; r <= repeat; r++) {
|
||||
uint16_t bits_so_far = kXmpWordSize;
|
||||
for (uint64_t mask = ((uint64_t)kXmpMaxWordValue) << (nbits - kXmpWordSize);
|
||||
for (uint64_t mask = static_cast<uint64_t>(kXmpMaxWordValue) <<
|
||||
(nbits - kXmpWordSize);
|
||||
mask;
|
||||
mask >>= kXmpWordSize) {
|
||||
uint8_t word = (send_data & mask) >> (nbits - bits_so_far);
|
||||
|
||||
@ -751,6 +751,9 @@ D_STR_INDIRECT " " D_STR_MODE
|
||||
#ifndef D_STR_ARRIS
|
||||
#define D_STR_ARRIS "ARRIS"
|
||||
#endif // D_STR_ARRIS
|
||||
#ifndef D_STR_BLUESTARHEACY
|
||||
#define D_STR_BLUESTARHEAVY "BLUESTARHEAVY"
|
||||
#endif // D_STR_TESTEXAMPLE
|
||||
#ifndef D_STR_BOSCH
|
||||
#define D_STR_BOSCH "BOSCH"
|
||||
#endif // D_STR_BOSCH
|
||||
@ -841,6 +844,9 @@ D_STR_INDIRECT " " D_STR_MODE
|
||||
#ifndef D_STR_EPSON
|
||||
#define D_STR_EPSON "EPSON"
|
||||
#endif // D_STR_EPSON
|
||||
#ifndef D_STR_EUROM
|
||||
#define D_STR_EUROM "EUROM"
|
||||
#endif // D_STR_EUROM
|
||||
#ifndef D_STR_FUJITSU_AC
|
||||
#define D_STR_FUJITSU_AC "FUJITSU_AC"
|
||||
#endif // D_STR_FUJITSU_AC
|
||||
@ -1120,6 +1126,12 @@ D_STR_INDIRECT " " D_STR_MODE
|
||||
#ifndef D_STR_ZEPEAL
|
||||
#define D_STR_ZEPEAL "ZEPEAL"
|
||||
#endif // D_STR_ZEPEAL
|
||||
#ifndef D_STR_TOSHIBAGENERICREMOTEA
|
||||
#define D_STR_TOSHIBAGENERICREMOTEA "TOSHIBA REMOTE A"
|
||||
#endif // D_STR_TOSHIBAGENERICREMOTEA
|
||||
#ifndef D_STR_TOSHIBAGENERICREMOTEB
|
||||
#define D_STR_TOSHIBAGENERICREMOTEB "TOSHIBA REMOTE B"
|
||||
#endif // D_STR_TOSHIBAGENERICREMOTEB
|
||||
|
||||
// IRrecvDumpV2+
|
||||
#ifndef D_STR_TIMESTAMP
|
||||
|
||||
@ -143,7 +143,7 @@
|
||||
#define D_STR_MESGDESC "Описание Сообщения."
|
||||
#define D_STR_TOLERANCE "Допуск"
|
||||
#define D_STR_IRRECVDUMP_STARTUP \
|
||||
"IRrecvDump запущен и ождает ИК команды на Входе %d"
|
||||
"IRrecvDump запущен и ожидает ИК команды на Входе %d"
|
||||
#define D_WARN_BUFFERFULL \
|
||||
"ПРЕДУПРЕЖДЕНИЕ: ИК код слишком велик для буфера (>= %d). " \
|
||||
"Этому результату не следует доверять, пока это не будет исправлено. " \
|
||||
|
||||
190
lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/locale/sk-SK.h
Normal file
190
lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/locale/sk-SK.h
Normal file
@ -0,0 +1,190 @@
|
||||
// Copyright 2024 - @misa1515
|
||||
// Locale/language file for Slovakia.
|
||||
// This file will override the default values located in `defaults.h`.
|
||||
#ifndef LOCALE_SK_SK_H_
|
||||
#define LOCALE_SK_SK_H_
|
||||
|
||||
#define D_STR_UNKNOWN "NEZNÁME"
|
||||
#define D_STR_PROTOCOL "Protokol"
|
||||
#define D_STR_POWER "Výkon"
|
||||
#define D_STR_PREVIOUS "Predchádzajúce"
|
||||
#define D_STR_ON "Zap"
|
||||
#define D_STR_OFF "Vyp"
|
||||
#define D_STR_MODE "Režim"
|
||||
#define D_STR_TOGGLE "Prepnúť"
|
||||
#define D_STR_SLEEP "Spať"
|
||||
#define D_STR_LIGHT "Svetlo"
|
||||
#define D_STR_POWERFUL "Výkonný"
|
||||
#define D_STR_QUIET "Tichý"
|
||||
#define D_STR_ECONO "Econo"
|
||||
#define D_STR_SWING "Kývanie"
|
||||
#define D_STR_SWINGH D_STR_SWING"(H)" // Set `D_STR_SWING` prvé!
|
||||
#define D_STR_SWINGV D_STR_SWING"(V)" // Set `D_STR_SWING` prvé!
|
||||
#define D_STR_BEEP "Pípnutie"
|
||||
#define D_STR_MOULD "Pleseň"
|
||||
#define D_STR_CLEAN "Čistiť"
|
||||
#define D_STR_PURIFY "Čistota"
|
||||
#define D_STR_TIMER "Časovač"
|
||||
#define D_STR_ONTIMER D_STR_ON " " D_STR_TIMER // Set `D_STR_ON` prvé!
|
||||
#define D_STR_OFFTIMER D_STR_OFF " " D_STR_TIMER // Set `D_STR_OFF` prvé!
|
||||
#define D_STR_TIMERMODE D_STR_TIMER " " D_STR_MODE // Set `D_STR_MODE` prvé!
|
||||
#define D_STR_CLOCK "Hodiny"
|
||||
#define D_STR_COMMAND "Príkaz"
|
||||
#define D_STR_XFAN "XVentilátor"
|
||||
#define D_STR_HEALTH "Zdravie"
|
||||
#define D_STR_TEMP "Teplota"
|
||||
#define D_STR_IFEEL "IPocitovo"
|
||||
#define D_STR_ISEE "IVidieť"
|
||||
#define D_STR_HUMID "Vlhkosť"
|
||||
#define D_STR_SAVE "Uložiť"
|
||||
#define D_STR_EYE "Oči"
|
||||
#define D_STR_FOLLOW "Nasledovať"
|
||||
#define D_STR_FRESH "Čerstvé"
|
||||
#define D_STR_HOLD "Podržať"
|
||||
#define D_STR_8C_HEAT "8C " D_STR_HEAT // Set `D_STR_HEAT` prvé!
|
||||
#define D_STR_10C_HEAT "10C " D_STR_HEAT // Set `D_STR_HEAT` prvé!
|
||||
#define D_STR_BUTTON "Tlačidlo"
|
||||
#define D_STR_NIGHT "Noc"
|
||||
#define D_STR_SILENT "Tiché"
|
||||
#define D_STR_CELSIUS "Celzia"
|
||||
#define D_STR_FAHRENHEIT "Fahrenheit"
|
||||
#define D_STR_CELSIUS_FAHRENHEIT D_STR_CELSIUS "/" D_STR_FAHRENHEIT
|
||||
#define D_STR_UP "Hore"
|
||||
#define D_STR_TEMPUP D_STR_TEMP " " D_STR_UP // Set `D_STR_TEMP` prvé!
|
||||
#define D_STR_DOWN "Dole"
|
||||
#define D_STR_TEMPDOWN D_STR_TEMP " " D_STR_DOWN // Set `D_STR_TEMP` prvé!
|
||||
#define D_STR_CHANGE "Zmeniť"
|
||||
#define D_STR_START "Štart"
|
||||
#define D_STR_MOVE "Posun"
|
||||
#define D_STR_SET "Nastaviť"
|
||||
#define D_STR_CANCEL "Zrušiť"
|
||||
#define D_STR_COMFORT "Komfort"
|
||||
#define D_STR_SENSOR "Snímač"
|
||||
#define D_STR_ABSENSEDETECT "Detekcia neprítomnosti"
|
||||
#define D_STR_DIRECT "Priamo"
|
||||
#define D_STR_INDIRECT "Nepriamo"
|
||||
#define D_STR_DIRECTINDIRECTMODE D_STR_DIRECT " / " \
|
||||
D_STR_INDIRECT " " D_STR_MODE
|
||||
#define D_STR_DISPLAY "Displej"
|
||||
#define D_STR_WEEKLY "Týždenne"
|
||||
#define D_STR_WEEKLYTIMER D_STR_WEEKLY " " D_STR_TIMER // Needs `D_STR_WEEKLY`!
|
||||
#define D_STR_LAST "Posledné"
|
||||
#define D_STR_FAST "Rýchlo"
|
||||
#define D_STR_SLOW "Pomaly"
|
||||
#define D_STR_AIRFLOW "Prúd vzduchu"
|
||||
#define D_STR_STEP "Krok"
|
||||
#define D_STR_INSIDE "Vnútri"
|
||||
#define D_STR_OUTSIDE "Vonku"
|
||||
#define D_STR_LOUD "Hlasno"
|
||||
#define D_STR_UPPER "Horná"
|
||||
#define D_STR_LOWER "Dolná"
|
||||
#define D_STR_BREEZE "Vánok"
|
||||
#define D_STR_CIRCULATE "Cirkulácia"
|
||||
#define D_STR_CEILING "Strop"
|
||||
#define D_STR_WALL "Stena"
|
||||
#define D_STR_ROOM "Izba"
|
||||
#define D_STR_6THSENSE "6ty zmysel"
|
||||
#define D_STR_ZONEFOLLOW "Sledovanie zóny"
|
||||
#define D_STR_FIXED "Fixované"
|
||||
#define D_STR_TYPE "Typ"
|
||||
#define D_STR_SPECIAL "Špeciálne"
|
||||
#define D_STR_RECYCLE "Recyklovať"
|
||||
#define D_STR_LOCK "Zamknuté"
|
||||
#define D_STR_AUTOMATIC "Automatické"
|
||||
#define D_STR_MANUAL "Manuálne"
|
||||
#define D_STR_COOL "Chladiť"
|
||||
#define D_STR_COOLING "Chladenie"
|
||||
#define D_STR_HEAT "Ohrev"
|
||||
#define D_STR_HEATING "Kúrenie"
|
||||
#define D_STR_FAN "Ventilátor"
|
||||
#define D_STR_FANONLY "len ventilátor"
|
||||
#define D_STR_FAN_ONLY "len_ventilátor"
|
||||
#define D_STR_ONLY "Len"
|
||||
#define D_STR_FANSPACEONLY D_STR_FAN " " D_STR_ONLY
|
||||
#define D_STR_FANONLYNOSPACE D_STR_FAN D_STR_ONLY
|
||||
#define D_STR_DRY "Sušiť"
|
||||
#define D_STR_DRYING "Sušenie"
|
||||
#define D_STR_DEHUMIDIFY "Odvlhčiť"
|
||||
#define D_STR_MAX "Max"
|
||||
#define D_STR_MIN "Min"
|
||||
#define D_STR_MED "Str"
|
||||
#define D_STR_MEDIUM "Stredné"
|
||||
#define D_STR_MED_HIGH D_STR_MED "-" D_STR_HIGH
|
||||
#define D_STR_HIGHEST "Najvyššie"
|
||||
#define D_STR_HIGH "Vysoké"
|
||||
#define D_STR_HI "Vys"
|
||||
#define D_STR_MID "Str"
|
||||
#define D_STR_MIDDLE "Stredné"
|
||||
#define D_STR_LOW "Nózke"
|
||||
#define D_STR_LO "Níz"
|
||||
#define D_STR_LOWEST "Najnižšie"
|
||||
#define D_STR_RIGHT "Pravé"
|
||||
#define D_STR_MAXRIGHT D_STR_MAX " " D_STR_RIGHT // Set `D_STR_MAX` prvé!
|
||||
#define D_STR_MAXRIGHT_NOSPACE D_STR_MAX D_STR_RIGHT // Set `D_STR_MAX` prvé!
|
||||
#define D_STR_RIGHTMAX D_STR_RIGHT " " D_STR_MAX // Set `D_STR_MAX` prvé!
|
||||
#define D_STR_RIGHTMAX_NOSPACE D_STR_RIGHT D_STR_MAX // Set `D_STR_MAX` prvé!
|
||||
#define D_STR_LEFT "Vľavo"
|
||||
#define D_STR_MAXLEFT D_STR_MAX " " D_STR_LEFT // Set `D_STR_MAX` prvé!
|
||||
#define D_STR_MAXLEFT_NOSPACE D_STR_MAX D_STR_LEFT // Set `D_STR_MAX` prvé!
|
||||
#define D_STR_LEFTMAX D_STR_LEFT " " D_STR_MAX // Set `D_STR_MAX` prvé!
|
||||
#define D_STR_LEFTMAX_NOSPACE D_STR_LEFT D_STR_MAX // Set `D_STR_MAX` prvé!
|
||||
#define D_STR_WIDE "Široké"
|
||||
#define D_STR_CENTRE "Stredné"
|
||||
#define D_STR_TOP "Horné"
|
||||
#define D_STR_BOTTOM "Dolné"
|
||||
#define D_STR_UPPER_MIDDLE D_STR_UPPER "-" D_STR_MIDDLE
|
||||
#define D_STR_CONFIG "Konfigurácia"
|
||||
#define D_STR_CONTROL "Riadenie"
|
||||
#define D_STR_SET_TIMER D_STR_SET " " D_STR_TIMER
|
||||
#define D_STR_SCHEDULE "Rozvrh"
|
||||
#define D_STR_CH "CH#"
|
||||
#define D_STR_TIMER_ACTIVE_DAYS "TimerActiveDays"
|
||||
#define D_STR_KEY "Kľúč"
|
||||
#define D_STR_VALUE "Hodnota"
|
||||
|
||||
// Compound words/phrases/descriptions from pre-defined words.
|
||||
// Note: Obviously these need to be defined *after* their component words.
|
||||
#define D_STR_ECONOTOGGLE D_STR_ECONO " " D_STR_TOGGLE
|
||||
#define D_STR_EYEAUTO D_STR_EYE " " D_STR_AUTO
|
||||
#define D_STR_LIGHTTOGGLE D_STR_LIGHT " " D_STR_TOGGLE
|
||||
#define D_STR_OUTSIDEQUIET D_STR_OUTSIDE " " D_STR_QUIET
|
||||
#define D_STR_POWERTOGGLE D_STR_POWER " " D_STR_TOGGLE
|
||||
#define D_STR_POWERBUTTON D_STR_POWER " " D_STR_BUTTON
|
||||
#define D_STR_PREVIOUSPOWER D_STR_PREVIOUS " " D_STR_POWER
|
||||
#define D_STR_DISPLAYTEMP D_STR_DISPLAY " " D_STR_TEMP
|
||||
#define D_STR_IFEELREPORT D_STR_IFEEL " " D_STR_REPORT
|
||||
#define D_STR_SENSORTEMP D_STR_SENSOR " " D_STR_TEMP
|
||||
#define D_STR_SLEEP_TIMER D_STR_SLEEP " " D_STR_TIMER
|
||||
#define D_STR_SWINGVMODE D_STR_SWINGV " " D_STR_MODE
|
||||
#define D_STR_SWINGVTOGGLE D_STR_SWINGV " " D_STR_TOGGLE
|
||||
#define D_STR_TURBOTOGGLE D_STR_TURBO " " D_STR_TOGGLE
|
||||
|
||||
// Separators
|
||||
#define D_STR_DAY "Deň"
|
||||
#define D_STR_DAYS D_STR_DAY "s"
|
||||
#define D_STR_HOUR "Hodina"
|
||||
#define D_STR_HOURS D_STR_HOUR "s"
|
||||
#define D_STR_MINUTE "Minúta"
|
||||
#define D_STR_MINUTES D_STR_MINUTE "s"
|
||||
#define D_STR_SECOND "Sekunda"
|
||||
#define D_STR_SECONDS D_STR_SECOND "s"
|
||||
#define D_STR_NOW "Teraz"
|
||||
#define D_STR_YES "Áno"
|
||||
#define D_STR_NO "Nie"
|
||||
#define D_STR_REPEAT "Opakovať"
|
||||
#define D_STR_CODE "Kód"
|
||||
#define D_STR_BITS "Bity"
|
||||
|
||||
// IRrecvDumpV2+
|
||||
#define D_STR_TIMESTAMP "Časová pečiatka"
|
||||
#define D_STR_LIBRARY "Knižnica"
|
||||
#define D_STR_MESGDESC "Mesg Desc."
|
||||
#define D_STR_TOLERANCE "Tolerancia"
|
||||
#define D_STR_IRRECVDUMP_STARTUP \
|
||||
"IRrecvDump teraz beží a čaká na IR vstup na pine %d"
|
||||
#define D_WARN_BUFFERFULL \
|
||||
"UPOZORNENIE: IR kód je príliš veľký pre vyrovnávaciu pamäť (>= %d). " \
|
||||
"Tomuto výsledku by sa nemalo dôverovať, kým sa to nevyrieši. " \
|
||||
"Upraviť a zväčšiť `kCaptureBufferSize`."
|
||||
|
||||
#endif // LOCALE_SK_SK_H_
|
||||
@ -247,6 +247,36 @@ TEST(TestIRac, Coolix) {
|
||||
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
|
||||
}
|
||||
|
||||
TEST(TestIRac, Coolix_Issue2103) {
|
||||
IRCoolixAC ac(kGpioUnused);
|
||||
IRac irac(kGpioUnused);
|
||||
IRrecv capture(kGpioUnused);
|
||||
char expected[] =
|
||||
"Power: On, Mode: 4 (Fan), Fan: 5 (Auto), Zone Follow: Off, "
|
||||
"Sensor Temp: Off";
|
||||
|
||||
ac.begin();
|
||||
irac.coolix(&ac,
|
||||
true, // Power
|
||||
stdAc::opmode_t::kFan, // Mode
|
||||
21, // Celsius
|
||||
kNoTempValue, // Sensor Temp
|
||||
stdAc::fanspeed_t::kAuto, // Fan speed
|
||||
stdAc::swingv_t::kOff, // Vertical swing
|
||||
stdAc::swingh_t::kOff, // Horizontal swing
|
||||
false, // iFeel
|
||||
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);
|
||||
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
|
||||
}
|
||||
|
||||
TEST(TestIRac, Corona) {
|
||||
IRCoronaAc ac(kGpioUnused);
|
||||
IRac irac(kGpioUnused);
|
||||
@ -613,7 +643,7 @@ TEST(TestIRac, Electra) {
|
||||
char expected[] =
|
||||
"Power: On, Mode: 6 (Fan), Temp: 26C, Fan: 1 (High), "
|
||||
"Swing(V): On, Swing(H): On, Light: Toggle, Clean: On, Turbo: On, "
|
||||
"IFeel: Off";
|
||||
"Quiet: On, IFeel: Off";
|
||||
|
||||
ac.begin();
|
||||
irac.electra(&ac,
|
||||
@ -625,6 +655,7 @@ TEST(TestIRac, Electra) {
|
||||
stdAc::swingv_t::kAuto, // Vertical swing
|
||||
stdAc::swingh_t::kLeft, // Horizontal swing
|
||||
false, // iFeel
|
||||
true, // Quiet
|
||||
true, // Turbo
|
||||
true, // Light (toggle)
|
||||
true); // Clean
|
||||
@ -2157,8 +2188,8 @@ TEST(TestIRac, Toshiba) {
|
||||
IRac irac(kGpioUnused);
|
||||
IRrecv capture(kGpioUnused);
|
||||
char expected[] =
|
||||
"Temp: 29C, Power: On, Mode: 2 (Dry), Fan: 2 (UNKNOWN), "
|
||||
"Turbo: Off, Econo: On, Filter: Off";
|
||||
"Model: 0 (TOSHIBA REMOTE A), Temp: 29C, Power: On, Mode: 2 (Dry), "
|
||||
"Fan: 2 (UNKNOWN), Turbo: Off, Econo: On, Filter: Off";
|
||||
|
||||
ac.begin();
|
||||
irac.toshiba(&ac,
|
||||
@ -3144,8 +3175,8 @@ TEST(TestIRac, Issue1250) {
|
||||
|
||||
// Now send the state so we can actually decode/capture what we sent.
|
||||
char expected_on[] =
|
||||
"Temp: 19C, Power: On, Mode: 4 (Fan), Fan: 0 (Auto), "
|
||||
"Turbo: Off, Econo: Off, Filter: Off";
|
||||
"Model: 0 (TOSHIBA REMOTE A), Temp: 19C, Power: On, Mode: 4 (Fan), "
|
||||
"Fan: 0 (Auto), Turbo: Off, Econo: Off, Filter: Off";
|
||||
ac._irsend.reset();
|
||||
irac.toshiba(&ac,
|
||||
irac.next.power, // Power
|
||||
@ -3171,8 +3202,8 @@ TEST(TestIRac, Issue1250) {
|
||||
irac.sendAc();
|
||||
// Now send the state so we can actually decode/capture what we sent.
|
||||
char expected_off[] =
|
||||
"Temp: 19C, Power: Off, Fan: 0 (Auto), Turbo: Off, Econo: Off, "
|
||||
"Filter: Off";
|
||||
"Model: 0 (TOSHIBA REMOTE A), Temp: 19C, Power: Off, Fan: 0 (Auto), "
|
||||
"Turbo: Off, Econo: Off, Filter: Off";
|
||||
ac._irsend.reset();
|
||||
irac.toshiba(&ac,
|
||||
irac.next.power, // Power
|
||||
|
||||
@ -674,16 +674,16 @@ TEST(TestSend, GenericSimpleSendMethodFailure) {
|
||||
for (int i = 0; i <= kLastDecodeType; i++) {
|
||||
if (hasACState((decode_type_t)i) && i != GREE) { // Gree is an exception.
|
||||
// Check it fails.
|
||||
ASSERT_FALSE(irsend.send((decode_type_t)i, (uint64_t)0, 0));
|
||||
ASSERT_FALSE(irsend.send((decode_type_t)i, static_cast<uint64_t>(0), 0));
|
||||
}
|
||||
}
|
||||
|
||||
// Test some other special cases.
|
||||
ASSERT_FALSE(irsend.send(UNKNOWN, (uint64_t)0, 0));
|
||||
ASSERT_FALSE(irsend.send(UNUSED, (uint64_t)0, 0));
|
||||
ASSERT_FALSE(irsend.send(RAW, (uint64_t)0, 0));
|
||||
ASSERT_FALSE(irsend.send(PRONTO, (uint64_t)0, 0));
|
||||
ASSERT_FALSE(irsend.send(GLOBALCACHE, (uint64_t)0, 0));
|
||||
ASSERT_FALSE(irsend.send(UNKNOWN, static_cast<uint64_t>(0), 0));
|
||||
ASSERT_FALSE(irsend.send(UNUSED, static_cast<uint64_t>(0), 0));
|
||||
ASSERT_FALSE(irsend.send(RAW, static_cast<uint64_t>(0), 0));
|
||||
ASSERT_FALSE(irsend.send(PRONTO, static_cast<uint64_t>(0), 0));
|
||||
ASSERT_FALSE(irsend.send(GLOBALCACHE, static_cast<uint64_t>(0), 0));
|
||||
}
|
||||
|
||||
// Test expected to work/produce a message for complex irsend:send()
|
||||
|
||||
@ -72,7 +72,7 @@ class IRsendTest : public IRsend {
|
||||
capture.decode_type = UNKNOWN;
|
||||
capture.bits = 0;
|
||||
capture.rawlen = last + 2 - offset;
|
||||
capture.overflow = (last - offset >= (int16_t)RAW_BUF);
|
||||
capture.overflow = (last - offset >= static_cast<uint16_t>(RAW_BUF));
|
||||
capture.repeat = false;
|
||||
capture.address = 0;
|
||||
capture.command = 0;
|
||||
|
||||
@ -582,12 +582,12 @@ TEST(TestUtils, getBit) {
|
||||
EXPECT_FALSE(GETBIT8((uint8_t)0b01111111, 7));
|
||||
EXPECT_TRUE(GETBIT8((uint8_t)0b10000000, 7));
|
||||
// uint64_t method.
|
||||
EXPECT_FALSE(irutils::getBit((uint64_t)0, 0));
|
||||
EXPECT_TRUE(irutils::getBit((uint64_t)1, 0));
|
||||
EXPECT_FALSE(irutils::getBit((uint64_t)0b01, 1));
|
||||
EXPECT_TRUE(irutils::getBit((uint64_t)0b10, 1));
|
||||
EXPECT_FALSE(irutils::getBit((uint64_t)0b01111111, 7));
|
||||
EXPECT_TRUE(irutils::getBit((uint64_t)0b10000000, 7));
|
||||
EXPECT_FALSE(irutils::getBit(static_cast<uint64_t>(0), 0));
|
||||
EXPECT_TRUE(irutils::getBit(static_cast<uint64_t>(1), 0));
|
||||
EXPECT_FALSE(irutils::getBit(static_cast<uint64_t>(0b01), 1));
|
||||
EXPECT_TRUE(irutils::getBit(static_cast<uint64_t>(0b10), 1));
|
||||
EXPECT_FALSE(irutils::getBit(static_cast<uint64_t>(0b01111111), 7));
|
||||
EXPECT_TRUE(irutils::getBit(static_cast<uint64_t>(0b10000000), 7));
|
||||
}
|
||||
|
||||
TEST(TestUtils, setBit) {
|
||||
@ -603,16 +603,17 @@ TEST(TestUtils, setBit) {
|
||||
EXPECT_EQ(0b11111111, irutils::setBit((uint8_t)0b01111111, 7, true));
|
||||
EXPECT_EQ(0, irutils::setBit((uint8_t)0b10000000, 7, false));
|
||||
// uint64_t method.
|
||||
EXPECT_EQ(0, irutils::setBit((uint64_t)0, 0, false));
|
||||
EXPECT_EQ(0, irutils::setBit((uint64_t)1, 0, false));
|
||||
EXPECT_EQ(1, irutils::setBit((uint64_t)0, 0, true));
|
||||
EXPECT_EQ(1, irutils::setBit((uint64_t)1, 0, true));
|
||||
EXPECT_EQ(0b101, irutils::setBit((uint64_t)0b101, 1, false));
|
||||
EXPECT_EQ(0b100, irutils::setBit((uint64_t)0b110, 1, false));
|
||||
EXPECT_EQ(0b111, irutils::setBit((uint64_t)0b101, 1, true));
|
||||
EXPECT_EQ(0b110, irutils::setBit((uint64_t)0b110, 1, true));
|
||||
EXPECT_EQ(0b11111111, irutils::setBit((uint64_t)0b01111111, 7, true));
|
||||
EXPECT_EQ(0, irutils::setBit((uint64_t)0b10000000, 7, false));
|
||||
EXPECT_EQ(0, irutils::setBit(static_cast<uint64_t>(0), 0, false));
|
||||
EXPECT_EQ(0, irutils::setBit(static_cast<uint64_t>(1), 0, false));
|
||||
EXPECT_EQ(1, irutils::setBit(static_cast<uint64_t>(0), 0, true));
|
||||
EXPECT_EQ(1, irutils::setBit(static_cast<uint64_t>(1), 0, true));
|
||||
EXPECT_EQ(0b101, irutils::setBit(static_cast<uint64_t>(0b101), 1, false));
|
||||
EXPECT_EQ(0b100, irutils::setBit(static_cast<uint64_t>(0b110), 1, false));
|
||||
EXPECT_EQ(0b111, irutils::setBit(static_cast<uint64_t>(0b101), 1, true));
|
||||
EXPECT_EQ(0b110, irutils::setBit(static_cast<uint64_t>(0b110), 1, true));
|
||||
EXPECT_EQ(0b11111111,
|
||||
irutils::setBit(static_cast<uint64_t>(0b01111111), 7, true));
|
||||
EXPECT_EQ(0, irutils::setBit(static_cast<uint64_t>(0b10000000), 7, false));
|
||||
// uint8_t Pointer method.
|
||||
uint8_t data = 0;
|
||||
irutils::setBit(&data, 0, false);
|
||||
|
||||
@ -2,7 +2,13 @@
|
||||
// Copyright 2022 Mateusz Bronk (mbronk)
|
||||
#include <gtest/gtest.h>
|
||||
#include <gmock/gmock.h>
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include "ir_Argo.h"
|
||||
#include "IRac.h"
|
||||
#include "IRrecv.h"
|
||||
|
||||
@ -393,6 +393,7 @@ TEST(TestCoolixACClass, SetAndGetRaw) {
|
||||
TEST(TestCoolixACClass, SetAndGetTemp) {
|
||||
IRCoolixAC ac(kGpioUnused);
|
||||
|
||||
// Celcius
|
||||
ac.setTemp(25);
|
||||
EXPECT_EQ(25, ac.getTemp());
|
||||
ac.setTemp(kCoolixTempMin);
|
||||
@ -403,6 +404,26 @@ TEST(TestCoolixACClass, SetAndGetTemp) {
|
||||
EXPECT_EQ(kCoolixTempMin, ac.getTemp());
|
||||
ac.setTemp(kCoolixTempMax + 1);
|
||||
EXPECT_EQ(kCoolixTempMax, ac.getTemp());
|
||||
|
||||
// Fahrenheit low
|
||||
ac.setTemp(70);
|
||||
EXPECT_EQ(70, ac.getTemp());
|
||||
ac.setTemp(kCoolixTempLowFMin);
|
||||
EXPECT_EQ(kCoolixTempLowFMin, ac.getTemp());
|
||||
ac.setTemp(kCoolixTempLowFMax);
|
||||
EXPECT_EQ(kCoolixTempLowFMax, ac.getTemp());
|
||||
ac.setTemp(kCoolixTempLowFMin - 1);
|
||||
EXPECT_EQ(kCoolixTempMax, ac.getTemp());
|
||||
|
||||
// Fahrenheit high
|
||||
ac.setTemp(80);
|
||||
EXPECT_EQ(80, ac.getTemp());
|
||||
ac.setTemp(kCoolixTempHighFMin);
|
||||
EXPECT_EQ(kCoolixTempHighFMin, ac.getTemp());
|
||||
ac.setTemp(kCoolixTempHighFMax);
|
||||
EXPECT_EQ(kCoolixTempHighFMax, ac.getTemp());
|
||||
ac.setTemp(kCoolixTempHighFMax + 1);
|
||||
EXPECT_EQ(kCoolixTempMax, ac.getTemp());
|
||||
}
|
||||
|
||||
TEST(TestCoolixACClass, SetAndGetMode) {
|
||||
@ -1104,3 +1125,55 @@ TEST(TestCoolixACClass, Issue2012) {
|
||||
ac.toString());
|
||||
EXPECT_EQ(kNoTempValue, ac.toCommon().sensorTemperature);
|
||||
}
|
||||
|
||||
// Test decoding Fahrenheit from Coolix48.
|
||||
TEST(TestCoolixACClass, SetRawFahrenheit) {
|
||||
IRsendTest irsend(kGpioUnused);
|
||||
IRrecv irrecv(kGpioUnused);
|
||||
IRCoolixAC ac(kGpioUnused);
|
||||
|
||||
ac.stateReset();
|
||||
ac.setRawFromCoolix48(0xB25DFF00C03F);
|
||||
EXPECT_EQ(
|
||||
"Power: On, Mode: 0 (Cool), Fan: 7 (Fixed), Temp: 63F, "
|
||||
"Zone Follow: Off, Sensor Temp: Off",
|
||||
ac.toString());
|
||||
}
|
||||
|
||||
// Test sending and decoding of Fahrenheit values.
|
||||
TEST(TestCoolixACClass, SendFahrenheit) {
|
||||
IRrecv irrecv(kGpioUnused);
|
||||
IRCoolixAC ac(kGpioUnused);
|
||||
|
||||
const uint32_t on_cool_63f_fan_fixed_noparity = 0xB2FFC0;
|
||||
ac.begin();
|
||||
ac.on();
|
||||
ac.setPower(true);
|
||||
ac.setMode(kCoolixCool);
|
||||
ac.setFan(kCoolixFanFixed);
|
||||
ac.setTemp(63);
|
||||
EXPECT_EQ(on_cool_63f_fan_fixed_noparity, ac.getRaw());
|
||||
|
||||
ac.send();
|
||||
ac._irsend.makeDecodeResult();
|
||||
ASSERT_TRUE(irrecv.decode(&ac._irsend.capture));
|
||||
EXPECT_EQ(COOLIX48, ac._irsend.capture.decode_type);
|
||||
EXPECT_EQ(kCoolix48Bits, ac._irsend.capture.bits);
|
||||
EXPECT_EQ(0xB25DFF00C03F, ac._irsend.capture.value);
|
||||
EXPECT_EQ(0x0, ac._irsend.capture.address);
|
||||
EXPECT_EQ(0x0, ac._irsend.capture.command);
|
||||
|
||||
const uint32_t on_cool_80f_fan_fixed_noparity = 0xB2FF20;
|
||||
ac.setTemp(80);
|
||||
EXPECT_EQ(on_cool_80f_fan_fixed_noparity, ac.getRaw());
|
||||
|
||||
ac._irsend.reset();
|
||||
ac.send();
|
||||
ac._irsend.makeDecodeResult();
|
||||
ASSERT_TRUE(irrecv.decode(&ac._irsend.capture));
|
||||
EXPECT_EQ(COOLIX48, ac._irsend.capture.decode_type);
|
||||
EXPECT_EQ(kCoolix48Bits, ac._irsend.capture.bits);
|
||||
EXPECT_EQ(0xB27DFF0020DF, ac._irsend.capture.value);
|
||||
EXPECT_EQ(0x0, ac._irsend.capture.address);
|
||||
EXPECT_EQ(0x0, ac._irsend.capture.command);
|
||||
}
|
||||
|
||||
@ -102,7 +102,7 @@ TEST(TestDecodeElectraAC, RealExampleDecode) {
|
||||
EXPECT_EQ(
|
||||
"Power: On, Mode: 1 (Cool), Temp: 24C, Fan: 3 (Low), "
|
||||
"Swing(V): Off, Swing(H): Off, Light: -, Clean: Off, Turbo: Off, "
|
||||
"IFeel: Off",
|
||||
"Quiet: Off, IFeel: Off",
|
||||
IRAcUtils::resultAcToString(&irsend.capture));
|
||||
stdAc::state_t r, p;
|
||||
ASSERT_TRUE(IRAcUtils::decodeToState(&irsend.capture, &r, &p));
|
||||
@ -237,7 +237,7 @@ TEST(TestIRElectraAcClass, HumanReadable) {
|
||||
EXPECT_EQ(
|
||||
"Power: On, Mode: 1 (Cool), Temp: 32C, Fan: 5 (Auto), "
|
||||
"Swing(V): Off, Swing(H): Off, Light: -, Clean: Off, Turbo: Off, "
|
||||
"IFeel: Off",
|
||||
"Quiet: Off, IFeel: Off",
|
||||
ac.toString());
|
||||
uint8_t on_cool_16C_auto_voff[13] = {
|
||||
0xC3, 0x47, 0xE0, 0x00, 0xA0, 0x00, 0x20,
|
||||
@ -246,7 +246,7 @@ TEST(TestIRElectraAcClass, HumanReadable) {
|
||||
EXPECT_EQ(
|
||||
"Power: On, Mode: 1 (Cool), Temp: 16C, Fan: 5 (Auto), "
|
||||
"Swing(V): Off, Swing(H): Off, Light: -, Clean: Off, Turbo: Off, "
|
||||
"IFeel: Off",
|
||||
"Quiet: Off, IFeel: Off",
|
||||
ac.toString());
|
||||
uint8_t on_cool_16C_low_voff[13] = {
|
||||
0xC3, 0x47, 0xE0, 0x00, 0x60, 0x00, 0x20,
|
||||
@ -255,7 +255,7 @@ TEST(TestIRElectraAcClass, HumanReadable) {
|
||||
EXPECT_EQ(
|
||||
"Power: On, Mode: 1 (Cool), Temp: 16C, Fan: 3 (Low), "
|
||||
"Swing(V): Off, Swing(H): Off, Light: -, Clean: Off, Turbo: Off, "
|
||||
"IFeel: Off",
|
||||
"Quiet: Off, IFeel: Off",
|
||||
ac.toString());
|
||||
}
|
||||
|
||||
@ -280,7 +280,7 @@ TEST(TestIRElectraAcClass, Clean) {
|
||||
EXPECT_EQ(
|
||||
"Power: On, Mode: 1 (Cool), Temp: 24C, Fan: 3 (Low), "
|
||||
"Swing(V): Off, Swing(H): Off, Light: Toggle, Clean: On, Turbo: Off, "
|
||||
"IFeel: Off",
|
||||
"Quiet: Off, IFeel: Off",
|
||||
ac.toString());
|
||||
}
|
||||
|
||||
@ -307,7 +307,7 @@ TEST(TestIRElectraAcClass, Turbo) {
|
||||
EXPECT_EQ(
|
||||
"Power: On, Mode: 1 (Cool), Temp: 24C, Fan: 3 (Low), "
|
||||
"Swing(V): Off, Swing(H): Off, Light: -, Clean: Off, Turbo: On, "
|
||||
"IFeel: Off",
|
||||
"Quiet: Off, IFeel: Off",
|
||||
ac.toString());
|
||||
}
|
||||
|
||||
@ -332,7 +332,7 @@ TEST(TestIRElectraAcClass, LightToggle) {
|
||||
EXPECT_EQ(
|
||||
"Power: On, Mode: 1 (Cool), Temp: 24C, Fan: 3 (Low), "
|
||||
"Swing(V): Off, Swing(H): Off, Light: Toggle, Clean: On, Turbo: Off, "
|
||||
"IFeel: Off",
|
||||
"Quiet: Off, IFeel: Off",
|
||||
ac.toString());
|
||||
}
|
||||
|
||||
@ -360,7 +360,7 @@ TEST(TestIRElectraAcClass, ConstructKnownState) {
|
||||
EXPECT_EQ(
|
||||
"Power: On, Mode: 1 (Cool), Temp: 24C, Fan: 3 (Low), "
|
||||
"Swing(V): Off, Swing(H): Off, Light: Toggle, Clean: On, Turbo: Off, "
|
||||
"IFeel: Off",
|
||||
"Quiet: Off, IFeel: Off",
|
||||
ac.toString());
|
||||
EXPECT_STATE_EQ(on_cool_24C_fan1_swing_off_turbo_off_clean_on,
|
||||
ac.getRaw(), kElectraAcBits);
|
||||
@ -379,7 +379,7 @@ TEST(TestIRElectraAcClass, IFeelAndSensor) {
|
||||
EXPECT_EQ(
|
||||
"Power: On, Mode: 1 (Cool), Temp: 21C, Fan: 5 (Auto), "
|
||||
"Swing(V): Off, Swing(H): Off, Light: -, Clean: Off, Turbo: Off, "
|
||||
"IFeel: On, Sensor Temp: 26C",
|
||||
"Quiet: Off, IFeel: On, Sensor Temp: 26C",
|
||||
ac.toString());
|
||||
|
||||
ac.stateReset();
|
||||
@ -429,6 +429,6 @@ TEST(TestIRElectraAcClass, IFeelAndSensor) {
|
||||
EXPECT_EQ(
|
||||
"Power: On, Mode: 4 (Heat), Temp: 27C, Fan: 5 (Auto), "
|
||||
"Swing(V): Off, Swing(H): Off, Light: -, Clean: Off, Turbo: Off, "
|
||||
"IFeel: On, Sensor Temp: 28C",
|
||||
"Quiet: Off, IFeel: On, Sensor Temp: 28C",
|
||||
ac.toString());
|
||||
}
|
||||
|
||||
@ -0,0 +1,377 @@
|
||||
// Copyright 2025 GottemHams
|
||||
|
||||
#include "ir_Eurom.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "IRac.h"
|
||||
#include "IRrecv.h"
|
||||
#include "IRrecv_test.h"
|
||||
#include "IRsend.h"
|
||||
#include "IRsend_test.h"
|
||||
|
||||
TEST(TestEurom, Housekeeping) {
|
||||
ASSERT_EQ("EUROM", typeToString(decode_type_t::EUROM));
|
||||
ASSERT_EQ(decode_type_t::EUROM, strToDecodeType("EUROM"));
|
||||
ASSERT_TRUE(hasACState(decode_type_t::EUROM));
|
||||
ASSERT_TRUE(IRac::isProtocolSupported(decode_type_t::EUROM));
|
||||
ASSERT_EQ(kEuromBits, IRsend::defaultBits(decode_type_t::EUROM));
|
||||
}
|
||||
|
||||
/// Tests for sendEurom().
|
||||
|
||||
/// Test sending typical data only.
|
||||
TEST(TestSendEurom, SendDataOnly) {
|
||||
IRsendTest irsend(kGpioUnused);
|
||||
|
||||
const uint8_t state[kEuromStateLength] = {
|
||||
0x18, 0x27,
|
||||
0x71, // Cooling mode, 23 C
|
||||
0x80, // Power on, swing off
|
||||
0x00, // No Fahrenheit
|
||||
0x00, // Sleep disabled, no "on timer"
|
||||
0x00,
|
||||
0x80, // No "off timer"
|
||||
0x00, // "Off timer" disabled
|
||||
0x80,
|
||||
0x10, // Low fan
|
||||
0x21, // Checksum
|
||||
};
|
||||
|
||||
irsend.begin();
|
||||
irsend.reset();
|
||||
irsend.sendEurom(state);
|
||||
EXPECT_EQ(
|
||||
"f38000d50"
|
||||
"m3257s3187"
|
||||
"m454s355m454s355m454s355m454s1162m454s1162m454s355m454s355m454s355m454s355"
|
||||
"m454s355m454s1162m454s355m454s355m454s1162m454s1162m454s1162m454s355m454"
|
||||
"s1162m454s1162m454s1162m454s355m454s355m454s355m454s1162m454s1162m454s355"
|
||||
"m454s355m454s355m454s355m454s355m454s355m454s355m454s355m454s355m454s355"
|
||||
"m454s355m454s355m454s355m454s355m454s355m454s355m454s355m454s355m454s355"
|
||||
"m454s355m454s355m454s355m454s355m454s355m454s355m454s355m454s355m454s355"
|
||||
"m454s355m454s355m454s355m454s1162m454s355m454s355m454s355m454s355m454s355"
|
||||
"m454s355m454s355m454s355m454s355m454s355m454s355m454s355m454s355m454s355"
|
||||
"m454s355m454s1162m454s355m454s355m454s355m454s355m454s355m454s355m454s355"
|
||||
"m454s355m454s355m454s355m454s1162m454s355m454s355m454s355m454s355m454s355"
|
||||
"m454s355m454s1162m454s355m454s355m454s355m454s355m454s1162m454"
|
||||
"s50058",
|
||||
irsend.outputStr());
|
||||
|
||||
irsend.reset();
|
||||
}
|
||||
|
||||
/// Tests for decodeEurom().
|
||||
|
||||
/// Decode a normal Eurom message.
|
||||
TEST(TestDecodeEurom, SyntheticExample) {
|
||||
IRsendTest irsend(kGpioUnused);
|
||||
IRrecv irrecv(kGpioUnused);
|
||||
|
||||
// This is the same state as used in SendDataOnly
|
||||
const uint8_t state[kEuromStateLength] = {
|
||||
0x18, 0x27,
|
||||
0x71, // Cooling mode, 23 C
|
||||
0x80, // Power on, swing off
|
||||
0x00, // No Fahrenheit
|
||||
0x00, // Sleep disabled, no "on timer"
|
||||
0x00,
|
||||
0x80, // No "off timer"
|
||||
0x00, // "Off timer" disabled
|
||||
0x80,
|
||||
0x10, // Low fan
|
||||
0x21, // Checksum
|
||||
};
|
||||
|
||||
irsend.begin();
|
||||
irsend.reset();
|
||||
irsend.sendEurom(state);
|
||||
irsend.makeDecodeResult();
|
||||
|
||||
ASSERT_TRUE(irrecv.decode(&irsend.capture));
|
||||
EXPECT_EQ(decode_type_t::EUROM, irsend.capture.decode_type);
|
||||
EXPECT_EQ(kEuromBits, irsend.capture.bits);
|
||||
EXPECT_FALSE(irsend.capture.repeat);
|
||||
|
||||
EXPECT_STATE_EQ(state, irsend.capture.state, irsend.capture.bits);
|
||||
EXPECT_EQ(
|
||||
"Power: On, Mode: 1 (Cool), Temp: 23C, Fan: 16 (Low), Swing(V): Off"
|
||||
", Sleep: Off, Off Timer: Off, On Timer: Off",
|
||||
IRAcUtils::resultAcToString(&irsend.capture));
|
||||
|
||||
stdAc::state_t r, p;
|
||||
ASSERT_TRUE(IRAcUtils::decodeToState(&irsend.capture, &r, &p));
|
||||
|
||||
irsend.reset();
|
||||
}
|
||||
|
||||
/// Decode a real example.
|
||||
TEST(TestDecodeEurom, RealExample) {
|
||||
IRsendTest irsend(kGpioUnused);
|
||||
IRrecv irrecv(kGpioUnused);
|
||||
|
||||
// UNKNOWN 1C60B17
|
||||
const uint16_t raw_data[391] = {
|
||||
3318, 3136,
|
||||
490, 318, 490, 322, 486, 324, 488, 1126, 490, 1118, 490, 322, 490, 318, 490,
|
||||
326, 490, 318, 488, 322, 486, 1124, 490, 328, 488, 318, 490, 1124, 490,
|
||||
1122, 486, 1130, 484, 324, 490, 1122, 486, 1122, 490, 1128, 490, 322, 486,
|
||||
322, 490, 322, 486, 1132, 484, 1124, 488, 1124, 486, 322, 490, 328, 488,
|
||||
318, 490, 322, 486, 322, 490, 328, 486, 322, 490, 322, 486, 322, 486, 330,
|
||||
486, 322, 486, 322, 490, 322, 486, 332, 486, 322, 486, 322, 490, 322, 484,
|
||||
328, 490, 322, 486, 322, 486, 322, 490, 326, 484, 324, 488, 324, 484, 324,
|
||||
484, 332, 486, 322, 486, 326, 486, 322, 486, 330, 486, 1122, 490, 324, 486,
|
||||
322, 484, 332, 486, 322, 486, 328, 484, 322, 486, 332, 484, 322, 490, 324,
|
||||
484, 322, 486, 332, 486, 326, 486, 322, 486, 322, 484, 336, 486, 1124, 486,
|
||||
348, 458, 328, 486, 330, 486, 350, 458, 326, 486, 324, 484, 332, 484, 326,
|
||||
486, 322, 486, 322, 486, 1136, 486, 322, 484, 348, 438, 348, 484, 332, 484,
|
||||
348, 460, 326, 486, 1122, 486, 336, 486, 344, 464, 1148, 438, 348, 486,
|
||||
1130, 486,
|
||||
50010,
|
||||
3308, 3140,
|
||||
490, 322, 486, 322, 486, 322, 486, 1132, 490, 1122, 486, 324, 484, 328, 484,
|
||||
328, 490, 322, 486, 322, 486, 1126, 486, 328, 488, 324, 484, 1124, 490,
|
||||
1122, 486, 1132, 486, 322, 490, 1122, 486, 1128, 484, 1132, 486, 322, 486,
|
||||
322, 490, 322, 486, 1132, 486, 1122, 490, 1122, 486, 322, 490, 326, 486,
|
||||
328, 484, 324, 486, 322, 484, 332, 486, 322, 486, 328, 484, 322, 486, 330,
|
||||
486, 324, 484, 322, 486, 326, 486, 328, 484, 328, 486, 324, 484, 322, 486,
|
||||
330, 486, 322, 486, 326, 486, 322, 486, 332, 486, 322, 484, 348, 460, 328,
|
||||
486, 330, 482, 326, 486, 322, 486, 322, 486, 330, 486, 1128, 484, 324, 484,
|
||||
322, 486, 332, 484, 348, 460, 328, 484, 324, 484, 358, 460, 326, 486, 322,
|
||||
486, 348, 460, 336, 480, 328, 484, 348, 460, 328, 480, 336, 486, 1148, 460,
|
||||
328, 484, 324, 484, 358, 460, 326, 482, 326, 486, 348, 458, 336, 480, 348,
|
||||
464, 348, 460, 328, 480, 1136, 484, 348, 460, 328, 480, 328, 484, 358, 460,
|
||||
326, 482, 348, 460, 1152, 460, 356, 460, 354, 458, 1148, 460, 328, 484,
|
||||
1162, 460,
|
||||
};
|
||||
|
||||
// Note that this is a different state than before
|
||||
const uint8_t expected_state[kEuromStateLength] = {
|
||||
0x18, 0x27, 0x71, 0xC0, 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x10, 0x25,
|
||||
};
|
||||
|
||||
irsend.begin();
|
||||
irsend.reset();
|
||||
irsend.sendRaw(raw_data, 391, kEuromFreq);
|
||||
irsend.makeDecodeResult();
|
||||
|
||||
ASSERT_TRUE(irrecv.decode(&irsend.capture));
|
||||
EXPECT_EQ(decode_type_t::EUROM, irsend.capture.decode_type);
|
||||
EXPECT_EQ(kEuromBits, irsend.capture.bits);
|
||||
EXPECT_FALSE(irsend.capture.repeat);
|
||||
|
||||
EXPECT_STATE_EQ(expected_state, irsend.capture.state, irsend.capture.bits);
|
||||
EXPECT_EQ(
|
||||
"Power: On, Mode: 1 (Cool), Temp: 23C, Fan: 16 (Low), Swing(V): On"
|
||||
", Sleep: Off, Off Timer: Off, On Timer: Off",
|
||||
IRAcUtils::resultAcToString(&irsend.capture));
|
||||
|
||||
stdAc::state_t r, p;
|
||||
ASSERT_TRUE(IRAcUtils::decodeToState(&irsend.capture, &r, &p));
|
||||
|
||||
irsend.reset();
|
||||
}
|
||||
|
||||
/// Decode a real example without repeat.
|
||||
TEST(TestDecodeEurom, RealExampleNoRepeat) {
|
||||
IRsendTest irsend(kGpioUnused);
|
||||
IRrecv irrecv(kGpioUnused);
|
||||
|
||||
// UNKNOWN 14601C1D
|
||||
const uint16_t raw_data[195] = {
|
||||
3260, 3186,
|
||||
468, 344, 438, 374, 438, 370, 438, 1178, 438, 1174, 438, 374, 438, 370, 438,
|
||||
378, 438, 370, 438, 374, 438, 1174, 438, 378, 438, 370, 438, 1174, 438,
|
||||
1170, 438, 1184, 438, 370, 438, 1174, 438, 370, 438, 1182, 434, 374, 438,
|
||||
374, 434, 374, 438, 1178, 438, 374, 438, 370, 438, 374, 434, 382, 434, 374,
|
||||
438, 374, 434, 374, 438, 378, 438, 370, 438, 374, 434, 374, 438, 378, 438,
|
||||
370, 438, 374, 434, 374, 438, 378, 438, 370, 438, 374, 438, 370, 438, 378,
|
||||
438, 374, 434, 374, 438, 370, 438, 378, 438, 374, 434, 374, 438, 374, 434,
|
||||
378, 438, 374, 438, 370, 438, 374, 434, 382, 434, 1174, 438, 374, 438, 370,
|
||||
438, 378, 438, 370, 438, 374, 438, 370, 438, 382, 434, 374, 438, 370, 438,
|
||||
374, 438, 378, 438, 374, 434, 374, 438, 370, 438, 382, 434, 1174, 464, 348,
|
||||
434, 374, 438, 382, 434, 374, 438, 370, 438, 374, 438, 378, 438, 374, 434,
|
||||
374, 438, 370, 438, 1182, 438, 374, 434, 374, 438, 370, 438, 382, 434, 374,
|
||||
438, 374, 434, 374, 438, 1182, 434, 374, 438, 1174, 434, 1174, 438, 1182,
|
||||
434,
|
||||
};
|
||||
|
||||
// This is also another state than all the earlier tests
|
||||
const uint8_t expected_state[kEuromStateLength] = {
|
||||
0x18, 0x27, 0x51, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x10, 0x17,
|
||||
};
|
||||
|
||||
irsend.begin();
|
||||
irsend.reset();
|
||||
irsend.sendRaw(raw_data, 195, kEuromFreq);
|
||||
irsend.makeDecodeResult();
|
||||
|
||||
ASSERT_TRUE(irrecv.decode(&irsend.capture));
|
||||
EXPECT_EQ(decode_type_t::EUROM, irsend.capture.decode_type);
|
||||
EXPECT_EQ(kEuromBits, irsend.capture.bits);
|
||||
EXPECT_FALSE(irsend.capture.repeat);
|
||||
|
||||
EXPECT_STATE_EQ(expected_state, irsend.capture.state, irsend.capture.bits);
|
||||
EXPECT_EQ(
|
||||
"Power: Off, Mode: 1 (Cool), Temp: 23C, Fan: 16 (Low), Swing(V): Off"
|
||||
", Sleep: Off, Off Timer: Off, On Timer: Off",
|
||||
IRAcUtils::resultAcToString(&irsend.capture));
|
||||
|
||||
stdAc::state_t r, p;
|
||||
ASSERT_TRUE(IRAcUtils::decodeToState(&irsend.capture, &r, &p));
|
||||
|
||||
irsend.reset();
|
||||
}
|
||||
|
||||
/// Tests for the IREuromAc class.
|
||||
|
||||
/// Test power setting and getting.
|
||||
TEST(TestEuromAc, SetAndGetPower) {
|
||||
IREuromAc ac(kGpioUnused);
|
||||
|
||||
// The initial state is powered off
|
||||
ASSERT_FALSE(ac.getPower());
|
||||
|
||||
ac.setPower(true);
|
||||
EXPECT_TRUE(ac.getPower());
|
||||
}
|
||||
|
||||
/// Test operation mode setting and getting.
|
||||
TEST(TestEuromAc, SetAndGetMode) {
|
||||
IREuromAc ac(kGpioUnused);
|
||||
|
||||
// The initial state is cooling mode
|
||||
ASSERT_EQ(kEuromCool, ac.getMode());
|
||||
|
||||
// Temperature is not used in dehumidification/ventilation modes
|
||||
ac.setMode(kEuromDehumidify);
|
||||
EXPECT_EQ(kEuromDehumidify, ac.getMode());
|
||||
|
||||
ac.setMode(kEuromVentilate);
|
||||
EXPECT_EQ(kEuromVentilate, ac.getMode());
|
||||
|
||||
ac.setMode(kEuromHeat);
|
||||
EXPECT_EQ(kEuromHeat, ac.getMode());
|
||||
}
|
||||
|
||||
/// Test temperature setting and getting.
|
||||
TEST(TestEuromAc, SetAndGetTemperature) {
|
||||
IREuromAc ac(kGpioUnused);
|
||||
|
||||
// The initial state is 23 C
|
||||
ASSERT_FALSE(ac.getTempIsFahrenheit());
|
||||
ASSERT_EQ(23, ac.getTemp());
|
||||
|
||||
ac.setTemp(22);
|
||||
ASSERT_FALSE(ac.getTempIsFahrenheit());
|
||||
EXPECT_EQ(22, ac.getTemp());
|
||||
}
|
||||
|
||||
/// Test temperature setting and getting with Fahrenheit.
|
||||
TEST(TestEuromAc, SetAndGetTemperatureFahrenheit) {
|
||||
IREuromAc ac(kGpioUnused);
|
||||
|
||||
// The initial state is not using Fahrenheit
|
||||
ASSERT_FALSE(ac.getTempIsFahrenheit());
|
||||
|
||||
// This corresponds to 16 C
|
||||
ac.setTemp(70, true);
|
||||
ASSERT_TRUE(ac.getTempIsFahrenheit());
|
||||
EXPECT_EQ(70, ac.getTemp());
|
||||
}
|
||||
|
||||
/// Test fan speed setting and getting.
|
||||
TEST(TestEuromAc, SetAndGetFan) {
|
||||
IREuromAc ac(kGpioUnused);
|
||||
|
||||
// The initial state is low fan
|
||||
ASSERT_EQ(kEuromFanLow, ac.getFan());
|
||||
|
||||
ac.setFan(kEuromFanHigh);
|
||||
EXPECT_EQ(kEuromFanHigh, ac.getFan());
|
||||
}
|
||||
|
||||
/// Test swing setting and getting.
|
||||
TEST(TestEuromAc, SetAndGetSwing) {
|
||||
IREuromAc ac(kGpioUnused);
|
||||
|
||||
// The initial state is swing disabled
|
||||
ASSERT_FALSE(ac.getSwing());
|
||||
|
||||
ac.setSwing(true);
|
||||
EXPECT_TRUE(ac.getSwing());
|
||||
}
|
||||
|
||||
/// Test sleep mode setting and getting.
|
||||
TEST(TestEuromAc, SetAndGetSleep) {
|
||||
IREuromAc ac(kGpioUnused);
|
||||
|
||||
// The initial state is sleep disabled
|
||||
ASSERT_FALSE(ac.getSleep());
|
||||
|
||||
ac.setSleep(true);
|
||||
EXPECT_TRUE(ac.getSleep());
|
||||
}
|
||||
|
||||
/// Test "off timer" setting and getting.
|
||||
TEST(TestEuromAc, SetAndGetOffTimer) {
|
||||
IREuromAc ac(kGpioUnused);
|
||||
|
||||
// The initial state is no timer
|
||||
ASSERT_EQ(kEuromTimerMin, ac.getOffTimer());
|
||||
|
||||
ac.setOffTimer(kEuromTimerMax);
|
||||
EXPECT_EQ(kEuromTimerMax, ac.getOffTimer());
|
||||
}
|
||||
|
||||
/// Test "on timer" setting and getting.
|
||||
TEST(TestEuromAc, SetAndGetOnTimer) {
|
||||
IREuromAc ac(kGpioUnused);
|
||||
|
||||
// The initial state is no timer
|
||||
ASSERT_EQ(kEuromTimerMin, ac.getOnTimer());
|
||||
|
||||
ac.setOnTimer(kEuromTimerMax);
|
||||
EXPECT_EQ(kEuromTimerMax, ac.getOnTimer());
|
||||
}
|
||||
|
||||
/// Test checksumming for the initial state.
|
||||
TEST(TestEuromAc, ChecksumInitial) {
|
||||
IREuromAc ac(kGpioUnused);
|
||||
|
||||
// The initial state is powered off, cooling mode, 23 C, low fan, swing and
|
||||
// sleep disabled, no timers
|
||||
const uint8_t *raw_state = ac.getRaw();
|
||||
ASSERT_EQ(0x19, raw_state[kEuromStateLength - 1]);
|
||||
}
|
||||
|
||||
/// Test checksumming with every "feature" set to the "highest" value, which
|
||||
/// also includes the special case of using the max temperature.
|
||||
TEST(TestEuromAc, ChecksumHigh) {
|
||||
IREuromAc ac(kGpioUnused);
|
||||
|
||||
// The initial state is powered off, cooling mode, 23 C, low fan, swing and
|
||||
// sleep disabled, no timers
|
||||
ac.setPower(true);
|
||||
ac.setMode(kEuromHeat);
|
||||
ac.setTemp(kEuromMaxTempF, true);
|
||||
ac.setFan(kEuromFanHigh);
|
||||
ac.setSwing(true);
|
||||
ac.setSleep(true);
|
||||
ac.setOffTimer(kEuromTimerMax);
|
||||
ac.setOnTimer(kEuromTimerMax);
|
||||
|
||||
const uint8_t expected_state[kEuromStateLength] = {
|
||||
0x18, 0x27,
|
||||
0x0C, // Heating mode, 32 C (changing Fahrenheit updates this too)
|
||||
0xC0, // Power on, swing on
|
||||
0x5E, // 90 F
|
||||
0x64, // Sleep enabled, "on timer" set to 24 hours
|
||||
0x00,
|
||||
0xA4, // "Off timer" set to 24 hours
|
||||
0x80, // "Off timer" enabled
|
||||
0x80,
|
||||
0x40, // High fan
|
||||
0x57, // Checksum
|
||||
};
|
||||
|
||||
EXPECT_STATE_EQ(expected_state, ac.getRaw(), kEuromBits);
|
||||
}
|
||||
@ -1,5 +1,7 @@
|
||||
// Copyright 2022 Mateusz Bronk (mbronk)
|
||||
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
#include "IRac.h"
|
||||
#include "IRsend.h"
|
||||
#include "IRsend_test.h"
|
||||
|
||||
@ -202,7 +202,7 @@ TEST(TestSendGree, CompareUint64ToCharResults) {
|
||||
irsend_chars.reset();
|
||||
irsend_uint64.reset();
|
||||
irsend_chars.sendGree(gree_zero_code);
|
||||
irsend_uint64.sendGree((uint64_t)0x0);
|
||||
irsend_uint64.sendGree(static_cast<uint64_t>(0x0));
|
||||
ASSERT_EQ(irsend_chars.outputStr(), irsend_uint64.outputStr());
|
||||
}
|
||||
|
||||
@ -701,6 +701,11 @@ TEST(TestGreeClass, toCommon) {
|
||||
ASSERT_FALSE(ac.toCommon().filter);
|
||||
ASSERT_FALSE(ac.toCommon().beep);
|
||||
ASSERT_EQ(-1, ac.toCommon().clock);
|
||||
|
||||
// Test kGreeSwingLastPos following the pattern in IRac::gree().
|
||||
ASSERT_EQ(kGreeSwingLastPos, ac.convertSwingV(stdAc::swingv_t::kOff));
|
||||
ac.setSwingVertical(false, kGreeSwingLastPos);
|
||||
ASSERT_EQ(stdAc::swingv_t::kOff, ac.toCommon().swingv);
|
||||
}
|
||||
|
||||
TEST(TestGreeClass, Issue814Power) {
|
||||
|
||||
@ -311,22 +311,25 @@ TEST(TestToshibaACClass, HumanReadableOutput) {
|
||||
0x00, 0xC1, 0x00, 0xC0};
|
||||
|
||||
ac.setRaw(initial_state);
|
||||
EXPECT_EQ("Temp: 17C, Power: On, Mode: 0 (Auto), Fan: 0 (Auto), "
|
||||
"Turbo: Off, Econo: Off, Filter: Off",
|
||||
EXPECT_EQ("Model: 0 (TOSHIBA REMOTE A), Temp: 17C, Power: On, "
|
||||
"Mode: 0 (Auto), Fan: 0 (Auto), Turbo: Off, Econo: Off, "
|
||||
"Filter: Off",
|
||||
ac.toString());
|
||||
ac.setRaw(modified_state);
|
||||
EXPECT_EQ("Temp: 17C, Power: On, Mode: 1 (Cool), Fan: 5 (High), "
|
||||
"Turbo: Off, Econo: Off, Filter: Off",
|
||||
EXPECT_EQ("Model: 0 (TOSHIBA REMOTE A), Temp: 17C, Power: On, "
|
||||
"Mode: 1 (Cool), Fan: 5 (High), Turbo: Off, Econo: Off, "
|
||||
"Filter: Off",
|
||||
ac.toString());
|
||||
ac.setTemp(25);
|
||||
ac.setFan(3);
|
||||
ac.setMode(kToshibaAcDry);
|
||||
EXPECT_EQ("Temp: 25C, Power: On, Mode: 2 (Dry), Fan: 3 (Medium), "
|
||||
"Turbo: Off, Econo: Off, Filter: Off",
|
||||
EXPECT_EQ("Model: 0 (TOSHIBA REMOTE A), Temp: 25C, Power: On, "
|
||||
"Mode: 2 (Dry), Fan: 3 (Medium), Turbo: Off, Econo: Off, "
|
||||
"Filter: Off",
|
||||
ac.toString());
|
||||
ac.off();
|
||||
EXPECT_EQ("Temp: 25C, Power: Off, Fan: 3 (Medium), Turbo: Off, Econo: Off, "
|
||||
"Filter: Off",
|
||||
EXPECT_EQ("Model: 0 (TOSHIBA REMOTE A), Temp: 25C, Power: Off, "
|
||||
"Fan: 3 (Medium), Turbo: Off, Econo: Off, Filter: Off",
|
||||
ac.toString());
|
||||
}
|
||||
|
||||
@ -379,8 +382,8 @@ TEST(TestDecodeToshibaAC, SyntheticExample) {
|
||||
ASSERT_EQ(kToshibaACBits, irsend.capture.bits);
|
||||
EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits);
|
||||
EXPECT_EQ(
|
||||
"Temp: 17C, Power: On, Mode: 0 (Auto), Fan: 0 (Auto), Turbo: Off, "
|
||||
"Econo: Off, Filter: Off",
|
||||
"Model: 0 (TOSHIBA REMOTE A), Temp: 17C, Power: On, Mode: 0 (Auto), "
|
||||
"Fan: 0 (Auto), Turbo: Off, Econo: Off, Filter: Off",
|
||||
IRAcUtils::resultAcToString(&irsend.capture));
|
||||
stdAc::state_t r, p;
|
||||
ASSERT_TRUE(IRAcUtils::decodeToState(&irsend.capture, &r, &p));
|
||||
@ -627,8 +630,8 @@ TEST(TestDecodeToshibaAC, RealLongExample) {
|
||||
EXPECT_EQ(kToshibaACBitsLong, irsend.capture.bits);
|
||||
EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits);
|
||||
EXPECT_EQ(
|
||||
"Temp: 22C, Power: On, Mode: 0 (Auto), Fan: 0 (Auto), Turbo: On, "
|
||||
"Econo: Off, Filter: Off",
|
||||
"Model: 0 (TOSHIBA REMOTE A), Temp: 22C, Power: On, Mode: 0 (Auto), "
|
||||
"Fan: 0 (Auto), Turbo: On, Econo: Off, Filter: Off",
|
||||
IRAcUtils::resultAcToString(&irsend.capture));
|
||||
}
|
||||
|
||||
@ -718,7 +721,7 @@ TEST(TestDecodeToshibaAC, RealShortExample) {
|
||||
EXPECT_EQ(kToshibaACBitsShort, irsend.capture.bits);
|
||||
EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits);
|
||||
EXPECT_EQ(
|
||||
"Temp: 17C, Swing(V): 0 (Step)",
|
||||
"Model: 0 (TOSHIBA REMOTE A), Temp: 17C, Swing(V): 0 (Step)",
|
||||
IRAcUtils::resultAcToString(&irsend.capture));
|
||||
}
|
||||
|
||||
@ -732,8 +735,8 @@ TEST(TestToshibaACClass, ConstructLongState) {
|
||||
ac.setTurbo(false);
|
||||
ac.setEcono(true);
|
||||
EXPECT_EQ(
|
||||
"Temp: 29C, Power: On, Mode: 2 (Dry), Fan: 2 (UNKNOWN), "
|
||||
"Turbo: Off, Econo: On, Filter: Off",
|
||||
"Model: 0 (TOSHIBA REMOTE A), Temp: 29C, Power: On, Mode: 2 (Dry), "
|
||||
"Fan: 2 (UNKNOWN), Turbo: Off, Econo: On, Filter: Off",
|
||||
ac.toString());
|
||||
EXPECT_EQ(kToshibaACStateLengthLong, ac.getStateLength());
|
||||
const uint8_t expectedState[kToshibaACStateLengthLong] = {
|
||||
@ -783,8 +786,8 @@ TEST(TestDecodeToshibaAC, RealExample_WHUB03NJ) {
|
||||
EXPECT_EQ(kToshibaACBits, irsend.capture.bits);
|
||||
EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits);
|
||||
EXPECT_EQ(
|
||||
"Temp: 20C, Power: Off, Fan: 0 (Auto), Turbo: Off, Econo: Off, "
|
||||
"Filter: Off",
|
||||
"Model: 0 (TOSHIBA REMOTE A), Temp: 20C, Power: Off, Fan: 0 (Auto), "
|
||||
"Turbo: Off, Econo: Off, Filter: Off",
|
||||
IRAcUtils::resultAcToString(&irsend.capture));
|
||||
}
|
||||
|
||||
@ -805,7 +808,7 @@ TEST(TestToshibaACClass, SwingCodes) {
|
||||
ac.setSwing(kToshibaAcSwingOn);
|
||||
|
||||
EXPECT_EQ(
|
||||
"Temp: 17C, Swing(V): 1 (On)",
|
||||
"Model: 0 (TOSHIBA REMOTE A), Temp: 17C, Swing(V): 1 (On)",
|
||||
ac.toString());
|
||||
EXPECT_EQ(kToshibaACStateLengthShort, ac.getStateLength());
|
||||
const uint8_t swingOnState[kToshibaACStateLengthShort] = {
|
||||
@ -815,7 +818,7 @@ TEST(TestToshibaACClass, SwingCodes) {
|
||||
|
||||
ac.setSwing(kToshibaAcSwingOff);
|
||||
EXPECT_EQ(
|
||||
"Temp: 17C, Swing(V): 2 (Off)",
|
||||
"Model: 0 (TOSHIBA REMOTE A), Temp: 17C, Swing(V): 2 (Off)",
|
||||
ac.toString());
|
||||
EXPECT_EQ(kToshibaACStateLengthShort, ac.getStateLength());
|
||||
const uint8_t swingOffState[kToshibaACStateLengthShort] = {
|
||||
@ -828,7 +831,7 @@ TEST(TestToshibaACClass, SwingCodes) {
|
||||
ac.setRaw(swingToggleState, kToshibaACStateLengthShort);
|
||||
EXPECT_EQ(kToshibaAcSwingToggle, ac.getSwing());
|
||||
EXPECT_EQ(
|
||||
"Temp: 17C, Swing(V): 4 (Toggle)",
|
||||
"Model: 0 (TOSHIBA REMOTE A), Temp: 17C, Swing(V): 4 (Toggle)",
|
||||
ac.toString());
|
||||
}
|
||||
|
||||
|
||||
@ -105,7 +105,7 @@ class RawIRMessage():
|
||||
code.append(f" // Data Section #{self.section_count}")
|
||||
code.append(f" // e.g. data = 0x{int(bin_str, 2):X}, nbits = {nbits}")
|
||||
code.append(f" sendData(k{name}BitMark, k{name}OneSpace, k{name}BitMark,"
|
||||
f" k{name}ZeroSpace, send_data, {nbits}, true);")
|
||||
f" k{name}ZeroSpace, send_data, {nbits}, k{name}MsbFirst);")
|
||||
code.append(f" send_data >>= {nbits};")
|
||||
if footer:
|
||||
code.append(" // Footer")
|
||||
@ -122,7 +122,8 @@ class RawIRMessage():
|
||||
f" // e.g. data_result.data = 0x{int(bin_str, 2):X}, nbits = {nbits}",
|
||||
f" data_result = matchData(&(results->rawbuf[offset]), {nbits},",
|
||||
f" k{name}BitMark, k{name}OneSpace,",
|
||||
f" k{name}BitMark, k{name}ZeroSpace);",
|
||||
f" k{name}BitMark, k{name}ZeroSpace,",
|
||||
f" kUseDefTol, kMarkExcess, k{name}MsbFirst);",
|
||||
" offset += data_result.used;",
|
||||
" if (data_result.success == false) return false; // Fail",
|
||||
f" data <<= {nbits}; // Make room for the new bits of data.",
|
||||
@ -163,7 +164,8 @@ class RawIRMessage():
|
||||
f" k{name}BitMark, k{name}ZeroSpace,",
|
||||
f" {lastmark}, {lastspace},",
|
||||
f" data + pos, {int(nbytes)}, // Bytes",
|
||||
f" k{name}Freq, true, kNoRepeat, kDutyDefault);",
|
||||
f" k{name}Freq, k{name}MsbFirst, kNoRepeat,"
|
||||
" kDutyDefault);",
|
||||
f" pos += {int(nbytes)};"
|
||||
f" // Adjust by how many bytes of data we sent"])
|
||||
return code
|
||||
@ -198,7 +200,7 @@ class RawIRMessage():
|
||||
f" {firstmark}, {firstspace},",
|
||||
f" k{name}BitMark, k{name}OneSpace,",
|
||||
f" k{name}BitMark, k{name}ZeroSpace,",
|
||||
f" {lastmark}, {lastspace}, true);",
|
||||
f" {lastmark}, {lastspace}, k{name}MsbFirst);",
|
||||
" if (used == 0) return false; // We failed to find any data.",
|
||||
" offset += used; // Adjust for how much of the message we read.",
|
||||
f" pos += {int(nbytes)};"
|
||||
@ -351,6 +353,7 @@ def dump_constants(message, defines, name="", output=sys.stdout):
|
||||
defines.append(f"const uint16_t k{name}SpaceGap{count} = {gap};")
|
||||
defines.append(f"const uint16_t k{name}Freq = 38000; "
|
||||
"// Hz. (Guessing the most common frequency.)")
|
||||
defines.append(f"const bool k{name}MsbFirst = true; // default assumption")
|
||||
|
||||
|
||||
def parse_and_report(rawdata_str, margin, gen_code=False, name="",
|
||||
|
||||
@ -76,7 +76,8 @@ class TestAutoAnalyseRawData(unittest.TestCase):
|
||||
'const uint16_t kBAROneSpace = 1485;',
|
||||
'const uint16_t kBARZeroSpace = 520;',
|
||||
'const uint16_t kBARFreq = 38000; // Hz. (Guessing the most common '
|
||||
'frequency.)'
|
||||
'frequency.)',
|
||||
'const bool kBARMsbFirst = true; // default assumption'
|
||||
])
|
||||
self.assertEqual(
|
||||
output.getvalue(), 'Guessing key value:\n'
|
||||
@ -113,7 +114,8 @@ class TestAutoAnalyseRawData(unittest.TestCase):
|
||||
'const uint16_t kTESTZeroSpace = 554;',
|
||||
'const uint16_t kTESTSpaceGap = 19990;',
|
||||
'const uint16_t kTESTFreq = 38000; // Hz. (Guessing the most common '
|
||||
'frequency.)'
|
||||
'frequency.)',
|
||||
'const bool kTESTMsbFirst = true; // default assumption'
|
||||
])
|
||||
self.assertEqual(
|
||||
output.getvalue(), 'Guessing key value:\n'
|
||||
@ -302,6 +304,7 @@ class TestAutoAnalyseRawData(unittest.TestCase):
|
||||
'const uint16_t kFOOZeroSpace = 520;\n'
|
||||
'const uint16_t kFOOFreq = 38000; // Hz. (Guessing the most common'
|
||||
' frequency.)\n'
|
||||
'const bool kFOOMsbFirst = true; // default assumption\n'
|
||||
'const uint16_t kFOOBits = 16; // Move to IRremoteESP8266.h\n'
|
||||
'const uint16_t kFOOOverhead = 5;\n'
|
||||
'\n'
|
||||
@ -323,7 +326,7 @@ class TestAutoAnalyseRawData(unittest.TestCase):
|
||||
' // Data Section #1\n'
|
||||
' // e.g. data = 0xEB, nbits = 8\n'
|
||||
' sendData(kFOOBitMark, kFOOOneSpace, kFOOBitMark, kFOOZeroSpace,'
|
||||
' send_data, 8, true);\n'
|
||||
' send_data, 8, kFOOMsbFirst);\n'
|
||||
' send_data >>= 8;\n'
|
||||
' // Footer\n'
|
||||
' mark(kFOOBitMark);\n'
|
||||
@ -331,7 +334,7 @@ class TestAutoAnalyseRawData(unittest.TestCase):
|
||||
' // Data Section #2\n'
|
||||
' // e.g. data = 0x1, nbits = 8\n'
|
||||
' sendData(kFOOBitMark, kFOOOneSpace, kFOOBitMark, kFOOZeroSpace,'
|
||||
' send_data, 8, true);\n'
|
||||
' send_data, 8, kFOOMsbFirst);\n'
|
||||
' send_data >>= 8;\n'
|
||||
' // Footer\n'
|
||||
' mark(kFOOBitMark);\n'
|
||||
@ -374,7 +377,8 @@ class TestAutoAnalyseRawData(unittest.TestCase):
|
||||
' // e.g. data_result.data = 0xEB, nbits = 8\n'
|
||||
' data_result = matchData(&(results->rawbuf[offset]), 8,\n'
|
||||
' kFOOBitMark, kFOOOneSpace,\n'
|
||||
' kFOOBitMark, kFOOZeroSpace);\n'
|
||||
' kFOOBitMark, kFOOZeroSpace,\n'
|
||||
' kUseDefTol, kMarkExcess, kFOOMsbFirst);\n'
|
||||
' offset += data_result.used;\n'
|
||||
' if (data_result.success == false) return false; // Fail\n'
|
||||
' data <<= 8; // Make room for the new bits of data.\n'
|
||||
@ -390,7 +394,8 @@ class TestAutoAnalyseRawData(unittest.TestCase):
|
||||
' // e.g. data_result.data = 0x1, nbits = 8\n'
|
||||
' data_result = matchData(&(results->rawbuf[offset]), 8,\n'
|
||||
' kFOOBitMark, kFOOOneSpace,\n'
|
||||
' kFOOBitMark, kFOOZeroSpace);\n'
|
||||
' kFOOBitMark, kFOOZeroSpace,\n'
|
||||
' kUseDefTol, kMarkExcess, kFOOMsbFirst);\n'
|
||||
' offset += data_result.used;\n'
|
||||
' if (data_result.success == false) return false; // Fail\n'
|
||||
' data <<= 8; // Make room for the new bits of data.\n'
|
||||
@ -585,6 +590,7 @@ class TestAutoAnalyseRawData(unittest.TestCase):
|
||||
'const uint16_t kHitachiSpaceGap = 49290;\n'
|
||||
'const uint16_t kHitachiFreq = 38000; // Hz. (Guessing the most'
|
||||
' common frequency.)\n'
|
||||
'const bool kHitachiMsbFirst = true; // default assumption\n'
|
||||
'const uint16_t kHitachiBits = 424; // Move to IRremoteESP8266.h\n'
|
||||
'const uint16_t kHitachiStateLength = 53; // Move to IRremoteESP8266.h'
|
||||
'\n'
|
||||
@ -616,7 +622,7 @@ class TestAutoAnalyseRawData(unittest.TestCase):
|
||||
'FFCA358F7000FF00FF01FEC03F807F11EE00FF00FFFF00FF00FF00FF00,'
|
||||
' nbits = 424\n'
|
||||
' sendData(kHitachiBitMark, kHitachiOneSpace, kHitachiBitMark,'
|
||||
' kHitachiZeroSpace, send_data, 424, true);\n'
|
||||
' kHitachiZeroSpace, send_data, 424, kHitachiMsbFirst);\n'
|
||||
' send_data >>= 424;\n'
|
||||
' // Footer\n'
|
||||
' mark(kHitachiBitMark);\n'
|
||||
@ -663,7 +669,8 @@ class TestAutoAnalyseRawData(unittest.TestCase):
|
||||
' kHitachiBitMark, kHitachiZeroSpace,\n'
|
||||
' kHitachiBitMark, kHitachiSpaceGap,\n'
|
||||
' data + pos, 53, // Bytes\n'
|
||||
' kHitachiFreq, true, kNoRepeat, kDutyDefault);\n'
|
||||
' kHitachiFreq, kHitachiMsbFirst, kNoRepeat,'
|
||||
' kDutyDefault);\n'
|
||||
' pos += 53; // Adjust by how many bytes of data we sent\n'
|
||||
' }\n'
|
||||
'}\n'
|
||||
@ -714,7 +721,9 @@ class TestAutoAnalyseRawData(unittest.TestCase):
|
||||
' nbits = 424\n'
|
||||
' data_result = matchData(&(results->rawbuf[offset]), 424,\n'
|
||||
' kHitachiBitMark, kHitachiOneSpace,\n'
|
||||
' kHitachiBitMark, kHitachiZeroSpace);\n'
|
||||
' kHitachiBitMark, kHitachiZeroSpace,\n'
|
||||
' kUseDefTol, kMarkExcess,'
|
||||
' kHitachiMsbFirst);\n'
|
||||
' offset += data_result.used;\n'
|
||||
' if (data_result.success == false) return false; // Fail\n'
|
||||
' data <<= 424; // Make room for the new bits of data.\n'
|
||||
@ -772,7 +781,8 @@ class TestAutoAnalyseRawData(unittest.TestCase):
|
||||
' kHitachiHdrMark, kHitachiHdrSpace,\n'
|
||||
' kHitachiBitMark, kHitachiOneSpace,\n'
|
||||
' kHitachiBitMark, kHitachiZeroSpace,\n'
|
||||
' kHitachiBitMark, kHitachiSpaceGap, true);\n'
|
||||
' kHitachiBitMark, kHitachiSpaceGap,'
|
||||
' kHitachiMsbFirst);\n'
|
||||
' if (used == 0) return false; // We failed to find any data.\n'
|
||||
' offset += used; // Adjust for how much of the message we read.\n'
|
||||
' pos += 53; // Adjust by how many bytes of data we read\n'
|
||||
@ -898,6 +908,7 @@ class TestAutoAnalyseRawData(unittest.TestCase):
|
||||
'const uint16_t kFOOSpaceGap = 13996;\n'
|
||||
'const uint16_t kFOOFreq = 38000; // Hz. (Guessing the most common'
|
||||
' frequency.)\n'
|
||||
'const bool kFOOMsbFirst = true; // default assumption\n'
|
||||
'const uint16_t kFOOBits = 128; // Move to IRremoteESP8266.h\n'
|
||||
'const uint16_t kFOOStateLength = 16; // Move to IRremoteESP8266.h\n'
|
||||
'const uint16_t kFOOOverhead = 16;\n'
|
||||
@ -922,7 +933,7 @@ class TestAutoAnalyseRawData(unittest.TestCase):
|
||||
' // Data Section #1\n'
|
||||
' // e.g. data = 0x5F5F4040, nbits = 32\n'
|
||||
' sendData(kFOOBitMark, kFOOOneSpace, kFOOBitMark, kFOOZeroSpace,'
|
||||
' send_data, 32, true);\n'
|
||||
' send_data, 32, kFOOMsbFirst);\n'
|
||||
' send_data >>= 32;\n'
|
||||
' // Header\n'
|
||||
' mark(kFOOHdrMark);\n'
|
||||
@ -930,7 +941,7 @@ class TestAutoAnalyseRawData(unittest.TestCase):
|
||||
' // Data Section #2\n'
|
||||
' // e.g. data = 0x5F5F4040, nbits = 32\n'
|
||||
' sendData(kFOOBitMark, kFOOOneSpace, kFOOBitMark, kFOOZeroSpace,'
|
||||
' send_data, 32, true);\n'
|
||||
' send_data, 32, kFOOMsbFirst);\n'
|
||||
' send_data >>= 32;\n'
|
||||
' // Header\n'
|
||||
' mark(kFOOHdrMark);\n'
|
||||
@ -944,7 +955,7 @@ class TestAutoAnalyseRawData(unittest.TestCase):
|
||||
' // Data Section #3\n'
|
||||
' // e.g. data = 0x2F2F6C6C, nbits = 32\n'
|
||||
' sendData(kFOOBitMark, kFOOOneSpace, kFOOBitMark, kFOOZeroSpace,'
|
||||
' send_data, 32, true);\n'
|
||||
' send_data, 32, kFOOMsbFirst);\n'
|
||||
' send_data >>= 32;\n'
|
||||
' // Header\n'
|
||||
' mark(kFOOHdrMark);\n'
|
||||
@ -952,7 +963,7 @@ class TestAutoAnalyseRawData(unittest.TestCase):
|
||||
' // Data Section #4\n'
|
||||
' // e.g. data = 0x2F2F6C6C, nbits = 32\n'
|
||||
' sendData(kFOOBitMark, kFOOOneSpace, kFOOBitMark, kFOOZeroSpace,'
|
||||
' send_data, 32, true);\n'
|
||||
' send_data, 32, kFOOMsbFirst);\n'
|
||||
' send_data >>= 32;\n'
|
||||
' // Header\n'
|
||||
' mark(kFOOHdrMark);\n'
|
||||
@ -994,7 +1005,7 @@ class TestAutoAnalyseRawData(unittest.TestCase):
|
||||
' kFOOBitMark, kFOOZeroSpace,\n'
|
||||
' kFOOHdrMark, kFOOHdrSpace,\n'
|
||||
' data + pos, 4, // Bytes\n'
|
||||
' kFOOFreq, true, kNoRepeat, kDutyDefault);\n'
|
||||
' kFOOFreq, kFOOMsbFirst, kNoRepeat, kDutyDefault);\n'
|
||||
' pos += 4; // Adjust by how many bytes of data we sent\n'
|
||||
' // Data Section #2\n'
|
||||
' // e.g.\n'
|
||||
@ -1005,7 +1016,7 @@ class TestAutoAnalyseRawData(unittest.TestCase):
|
||||
' kFOOBitMark, kFOOZeroSpace,\n'
|
||||
' kFOOHdrMark, kFOOHdrSpace,\n'
|
||||
' data + pos, 4, // Bytes\n'
|
||||
' kFOOFreq, true, kNoRepeat, kDutyDefault);\n'
|
||||
' kFOOFreq, kFOOMsbFirst, kNoRepeat, kDutyDefault);\n'
|
||||
' pos += 4; // Adjust by how many bytes of data we sent\n'
|
||||
' // Data Section #3\n'
|
||||
' // e.g.\n'
|
||||
@ -1016,7 +1027,7 @@ class TestAutoAnalyseRawData(unittest.TestCase):
|
||||
' kFOOBitMark, kFOOZeroSpace,\n'
|
||||
' kFOOHdrMark, kFOOHdrSpace,\n'
|
||||
' data + pos, 4, // Bytes\n'
|
||||
' kFOOFreq, true, kNoRepeat, kDutyDefault);\n'
|
||||
' kFOOFreq, kFOOMsbFirst, kNoRepeat, kDutyDefault);\n'
|
||||
' pos += 4; // Adjust by how many bytes of data we sent\n'
|
||||
' // Data Section #4\n'
|
||||
' // e.g.\n'
|
||||
@ -1027,7 +1038,7 @@ class TestAutoAnalyseRawData(unittest.TestCase):
|
||||
' kFOOBitMark, kFOOZeroSpace,\n'
|
||||
' kFOOHdrMark, kFOOHdrSpace,\n'
|
||||
' data + pos, 4, // Bytes\n'
|
||||
' kFOOFreq, true, kNoRepeat, kDutyDefault);\n'
|
||||
' kFOOFreq, kFOOMsbFirst, kNoRepeat, kDutyDefault);\n'
|
||||
' pos += 4; // Adjust by how many bytes of data we sent\n'
|
||||
' }\n'
|
||||
'}\n'
|
||||
@ -1068,7 +1079,8 @@ class TestAutoAnalyseRawData(unittest.TestCase):
|
||||
' // e.g. data_result.data = 0x5F5F4040, nbits = 32\n'
|
||||
' data_result = matchData(&(results->rawbuf[offset]), 32,\n'
|
||||
' kFOOBitMark, kFOOOneSpace,\n'
|
||||
' kFOOBitMark, kFOOZeroSpace);\n'
|
||||
' kFOOBitMark, kFOOZeroSpace,\n'
|
||||
' kUseDefTol, kMarkExcess, kFOOMsbFirst);\n'
|
||||
' offset += data_result.used;\n'
|
||||
' if (data_result.success == false) return false; // Fail\n'
|
||||
' data <<= 32; // Make room for the new bits of data.\n'
|
||||
@ -1084,7 +1096,8 @@ class TestAutoAnalyseRawData(unittest.TestCase):
|
||||
' // e.g. data_result.data = 0x5F5F4040, nbits = 32\n'
|
||||
' data_result = matchData(&(results->rawbuf[offset]), 32,\n'
|
||||
' kFOOBitMark, kFOOOneSpace,\n'
|
||||
' kFOOBitMark, kFOOZeroSpace);\n'
|
||||
' kFOOBitMark, kFOOZeroSpace,\n'
|
||||
' kUseDefTol, kMarkExcess, kFOOMsbFirst);\n'
|
||||
' offset += data_result.used;\n'
|
||||
' if (data_result.success == false) return false; // Fail\n'
|
||||
' data <<= 32; // Make room for the new bits of data.\n'
|
||||
@ -1112,7 +1125,8 @@ class TestAutoAnalyseRawData(unittest.TestCase):
|
||||
' // e.g. data_result.data = 0x2F2F6C6C, nbits = 32\n'
|
||||
' data_result = matchData(&(results->rawbuf[offset]), 32,\n'
|
||||
' kFOOBitMark, kFOOOneSpace,\n'
|
||||
' kFOOBitMark, kFOOZeroSpace);\n'
|
||||
' kFOOBitMark, kFOOZeroSpace,\n'
|
||||
' kUseDefTol, kMarkExcess, kFOOMsbFirst);\n'
|
||||
' offset += data_result.used;\n'
|
||||
' if (data_result.success == false) return false; // Fail\n'
|
||||
' data <<= 32; // Make room for the new bits of data.\n'
|
||||
@ -1128,7 +1142,8 @@ class TestAutoAnalyseRawData(unittest.TestCase):
|
||||
' // e.g. data_result.data = 0x2F2F6C6C, nbits = 32\n'
|
||||
' data_result = matchData(&(results->rawbuf[offset]), 32,\n'
|
||||
' kFOOBitMark, kFOOOneSpace,\n'
|
||||
' kFOOBitMark, kFOOZeroSpace);\n'
|
||||
' kFOOBitMark, kFOOZeroSpace,\n'
|
||||
' kUseDefTol, kMarkExcess, kFOOMsbFirst);\n'
|
||||
' offset += data_result.used;\n'
|
||||
' if (data_result.success == false) return false; // Fail\n'
|
||||
' data <<= 32; // Make room for the new bits of data.\n'
|
||||
@ -1189,7 +1204,7 @@ class TestAutoAnalyseRawData(unittest.TestCase):
|
||||
' kFOOHdrMark, kFOOHdrSpace,\n'
|
||||
' kFOOBitMark, kFOOOneSpace,\n'
|
||||
' kFOOBitMark, kFOOZeroSpace,\n'
|
||||
' kFOOHdrMark, kFOOHdrSpace, true);\n'
|
||||
' kFOOHdrMark, kFOOHdrSpace, kFOOMsbFirst);\n'
|
||||
' if (used == 0) return false; // We failed to find any data.\n'
|
||||
' offset += used; // Adjust for how much of the message we read.\n'
|
||||
' pos += 4; // Adjust by how many bytes of data we read\n'
|
||||
@ -1204,7 +1219,7 @@ class TestAutoAnalyseRawData(unittest.TestCase):
|
||||
' kFOOHdrMark, kFOOHdrSpace,\n'
|
||||
' kFOOBitMark, kFOOOneSpace,\n'
|
||||
' kFOOBitMark, kFOOZeroSpace,\n'
|
||||
' kFOOHdrMark, kFOOHdrSpace, true);\n'
|
||||
' kFOOHdrMark, kFOOHdrSpace, kFOOMsbFirst);\n'
|
||||
' if (used == 0) return false; // We failed to find any data.\n'
|
||||
' offset += used; // Adjust for how much of the message we read.\n'
|
||||
' pos += 4; // Adjust by how many bytes of data we read\n'
|
||||
@ -1219,7 +1234,7 @@ class TestAutoAnalyseRawData(unittest.TestCase):
|
||||
' kFOOHdrMark, kFOOHdrSpace,\n'
|
||||
' kFOOBitMark, kFOOOneSpace,\n'
|
||||
' kFOOBitMark, kFOOZeroSpace,\n'
|
||||
' kFOOHdrMark, kFOOHdrSpace, true);\n'
|
||||
' kFOOHdrMark, kFOOHdrSpace, kFOOMsbFirst);\n'
|
||||
' if (used == 0) return false; // We failed to find any data.\n'
|
||||
' offset += used; // Adjust for how much of the message we read.\n'
|
||||
' pos += 4; // Adjust by how many bytes of data we read\n'
|
||||
@ -1234,7 +1249,7 @@ class TestAutoAnalyseRawData(unittest.TestCase):
|
||||
' kFOOHdrMark, kFOOHdrSpace,\n'
|
||||
' kFOOBitMark, kFOOOneSpace,\n'
|
||||
' kFOOBitMark, kFOOZeroSpace,\n'
|
||||
' kFOOHdrMark, kFOOHdrSpace, true);\n'
|
||||
' kFOOHdrMark, kFOOHdrSpace, kFOOMsbFirst);\n'
|
||||
' if (used == 0) return false; // We failed to find any data.\n'
|
||||
' offset += used; // Adjust for how much of the message we read.\n'
|
||||
' pos += 4; // Adjust by how many bytes of data we read\n'
|
||||
@ -1333,6 +1348,7 @@ class TestAutoAnalyseRawData(unittest.TestCase):
|
||||
'const uint16_t kZeroSpace = 547;\n'
|
||||
'const uint16_t kFreq = 38000; // Hz. (Guessing the most common'
|
||||
' frequency.)\n'
|
||||
'const bool kMsbFirst = true; // default assumption\n'
|
||||
'const uint16_t kBits = 128; // Move to IRremoteESP8266.h\n'
|
||||
'const uint16_t kStateLength = 16; // Move to IRremoteESP8266.h\n'
|
||||
'const uint16_t kOverhead = 1;\n'
|
||||
@ -1354,7 +1370,7 @@ class TestAutoAnalyseRawData(unittest.TestCase):
|
||||
' // Data Section #1\n'
|
||||
' // e.g. data = 0xA55A0000400000000000000000000080, nbits = 128\n'
|
||||
' sendData(kBitMark, kOneSpace, kBitMark, kZeroSpace, send_data,'
|
||||
' 128, true);\n'
|
||||
' 128, kMsbFirst);\n'
|
||||
' send_data >>= 128;\n'
|
||||
' // Footer\n'
|
||||
' mark(kBitMark);\n'
|
||||
@ -1393,7 +1409,7 @@ class TestAutoAnalyseRawData(unittest.TestCase):
|
||||
' kBitMark, kZeroSpace,\n'
|
||||
' kBitMark, kDefaultMessageGap,\n'
|
||||
' data + pos, 16, // Bytes\n'
|
||||
' kFreq, true, kNoRepeat, kDutyDefault);\n'
|
||||
' kFreq, kMsbFirst, kNoRepeat, kDutyDefault);\n'
|
||||
' pos += 16; // Adjust by how many bytes of data we sent\n'
|
||||
' }\n'
|
||||
'}\n'
|
||||
@ -1429,7 +1445,8 @@ class TestAutoAnalyseRawData(unittest.TestCase):
|
||||
' = 128\n'
|
||||
' data_result = matchData(&(results->rawbuf[offset]), 128,\n'
|
||||
' kBitMark, kOneSpace,\n'
|
||||
' kBitMark, kZeroSpace);\n'
|
||||
' kBitMark, kZeroSpace,\n'
|
||||
' kUseDefTol, kMarkExcess, kMsbFirst);\n'
|
||||
' offset += data_result.used;\n'
|
||||
' if (data_result.success == false) return false; // Fail\n'
|
||||
' data <<= 128; // Make room for the new bits of data.\n'
|
||||
@ -1483,7 +1500,7 @@ class TestAutoAnalyseRawData(unittest.TestCase):
|
||||
' 0, 0,\n'
|
||||
' kBitMark, kOneSpace,\n'
|
||||
' kBitMark, kZeroSpace,\n'
|
||||
' kBitMark, kDefaultMessageGap, true);\n'
|
||||
' kBitMark, kDefaultMessageGap, kMsbFirst);\n'
|
||||
' if (used == 0) return false; // We failed to find any data.\n'
|
||||
' offset += used; // Adjust for how much of the message we read.\n'
|
||||
' pos += 16; // Adjust by how many bytes of data we read\n'
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include "IRac.h"
|
||||
#include "IRsend.h"
|
||||
|
||||
@ -6,6 +6,8 @@
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <cstdio>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include "IRac.h"
|
||||
#include "IRsend.h"
|
||||
@ -21,7 +23,7 @@ void str_to_uint16(char *str, uint16_t *res, uint8_t base) {
|
||||
if (errno == ERANGE || val < 0 || val > UINT16_MAX || end == str ||
|
||||
*end != '\0')
|
||||
return;
|
||||
*res = (uint16_t)val;
|
||||
*res = static_cast<uint16_t>(val);
|
||||
}
|
||||
|
||||
void usage_error(char *name) {
|
||||
|
||||
@ -21,6 +21,7 @@ space 500000
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <cstdio>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
@ -37,7 +38,7 @@ void str_to_uint16(char *str, uint16_t *res, uint8_t base) {
|
||||
if (errno == ERANGE || val < 0 || val > UINT16_MAX || end == str ||
|
||||
*end != '\0')
|
||||
return;
|
||||
*res = (uint16_t)val;
|
||||
*res = static_cast<uint16_t>(val);
|
||||
}
|
||||
|
||||
void usage_error(char *name) {
|
||||
|
||||
@ -8,7 +8,7 @@ from auto_analyse_raw_data import convert_rawdata, add_rawdata_args, get_rawdata
|
||||
|
||||
|
||||
# pylint: disable=too-many-arguments
|
||||
def parse_and_report(rawdata_str, hertz=38000, end_usecs=100000,
|
||||
def parse_and_report(rawdata_str, hertz=38000, *, end_usecs=100000,
|
||||
use_initial=False, generate_code=False, verbose=False,
|
||||
output=sys.stdout):
|
||||
"""Analyse the rawdata c++ definition of a IR message."""
|
||||
@ -94,9 +94,11 @@ def main():
|
||||
default=False)
|
||||
add_rawdata_args(arg_parser)
|
||||
arg_options = arg_parser.parse_args()
|
||||
parse_and_report(get_rawdata(arg_options), arg_options.hertz,
|
||||
arg_options.usecs, arg_options.use_initial,
|
||||
arg_options.generate_code, arg_options.verbose)
|
||||
parse_and_report(get_rawdata(arg_options), hertz=arg_options.hertz,
|
||||
end_usecs=arg_options.usecs,
|
||||
use_initial=arg_options.use_initial,
|
||||
generate_code=arg_options.generate_code,
|
||||
verbose=arg_options.verbose)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
@ -14,8 +14,9 @@ class TestRawToPronto(unittest.TestCase):
|
||||
input_str = """
|
||||
uint16_t rawData[7] = {
|
||||
20100, 20472, 15092, 30704, 20102, 20472, 15086};"""
|
||||
pronto.parse_and_report(input_str, 38000, 100000, True, False, False,
|
||||
output)
|
||||
pronto.parse_and_report(input_str, hertz=38000, end_usecs=100000,
|
||||
use_initial=True, generate_code=False,
|
||||
verbose=False, output=output)
|
||||
self.assertEqual(
|
||||
output.getvalue(),
|
||||
"Pronto code = "
|
||||
@ -28,8 +29,9 @@ class TestRawToPronto(unittest.TestCase):
|
||||
input_str = """
|
||||
uint16_t rawData[7] = {
|
||||
20100, 20472, 15092, 30704, 20102, 20472, 15086};"""
|
||||
pronto.parse_and_report(input_str, 36000, 100000, True, False, False,
|
||||
output)
|
||||
pronto.parse_and_report(input_str, hertz=36000, end_usecs=100000,
|
||||
use_initial=True, generate_code=False,
|
||||
verbose=False, output=output)
|
||||
self.assertEqual(
|
||||
output.getvalue(),
|
||||
"Pronto code = "
|
||||
@ -42,8 +44,9 @@ class TestRawToPronto(unittest.TestCase):
|
||||
input_str = """
|
||||
uint16_t rawData[7] = {
|
||||
20100, 20472, 15092, 30704, 20102, 20472, 15086};"""
|
||||
pronto.parse_and_report(input_str, 57600, 100000, True, False, False,
|
||||
output)
|
||||
pronto.parse_and_report(input_str, hertz=57600, end_usecs=100000,
|
||||
use_initial=True, generate_code=False,
|
||||
verbose=False, output=output)
|
||||
self.assertEqual(
|
||||
output.getvalue(),
|
||||
"Pronto code = "
|
||||
@ -56,8 +59,9 @@ class TestRawToPronto(unittest.TestCase):
|
||||
input_str = """
|
||||
uint16_t rawData[7] = {
|
||||
20100, 20472, 15092, 30704, 20102, 20472, 15086};"""
|
||||
pronto.parse_and_report(input_str, 38000, 30000, False, False, False,
|
||||
output)
|
||||
pronto.parse_and_report(input_str, hertz=38000, end_usecs=30000,
|
||||
use_initial=False, generate_code=False,
|
||||
verbose=False, output=output)
|
||||
self.assertEqual(
|
||||
output.getvalue(),
|
||||
"Pronto code = "
|
||||
@ -70,7 +74,9 @@ class TestRawToPronto(unittest.TestCase):
|
||||
input_str = """
|
||||
uint16_t rawData[7] = {
|
||||
20100, 20472, 15092, 30704, 20102, 20472, 15086};"""
|
||||
pronto.parse_and_report(input_str, 38000, 30000, True, True, False, output)
|
||||
pronto.parse_and_report(input_str, 38000, end_usecs=30000,
|
||||
use_initial=True, generate_code=True,
|
||||
verbose=False, output=output)
|
||||
self.assertEqual(
|
||||
output.getvalue(),
|
||||
"uint16_t pronto[12] = {0x0000, 0x006D, 0x0004, 0x0000, 0x02fb, "
|
||||
|
||||
Loading…
Reference in New Issue
Block a user