From b9a0581280e66d8b55df84ff9e169cc93a0e509b Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sun, 31 Mar 2019 13:06:42 +0200 Subject: [PATCH] Fix parameter exceptions (#5555) Fix parameter exceptions (#5555) --- sonoff/xdrv_05_irremote.ino | 261 +++++++++++++++++++----------------- 1 file changed, 141 insertions(+), 120 deletions(-) diff --git a/sonoff/xdrv_05_irremote.ino b/sonoff/xdrv_05_irremote.ino index 864d77e8c..d62be8ee3 100644 --- a/sonoff/xdrv_05_irremote.ino +++ b/sonoff/xdrv_05_irremote.ino @@ -26,6 +26,8 @@ #include +enum IrErrors { IE_NO_ERROR, IE_INVALID_RAWDATA, IE_INVALID_JSON, IE_SYNTAX_IRSEND, IE_SYNTAX_IRHVAC }; + enum IrRemoteCommands { CMND_IRSEND, CMND_IRHVAC }; const char kIrRemoteCommands[] PROGMEM = D_CMND_IRSEND "|" D_CMND_IRHVAC ; @@ -180,7 +182,7 @@ void IrReceiveCheck(void) TOSHIBA ********************/ -bool IrHvacToshiba(const char *HVAC_Mode, const char *HVAC_FanMode, bool HVAC_Power, int HVAC_Temp) +uint8_t IrHvacToshiba(const char *HVAC_Mode, const char *HVAC_FanMode, bool HVAC_Power, int HVAC_Temp) { uint16_t rawdata[2 + 2 * 8 * HVAC_TOSHIBA_DATALEN + 2]; uint8_t data[HVAC_TOSHIBA_DATALEN] = {0xF2, 0x0D, 0x03, 0xFC, 0x01, 0x00, 0x00, 0x00, 0x00}; @@ -195,7 +197,7 @@ bool IrHvacToshiba(const char *HVAC_Mode, const char *HVAC_FanMode, bool HVAC_Po p = strchr(kHvacModeOptions, toupper(HVAC_Mode[0])); } if (!p) { - return true; + return IE_SYNTAX_IRHVAC; } data[6] = (p - kHvacModeOptions) ^ 0x03; // HOT = 0x03, DRY = 0x02, COOL = 0x01, AUTO = 0x00 @@ -210,7 +212,7 @@ bool IrHvacToshiba(const char *HVAC_Mode, const char *HVAC_FanMode, bool HVAC_Po p = strchr(kFanSpeedOptions, toupper(HVAC_FanMode[0])); } if (!p) { - return true; + return IE_SYNTAX_IRHVAC; } mode = p - kFanSpeedOptions + 1; if ((1 == mode) || (7 == mode)) { @@ -267,7 +269,7 @@ bool IrHvacToshiba(const char *HVAC_Mode, const char *HVAC_FanMode, bool HVAC_Po irsend->sendRaw(rawdata, i, 38); // interrupts(); - return false; + return IE_NO_ERROR; } @@ -275,7 +277,7 @@ bool IrHvacToshiba(const char *HVAC_Mode, const char *HVAC_FanMode, bool HVAC_Po MITSUBISHI ********************/ -bool IrHvacMitsubishi(const char *HVAC_Mode, const char *HVAC_FanMode, bool HVAC_Power, int HVAC_Temp) +uint8_t IrHvacMitsubishi(const char *HVAC_Mode, const char *HVAC_FanMode, bool HVAC_Power, int HVAC_Temp) { char *p; uint8_t mode; @@ -289,7 +291,7 @@ bool IrHvacMitsubishi(const char *HVAC_Mode, const char *HVAC_FanMode, bool HVAC p = strchr(kHvacModeOptions, toupper(HVAC_Mode[0])); } if (!p) { - return true; + return IE_SYNTAX_IRHVAC; } mode = (p - kHvacModeOptions + 1) << 3; // HOT = 0x08, DRY = 0x10, COOL = 0x18, AUTO = 0x20 mitsubir->setMode(mode); @@ -303,7 +305,7 @@ bool IrHvacMitsubishi(const char *HVAC_Mode, const char *HVAC_FanMode, bool HVAC p = strchr(kFanSpeedOptions, toupper(HVAC_FanMode[0])); } if (!p) { - return true; + return IE_SYNTAX_IRHVAC; } mode = p - kFanSpeedOptions; // AUTO = 0, SPEED = 1 .. 5, SILENT = 6 mitsubir->setFan(mode); @@ -315,7 +317,7 @@ bool IrHvacMitsubishi(const char *HVAC_Mode, const char *HVAC_FanMode, bool HVAC // AddLog_P2(LOG_LEVEL_DEBUG, PSTR("IRHVAC: Mitsubishi Power %d, Mode %d, FanSpeed %d, Temp %d, VaneMode %d"), // mitsubir->getPower(), mitsubir->getMode(), mitsubir->getFan(), mitsubir->getTemp(), mitsubir->getVane()); - return false; + return IE_NO_ERROR; } @@ -323,7 +325,7 @@ bool IrHvacMitsubishi(const char *HVAC_Mode, const char *HVAC_FanMode, bool HVAC LG ********************/ -bool IrHvacLG(const char *HVAC_Mode, const char *HVAC_FanMode, bool HVAC_Power, int HVAC_Temp) +uint8_t IrHvacLG(const char *HVAC_Mode, const char *HVAC_FanMode, bool HVAC_Power, int HVAC_Temp) { uint32_t LG_Code; uint8_t data[HVAC_LG_DATALEN]; @@ -356,7 +358,7 @@ bool IrHvacLG(const char *HVAC_Mode, const char *HVAC_FanMode, bool HVAC_Power, p = strchr(kHvacModeOptions, toupper(HVAC_Mode[0])); } if (!p) { - return true; + return IE_SYNTAX_IRHVAC; } mode = (p - kHvacModeOptions) ^ 0x03; // HOT = 0x03, DRY = 0x02, COOL = 0x01, AUTO = 0x00 switch (mode) { @@ -400,7 +402,7 @@ bool IrHvacLG(const char *HVAC_Mode, const char *HVAC_FanMode, bool HVAC_Power, p = strchr(kFanSpeedOptions, toupper(HVAC_FanMode[0])); } if (!p) { - return true; + return IE_SYNTAX_IRHVAC; } mode = p - kFanSpeedOptions; if ((mode == 0) || (mode > 3)) { @@ -431,7 +433,7 @@ bool IrHvacLG(const char *HVAC_Mode, const char *HVAC_FanMode, bool HVAC_Power, irsend->sendLG(LG_Code, 28); // interrupts(); - return false; + return IE_NO_ERROR; } @@ -439,7 +441,7 @@ bool IrHvacLG(const char *HVAC_Mode, const char *HVAC_FanMode, bool HVAC_Power, Fujitsu ********************/ -bool IrHvacFujitsu(const char *HVAC_Mode, const char *HVAC_FanMode, bool HVAC_Power, int HVAC_Temp) +uint8_t IrHvacFujitsu(const char *HVAC_Mode, const char *HVAC_FanMode, bool HVAC_Power, int HVAC_Temp) { const char kFujitsuHvacModeOptions[] = "HDCAF"; @@ -452,7 +454,7 @@ bool IrHvacFujitsu(const char *HVAC_Mode, const char *HVAC_FanMode, bool HVAC_Po if (0 == HVAC_Power) { ac.off(); ac.send(); - return false; + return IE_NO_ERROR; } uint8_t modes[5] = {FUJITSU_AC_MODE_HEAT, FUJITSU_AC_MODE_DRY, FUJITSU_AC_MODE_COOL, FUJITSU_AC_MODE_AUTO, FUJITSU_AC_MODE_FAN}; @@ -468,7 +470,7 @@ bool IrHvacFujitsu(const char *HVAC_Mode, const char *HVAC_FanMode, bool HVAC_Po p = strchr(kFujitsuHvacModeOptions, toupper(HVAC_Mode[0])); } if (!p) { - return true; + return IE_SYNTAX_IRHVAC; } ac.setMode(modes[p - kFujitsuHvacModeOptions]); @@ -479,14 +481,14 @@ bool IrHvacFujitsu(const char *HVAC_Mode, const char *HVAC_FanMode, bool HVAC_Po p = strchr(kFanSpeedOptions, toupper(HVAC_FanMode[0])); } if (!p) { - return true; + return IE_SYNTAX_IRHVAC; } ac.setFanSpeed(fanModes[p - kFanSpeedOptions]); ac.setTemp(HVAC_Temp); ac.send(); - return false; + return IE_NO_ERROR; } #endif // USE_IR_HVAC @@ -507,7 +509,7 @@ bool IrSendCommand(void) { char command [CMDSZ]; bool serviced = true; - bool error = false; + uint8_t error = IE_NO_ERROR; int command_code = GetCommandCode(command, sizeof(command), XdrvMailbox.topic, kIrRemoteCommands); if (-1 == command_code) { @@ -521,86 +523,87 @@ bool IrSendCommand(void) // IRSend frequency, rawdata, rawdata ... char *p; char *str = strtok_r(XdrvMailbox.data, ", ", &p); - uint16_t freq = atoi(str); - if (!freq) { freq = 38000; } // Default to 38kHz - uint16_t count = 0; - char *q = p; - for (; *q; count += (*q++ == ',')); - if (count) { // At least two raw data values - count++; - uint16_t raw_array[count]; // It's safe to use stack for up to 240 packets (limited by mqtt_data length) - uint8_t i = 0; - for (str = strtok_r(nullptr, ", ", &p); str && i < count; str = strtok_r(nullptr, ", ", &p)) { - raw_array[i++] = strtoul(str, nullptr, 0); // Allow decimal (5246996) and hexadecimal (0x501014) input - } + if (p == nullptr) { + error = IE_INVALID_RAWDATA; + } else { + uint16_t freq = atoi(str); + if (!freq) { freq = 38000; } // Default to 38kHz + uint16_t count = 0; + char *q = p; + for (; *q; count += (*q++ == ',')); + if (0 == count) { + error = IE_INVALID_RAWDATA; + } else { // At least two raw data values + count++; + uint16_t raw_array[count]; // It's safe to use stack for up to 240 packets (limited by mqtt_data length) + uint8_t i = 0; + for (str = strtok_r(nullptr, ", ", &p); str && i < count; str = strtok_r(nullptr, ", ", &p)) { + raw_array[i++] = strtoul(str, nullptr, 0); // Allow decimal (5246996) and hexadecimal (0x501014) input + } -// AddLog_P2(LOG_LEVEL_DEBUG, PSTR("IRS: Count %d, Freq %d, Arr[0] %d, Arr[count -1] %d"), count, freq, raw_array[0], raw_array[count -1]); - - irsend_active = true; - irsend->sendRaw(raw_array, count, freq); - if (!count) { - Response_P(S_JSON_COMMAND_SVALUE, command, D_JSON_FAILED); - } - } - else { - Response_P(S_JSON_COMMAND_SVALUE, command, D_JSON_INVALID_RAWDATA); - } - } - else { - char dataBufUc[XdrvMailbox.data_len]; - UpperCase(dataBufUc, XdrvMailbox.data); - StaticJsonBuffer<128> jsonBuf; - JsonObject &root = jsonBuf.parseObject(dataBufUc); - if (!root.success()) { - Response_P(S_JSON_COMMAND_SVALUE, command, D_JSON_INVALID_JSON); - } - else { - // IRsend { "protocol": "SAMSUNG", "bits": 32, "data": 551502015 } - char parm_uc[10]; - const char *protocol = root[UpperCase_P(parm_uc, PSTR(D_JSON_IR_PROTOCOL))]; - uint32_t bits = root[UpperCase_P(parm_uc, PSTR(D_JSON_IR_BITS))]; - uint32_t data = strtoul(root[UpperCase_P(parm_uc, PSTR(D_JSON_IR_DATA))], nullptr, 0); - if (protocol && bits) { - char protocol_text[20]; - int protocol_code = GetCommandCode(protocol_text, sizeof(protocol_text), protocol, kIrRemoteProtocols); - - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("IRS: protocol_text %s, protocol %s, bits %d, data %u (0x%lX), protocol_code %d"), - protocol_text, protocol, bits, data, data, protocol_code); +// AddLog_P2(LOG_LEVEL_DEBUG, PSTR("IRS: Count %d, Freq %d, Arr[0] %d, Arr[count -1] %d"), count, freq, raw_array[0], raw_array[count -1]); irsend_active = true; - switch (protocol_code) { - case NEC: - irsend->sendNEC(data, (bits > NEC_BITS) ? NEC_BITS : bits); break; - case SONY: - irsend->sendSony(data, (bits > SONY_20_BITS) ? SONY_20_BITS : bits, 2); break; - case RC5: - irsend->sendRC5(data, bits); break; - case RC6: - irsend->sendRC6(data, bits); break; - case DISH: - irsend->sendDISH(data, (bits > DISH_BITS) ? DISH_BITS : bits); break; - case JVC: - irsend->sendJVC(data, (bits > JVC_BITS) ? JVC_BITS : bits, 1); break; - case SAMSUNG: - irsend->sendSAMSUNG(data, (bits > SAMSUNG_BITS) ? SAMSUNG_BITS : bits); break; - case PANASONIC: - irsend->sendPanasonic(bits, data); break; - default: - irsend_active = false; - Response_P(S_JSON_COMMAND_SVALUE, command, D_JSON_PROTOCOL_NOT_SUPPORTED); + irsend->sendRaw(raw_array, count, freq); + if (!count) { + Response_P(S_JSON_COMMAND_SVALUE, command, D_JSON_FAILED); } } - else { - error = true; + } + } else { + char dataBufUc[XdrvMailbox.data_len]; + UpperCase(dataBufUc, XdrvMailbox.data); + RemoveSpace(dataBufUc); + if (strlen(dataBufUc) < 8) { + error = IE_INVALID_JSON; + } else { + StaticJsonBuffer<128> jsonBuf; + JsonObject &root = jsonBuf.parseObject(dataBufUc); + if (!root.success()) { + error = IE_INVALID_JSON; + } else { + // IRsend { "protocol": "SAMSUNG", "bits": 32, "data": 551502015 } + char parm_uc[10]; + const char *protocol = root[UpperCase_P(parm_uc, PSTR(D_JSON_IR_PROTOCOL))]; + uint32_t bits = root[UpperCase_P(parm_uc, PSTR(D_JSON_IR_BITS))]; + uint32_t data = strtoul(root[UpperCase_P(parm_uc, PSTR(D_JSON_IR_DATA))], nullptr, 0); + if (protocol && bits) { + char protocol_text[20]; + int protocol_code = GetCommandCode(protocol_text, sizeof(protocol_text), protocol, kIrRemoteProtocols); + + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("IRS: protocol_text %s, protocol %s, bits %d, data %u (0x%lX), protocol_code %d"), + protocol_text, protocol, bits, data, data, protocol_code); + + irsend_active = true; + switch (protocol_code) { + case NEC: + irsend->sendNEC(data, (bits > NEC_BITS) ? NEC_BITS : bits); break; + case SONY: + irsend->sendSony(data, (bits > SONY_20_BITS) ? SONY_20_BITS : bits, 2); break; + case RC5: + irsend->sendRC5(data, bits); break; + case RC6: + irsend->sendRC6(data, bits); break; + case DISH: + irsend->sendDISH(data, (bits > DISH_BITS) ? DISH_BITS : bits); break; + case JVC: + irsend->sendJVC(data, (bits > JVC_BITS) ? JVC_BITS : bits, 1); break; + case SAMSUNG: + irsend->sendSAMSUNG(data, (bits > SAMSUNG_BITS) ? SAMSUNG_BITS : bits); break; + case PANASONIC: + irsend->sendPanasonic(bits, data); break; + default: + irsend_active = false; + Response_P(S_JSON_COMMAND_SVALUE, command, D_JSON_PROTOCOL_NOT_SUPPORTED); + } + } else { + error = IE_SYNTAX_IRSEND; + } } } } - } - else { - error = true; - } - if (error) { - Response_P(PSTR("{\"" D_CMND_IRSEND "\":\"" D_JSON_NO " " D_JSON_IR_PROTOCOL ", " D_JSON_IR_BITS " " D_JSON_OR " " D_JSON_IR_DATA "\"}")); + } else { + error = IE_SYNTAX_IRSEND; } } #ifdef USE_IR_HVAC @@ -614,47 +617,65 @@ bool IrSendCommand(void) if (XdrvMailbox.data_len) { char dataBufUc[XdrvMailbox.data_len]; UpperCase(dataBufUc, XdrvMailbox.data); - StaticJsonBuffer<164> jsonBufer; - JsonObject &root = jsonBufer.parseObject(dataBufUc); - if (!root.success()) { - Response_P(S_JSON_COMMAND_SVALUE, command, D_JSON_INVALID_JSON); - } - else { - Response_P(S_JSON_COMMAND_SVALUE, command, D_JSON_DONE); - HVAC_Vendor = root[D_JSON_IRHVAC_VENDOR]; - HVAC_Power = root[D_JSON_IRHVAC_POWER]; - HVAC_Mode = root[D_JSON_IRHVAC_MODE]; - HVAC_FanMode = root[D_JSON_IRHVAC_FANSPEED]; - HVAC_Temp = root[D_JSON_IRHVAC_TEMP]; + RemoveSpace(dataBufUc); + if (strlen(dataBufUc) < 8) { + error = IE_INVALID_JSON; + } else { + StaticJsonBuffer<164> jsonBufer; + JsonObject &root = jsonBufer.parseObject(dataBufUc); + if (!root.success()) { + error = IE_INVALID_JSON; + } else { + Response_P(S_JSON_COMMAND_SVALUE, command, D_JSON_DONE); + HVAC_Vendor = root[D_JSON_IRHVAC_VENDOR]; + HVAC_Power = root[D_JSON_IRHVAC_POWER]; + HVAC_Mode = root[D_JSON_IRHVAC_MODE]; + HVAC_FanMode = root[D_JSON_IRHVAC_FANSPEED]; + HVAC_Temp = root[D_JSON_IRHVAC_TEMP]; -// AddLog_P2(LOG_LEVEL_DEBUG, PSTR("IRHVAC: Received Vendor %s, Power %d, Mode %s, FanSpeed %s, Temp %d"), HVAC_Vendor, HVAC_Power, HVAC_Mode, HVAC_FanMode, HVAC_Temp); + // AddLog_P2(LOG_LEVEL_DEBUG, PSTR("IRHVAC: Received Vendor %s, Power %d, Mode %s, FanSpeed %s, Temp %d"), HVAC_Vendor, HVAC_Power, HVAC_Mode, HVAC_FanMode, HVAC_Temp); - char vendor[20]; - int vendor_code = GetCommandCode(vendor, sizeof(vendor), HVAC_Vendor, kIrHvacVendors); - switch (vendor_code) { - case VNDR_TOSHIBA: - error = IrHvacToshiba(HVAC_Mode, HVAC_FanMode, HVAC_Power, HVAC_Temp); break; - case VNDR_MITSUBISHI: - error = IrHvacMitsubishi(HVAC_Mode, HVAC_FanMode, HVAC_Power, HVAC_Temp); break; - case VNDR_LG: - error = IrHvacLG(HVAC_Mode, HVAC_FanMode, HVAC_Power, HVAC_Temp); break; - case VNDR_FUJITSU: - error = IrHvacFujitsu(HVAC_Mode, HVAC_FanMode, HVAC_Power, HVAC_Temp); break; - default: - error = true; + char vendor[20]; + int vendor_code = GetCommandCode(vendor, sizeof(vendor), HVAC_Vendor, kIrHvacVendors); + switch (vendor_code) { + case VNDR_TOSHIBA: + error = IrHvacToshiba(HVAC_Mode, HVAC_FanMode, HVAC_Power, HVAC_Temp); break; + case VNDR_MITSUBISHI: + error = IrHvacMitsubishi(HVAC_Mode, HVAC_FanMode, HVAC_Power, HVAC_Temp); break; + case VNDR_LG: + error = IrHvacLG(HVAC_Mode, HVAC_FanMode, HVAC_Power, HVAC_Temp); break; + case VNDR_FUJITSU: + error = IrHvacFujitsu(HVAC_Mode, HVAC_FanMode, HVAC_Power, HVAC_Temp); break; + default: + error = IE_SYNTAX_IRHVAC; + } } } } else { - error = true; - } - if (error) { - Response_P(PSTR("{\"" D_CMND_IRHVAC "\":\"" D_JSON_WRONG " " D_JSON_IRHVAC_VENDOR ", " D_JSON_IRHVAC_MODE " " D_JSON_OR " " D_JSON_IRHVAC_FANSPEED "\"}")); + error = IE_SYNTAX_IRHVAC; } } #endif // USE_IR_HVAC else serviced = false; // Unknown command + switch (error) { + case IE_INVALID_RAWDATA: + Response_P(S_JSON_COMMAND_SVALUE, command, D_JSON_INVALID_RAWDATA); + break; + case IE_INVALID_JSON: + Response_P(S_JSON_COMMAND_SVALUE, command, D_JSON_INVALID_JSON); + break; + case IE_SYNTAX_IRSEND: + Response_P(PSTR("{\"" D_CMND_IRSEND "\":\"" D_JSON_NO " " D_JSON_IR_PROTOCOL ", " D_JSON_IR_BITS " " D_JSON_OR " " D_JSON_IR_DATA "\"}")); + break; +#ifdef USE_IR_HVAC + case IE_SYNTAX_IRHVAC: + Response_P(PSTR("{\"" D_CMND_IRHVAC "\":\"" D_JSON_WRONG " " D_JSON_IRHVAC_VENDOR ", " D_JSON_IRHVAC_MODE " " D_JSON_OR " " D_JSON_IRHVAC_FANSPEED "\"}")); + break; +#endif // USE_IR_HVAC + } + return serviced; }