Fix parameter exceptions (#5555)

Fix parameter exceptions (#5555)
This commit is contained in:
Theo Arends 2019-03-31 13:06:42 +02:00
parent f7c30250c1
commit b9a0581280
1 changed files with 141 additions and 120 deletions

View File

@ -26,6 +26,8 @@
#include <IRremoteESP8266.h>
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;
}