Skip to content

Commit

Permalink
rewrite ir_Corona (#1274)
Browse files Browse the repository at this point in the history
* rewrite ir_Corona

* follow the suggestions
  • Loading branch information
siriuslzx authored Sep 20, 2020
1 parent 30be145 commit a49527f
Show file tree
Hide file tree
Showing 3 changed files with 132 additions and 147 deletions.
171 changes: 74 additions & 97 deletions src/ir_Corona.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ using irutils::addModeToString;
using irutils::addTempToString;
using irutils::addFanToString;
using irutils::minsToString;
using irutils::setBit;
using irutils::setBits;

// Constants
Expand Down Expand Up @@ -154,15 +153,15 @@ IRCoronaAc::IRCoronaAc(const uint16_t pin, const bool inverted,
/// @note The state is powered off.
void IRCoronaAc::stateReset(void) {
// known good state
remote_state[kCoronaAcSectionData0Pos] = kCoronaAcSectionData0Base;
remote_state[kCoronaAcSectionData1Pos] = 0x00; // ensure no unset mem
_.sections[kCoronaAcSettingsSection].Data0 = kCoronaAcSectionData0Base;
_.sections[kCoronaAcSettingsSection].Data1 = 0x00; // ensure no unset mem
setPowerButton(true); // we default to this on, any timer removes it
setTemp(kCoronaAcMinTemp);
setMode(kCoronaAcModeCool);
setFan(kCoronaAcFanAuto);
setOnTimer(kCoronaAcTimerOff);
setOffTimer(kCoronaAcTimerOff);
// headers and checks are fixed in getRaw by checksum(remote_state)
// headers and checks are fixed in getRaw by checksum(_.raw)
}

/// Get the byte that identifies the section
Expand Down Expand Up @@ -191,45 +190,46 @@ bool IRCoronaAc::validSection(const uint8_t state[], const uint16_t pos,
if ((section % kCoronaAcSections) * kCoronaAcSectionBytes != pos)
return false;
// all individual sections has the same prefix
if (state[pos + kCoronaAcSectionHeader0Pos] != kCoronaAcSectionHeader0) {
const CoronaSection *p = reinterpret_cast<const CoronaSection*>(state + pos);
if (p->Header0 != kCoronaAcSectionHeader0) {
DPRINT("State ");
DPRINT(pos + kCoronaAcSectionHeader0Pos);
DPRINT(&(p->Header0) - state);
DPRINT(" expected 0x28 was ");
DPRINTLN(uint64ToString(state[pos + kCoronaAcSectionHeader0Pos], 16));
DPRINTLN(uint64ToString(p->Header0, 16));
return false;
}
if (state[pos + kCoronaAcSectionHeader1Pos] != kCoronaAcSectionHeader1) {
if (p->Header1 != kCoronaAcSectionHeader1) {
DPRINT("State ");
DPRINT(pos + kCoronaAcSectionHeader1Pos);
DPRINT(&(p->Header1) - state);
DPRINT(" expected 0x61 was ");
DPRINTLN(uint64ToString(state[pos + kCoronaAcSectionHeader1Pos], 16));
DPRINTLN(uint64ToString(p->Header1, 16));
return false;
}

// checking section byte
if (state[pos + kCoronaAcSectionLabelPos] != getSectionByte(section)) {
if (p->Label != getSectionByte(section)) {
DPRINT("check 2 not matching, got ");
DPRINT(uint64ToString(state[pos + kCoronaAcSectionLabelPos], 16));
DPRINT(uint64ToString(p->Label, 16));
DPRINT(" expected ");
DPRINTLN(uint64ToString(getSectionByte(section), 16));
return false;
}

// checking inverts
uint8_t d0invinv = ~state[pos + kCoronaAcSectionData0InvPos];
if (state[pos + kCoronaAcSectionData0Pos] != d0invinv) {
uint8_t d0invinv = ~p->Data0Inv;
if (p->Data0 != d0invinv) {
DPRINT("inverted 3 - 4 not matching, got ");
DPRINT(uint64ToString(state[pos + kCoronaAcSectionData0Pos], 16));
DPRINT(uint64ToString(p->Data0, 16));
DPRINT(" vs ");
DPRINTLN(uint64ToString(state[pos + kCoronaAcSectionData0InvPos], 16));
DPRINTLN(uint64ToString(p->Data0Inv, 16));
return false;
}
uint8_t d1invinv = ~state[pos + kCoronaAcSectionData1InvPos];
if (state[pos + kCoronaAcSectionData1Pos] != d1invinv) {
uint8_t d1invinv = ~p->Data1Inv;
if (p->Data1 != d1invinv) {
DPRINT("inverted 5 - 6 not matching, got ");
DPRINT(uint64ToString(state[pos + kCoronaAcSectionData1Pos], 16));
DPRINT(uint64ToString(p->Data1, 16));
DPRINT(" vs ");
DPRINTLN(uint64ToString(state[pos + kCoronaAcSectionData1InvPos], 16));
DPRINTLN(uint64ToString(p->Data1Inv, 16));
return false;
}
return true;
Expand All @@ -238,16 +238,13 @@ bool IRCoronaAc::validSection(const uint8_t state[], const uint16_t pos,
/// Calculate and set the check values for the internal state.
/// @param[in,out] data The array to be modified
void IRCoronaAc::checksum(uint8_t* data) {
uint8_t pos;
for (uint8_t section = 0; section < kCoronaAcSections; section++) {
pos = section * kCoronaAcSectionBytes;
data[pos + kCoronaAcSectionHeader0Pos] = kCoronaAcSectionHeader0;
data[pos + kCoronaAcSectionHeader1Pos] = kCoronaAcSectionHeader1;
data[pos + kCoronaAcSectionLabelPos] = getSectionByte(section);
data[pos + kCoronaAcSectionData0InvPos] =
~data[pos + kCoronaAcSectionData0Pos];
data[pos + kCoronaAcSectionData1InvPos] =
~data[pos + kCoronaAcSectionData1Pos];
CoronaProtocol *p = reinterpret_cast<CoronaProtocol*>(data);
for (uint8_t i = 0; i < kCoronaAcSections; i++) {
p->sections[i].Header0 = kCoronaAcSectionHeader0;
p->sections[i].Header1 = kCoronaAcSectionHeader1;
p->sections[i].Label = getSectionByte(i);
p->sections[i].Data0Inv = ~p->sections[i].Data0;
p->sections[i].Data1Inv = ~p->sections[i].Data1;
}
}

Expand Down Expand Up @@ -275,45 +272,37 @@ void IRCoronaAc::send(const uint16_t repeat) {
/// @note To get stable AC state, if no timers, send once
/// without PowerButton set, and once with
uint8_t* IRCoronaAc::getRaw(void) {
checksum(remote_state); // Ensure correct check bits before sending.
return remote_state;
checksum(_.raw); // Ensure correct check bits before sending.
return _.raw;
}

/// Set the internal state from a valid code for this protocol.
/// @param[in] new_code A valid state for this protocol.
/// @param[in] length of the new_code array.
void IRCoronaAc::setRaw(const uint8_t new_code[], const uint16_t length) {
memcpy(remote_state, new_code, std::min(length, kCoronaAcStateLength));
memcpy(_.raw, new_code, std::min(length, kCoronaAcStateLength));
}

/// Set the temp in deg C.
/// @param[in] temp The desired temperature in Celsius.
void IRCoronaAc::setTemp(const uint8_t temp) {
uint8_t degrees = std::max(temp, kCoronaAcMinTemp);
degrees = std::min(degrees, kCoronaAcMaxTemp);
setBits(&remote_state[kCoronaAcSectionData1Pos], kCoronaAcTempOffset,
kCoronaAcTempSize, degrees - kCoronaAcMinTemp + 1);
_.Temp = degrees - kCoronaAcMinTemp + 1;
}

/// Get the current temperature from the internal state.
/// @return The current temperature in Celsius.
uint8_t IRCoronaAc::getTemp(void) {
return GETBITS8(remote_state[kCoronaAcSectionData1Pos], kCoronaAcTempOffset,
kCoronaAcTempSize) + kCoronaAcMinTemp - 1;
}

/// Change the power setting. (in practice Standby, remote power)
/// @param[in] on true, the setting is on. false, the setting is off.
void IRCoronaAc::_setPower(const bool on) {
setBit(&remote_state[kCoronaAcSectionData1Pos], kCoronaAcPowerOffset, on);
uint8_t IRCoronaAc::getTemp(void) const {
return _.Temp + kCoronaAcMinTemp - 1;
}

/// Change the power setting. (in practice Standby, remote power)
/// @param[in] on true, the setting is on. false, the setting is off.
/// @note If changed, setPowerButton is also needed,
/// unless timer is or was active
void IRCoronaAc::setPower(const bool on) {
_setPower(on);
_.Power = on;
// setting power state resets timers that would cause the state
if (on)
setOnTimer(kCoronaAcTimerOff);
Expand All @@ -323,8 +312,8 @@ void IRCoronaAc::setPower(const bool on) {

/// Get the current power setting. (in practice Standby, remote power)
/// @return true, the setting is on. false, the setting is off.
bool IRCoronaAc::getPower(void) {
return GETBIT8(remote_state[kCoronaAcSectionData1Pos], kCoronaAcPowerOffset);
bool IRCoronaAc::getPower(void) const {
return _.Power;
}

/// Change the power button setting.
Expand All @@ -337,15 +326,13 @@ bool IRCoronaAc::getPower(void) {
/// With AC Off, a command with setPower but not setPowerButton gives nothing
/// With AC Off, a command with setPower and setPowerButton is ok
void IRCoronaAc::setPowerButton(const bool on) {
setBit(&remote_state[kCoronaAcSectionData1Pos],
kCoronaAcPowerButtonOffset, on);
_.PowerButton = on;
}

/// Get the value of the current power button setting.
/// @return true, the setting is on. false, the setting is off.
bool IRCoronaAc::getPowerButton(void) {
return GETBIT8(remote_state[kCoronaAcSectionData1Pos],
kCoronaAcPowerButtonOffset);
bool IRCoronaAc::getPowerButton(void) const {
return _.PowerButton;
}

/// Change the power setting to On.
Expand All @@ -356,9 +343,8 @@ void IRCoronaAc::off(void) { setPower(false); }

/// Get the operating mode setting of the A/C.
/// @return The current operating mode setting.
uint8_t IRCoronaAc::getMode(void) {
return GETBITS8(remote_state[kCoronaAcSectionData1Pos],
kCoronaAcModeOffset, kCoronaAcModeSize);
uint8_t IRCoronaAc::getMode(void) const {
return _.Mode;
}

/// Set the operating mode of the A/C.
Expand All @@ -369,12 +355,10 @@ void IRCoronaAc::setMode(const uint8_t mode) {
case kCoronaAcModeDry:
case kCoronaAcModeFan:
case kCoronaAcModeHeat:
setBits(&remote_state[kCoronaAcSectionData1Pos],
kCoronaAcModeOffset, kCoronaAcModeSize,
mode);
_.Mode = mode;
return;
default:
this->setMode(kCoronaAcModeCool);
_.Mode = kCoronaAcModeCool;
}
}

Expand Down Expand Up @@ -405,32 +389,29 @@ stdAc::opmode_t IRCoronaAc::toCommonMode(const uint8_t mode) {

/// Get the operating speed of the A/C Fan
/// @return The current operating fan speed setting
uint8_t IRCoronaAc::getFan(void) {
return GETBITS8(remote_state[kCoronaAcSectionData0Pos],
kCoronaAcFanOffset, kCoronaAcFanSize);
uint8_t IRCoronaAc::getFan(void) const {
return _.Fan;
}

/// Set the operating speed of the A/C Fan
/// @param[in] speed The desired fan speed
void IRCoronaAc::setFan(const uint8_t speed) {
if (speed > kCoronaAcFanHigh)
setFan(kCoronaAcFanAuto);
_.Fan = kCoronaAcFanAuto;
else
setBits(&remote_state[kCoronaAcSectionData0Pos],
kCoronaAcFanOffset, kCoronaAcFanSize, speed);
_.Fan = speed;
}

/// Change the powersave setting.
/// @param[in] on true, the setting is on. false, the setting is off.
void IRCoronaAc::setEcono(const bool on) {
setBit(&remote_state[kCoronaAcSectionData0Pos], kCoronaAcPowerSaveOffset, on);
_.Econo = on;
}

/// Get the value of the current powersave setting.
/// @return true, the setting is on. false, the setting is off.
bool IRCoronaAc::getEcono(void) {
return GETBIT8(remote_state[kCoronaAcSectionData0Pos],
kCoronaAcPowerSaveOffset);
bool IRCoronaAc::getEcono(void) const {
return _.Econo;
}

/// Convert a standard A/C Fan speed into its native fan speed.
Expand Down Expand Up @@ -464,15 +445,13 @@ stdAc::fanspeed_t IRCoronaAc::toCommonFanSpeed(const uint8_t speed) {
/// @note This is a button press, and not a state
/// after sending it once you should turn it off
void IRCoronaAc::setSwingVToggle(const bool on) {
setBit(&remote_state[kCoronaAcSectionData0Pos],
kCoronaAcSwingVToggleOffset, on);
_.SwingVToggle = on;
}

/// Get the Vertical Swing toggle setting
/// @return true, the setting is on. false, the setting is off.
bool IRCoronaAc::getSwingVToggle(void) {
return GETBIT64(remote_state[kCoronaAcSectionData0Pos],
kCoronaAcSwingVToggleOffset);
bool IRCoronaAc::getSwingVToggle(void) const {
return _.SwingVToggle;
}

/// Set the Timer time
Expand All @@ -486,26 +465,24 @@ void IRCoronaAc::_setTimer(const uint8_t section, const uint16_t nr_of_mins) {
if (1 <= nr_of_mins && nr_of_mins <= kCoronaAcTimerMax)
hsecs = nr_of_mins * kCoronaAcTimerUnitsPerMin;

uint8_t pos = section * kCoronaAcSectionBytes;
// convert 16 bit value to separate 8 bit parts
remote_state[pos + kCoronaAcSectionData1Pos] = hsecs >> 8;
remote_state[pos + kCoronaAcSectionData0Pos] = hsecs;
_.sections[section].Data1 = hsecs >> 8;
_.sections[section].Data0 = hsecs;

// if any timer is enabled, then (remote) ac must be on (Standby)
if (hsecs != kCoronaAcTimerOff) {
_setPower(true);
_.Power = true;
setPowerButton(false);
}
}

/// Get the current Timer time
/// @return The number of minutes it is set for. 0 means it's off.
/// @note The A/C protocol supports 2 second increments
uint16_t IRCoronaAc::_getTimer(const uint8_t section) {
uint8_t pos = section * kCoronaAcSectionBytes;
uint16_t IRCoronaAc::_getTimer(const uint8_t section) const {
// combine separate 8 bit parts to 16 bit value
uint16_t hsecs = remote_state[pos + kCoronaAcSectionData1Pos] << 8 |
remote_state[pos + kCoronaAcSectionData0Pos];
uint16_t hsecs = _.sections[section].Data1 << 8 |
_.sections[section].Data0;

if (hsecs == kCoronaAcTimerOff)
return 0;
Expand All @@ -515,7 +492,7 @@ uint16_t IRCoronaAc::_getTimer(const uint8_t section) {

/// Get the current On Timer time
/// @return The number of minutes it is set for. 0 means it's off.
uint16_t IRCoronaAc::getOnTimer(void) {
uint16_t IRCoronaAc::getOnTimer(void) const {
return _getTimer(kCoronaAcOnTimerSection);
}

Expand All @@ -531,7 +508,7 @@ void IRCoronaAc::setOnTimer(const uint16_t nr_of_mins) {

/// Get the current Off Timer time
/// @return The number of minutes it is set for. 0 means it's off.
uint16_t IRCoronaAc::getOffTimer(void) {
uint16_t IRCoronaAc::getOffTimer(void) const {
return _getTimer(kCoronaAcOffTimerSection);
}

Expand All @@ -547,20 +524,20 @@ void IRCoronaAc::setOffTimer(const uint16_t nr_of_mins) {

/// Convert the internal state into a human readable string.
/// @return The current internal state expressed as a human readable String.
String IRCoronaAc::toString(void) {
String IRCoronaAc::toString(void) const {
String result = "";
result.reserve(140); // Reserve some heap for the string to reduce fragging.
result += addBoolToString(getPower(), kPowerStr, false);
result += addBoolToString(getPowerButton(), kPowerButtonStr);
result += addModeToString(getMode(), 0xFF, kCoronaAcModeCool,
result += addBoolToString(_.Power, kPowerStr, false);
result += addBoolToString(_.PowerButton, kPowerButtonStr);
result += addModeToString(_.Mode, 0xFF, kCoronaAcModeCool,
kCoronaAcModeHeat, kCoronaAcModeDry,
kCoronaAcModeFan);
result += addTempToString(getTemp());
result += addFanToString(getFan(), kCoronaAcFanHigh, kCoronaAcFanLow,
result += addFanToString(_.Fan, kCoronaAcFanHigh, kCoronaAcFanLow,
kCoronaAcFanAuto, kCoronaAcFanAuto,
kCoronaAcFanMedium);
result += addBoolToString(getSwingVToggle(), kSwingVToggleStr);
result += addBoolToString(getEcono(), kEconoStr);
result += addBoolToString(_.SwingVToggle, kSwingVToggleStr);
result += addBoolToString(_.Econo, kEconoStr);
result += addLabeledString(getOnTimer()
? minsToString(getOnTimer()) : kOffStr,
kOnTimerStr);
Expand All @@ -572,18 +549,18 @@ String IRCoronaAc::toString(void) {

/// Convert the A/C state to it's common stdAc::state_t equivalent.
/// @return A stdAc::state_t state.
stdAc::state_t IRCoronaAc::toCommon() {
stdAc::state_t IRCoronaAc::toCommon() const {
stdAc::state_t result;
result.protocol = decode_type_t::CORONA_AC;
result.model = -1; // No models used.
result.power = getPower();
result.mode = toCommonMode(getMode());
result.power = _.Power;
result.mode = toCommonMode(_.Mode);
result.celsius = true;
result.degrees = getTemp();
result.fanspeed = toCommonFanSpeed(getFan());
result.swingv = getSwingVToggle() ?
result.fanspeed = toCommonFanSpeed(_.Fan);
result.swingv = _.SwingVToggle ?
stdAc::swingv_t::kAuto : stdAc::swingv_t::kOff;
result.econo = getEcono();
result.econo = _.Econo;
// Not supported.
result.sleep = -1;
result.swingh = stdAc::swingh_t::kOff;
Expand Down
Loading

0 comments on commit a49527f

Please sign in to comment.