Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rewrite ir_Corona #1274

Merged
merged 2 commits into from
Sep 20, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
172 changes: 75 additions & 97 deletions src/ir_Corona.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@ using irutils::addModeToString;
using irutils::addTempToString;
using irutils::addFanToString;
using irutils::minsToString;
using irutils::setBit;
using irutils::setBits;

// Constants
const uint16_t kCoronaAcHdrMark = 3500;
Expand Down Expand Up @@ -154,15 +152,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
_.raw[kCoronaAcSectionData0Pos] = kCoronaAcSectionData0Base;
_.raw[kCoronaAcSectionData1Pos] = 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 All @@ -175,8 +173,7 @@ uint8_t IRCoronaAc::getSectionByte(const uint8_t section) {
// 2 enabled bits shifted 0-2 bits depending on section
if (section >= 3)
return 0b10010000 | b;
setBits(&b, kHighNibble, kNibbleSize, 0b11 << section);
return b;
return b | (0b11 << (section+kHighNibble));
crankyoldgit marked this conversation as resolved.
Show resolved Hide resolved
}

/// Check that a CoronaAc Section part is valid with section byte and inverted
Expand All @@ -191,45 +188,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) {
auto p = reinterpret_cast<const CoronaSection*>(state + pos);
crankyoldgit marked this conversation as resolved.
Show resolved Hide resolved
if (p->Header0 != kCoronaAcSectionHeader0) {
DPRINT("State ");
DPRINT(pos + kCoronaAcSectionHeader0Pos);
DPRINT(pos + offsetof(CoronaSection, Header0));
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->Data0;
if (p->Data0Inv != 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->Data1;
if (p->Data1Inv != 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 +236,14 @@ 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];
uint8_t* pos = data + section * kCoronaAcSectionBytes;
auto p = reinterpret_cast<CoronaSection*>(pos);
crankyoldgit marked this conversation as resolved.
Show resolved Hide resolved
p->Header0 = kCoronaAcSectionHeader0;
p->Header1 = kCoronaAcSectionHeader1;
p->Label = getSectionByte(section);
p->Data0Inv = ~p->Data0;
p->Data1Inv = ~p->Data1;
}
}

Expand Down Expand Up @@ -275,45 +271,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 +311,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 +325,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 +342,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 +354,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 +388,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 +444,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 @@ -488,24 +466,24 @@ void IRCoronaAc::_setTimer(const uint8_t section, const uint16_t nr_of_mins) {

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;
_.raw[pos + kCoronaAcSectionData1Pos] = hsecs >> 8;
_.raw[pos + kCoronaAcSectionData0Pos] = 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) {
uint16_t IRCoronaAc::_getTimer(const uint8_t section) const {
uint8_t pos = section * kCoronaAcSectionBytes;
// combine separate 8 bit parts to 16 bit value
uint16_t hsecs = remote_state[pos + kCoronaAcSectionData1Pos] << 8 |
remote_state[pos + kCoronaAcSectionData0Pos];
uint16_t hsecs = _.raw[pos + kCoronaAcSectionData1Pos] << 8 |
_.raw[pos + kCoronaAcSectionData0Pos];

if (hsecs == kCoronaAcTimerOff)
return 0;
Expand All @@ -515,7 +493,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 +509,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 +525,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 +550,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