Merge pull request #419 from MichaelDvP/v2

V2
This commit is contained in:
Proddy
2020-07-05 17:46:15 +02:00
committed by GitHub
10 changed files with 284 additions and 188 deletions

View File

@@ -54,6 +54,7 @@ Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_i
} else if ((flags == EMSdevice::EMS_DEVICE_FLAG_RC35) || (flags == EMSdevice::EMS_DEVICE_FLAG_RC30_1)) { } else if ((flags == EMSdevice::EMS_DEVICE_FLAG_RC35) || (flags == EMSdevice::EMS_DEVICE_FLAG_RC30_1)) {
monitor_typeids = {0x3E, 0x48, 0x52, 0x5C}; monitor_typeids = {0x3E, 0x48, 0x52, 0x5C};
set_typeids = {0x3D, 0x47, 0x51, 0x5B}; set_typeids = {0x3D, 0x47, 0x51, 0x5B};
timer_typeids = {0x3F, 0x49, 0x53, 0x5D};
for (uint8_t i = 0; i < monitor_typeids.size(); i++) { for (uint8_t i = 0; i < monitor_typeids.size(); i++) {
register_telegram_type(monitor_typeids[i], F("RC35Monitor"), false, std::bind(&Thermostat::process_RC35Monitor, this, _1)); register_telegram_type(monitor_typeids[i], F("RC35Monitor"), false, std::bind(&Thermostat::process_RC35Monitor, this, _1));
register_telegram_type(set_typeids[i], F("RC35Set"), false, std::bind(&Thermostat::process_RC35Set, this, _1)); register_telegram_type(set_typeids[i], F("RC35Set"), false, std::bind(&Thermostat::process_RC35Set, this, _1));
@@ -230,7 +231,8 @@ void Thermostat::add_context_menu() {
} }
// general MQTT command for controlling thermostat // general MQTT command for controlling thermostat
// e.g. { "cmd":"daytemp2", "data": 20 } // e.g. { "hc": 1, "cmd":"daytemp", "data": 20 }
// or { "hc": 1, "daytemp": 20 } or { "hc2": { "daytemp":20 }}
void Thermostat::thermostat_cmd(const char * message) { void Thermostat::thermostat_cmd(const char * message) {
StaticJsonDocument<EMSESP_MAX_JSON_SIZE_SMALL> doc; StaticJsonDocument<EMSESP_MAX_JSON_SIZE_SMALL> doc;
DeserializationError error = deserializeJson(doc, message); DeserializationError error = deserializeJson(doc, message);
@@ -246,7 +248,7 @@ void Thermostat::thermostat_cmd(const char * message) {
uint8_t hc_num = hc->hc_num(); uint8_t hc_num = hc->hc_num();
strlcat(hc_name, Helpers::itoa(s, hc_num), 6); strlcat(hc_name, Helpers::itoa(s, hc_num), 6);
if (nullptr != doc[hc_name]["mode"]) { if (nullptr != doc[hc_name]["mode"]) {
std::string mode = doc[hc_name]["mode"]; // first check mode std::string mode = doc[hc_name]["mode"];
set_mode(mode, hc_num); set_mode(mode, hc_num);
} }
if (float f = doc[hc_name]["temp"]) { if (float f = doc[hc_name]["temp"]) {
@@ -290,7 +292,19 @@ void Thermostat::thermostat_cmd(const char * message) {
uint8_t ctrl = doc[hc_name]["control"]; uint8_t ctrl = doc[hc_name]["control"];
set_control(ctrl, hc_num); set_control(ctrl, hc_num);
} }
} if (nullptr != doc[hc_name]["pause"]) {
uint8_t p = doc[hc_name]["pause"];
set_pause(p, hc_num);
}
if (nullptr != doc[hc_name]["party"]) {
uint8_t p = doc[hc_name]["party"];
set_party(p, hc_num);
}
if (nullptr != doc[hc_name]["holiday"]) {
std::string holiday = doc[hc_name]["holiday"];
set_holiday(holiday.c_str(), hc_num);
}
}
if (nullptr != doc["wwmode"]) { if (nullptr != doc["wwmode"]) {
std::string mode = doc["wwmode"]; std::string mode = doc["wwmode"];
set_ww_mode(mode); set_ww_mode(mode);
@@ -332,7 +346,7 @@ void Thermostat::thermostat_cmd(const char * message) {
// check for unnested commands like {"temp":21} or {"hc":2,"temp":21,"mode":"auto"} // check for unnested commands like {"temp":21} or {"hc":2,"temp":21,"mode":"auto"}
if (nullptr != doc["mode"]) { if (nullptr != doc["mode"]) {
std::string mode = doc["mode"]; // first check mode std::string mode = doc["mode"];
set_mode(mode, hc_num); set_mode(mode, hc_num);
} }
if (float f = doc["temp"]) { if (float f = doc["temp"]) {
@@ -376,6 +390,22 @@ void Thermostat::thermostat_cmd(const char * message) {
uint8_t ctrl = doc["control"]; uint8_t ctrl = doc["control"];
set_control(ctrl, hc_num); set_control(ctrl, hc_num);
} }
if (nullptr != doc["pause"]) {
uint8_t p = doc["pause"];
set_pause(p, hc_num);
}
if (nullptr != doc["party"]) {
uint8_t p = doc["party"];
set_party(p, hc_num);
}
if (nullptr != doc["holiday"]) {
std::string holiday = doc["holiday"];
set_holiday(holiday.c_str(), hc_num);
}
if (nullptr != doc["date"]) {
std::string date = doc["date"];
set_datetime(date.c_str());
}
// check for commands like {"hc":2,"cmd":"temp","data":21} // check for commands like {"hc":2,"cmd":"temp","data":21}
const char * command = doc["cmd"]; const char * command = doc["cmd"];
@@ -821,21 +851,21 @@ uint8_t Thermostat::HeatingCircuit::get_mode_type(uint8_t flags) const {
if (flags == EMS_DEVICE_FLAG_JUNKERS) { if (flags == EMS_DEVICE_FLAG_JUNKERS) {
if (mode_type == 3) { if (mode_type == 3) {
return HeatingCircuit::Mode::HEAT; return HeatingCircuit::Mode::HEAT;
} else if (mode == 2) { } else if (mode_type == 2) {
return HeatingCircuit::Mode::ECO; return HeatingCircuit::Mode::ECO;
} else if (mode == 1) { } else if (mode_type == 1) {
return HeatingCircuit::Mode::NOFROST; return HeatingCircuit::Mode::NOFROST;
} }
} else if ((flags == EMS_DEVICE_FLAG_RC35) || (flags == EMS_DEVICE_FLAG_RC30_1)) { } else if ((flags == EMS_DEVICE_FLAG_RC35) || (flags == EMS_DEVICE_FLAG_RC30_1)) {
if (mode_type == 0) { if (mode_type == 0) {
return HeatingCircuit::Mode::NIGHT; return HeatingCircuit::Mode::NIGHT;
} else if (mode == 1) { } else if (mode_type == 1) {
return HeatingCircuit::Mode::DAY; return HeatingCircuit::Mode::DAY;
} }
} else if (flags == EMS_DEVICE_FLAG_RC300) { } else if (flags == EMS_DEVICE_FLAG_RC300) {
if (mode_type == 0) { if (mode_type == 0) {
return HeatingCircuit::Mode::ECO; return HeatingCircuit::Mode::ECO;
} else if (mode == 1) { } else if (mode_type == 1) {
return HeatingCircuit::Mode::COMFORT; return HeatingCircuit::Mode::COMFORT;
} }
} else if (flags == EMS_DEVICE_FLAG_RC100) { } else if (flags == EMS_DEVICE_FLAG_RC100) {
@@ -1339,18 +1369,18 @@ void Thermostat::set_settings_language(const uint8_t lg) {
void Thermostat::set_control(const uint8_t ctrl, const uint8_t hc_num) { void Thermostat::set_control(const uint8_t ctrl, const uint8_t hc_num) {
std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(hc_num); std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(hc_num);
if (hc == nullptr) { if (hc == nullptr) {
LOG_WARNING(F("set control: Heating Circuit %d not found or activated"), hc_num); LOG_WARNING(F("Set control: Heating Circuit %d not found or activated"), hc_num);
return; return;
} }
if (ctrl > 2) { if (ctrl > 2) {
LOG_WARNING(F("set control: Invalid control mode: %d"), ctrl); LOG_WARNING(F("Set control: Invalid control mode: %d"), ctrl);
return; return;
} }
if ((flags() & 0x0F) == EMS_DEVICE_FLAG_RC35 || (flags() & 0x0F) == EMS_DEVICE_FLAG_RC30_1) { if ((flags() & 0x0F) == EMS_DEVICE_FLAG_RC35 || (flags() & 0x0F) == EMS_DEVICE_FLAG_RC30_1) {
LOG_INFO(F("Setting circuit-control for hc%d to %d"), hc_num, ctrl); LOG_INFO(F("Setting circuit-control for hc%d to %d"), hc_num, ctrl);
write_command(set_typeids[hc->hc_num() - 1], 26, ctrl); write_command(set_typeids[hc->hc_num() - 1], 26, ctrl);
} else { } else {
LOG_INFO(F("set circuit-control not supported")); LOG_INFO(F("Set circuit-control not supported"));
} }
} }
@@ -1366,7 +1396,79 @@ void Thermostat::set_ww_mode(const std::string & mode) {
LOG_INFO(F("Setting thermostat warm water mode to %s"), mode.c_str()); LOG_INFO(F("Setting thermostat warm water mode to %s"), mode.c_str());
write_command(EMS_TYPE_wwSettings, 2, 2); write_command(EMS_TYPE_wwSettings, 2, 2);
} else { } else {
LOG_WARNING(F("set thermostat warm water mode: Invalid mode: %s"), mode.c_str()); LOG_WARNING(F("Set thermostat warm water mode: Invalid mode: %s"), mode.c_str());
}
}
// set the holiday as string dd.mm.yyyy-dd.mm.yyyy
void Thermostat::set_holiday(const char * hd, const uint8_t hc_num) {
std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(hc_num);
if (hc == nullptr) {
LOG_WARNING(F("Set holiday: Heating Circuit %d not found or activated for device ID 0x%02X"), hc_num, device_id());
return;
}
uint8_t data[6];
data[0] = (hd[0] - '0') * 10 + (hd[1] - '0');
data[1] = (hd[3] - '0') * 10 + (hd[4] - '0');
data[2] = (hd[7] - '0') * 100 + (hd[8] - '0') * 10 + (hd[9] - '0');
data[3] = (hd[11] - '0') * 10 + (hd[11] - '0');
data[4] = (hd[14] - '0') * 10 + (hd[15] - '0');
data[5] = (hd[18] - '0') * 100 + (hd[19] - '0') * 10 + (hd[20] - '0');
if ((flags() & 0x0F) == EMS_DEVICE_FLAG_RC35 || (flags() & 0x0F) == EMS_DEVICE_FLAG_RC30_1) {
LOG_INFO(F("Setting holiday for hc %d"), hc->hc_num());
write_command(timer_typeids[hc->hc_num() - 1], 87, data, 6, 0);
} else {
LOG_INFO(F("Set holiday not supported"));
}
}
// set pause in hours
void Thermostat::set_pause(const uint8_t hrs, const uint8_t hc_num) {
std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(hc_num);
if (hc == nullptr) {
LOG_WARNING(F("Set pause: Heating Circuit %d not found or activated for device ID 0x%02X"), hc_num, device_id());
return;
}
if ((flags() & 0x0F) == EMS_DEVICE_FLAG_RC35 || (flags() & 0x0F) == EMS_DEVICE_FLAG_RC30_1) {
LOG_INFO(F("Setting pause: %d hours, hc: %d"), hrs, hc->hc_num());
write_command(timer_typeids[hc->hc_num() - 1], 85, hrs);
} else {
LOG_INFO(F("Set pause not supported"));
}
}
// set partymode in hours
void Thermostat::set_party(const uint8_t hrs, const uint8_t hc_num) {
std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(hc_num);
if (hc == nullptr) {
LOG_WARNING(F("Set party: Heating Circuit %d not found or activated for device ID 0x%02X"), hc_num, device_id());
return;
}
if ((flags() & 0x0F) == EMS_DEVICE_FLAG_RC35 || (flags() & 0x0F) == EMS_DEVICE_FLAG_RC30_1) {
LOG_INFO(F("Setting party: %d hours, hc: %d"), hrs, hc->hc_num());
write_command(timer_typeids[hc->hc_num() - 1], 86, hrs);
} else {
LOG_INFO(F("Set party not supported"));
}
}
// set date&time as string hh:mm:ss-dd.mm.yyyy-dw-dst
// dw - day of week (0..6), dst- summertime (0/1)
void Thermostat::set_datetime(const char * dt) {
uint8_t data[9];
data[0] = (dt[16] - '0') * 100 + (dt[17] - '0') * 10 + (dt[18] - '0'); // year
data[1] = (dt[12] - '0') * 10 + (dt[13] - '0'); // month
data[2] = (dt[0] - '0') * 10 + (dt[1] - '0'); // hour
data[3] = (dt[9] - '0') * 10 + (dt[10] - '0'); // day
data[4] = (dt[3] - '0') * 10 + (dt[4] - '0'); // min
data[5] = (dt[6] - '0') * 10 + (dt[7] - '0'); // sec
data[6] = (dt[20] - '0'); // day of week
data[7] = (dt[22] - '0'); // summerime
if ((flags() & 0x0F) == EMS_DEVICE_FLAG_RC35 || (flags() & 0x0F) == EMS_DEVICE_FLAG_RC30_1) {
LOG_INFO(F("Setting date and time"));
write_command(6, 0, data, 8, 0);
} else {
LOG_INFO(F("Set date not supported"));
} }
} }
@@ -1388,8 +1490,8 @@ void Thermostat::set_mode(const std::string & mode, const uint8_t hc_num) {
set_mode(HeatingCircuit::Mode::NOFROST, hc_num); set_mode(HeatingCircuit::Mode::NOFROST, hc_num);
} else if (mode_tostring(HeatingCircuit::Mode::ECO) == mode) { } else if (mode_tostring(HeatingCircuit::Mode::ECO) == mode) {
set_mode(HeatingCircuit::Mode::ECO, hc_num); set_mode(HeatingCircuit::Mode::ECO, hc_num);
} else if (mode_tostring(HeatingCircuit::Mode::HOLIDAY) == mode) { // } else if (mode_tostring(HeatingCircuit::Mode::HOLIDAY) == mode) {
set_mode(HeatingCircuit::Mode::HOLIDAY, hc_num); // set_mode(HeatingCircuit::Mode::HOLIDAY, hc_num);
} else if (mode_tostring(HeatingCircuit::Mode::COMFORT) == mode) { } else if (mode_tostring(HeatingCircuit::Mode::COMFORT) == mode) {
set_mode(HeatingCircuit::Mode::COMFORT, hc_num); set_mode(HeatingCircuit::Mode::COMFORT, hc_num);
} else { } else {
@@ -1407,13 +1509,13 @@ void Thermostat::set_mode(const uint8_t mode, const uint8_t hc_num) {
// get hc based on number // get hc based on number
std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(hc_num); std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(hc_num);
if (hc == nullptr) { if (hc == nullptr) {
LOG_WARNING(F("set mode: Heating Circuit %d not found or activated"), hc_num); LOG_WARNING(F("Set mode: Heating Circuit %d not found or activated"), hc_num);
return; return;
} }
uint8_t set_mode_value, offset; uint8_t set_mode_value, offset;
uint16_t validate_typeid = 0; uint16_t validate_typeid = 0;
uint8_t hc_p = hc->hc_num(); uint8_t hc_p = hc->hc_num() - 1;
// set the value to send via EMS depending on the mode type // set the value to send via EMS depending on the mode type
switch (mode) { switch (mode) {
@@ -1431,7 +1533,7 @@ void Thermostat::set_mode(const uint8_t mode, const uint8_t hc_num) {
default: default:
case HeatingCircuit::Mode::AUTO: case HeatingCircuit::Mode::AUTO:
case HeatingCircuit::Mode::HOLIDAY: // case HeatingCircuit::Mode::HOLIDAY:
case HeatingCircuit::Mode::ECO: case HeatingCircuit::Mode::ECO:
set_mode_value = 2; set_mode_value = 2;
break; break;
@@ -1491,7 +1593,7 @@ void Thermostat::set_mode(const uint8_t mode, const uint8_t hc_num) {
// add the write command to the Tx queue // add the write command to the Tx queue
// post validate is the corresponding monitor or set type IDs as they can differ per model // post validate is the corresponding monitor or set type IDs as they can differ per model
write_command(set_typeids[hc->hc_num() - 1], offset, set_mode_value, validate_typeid); write_command(set_typeids[hc_p], offset, set_mode_value, validate_typeid);
} }
// sets the thermostat temp, where mode is a string // sets the thermostat temp, where mode is a string
@@ -1533,12 +1635,14 @@ void Thermostat::set_temperature(const float temperature, const uint8_t mode, co
// get hc based on number // get hc based on number
std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(hc_num); std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(hc_num);
if (hc == nullptr) { if (hc == nullptr) {
LOG_WARNING(F("set temperature: Heating Circuit %d not found or activated for device ID 0x%02X"), hc_num, device_id()); LOG_WARNING(F("Set temperature: Heating Circuit %d not found or activated for device ID 0x%02X"), hc_num, device_id());
return; return;
} }
uint8_t model = flags() & 0x0F; uint8_t model = flags() & 0x0F;
int8_t offset = -1; // we use -1 to check if there is a value int8_t offset = -1; // we use -1 to check if there is a value
uint8_t factor = 2; // some temperatures only use 1
uint16_t validate_typeid = monitor_typeids[hc->hc_num() - 1];
if (model == EMS_DEVICE_FLAG_RC10) { if (model == EMS_DEVICE_FLAG_RC10) {
offset = EMS_OFFSET_RC10Set_temp; offset = EMS_OFFSET_RC10Set_temp;
@@ -1550,6 +1654,7 @@ void Thermostat::set_temperature(const float temperature, const uint8_t mode, co
offset = EMS_OFFSET_RC30Set_temp; offset = EMS_OFFSET_RC30Set_temp;
} else if ((model == EMS_DEVICE_FLAG_RC300) || (model == EMS_DEVICE_FLAG_RC100)) { } else if ((model == EMS_DEVICE_FLAG_RC300) || (model == EMS_DEVICE_FLAG_RC100)) {
validate_typeid = set_typeids[hc->hc_num() - 1];
if (mode == HeatingCircuit::Mode::AUTO) { if (mode == HeatingCircuit::Mode::AUTO) {
offset = 0x08; // auto offset offset = 0x08; // auto offset
} else if (mode == HeatingCircuit::Mode::MANUAL) { } else if (mode == HeatingCircuit::Mode::MANUAL) {
@@ -1569,6 +1674,7 @@ void Thermostat::set_temperature(const float temperature, const uint8_t mode, co
} }
} else if ((model == EMS_DEVICE_FLAG_RC35) || (model == EMS_DEVICE_FLAG_RC30_1)) { } else if ((model == EMS_DEVICE_FLAG_RC35) || (model == EMS_DEVICE_FLAG_RC30_1)) {
validate_typeid = set_typeids[hc->hc_num() - 1];
switch (mode) { switch (mode) {
case HeatingCircuit::Mode::NIGHT: // change the night temp case HeatingCircuit::Mode::NIGHT: // change the night temp
offset = EMS_OFFSET_RC35Set_temp_night; offset = EMS_OFFSET_RC35Set_temp_night;
@@ -1584,12 +1690,15 @@ void Thermostat::set_temperature(const float temperature, const uint8_t mode, co
break; break;
case HeatingCircuit::Mode::DESIGN: case HeatingCircuit::Mode::DESIGN:
offset = EMS_OFFSET_RC35Set_temp_design; offset = EMS_OFFSET_RC35Set_temp_design;
factor = 1;
break; break;
case HeatingCircuit::Mode::SUMMER: case HeatingCircuit::Mode::SUMMER:
offset = EMS_OFFSET_RC35Set_temp_summer; offset = EMS_OFFSET_RC35Set_temp_summer;
factor = 1;
break; break;
case HeatingCircuit::Mode::NOFROST: case HeatingCircuit::Mode::NOFROST:
offset = EMS_OFFSET_RC35Set_temp_nofrost; offset = EMS_OFFSET_RC35Set_temp_nofrost;
factor = 1;
break; break;
default: default:
case HeatingCircuit::Mode::AUTO: // automatic selection, if no type is defined, we use the standard code case HeatingCircuit::Mode::AUTO: // automatic selection, if no type is defined, we use the standard code
@@ -1662,9 +1771,8 @@ void Thermostat::set_temperature(const float temperature, const uint8_t mode, co
mode_tostring(mode).c_str()); mode_tostring(mode).c_str());
// add the write command to the Tx queue // add the write command to the Tx queue
// value is *2 // post validate is the corresponding monitor or set type IDs as they can differ per model
// post validate is the corresponding monitor type_id write_command(set_typeids[hc->hc_num() - 1], offset, (uint8_t)((float)temperature * (float)factor), validate_typeid);
write_command(set_typeids[hc->hc_num() - 1], offset, (uint8_t)((float)temperature * (float)2), monitor_typeids[hc->hc_num() - 1]);
} }
} }
@@ -1721,7 +1829,7 @@ void Thermostat::console_commands(Shell & shell, unsigned int context) {
flash_string_vector{F_(change), F_(mode)}, flash_string_vector{F_(change), F_(mode)},
flash_string_vector{F_(mode_mandatory), F_(hc_optional)}, flash_string_vector{F_(mode_mandatory), F_(hc_optional)},
[=](Shell & shell __attribute__((unused)), const std::vector<std::string> & arguments) { [=](Shell & shell __attribute__((unused)), const std::vector<std::string> & arguments) {
uint8_t hc = (arguments.size() == 2) ? arguments[1].at(0) - '0' : DEFAULT_HEATING_CIRCUIT; uint8_t hc = (arguments.size() == 2) ? arguments[1].at(0) - '0' : AUTO_HEATING_CIRCUIT;
set_mode(arguments.front(), hc); set_mode(arguments.front(), hc);
}, },
[](Shell & shell __attribute__((unused)), const std::vector<std::string> & arguments __attribute__((unused))) -> const std::vector<std::string> { [](Shell & shell __attribute__((unused)), const std::vector<std::string> & arguments __attribute__((unused))) -> const std::vector<std::string> {
@@ -1732,7 +1840,7 @@ void Thermostat::console_commands(Shell & shell, unsigned int context) {
read_flash_string(F("eco")), read_flash_string(F("eco")),
read_flash_string(F("comfort")), read_flash_string(F("comfort")),
read_flash_string(F("heat")), read_flash_string(F("heat")),
read_flash_string(F("holiday")), // read_flash_string(F("holiday")),
read_flash_string(F("nofrost")), read_flash_string(F("nofrost")),
read_flash_string(F("auto")) read_flash_string(F("auto"))
@@ -1747,7 +1855,6 @@ void Thermostat::console_commands(Shell & shell, unsigned int context) {
[=](Shell & shell __attribute__((unused)), const std::vector<std::string> & arguments) { set_ww_mode(arguments.front()); }, [=](Shell & shell __attribute__((unused)), const std::vector<std::string> & arguments) { set_ww_mode(arguments.front()); },
[](Shell & shell __attribute__((unused)), const std::vector<std::string> & arguments __attribute__((unused))) -> const std::vector<std::string> { [](Shell & shell __attribute__((unused)), const std::vector<std::string> & arguments __attribute__((unused))) -> const std::vector<std::string> {
return std::vector<std::string>{read_flash_string(F("off")), read_flash_string(F("on")), read_flash_string(F("auto")) return std::vector<std::string>{read_flash_string(F("off")), read_flash_string(F("on")), read_flash_string(F("auto"))
}; };
}); });

View File

@@ -104,6 +104,7 @@ class Thermostat : public EMSdevice {
// each thermostat has a list of heating controller type IDs for reading and writing // each thermostat has a list of heating controller type IDs for reading and writing
std::vector<uint16_t> monitor_typeids; std::vector<uint16_t> monitor_typeids;
std::vector<uint16_t> set_typeids; std::vector<uint16_t> set_typeids;
std::vector<uint16_t> timer_typeids;
private: private:
static uuid::log::Logger logger_; static uuid::log::Logger logger_;
@@ -251,6 +252,10 @@ class Thermostat : public EMSdevice {
void set_settings_language(const uint8_t lg); void set_settings_language(const uint8_t lg);
void set_control(const uint8_t ctrl, const uint8_t hc_num); void set_control(const uint8_t ctrl, const uint8_t hc_num);
void set_ww_mode(const std::string & mode); void set_ww_mode(const std::string & mode);
void set_holiday(const char * hd, const uint8_t hc_num);
void set_datetime(const char * dt);
void set_pause(const uint8_t hrs, const uint8_t hc_num);
void set_party(const uint8_t hrs, const uint8_t hc_num);
void set_mode(const uint8_t mode, const uint8_t hc_num); void set_mode(const uint8_t mode, const uint8_t hc_num);
void set_mode(const std::string & mode, const uint8_t hc_num); void set_mode(const std::string & mode, const uint8_t hc_num);
void set_temperature(const float temperature, const std::string & mode, const uint8_t hc_num); void set_temperature(const float temperature, const std::string & mode, const uint8_t hc_num);

View File

@@ -585,7 +585,7 @@ void EMSESP::send_write_request(const uint16_t type_id,
// the CRC check is not done here, only when it's added to the Rx queue with add() // the CRC check is not done here, only when it's added to the Rx queue with add()
void EMSESP::incoming_telegram(uint8_t * data, const uint8_t length) { void EMSESP::incoming_telegram(uint8_t * data, const uint8_t length) {
#ifdef EMSESP_DEBUG #ifdef EMSESP_DEBUG
static uint32_t tx_time_ = 0; static uint32_t rx_time_ = 0;
#endif #endif
// check first for echo // check first for echo
uint8_t first_value = data[0]; uint8_t first_value = data[0];
@@ -593,8 +593,7 @@ void EMSESP::incoming_telegram(uint8_t * data, const uint8_t length) {
// if we ask ourself at roomcontrol for version e.g. 0B 98 02 00 20 // if we ask ourself at roomcontrol for version e.g. 0B 98 02 00 20
Roomctrl::check((data[1] ^ 0x80 ^ rxservice_.ems_mask()), data); Roomctrl::check((data[1] ^ 0x80 ^ rxservice_.ems_mask()), data);
#ifdef EMSESP_DEBUG #ifdef EMSESP_DEBUG
// get_uptime is only updated once per loop, does not give the right time LOG_TRACE(F("[DEBUG] Echo after %d ms: %s"), ::millis() - rx_time_, Helpers::data_to_hex(data, length).c_str());
LOG_DEBUG(F("[DEBUG] Echo after %d ms: %s"), ::millis() - tx_time_, Helpers::data_to_hex(data, length).c_str());
#endif #endif
return; // it's an echo return; // it's an echo
} }
@@ -642,19 +641,29 @@ void EMSESP::incoming_telegram(uint8_t * data, const uint8_t length) {
// check for poll // check for poll
if (length == 1) { if (length == 1) {
#ifdef EMSESP_DEBUG
char s[4];
if(first_value & 0x80) {
LOG_TRACE(F("[DEBUG] next Poll %s after %d ms"), Helpers::hextoa(s, first_value), ::millis() - rx_time_);
// time measurement starts here, use millis because get_uptime is only updated once per loop
rx_time_ = ::millis();
} else {
LOG_TRACE(F("[DEBUG] Poll ack %s after %d ms"), Helpers::hextoa(s, first_value), ::millis() - rx_time_);
}
#endif
// check for poll to us, if so send top message from Tx queue immediately and quit // check for poll to us, if so send top message from Tx queue immediately and quit
// if ht3 poll must be ems_bus_id else if Buderus poll must be (ems_bus_id | 0x80) // if ht3 poll must be ems_bus_id else if Buderus poll must be (ems_bus_id | 0x80)
if ((first_value ^ 0x80 ^ rxservice_.ems_mask()) == txservice_.ems_bus_id()) { if ((first_value ^ 0x80 ^ rxservice_.ems_mask()) == txservice_.ems_bus_id()) {
EMSbus::last_bus_activity(uuid::get_uptime()); // set the flag indication the EMS bus is active EMSbus::last_bus_activity(uuid::get_uptime()); // set the flag indication the EMS bus is active
#ifdef EMSESP_DEBUG
tx_time_ = ::millis(); // get_uptime is only updated once per loop, does not give the right time
#endif
txservice_.send(); txservice_.send();
} }
// send remote room temperature if active // send remote room temperature if active
Roomctrl::send(first_value ^ 0x80 ^ rxservice_.ems_mask()); Roomctrl::send(first_value ^ 0x80 ^ rxservice_.ems_mask());
return; return;
} else { } else {
#ifdef EMSESP_DEBUG
LOG_TRACE(F("[DEBUG] Reply after %d ms: %s"), ::millis() - rx_time_, Helpers::data_to_hex(data, length).c_str());
#endif
// check if there is a message for the roomcontroller // check if there is a message for the roomcontroller
Roomctrl::check((data[1] ^ 0x80 ^ rxservice_.ems_mask()), data); Roomctrl::check((data[1] ^ 0x80 ^ rxservice_.ems_mask()), data);
// add to RxQueue, what ever it is. // add to RxQueue, what ever it is.

View File

@@ -73,7 +73,7 @@ void Sensors::loop() {
last_activity_ = time_now; last_activity_ = time_now;
} }
} else if (state_ == State::READING) { } else if (state_ == State::READING) {
if (temperature_convert_complete()) { if (temperature_convert_complete() && (time_now - last_activity_ > CONVERSION_MS)) {
// LOG_DEBUG(F("Scanning for sensors")); // uncomment for debug // LOG_DEBUG(F("Scanning for sensors")); // uncomment for debug
bus_.reset_search(); bus_.reset_search();
found_.clear(); found_.clear();

View File

@@ -89,6 +89,7 @@ class Sensors {
static constexpr uint8_t TYPE_DS1825 = 0x3B; static constexpr uint8_t TYPE_DS1825 = 0x3B;
static constexpr uint32_t READ_INTERVAL_MS = 5000; // 5 seconds static constexpr uint32_t READ_INTERVAL_MS = 5000; // 5 seconds
static constexpr uint32_t CONVERSION_MS = 1000; // 1 seconds
static constexpr uint32_t READ_TIMEOUT_MS = 2000; // 2 seconds static constexpr uint32_t READ_TIMEOUT_MS = 2000; // 2 seconds
static constexpr uint32_t SCAN_TIMEOUT_MS = 30000; // 30 seconds static constexpr uint32_t SCAN_TIMEOUT_MS = 30000; // 30 seconds

View File

@@ -421,7 +421,7 @@ void TxService::send_telegram(const uint8_t * data, const uint8_t length) {
// builds a Tx telegram and adds to queue // builds a Tx telegram and adds to queue
// given some details like the destination, type, offset and message block // given some details like the destination, type, offset and message block
void TxService::add(const uint8_t operation, const uint8_t dest, const uint16_t type_id, const uint8_t offset, uint8_t * message_data, const uint8_t message_length) { void TxService::add(const uint8_t operation, const uint8_t dest, const uint16_t type_id, const uint8_t offset, uint8_t * message_data, const uint8_t message_length, const bool front) {
auto telegram = std::make_shared<Telegram>(operation, ems_bus_id(), dest, type_id, offset, message_data, message_length); auto telegram = std::make_shared<Telegram>(operation, ems_bus_id(), dest, type_id, offset, message_data, message_length);
#ifdef EMSESP_DEBUG #ifdef EMSESP_DEBUG
LOG_DEBUG(F("[DEBUG] New Tx [#%d] telegram, length %d"), tx_telegram_id_, message_length); LOG_DEBUG(F("[DEBUG] New Tx [#%d] telegram, length %d"), tx_telegram_id_, message_length);
@@ -432,14 +432,18 @@ void TxService::add(const uint8_t operation, const uint8_t dest, const uint16_t
tx_telegrams_.pop_front(); tx_telegrams_.pop_front();
} }
tx_telegrams_.emplace_back(tx_telegram_id_++, std::move(telegram), false); // first tx, no retry if (front) {
tx_telegrams_.emplace_front(tx_telegram_id_++, std::move(telegram), false); // add to back of queue
} else {
tx_telegrams_.emplace_back(tx_telegram_id_++, std::move(telegram), false); // add to back of queue
}
} }
// builds a Tx telegram and adds to queue // builds a Tx telegram and adds to queue
// this is used by the retry() function to put the last failed Tx back into the queue // this is used by the retry() function to put the last failed Tx back into the queue
// format is EMS 1.0 (src, dest, type_id, offset, data) // format is EMS 1.0 (src, dest, type_id, offset, data)
// length is the length of the whole telegram data, excluding the CRC // length is the length of the whole telegram data, excluding the CRC
void TxService::add(uint8_t operation, const uint8_t * data, const uint8_t length) { void TxService::add(uint8_t operation, const uint8_t * data, const uint8_t length, const bool front) {
// build header. src, dest and offset have fixed positions // build header. src, dest and offset have fixed positions
uint8_t src = data[0]; uint8_t src = data[0];
uint8_t dest = data[1]; uint8_t dest = data[1];
@@ -494,8 +498,11 @@ void TxService::add(uint8_t operation, const uint8_t * data, const uint8_t lengt
#ifdef EMSESP_DEBUG #ifdef EMSESP_DEBUG
LOG_DEBUG(F("[DEBUG] New Tx [#%d] telegram, length %d"), tx_telegram_id_, message_length); LOG_DEBUG(F("[DEBUG] New Tx [#%d] telegram, length %d"), tx_telegram_id_, message_length);
#endif #endif
if (front) {
tx_telegrams_.emplace_back(tx_telegram_id_++, std::move(telegram), false); // add to back of queue tx_telegrams_.emplace_front(tx_telegram_id_++, std::move(telegram), false); // add to back of queue
} else {
tx_telegrams_.emplace_back(tx_telegram_id_++, std::move(telegram), false); // add to back of queue
}
} }
// send a Tx telegram to request data from an EMS device // send a Tx telegram to request data from an EMS device
@@ -583,8 +590,10 @@ bool TxService::is_last_tx(const uint8_t src, const uint8_t dest) const {
// sends a type_id read request to fetch values after a successful Tx write operation // sends a type_id read request to fetch values after a successful Tx write operation
void TxService::post_send_query() { void TxService::post_send_query() {
if (telegram_last_post_send_query_) { if (telegram_last_post_send_query_) {
uint8_t dest = (telegram_last_->dest & 0x7F); uint8_t dest = (telegram_last_->dest & 0x7F);
read_request(telegram_last_post_send_query_, dest, 0); // no offset uint8_t message_data[1] = {EMS_MAX_TELEGRAM_LENGTH}; // request all data, 32 bytes
add(Telegram::Operation::TX_READ, dest, telegram_last_post_send_query_, 0, message_data, 1, true);
// read_request(telegram_last_post_send_query_, dest, 0); // no offset
LOG_DEBUG(F("Sending post validate read, type ID 0x%02X to dest 0x%02X"), telegram_last_post_send_query_, dest); LOG_DEBUG(F("Sending post validate read, type ID 0x%02X to dest 0x%02X"), telegram_last_post_send_query_, dest);
} }
} }

View File

@@ -88,7 +88,7 @@ class Telegram {
// reads a bit value from a given telegram position // reads a bit value from a given telegram position
void read_bitvalue(uint8_t & value, const uint8_t index, const uint8_t bit) const { void read_bitvalue(uint8_t & value, const uint8_t index, const uint8_t bit) const {
uint8_t abs_index = (index - offset); uint8_t abs_index = (index - offset);
if (abs_index >= message_length) { if (abs_index >= message_length - 1) {
return; // out of bounds return; // out of bounds
} }
@@ -104,7 +104,7 @@ class Telegram {
// s is to override number of bytes read (e.g. use 3 to simulat a uint24_t) // s is to override number of bytes read (e.g. use 3 to simulat a uint24_t)
void read_value(Value & value, const uint8_t index, uint8_t s = 0) const { void read_value(Value & value, const uint8_t index, uint8_t s = 0) const {
uint8_t size = (!s) ? sizeof(Value) : s; uint8_t size = (!s) ? sizeof(Value) : s;
int8_t abs_index = ((index - offset + size - 1) >= message_length) ? -1 : (index - offset); int8_t abs_index = ((index - offset + size - 1) >= message_length - 1) ? -1 : (index - offset);
if (abs_index < 0) { if (abs_index < 0) {
return; // out of bounds, we don't change the value return; // out of bounds, we don't change the value
} }
@@ -270,8 +270,8 @@ class TxService : public EMSbus {
void loop(); void loop();
void send(); void send();
void add(const uint8_t operation, const uint8_t dest, const uint16_t type_id, const uint8_t offset, uint8_t * message_data, const uint8_t message_length); void add(const uint8_t operation, const uint8_t dest, const uint16_t type_id, const uint8_t offset, uint8_t * message_data, const uint8_t message_length, const bool front = false);
void add(const uint8_t operation, const uint8_t * data, const uint8_t length); void add(const uint8_t operation, const uint8_t * data, const uint8_t length, const bool front = false);
void read_request(const uint16_t type_id, const uint8_t dest, const uint8_t offset = 0); void read_request(const uint16_t type_id, const uint8_t dest, const uint8_t offset = 0);

View File

@@ -61,20 +61,9 @@ void IRAM_ATTR EMSuart::emsuart_rx_intr_handler(void * para) {
static uint8_t rxbuf[EMS_MAXBUFFERSIZE]; static uint8_t rxbuf[EMS_MAXBUFFERSIZE];
static uint8_t length; static uint8_t length;
if (EMS_UART.int_st.rxfifo_full) {
EMS_UART.int_clr.rxfifo_full = 1;
emsTxBufIdx++;
if (emsTxBufIdx < emsTxBufLen) {
EMS_UART.conf1.rxfifo_full_thrhd = emsTxBufIdx + 1;
EMS_UART.fifo.rw_byte = emsTxBuf[emsTxBufIdx];
} else if (emsTxBufIdx == emsTxBufLen) {
EMS_UART.conf0.txd_brk = 1; // <brk> after send
EMS_UART.int_ena.rxfifo_full = 0;
EMS_UART.conf1.rxfifo_full_thrhd = 0x7F;
}
}
if (EMS_UART.int_st.brk_det) { if (EMS_UART.int_st.brk_det) {
EMS_UART.int_clr.brk_det = 1; // clear flag EMS_UART.int_clr.brk_det = 1; // clear flag
EMS_UART.conf0.txd_brk = 0; // disable <brk>
if (emsTxBufIdx < emsTxBufLen) { // timer tx_mode is interrupted by <brk> if (emsTxBufIdx < emsTxBufLen) { // timer tx_mode is interrupted by <brk>
emsTxBufIdx = emsTxBufLen; // stop timer mode emsTxBufIdx = emsTxBufLen; // stop timer mode
drop_next_rx = true; // we have trash in buffer drop_next_rx = true; // we have trash in buffer
@@ -98,26 +87,31 @@ void IRAM_ATTR EMSuart::emsuart_rx_intr_handler(void * para) {
void IRAM_ATTR EMSuart::emsuart_tx_timer_intr_handler() { void IRAM_ATTR EMSuart::emsuart_tx_timer_intr_handler() {
if (emsTxBufIdx > EMS_MAXBUFFERSIZE) { if(emsTxBufLen == 0) {
return; return;
} }
if(tx_mode_ > 50) {
emsTxBufIdx++; for (uint8_t i = 0; i < emsTxBufLen; i++) {
EMS_UART.fifo.rw_byte = emsTxBuf[i];
if (emsTxBufIdx < emsTxBufLen) { }
EMS_UART.fifo.rw_byte = emsTxBuf[emsTxBufIdx];
timerAlarmWrite(timer, emsTxWait, false);
timerAlarmEnable(timer);
} else if (emsTxBufIdx == emsTxBufLen) {
EMS_UART.conf0.txd_brk = 1; // <brk> after send EMS_UART.conf0.txd_brk = 1; // <brk> after send
} else {
if (emsTxBufIdx + 1 < emsTxBufLen) {
EMS_UART.fifo.rw_byte = emsTxBuf[emsTxBufIdx];
timerAlarmWrite(timer, emsTxWait, false);
timerAlarmEnable(timer);
} else if (emsTxBufIdx + 1 == emsTxBufLen) {
EMS_UART.fifo.rw_byte = emsTxBuf[emsTxBufIdx];
EMS_UART.conf0.txd_brk = 1; // <brk> after send
}
emsTxBufIdx++;
} }
} }
/* /*
* init UART driver * init UART driver
*/ */
void EMSuart::start(uint8_t tx_mode) { void EMSuart::start(const uint8_t tx_mode) {
emsTxWait = EMSUART_TX_BIT_TIME * (tx_mode + 10);
if (tx_mode_ != 0xFF) { // uart already initialized if (tx_mode_ != 0xFF) { // uart already initialized
tx_mode_ = tx_mode; tx_mode_ = tx_mode;
restart(); restart();
@@ -142,12 +136,10 @@ void EMSuart::start(uint8_t tx_mode) {
buf_handle = xRingbufferCreate(128, RINGBUF_TYPE_NOSPLIT); buf_handle = xRingbufferCreate(128, RINGBUF_TYPE_NOSPLIT);
uart_isr_register(EMSUART_UART, emsuart_rx_intr_handler, NULL, ESP_INTR_FLAG_IRAM, &uart_handle); uart_isr_register(EMSUART_UART, emsuart_rx_intr_handler, NULL, ESP_INTR_FLAG_IRAM, &uart_handle);
xTaskCreate(emsuart_recvTask, "emsuart_recvTask", 2048, NULL, configMAX_PRIORITIES - 1, NULL); xTaskCreate(emsuart_recvTask, "emsuart_recvTask", 2048, NULL, configMAX_PRIORITIES - 1, NULL);
EMS_UART.int_ena.brk_det = 1; // activate only break
emsTxBufIdx = 0; timer = timerBegin(1, 80, true); // timer prescale to 1 µs, countup
emsTxBufLen = 0;
timer = timerBegin(1, 80, true); // timer prescale to 1 µs, countup
timerAttachInterrupt(timer, &emsuart_tx_timer_intr_handler, true); // Timer with edge interrupt timerAttachInterrupt(timer, &emsuart_tx_timer_intr_handler, true); // Timer with edge interrupt
restart();
} }
/* /*
@@ -169,49 +161,32 @@ void EMSuart::restart() {
EMS_UART.int_ena.brk_det = 1; // activate only break EMS_UART.int_ena.brk_det = 1; // activate only break
emsTxBufIdx = 0; emsTxBufIdx = 0;
emsTxBufLen = 0; emsTxBufLen = 0;
if (tx_mode_ == 1) {
EMS_UART.idle_conf.tx_idle_num = 5;
} else if (tx_mode_ == 2) {
EMS_UART.idle_conf.tx_idle_num = 10;
} else if (tx_mode_ == 3) {
EMS_UART.idle_conf.tx_idle_num = 7;
} else if (tx_mode_ == 4) {
EMS_UART.idle_conf.tx_idle_num = 2;
} else if (tx_mode_ == 5) {
EMS_UART.idle_conf.tx_idle_num = 2;
} else if (tx_mode_ <= 50) {
EMS_UART.idle_conf.tx_idle_num = tx_mode_;
emsTxWait = EMSUART_TX_BIT_TIME * (tx_mode_ + 10);
} else {
EMS_UART.idle_conf.tx_idle_num = 2;
emsTxWait = EMSUART_TX_BIT_TIME * (tx_mode_ - 50);
}
} }
/* /*
* Sends a 1-byte poll, ending with a <BRK> * Sends a 1-byte poll, ending with a <BRK>
*/ */
void EMSuart::send_poll(uint8_t data) { void EMSuart::send_poll(const uint8_t data) {
// if (tx_mode_ >= 6 || tx_mode_ < 4) { // modes 1, 2, 3 also here EMS_UART.fifo.rw_byte = data;
if (tx_mode_ >= 5) { EMS_UART.conf0.txd_brk = 1; // <brk> after send
EMS_UART.fifo.rw_byte = data; return;
emsTxBufIdx = 0;
emsTxBufLen = 1;
timerAlarmWrite(timer, emsTxWait, false);
timerAlarmEnable(timer);
} else if (tx_mode_ == 5) {
EMS_UART.fifo.rw_byte = data;
emsTxBufIdx = 0;
emsTxBufLen = 1;
EMS_UART.conf1.rxfifo_full_thrhd = 1;
EMS_UART.int_ena.rxfifo_full = 1;
} else if (tx_mode_ == EMS_TXMODE_NEW) {
EMS_UART.fifo.rw_byte = data;
EMS_UART.conf0.txd_brk = 1; // <brk> after send
} else if (tx_mode_ == EMS_TXMODE_HT3) {
EMS_UART.fifo.rw_byte = data;
delayMicroseconds(EMSUART_TX_WAIT_HT3);
EMS_UART.conf0.txd_brk = 1; // <brk>
// delayMicroseconds(EMSUART_TX_WAIT_BRK);
// EMS_UART.conf0.txd_brk = 0;
} else if (tx_mode_ == EMS_TXMODE_EMSPLUS) {
EMS_UART.fifo.rw_byte = data;
delayMicroseconds(EMSUART_TX_WAIT_PLUS);
EMS_UART.conf0.txd_brk = 1; // <brk>
// delayMicroseconds(EMSUART_TX_WAIT_BRK);
// EMS_UART.conf0.txd_brk = 0;
} else {
volatile uint8_t _usrxc = EMS_UART.status.rxfifo_cnt;
EMS_UART.fifo.rw_byte = data;
uint16_t timeoutcnt = EMSUART_TX_TIMEOUT;
while ((EMS_UART.status.rxfifo_cnt == _usrxc) && (--timeoutcnt > 0)) {
delayMicroseconds(EMSUART_TX_BUSY_WAIT); // burn CPU cycles...
}
EMS_UART.conf0.txd_brk = 1; // <brk>
}
} }
/* /*
@@ -219,36 +194,32 @@ void EMSuart::send_poll(uint8_t data) {
* buf contains the CRC and len is #bytes including the CRC * buf contains the CRC and len is #bytes including the CRC
* returns code, 1=success * returns code, 1=success
*/ */
uint16_t EMSuart::transmit(uint8_t * buf, uint8_t len) { uint16_t EMSuart::transmit(const uint8_t * buf, const uint8_t len) {
if (len == 0 || len >= EMS_MAXBUFFERSIZE) { if (len == 0 || len >= EMS_MAXBUFFERSIZE) {
return EMS_TX_STATUS_ERR; return EMS_TX_STATUS_ERR;
} }
// needs to be disabled for the delayed modes otherwise the uart makes a <brk> after every byte
EMS_UART.conf0.txd_brk = 0;
// if (tx_mode_ >= 6 || tx_mode_ < 4) { // timer controlled modes, also modes 1, 2, 3 because delays not working if (tx_mode_ > 5) { // timer controlled modes
if (tx_mode_ >= 5) { // timer controlled modes
for (uint8_t i = 0; i < len; i++) { for (uint8_t i = 0; i < len; i++) {
emsTxBuf[i] = buf[i]; emsTxBuf[i] = buf[i];
} }
EMS_UART.fifo.rw_byte = buf[0]; emsTxBufIdx = 0;
emsTxBufIdx = 0; emsTxBufLen = len;
emsTxBufLen = len;
timerAlarmWrite(timer, emsTxWait, false); timerAlarmWrite(timer, emsTxWait, false);
timerAlarmEnable(timer); timerAlarmEnable(timer);
return EMS_TX_STATUS_OK; return EMS_TX_STATUS_OK;
} }
if (tx_mode_ == 5) { if (tx_mode_ == 5) { // wait before sending
vTaskDelay(4 / portTICK_PERIOD_MS);
for (uint8_t i = 0; i < len; i++) { for (uint8_t i = 0; i < len; i++) {
emsTxBuf[i] = buf[i]; EMS_UART.fifo.rw_byte = buf[i];
} }
EMS_UART.fifo.rw_byte = buf[0]; EMS_UART.conf0.txd_brk = 1; // <brk> after send
emsTxBufIdx = 0;
emsTxBufLen = len;
EMS_UART.conf1.rxfifo_full_thrhd = 1;
EMS_UART.int_ena.rxfifo_full = 1;
return EMS_TX_STATUS_OK; return EMS_TX_STATUS_OK;
} }
if (tx_mode_ == EMS_TXMODE_NEW) { // hardware controlled modes if (tx_mode_ == EMS_TXMODE_NEW) { // hardware controlled modes
for (uint8_t i = 0; i < len; i++) { for (uint8_t i = 0; i < len; i++) {
EMS_UART.fifo.rw_byte = buf[i]; EMS_UART.fifo.rw_byte = buf[i];
@@ -258,24 +229,22 @@ uint16_t EMSuart::transmit(uint8_t * buf, uint8_t len) {
} }
if (tx_mode_ == EMS_TXMODE_EMSPLUS) { // EMS+ with long delay if (tx_mode_ == EMS_TXMODE_EMSPLUS) { // EMS+ with long delay
for (uint8_t i = 0; i < len; i++) { for (uint8_t i = 0; i < len - 1; i++) {
EMS_UART.fifo.rw_byte = buf[i]; EMS_UART.fifo.rw_byte = buf[i];
delayMicroseconds(EMSUART_TX_WAIT_PLUS); delayMicroseconds(EMSUART_TX_WAIT_PLUS);
} }
EMS_UART.fifo.rw_byte = buf[len - 1];
EMS_UART.conf0.txd_brk = 1; // <brk> after send, cleard by hardware after send EMS_UART.conf0.txd_brk = 1; // <brk> after send, cleard by hardware after send
// delayMicroseconds(EMSUART_TX_WAIT_BRK);
// EMS_UART.conf0.txd_brk = 0;
return EMS_TX_STATUS_OK; return EMS_TX_STATUS_OK;
} }
if (tx_mode_ == EMS_TXMODE_HT3) { // HT3 with 7 bittimes delay if (tx_mode_ == EMS_TXMODE_HT3) { // HT3 with 7 bittimes delay
for (uint8_t i = 0; i < len; i++) { for (uint8_t i = 0; i < len - 1; i++) {
EMS_UART.fifo.rw_byte = buf[i]; EMS_UART.fifo.rw_byte = buf[i];
delayMicroseconds(EMSUART_TX_WAIT_HT3); delayMicroseconds(EMSUART_TX_WAIT_HT3);
} }
EMS_UART.fifo.rw_byte = buf[len - 1];
EMS_UART.conf0.txd_brk = 1; // <brk> after send, cleard by hardware after send EMS_UART.conf0.txd_brk = 1; // <brk> after send, cleard by hardware after send
// delayMicroseconds(EMSUART_TX_WAIT_BRK);
// EMS_UART.conf0.txd_brk = 0;
return EMS_TX_STATUS_OK; return EMS_TX_STATUS_OK;
} }
@@ -283,17 +252,16 @@ uint16_t EMSuart::transmit(uint8_t * buf, uint8_t len) {
// flush fifos -- not supported in ESP32 uart #2! // flush fifos -- not supported in ESP32 uart #2!
// EMS_UART.conf0.rxfifo_rst = 1; // EMS_UART.conf0.rxfifo_rst = 1;
// EMS_UART.conf0.txfifo_rst = 1; // EMS_UART.conf0.txfifo_rst = 1;
for (uint8_t i = 0; i < len; i++) { for (uint8_t i = 0; i < len - 1; i++) {
volatile uint8_t _usrxc = EMS_UART.status.rxfifo_cnt; volatile uint8_t _usrxc = EMS_UART.status.rxfifo_cnt;
EMS_UART.fifo.rw_byte = buf[i]; // send each Tx byte EMS_UART.fifo.rw_byte = buf[i]; // send each Tx byte
uint16_t timeoutcnt = EMSUART_TX_TIMEOUT; uint16_t timeoutcnt = EMSUART_TX_TIMEOUT;
while ((EMS_UART.status.rxfifo_cnt == _usrxc) && (--timeoutcnt > 0)) { while ((EMS_UART.status.rxfifo_cnt == _usrxc) && (--timeoutcnt > 0)) {
delayMicroseconds(EMSUART_TX_BUSY_WAIT); // burn CPU cycles... delayMicroseconds(EMSUART_TX_BUSY_WAIT); // burn CPU cycles...
} }
} }
EMS_UART.fifo.rw_byte = buf[len - 1]; // send each Tx byte
EMS_UART.conf0.txd_brk = 1; // <brk> after send, cleard by hardware after send EMS_UART.conf0.txd_brk = 1; // <brk> after send, cleard by hardware after send
// delayMicroseconds(EMSUART_TX_WAIT_BRK);
// EMS_UART.conf0.txd_brk = 0;
return EMS_TX_STATUS_OK; return EMS_TX_STATUS_OK;
} }

View File

@@ -32,6 +32,7 @@
#include "freertos/ringbuf.h" #include "freertos/ringbuf.h"
#include "freertos/queue.h" #include "freertos/queue.h"
#include <driver/uart.h> #include <driver/uart.h>
#include <driver/timer.h>
#define EMS_MAXBUFFERSIZE 33 // max size of the buffer. EMS packets are max 32 bytes, plus extra for BRK #define EMS_MAXBUFFERSIZE 33 // max size of the buffer. EMS packets are max 32 bytes, plus extra for BRK
@@ -79,11 +80,11 @@ class EMSuart {
EMSuart() = default; EMSuart() = default;
~EMSuart() = default; ~EMSuart() = default;
static void start(uint8_t tx_mode); static void start(const uint8_t tx_mode);
static void send_poll(uint8_t data); static void send_poll(const uint8_t data);
static void stop(); static void stop();
static void restart(); static void restart();
static uint16_t transmit(uint8_t * buf, uint8_t len); static uint16_t transmit(const uint8_t * buf, const uint8_t len);
private: private:
static void emsuart_recvTask(void * para); static void emsuart_recvTask(void * para);

View File

@@ -44,18 +44,6 @@ void ICACHE_RAM_ATTR EMSuart::emsuart_rx_intr_handler(void * para) {
static uint8_t length = 0; static uint8_t length = 0;
static uint8_t uart_buffer[EMS_MAXBUFFERSIZE + 2]; static uint8_t uart_buffer[EMS_MAXBUFFERSIZE + 2];
if (USIS(EMSUART_UART) & ((1 << UIFF))) { // Fifo full, sending in Mode 5
USIC(EMSUART_UART) |= (1 << UIFF); // clear fifo interrupt
emsTxBufIdx++;
if (emsTxBufIdx < emsTxBufLen) {
USF(EMSUART_UART) = emsTxBuf[emsTxBufIdx]; // send next byte
USC1(EMSUART_UART) = ((emsTxBufIdx + 1) << UCFFT); // increase fifo full
} else if (emsTxBufIdx == emsTxBufLen) {
USC0(EMSUART_UART) |= (1 << UCBRK); // set <BRK>
USIE(EMSUART_UART) &= ~(1 << UIFF); // disable fifo-full irq
USC1(EMSUART_UART) = (0x7F << UCFFT); // fifo full to max
}
}
if (USIS(EMSUART_UART) & ((1 << UIBD))) { // BREAK detection = End of EMS data block if (USIS(EMSUART_UART) & ((1 << UIBD))) { // BREAK detection = End of EMS data block
USC0(EMSUART_UART) &= ~(1 << UCBRK); // reset tx-brk USC0(EMSUART_UART) &= ~(1 << UCBRK); // reset tx-brk
if (emsTxBufIdx < emsTxBufLen) { // irq tx_mode is interrupted by <brk> if (emsTxBufIdx < emsTxBufLen) { // irq tx_mode is interrupted by <brk>
@@ -110,15 +98,22 @@ void ICACHE_FLASH_ATTR EMSuart::emsuart_flush_fifos() {
// ISR to Fire when Timer is triggered // ISR to Fire when Timer is triggered
void ICACHE_RAM_ATTR EMSuart::emsuart_tx_timer_intr_handler() { void ICACHE_RAM_ATTR EMSuart::emsuart_tx_timer_intr_handler() {
if (emsTxBufIdx > EMS_MAXBUFFERSIZE) { if ( tx_mode_ > 50) {
return; for (uint8_t i = 0; i < emsTxBufLen; i++) {
} USF(EMSUART_UART) = emsTxBuf[i];
emsTxBufIdx++; }
if (emsTxBufIdx < emsTxBufLen) {
USF(EMSUART_UART) = emsTxBuf[emsTxBufIdx];
timer1_write(emsTxWait);
} else if (emsTxBufIdx == emsTxBufLen) {
USC0(EMSUART_UART) |= (1 << UCBRK); // set <BRK> USC0(EMSUART_UART) |= (1 << UCBRK); // set <BRK>
} else {
if (emsTxBufIdx > emsTxBufLen) {
return;
}
if (emsTxBufIdx < emsTxBufLen) {
USF(EMSUART_UART) = emsTxBuf[emsTxBufIdx];
timer1_write(emsTxWait);
} else if (emsTxBufIdx == emsTxBufLen) {
USC0(EMSUART_UART) |= (1 << UCBRK); // set <BRK>
}
emsTxBufIdx++;
} }
} }
@@ -126,8 +121,10 @@ void ICACHE_RAM_ATTR EMSuart::emsuart_tx_timer_intr_handler() {
* init UART0 driver * init UART0 driver
*/ */
void ICACHE_FLASH_ATTR EMSuart::start(uint8_t tx_mode) { void ICACHE_FLASH_ATTR EMSuart::start(uint8_t tx_mode) {
if (tx_mode >= 5) { if (tx_mode > 50) {
emsTxWait = 5 * EMSUART_TX_BIT_TIME * (tx_mode + 10); // bittimes for tx_mode emsTxWait = 5 * EMSUART_TX_BIT_TIME * (tx_mode - 50); // bittimes wait before sending
} else if (tx_mode > 5) {
emsTxWait = 5 * EMSUART_TX_BIT_TIME * (tx_mode + 10); // bittimes wait between bytes
} }
if (tx_mode_ != 0xFF) { // it's a restart no need to configure uart if (tx_mode_ != 0xFF) { // it's a restart no need to configure uart
tx_mode_ = tx_mode; tx_mode_ = tx_mode;
@@ -222,12 +219,6 @@ void ICACHE_FLASH_ATTR EMSuart::restart() {
emsTxBufIdx = 0; emsTxBufIdx = 0;
emsTxBufLen = 0; emsTxBufLen = 0;
timer1_enable(TIM_DIV16, TIM_EDGE, TIM_SINGLE); timer1_enable(TIM_DIV16, TIM_EDGE, TIM_SINGLE);
if (tx_mode_ == 5) {
USC0(EMSUART_UART) = 0x2C; // 8N1.5
} else {
USC0(EMSUART_UART) = EMSUART_CONFIG; // 8N1
}
} }
/* /*
@@ -260,21 +251,22 @@ void EMSuart::send_poll(uint8_t data) {
USC0(EMSUART_UART) &= ~(1 << UCBRK); USC0(EMSUART_UART) &= ~(1 << UCBRK);
sending_ = true; sending_ = true;
if (tx_mode_ > 5) { // timer controlled modes if (tx_mode_ > 50) { // timer controlled modes
USF(EMSUART_UART) = data; emsTxBuf[0] = data;
emsTxBufIdx = 0; emsTxBufLen = 1;
emsTxBufLen = 1;
timer1_write(emsTxWait); timer1_write(emsTxWait);
} else if (tx_mode_ == 5) { // reload sendbuffer in irq } else if (tx_mode_ > 5) { // timer controlled modes
USIC(EMSUART_UART) |= (1 << UIFF); // clear fifo-full irq emsTxBuf[0] = data;
USC1(EMSUART_UART) = (0x01 << UCFFT); // fifo full to 1 emsTxBufIdx = 0;
USF(EMSUART_UART) = data; emsTxBufLen = 1;
emsTxBufIdx = 0; timer1_write(emsTxWait);
emsTxBufLen = 1; }else if (tx_mode_ == 5) {
USIE(EMSUART_UART) |= (1 << UIFF); // enable fifo-full irq delayMicroseconds(3000);
USF(EMSUART_UART) = data;
USC0(EMSUART_UART) |= (1 << UCBRK);
} else if (tx_mode_ == EMS_TXMODE_NEW) { // hardware controlled modes } else if (tx_mode_ == EMS_TXMODE_NEW) { // hardware controlled modes
USF(EMSUART_UART) = data; USF(EMSUART_UART) = data;
USC0(EMSUART_UART) |= (1 << UCBRK); // brk after sendout USC0(EMSUART_UART) |= (1 << UCBRK);
} else if (tx_mode_ == EMS_TXMODE_HT3) { } else if (tx_mode_ == EMS_TXMODE_HT3) {
USF(EMSUART_UART) = data; USF(EMSUART_UART) = data;
delayMicroseconds(EMSUART_TX_WAIT_HT3); delayMicroseconds(EMSUART_TX_WAIT_HT3);
@@ -316,28 +308,32 @@ uint16_t ICACHE_FLASH_ATTR EMSuart::transmit(uint8_t * buf, uint8_t len) {
USC0(EMSUART_UART) &= ~(1 << UCBRK); USC0(EMSUART_UART) &= ~(1 << UCBRK);
sending_ = true; sending_ = true;
// all at once after a inititial timer delay
if (tx_mode_ > 50) {
for (uint8_t i = 0; i < len; i++) {
emsTxBuf[i] = buf[i];
}
emsTxBufLen = len;
timer1_write(emsTxWait);
return EMS_TX_STATUS_OK;
}
// timer controlled modes with extra delay // timer controlled modes with extra delay
if (tx_mode_ > 5) { if (tx_mode_ > 5) {
for (uint8_t i = 0; i < len; i++) { for (uint8_t i = 0; i < len; i++) {
emsTxBuf[i] = buf[i]; emsTxBuf[i] = buf[i];
} }
emsTxBufIdx = 0; emsTxBufIdx = 0;
emsTxBufLen = len; emsTxBufLen = len;
USF(EMSUART_UART) = buf[0];
timer1_write(emsTxWait); timer1_write(emsTxWait);
return EMS_TX_STATUS_OK; return EMS_TX_STATUS_OK;
} }
// interrupt controlled mode: readback in rx-irq and send next byte // fixed dealy before sending
if (tx_mode_ == 5) { if (tx_mode_ == 5) {
delayMicroseconds(3000);
for (uint8_t i = 0; i < len; i++) { for (uint8_t i = 0; i < len; i++) {
emsTxBuf[i] = buf[i]; USF(EMSUART_UART) = buf[i];
} }
USIC(EMSUART_UART) |= (1 << UIFF); // clear fifo-full irq USC0(EMSUART_UART) |= (1 << UCBRK); // send <BRK> at the end
emsTxBufIdx = 0;
emsTxBufLen = len;
USC1(EMSUART_UART) = (0x01 << UCFFT); // fifo full to 1
USIE(EMSUART_UART) |= (1 << UIFF); // enable fifo-full irq
USF(EMSUART_UART) = buf[0];
return EMS_TX_STATUS_OK; return EMS_TX_STATUS_OK;
} }