esp32 uart
This commit is contained in:
MichaelDvP
2020-05-29 16:06:10 +02:00
19 changed files with 179 additions and 119 deletions

View File

@@ -2,9 +2,9 @@
; For EMS-ESP
[platformio]
default_envs = esp8266
; default_envs = esp8266
; default_envs = esp32
;default_envs = esp32_d1
default_envs = esp32_d1
# override any settings with your own local ones in pio_local.ini
extra_configs = pio_local.ini
@@ -26,7 +26,11 @@ debug_flags =
; -D EMSESP_SAFE_MODE
; -D ENABLE_CORS -D CORS_ORIGIN=\"http://localhost:3000\"
build_flags = -std=c++11 -Os -fno-exceptions
; default platformio compile flags are:
; -fno-rtti -std=c++11 -Os -mlongcalls -mtext-section-literals -falign-functions=4 -ffunction-sections -fdata-sections -fno-exceptions -Wall
; (note -flto doesn't make a different to flash)
build_flags =
-D ONEWIRE_CRC16=0
-D NO_GLOBAL_ARDUINOOTA
-D ARDUINOJSON_ENABLE_STD_STRING=1
@@ -59,7 +63,7 @@ check_flags =
clangtidy: --checks=-*,clang-analyzer-*,performance-*
; USB upload
; upload_protocol = esptool
;upload_protocol = esptool
; example ports for OSX
;upload_port = /dev/cu.wchusbserial14403
;upload_port = /dev/cu.usbserial-1440
@@ -70,7 +74,7 @@ upload_protocol = espota
upload_flags =
--port=8266
--auth=neo
upload_port = 192.168.0.20
upload_port = 192.168.0.23
[env:esp8266]
build_type = release
@@ -80,9 +84,9 @@ board = esp12e
; board = d1_mini ; https://github.com/platformio/platform-espressif8266/blob/master/boards/d1_mini.json
lib_deps = ${common.libs_core} ${common.libs_esp8266}
board_build.f_cpu = 160000000L ; 160MHz
;board_build.ldscript = eagle.flash.4m1m.ld ; 1019 KB sketch, 1000 KB SPIFFS. 4KB EEPROM, 4KB RFCAL, 12KB WIFI stack, 2052 KB OTA & buffer
board_build.ldscript = eagle.flash.4m2m.ld ; 1019 KB sketch, 2024 KB SPIFFS. 4KB EEPROM, 4KB RFCAL, 12KB WIFI stack, 1028 KB OTA & buffer
build_flags = ${common.build_flags} ${common.debug_flags} -flto -D PIO_FRAMEWORK_ARDUINO_LWIP2_LOW_MEMORY
board_build.ldscript = eagle.flash.4m1m.ld ; 1019 KB sketch, 1000 KB SPIFFS. 4KB EEPROM, 4KB RFCAL, 12KB WIFI stack, 2052 KB OTA & buffer
; board_build.ldscript = eagle.flash.4m2m.ld ; 1019 KB sketch, 2024 KB SPIFFS. 4KB EEPROM, 4KB RFCAL, 12KB WIFI stack, 1028 KB OTA & buffer
build_flags = ${common.build_flags} ${common.debug_flags} -D PIO_FRAMEWORK_ARDUINO_LWIP2_LOW_MEMORY
[env:esp32]
build_type = release

View File

@@ -431,7 +431,7 @@ void Console::start() {
shell->log_level(uuid::log::Level::DEBUG); // order is: err, warning, notice, info, trace, debug, all
}
// always start the telnet service
// always start the telnet service, except on an ESP8266
// default idle is 10 minutes, default write timeout is 0 (automatic)
// note, this must be started after the network/wifi for ESP32 otherwise it'll crash
#ifndef EMSESP_STANDALONE

View File

@@ -58,9 +58,9 @@
// Switches - 0x11
{ 71, DeviceType::SWITCH, F("WM10"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x11
// Controllers - 0x09 / 0x10
// Controllers - 0x09 / 0x10 / 0x50
{ 68, DeviceType::CONTROLLER, F("BC10/RFM20"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x09
{ 89, DeviceType::CONTROLLER, F("BC"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x09
{ 89, DeviceType::CONTROLLER, F("BC10 GB142"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x09
{218, DeviceType::CONTROLLER, F("M200/RFM200"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x50
{190, DeviceType::CONTROLLER, F("BC10"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x09
{114, DeviceType::CONTROLLER, F("BC10"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x09
@@ -79,7 +79,7 @@
// Gateways - 0x48 / 0x18
{189, DeviceType::GATEWAY, F("KM200"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x48
{ 94, DeviceType::GATEWAY, F("RC"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x18
{ 94, DeviceType::GATEWAY, F("RFM20 Remote Base for RC20RF"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x18
// Thermostat - not currently supporting write operations, like the Easy/100 types - 0x18
{202, DeviceType::THERMOSTAT, F("Logamatic TC100/Moduline Easy"), DeviceFlags::EMS_DEVICE_FLAG_EASY | DeviceFlags::EMS_DEVICE_FLAG_NO_WRITE}, // 0x18, cannot write

View File

@@ -169,6 +169,17 @@ void EMSdevice::fetch_values() {
}
}
// toggle on/off automatic fetch for a telegram id
void EMSdevice::toggle_fetch(uint16_t telegram_id, bool toggle) {
LOG_DEBUG(F("Toggling fetch for device ID 0x%02X, telegram ID 0x%02X to %d"), device_id(), telegram_id, toggle);
for (auto & tf : telegram_functions_) {
if (tf.telegram_type_id_ == telegram_id) {
tf.fetch_ = toggle;
}
}
}
// list all the telegram type IDs for this device
void EMSdevice::show_telegram_handlers(uuid::console::Shell & shell) {
if (telegram_functions_.size() == 0) {
@@ -227,9 +238,17 @@ std::string EMSdevice::telegram_type_name(std::shared_ptr<const Telegram> telegr
// take a telegram_type_id and call the matching handler
// return true if match found
bool EMSdevice::process_telegram(std::shared_ptr<const Telegram> telegram) {
bool EMSdevice::handle_telegram(std::shared_ptr<const Telegram> telegram) {
for (const auto & tf : telegram_functions_) {
if (tf.telegram_type_id_ == telegram->type_id) {
// if the data block is empty, assume that this telegram is not recognized by the bus master
// so remove it from the automatic fetch list
if (telegram->message_length == 0) {
LOG_DEBUG(F("This telegram (%s) is not recognized by the EMS bus"), uuid::read_flash_string(tf.telegram_type_name_).c_str());
toggle_fetch(tf.telegram_type_id_, false);
return false;
}
LOG_DEBUG(F("Processing %s..."), uuid::read_flash_string(tf.telegram_type_name_).c_str());
tf.process_function_(telegram);
return true;

View File

@@ -99,7 +99,7 @@ class EMSdevice {
using process_function_p = std::function<void(std::shared_ptr<const Telegram>)>;
void register_telegram_type(const uint16_t telegram_type_id, const __FlashStringHelper * telegram_type_name, bool fetch, process_function_p cb);
bool process_telegram(std::shared_ptr<const Telegram> telegram);
bool handle_telegram(std::shared_ptr<const Telegram> telegram);
void write_command(const uint16_t type_id, const uint8_t offset, uint8_t * message_data, const uint8_t message_length, const uint16_t validate_typeid);
void write_command(const uint16_t type_id, const uint8_t offset, const uint8_t value, const uint16_t validate_typeid);
@@ -118,6 +118,7 @@ class EMSdevice {
std::string telegram_type_name(std::shared_ptr<const Telegram> telegram);
void fetch_values();
void toggle_fetch(uint16_t telegram_id, bool toggle);
void print_value(uuid::console::Shell & shell, uint8_t padding, const __FlashStringHelper * name, const __FlashStringHelper * prefix, const char * value);
void print_value(uuid::console::Shell & shell, uint8_t padding, const __FlashStringHelper * name, const char * value);

View File

@@ -422,7 +422,7 @@ bool EMSESP::process_telegram(std::shared_ptr<const Telegram> telegram) {
for (const auto & emsdevice : emsdevices) {
if (emsdevice) {
if (emsdevice->is_device_id(telegram->src)) {
found = emsdevice->process_telegram(telegram);
found = emsdevice->handle_telegram(telegram);
// check to see if we need to force an MQTT publish
if (found) {
if (emsdevice->updated_values()) {
@@ -702,6 +702,9 @@ void EMSESP::console_commands(Shell & shell, unsigned int context) {
settings.ems_tx_mode(tx_mode);
settings.commit();
shell.printfln(F_(tx_mode_fmt), settings.ems_tx_mode());
// reset the UART
EMSuart::stop();
EMSuart::start(tx_mode);
} else {
shell.println(F("Must be 1 for EMS generic, 2 for EMS+, 3 for HT3, 4 for experimental"));
}

View File

@@ -152,7 +152,7 @@ char * Helpers::render_value(char * result, const int16_t value, const uint8_t f
result[0] = '\0';
// remove errors or invalid values, 0x7D00 and higher
if ((value == EMS_VALUE_SHORT_NOTSET) || (value == EMS_VALUE_SHORT_INVALID)) {
if ((value == EMS_VALUE_SHORT_NOTSET) || (value == EMS_VALUE_SHORT_INVALID) || (value == EMS_VALUE_USHORT_NOTSET)) {
strlcpy(result, "?", 10);
return result;
}

View File

@@ -31,7 +31,7 @@ Mixing::Mixing(uint8_t device_type, uint8_t device_id, uint8_t product_id, const
if (flags == EMSdevice::EMS_DEVICE_FLAG_MMPLUS) {
if (device_id < 0x28) {
// telegram handlers 0x20 - 0x27 for HC
register_telegram_type(device_id -0x20 + 0x02D7, F("MMPLUSStatusMessage_HC"), true, std::bind(&Mixing::process_MMPLUSStatusMessage_HC, this, _1));
register_telegram_type(device_id - 0x20 + 0x02D7, F("MMPLUSStatusMessage_HC"), true, std::bind(&Mixing::process_MMPLUSStatusMessage_HC, this, _1));
} else {
// telegram handlers for warm water/DHW 0x28, 0x29
register_telegram_type(device_id - 0x28 + 0x0331, F("MMPLUSStatusMessage_WWC"), true, std::bind(&Mixing::process_MMPLUSStatusMessage_WWC, this, _1));
@@ -54,6 +54,15 @@ Mixing::Mixing(uint8_t device_type, uint8_t device_id, uint8_t product_id, const
void Mixing::add_context_menu() {
}
// check to see if values have been updated
bool Mixing::updated_values() {
return false;
}
// add console commands
void Mixing::console_commands() {
}
// display all values into the shell console
void Mixing::show_values(uuid::console::Shell & shell) {
EMSdevice::show_values(shell); // always call this to show header
@@ -86,10 +95,10 @@ void Mixing::publish_values() {
if (mqtt_format_ == Settings::MQTT_format::SINGLE) {
switch (type_) {
case Type::HC:
rootMixing["type"] = F("hc");
rootMixing["type"] = "hc";
break;
case Type::WWC:
rootMixing["type"] = F("wwc");
rootMixing["type"] = "wwc";
break;
case Type::NONE:
default:
@@ -141,15 +150,6 @@ void Mixing::publish_values() {
Mqtt::publish(topic, doc);
}
// check to see if values have been updated
bool Mixing::updated_values() {
return false;
}
// add console commands
void Mixing::console_commands() {
}
// heating circuits 0x02D7, 0x02D8 etc...
void Mixing::process_MMPLUSStatusMessage_HC(std::shared_ptr<const Telegram> telegram) {
type_ = Type::HC;

View File

@@ -73,14 +73,14 @@ void Network::sta_mode_start(WiFiEvent_t event, WiFiEventInfo_t info) {
#if defined(ESP8266)
void Network::sta_mode_connected(const WiFiEventStationModeConnected & event) {
LOG_INFO(F("Connected to %s (%02X:%02X:%02X:%02X:%02X:%02X) on channel %u"),
event.ssid.c_str(),
event.bssid[0],
event.bssid[1],
event.bssid[2],
event.bssid[3],
event.bssid[4],
event.bssid[5],
event.channel);
event.ssid.c_str(),
event.bssid[0],
event.bssid[1],
event.bssid[2],
event.bssid[3],
event.bssid[4],
event.bssid[5],
event.channel);
// turn off safe mode
System::save_safe_mode(false);
@@ -88,14 +88,14 @@ void Network::sta_mode_connected(const WiFiEventStationModeConnected & event) {
#elif defined(ESP32)
void Network::sta_mode_connected(WiFiEvent_t event, WiFiEventInfo_t info) {
LOG_INFO(F("Connected to %s (%02X:%02X:%02X:%02X:%02X:%02X) on channel %u"),
info.connected.ssid,
info.sta_connected.mac[0],
info.sta_connected.mac[1],
info.sta_connected.mac[2],
info.sta_connected.mac[3],
info.sta_connected.mac[4],
info.sta_connected.mac[5],
info.connected.channel);
info.connected.ssid,
info.sta_connected.mac[0],
info.sta_connected.mac[1],
info.sta_connected.mac[2],
info.sta_connected.mac[3],
info.sta_connected.mac[4],
info.sta_connected.mac[5],
info.connected.channel);
// turn off safe mode
System::save_safe_mode(false);
@@ -126,16 +126,16 @@ void Network::sta_mode_disconnected(WiFiEvent_t event, WiFiEventInfo_t info) {
#if defined(ESP8266)
void Network::sta_mode_got_ip(const WiFiEventStationModeGotIP & event) {
LOG_INFO(F("Obtained IPv4 address %s/%s and gateway %s"),
uuid::printable_to_string(event.ip).c_str(),
uuid::printable_to_string(event.mask).c_str(),
uuid::printable_to_string(event.gw).c_str());
uuid::printable_to_string(event.ip).c_str(),
uuid::printable_to_string(event.mask).c_str(),
uuid::printable_to_string(event.gw).c_str());
}
#elif defined(ESP32)
void Network::sta_mode_got_ip(WiFiEvent_t event, WiFiEventInfo_t info) {
LOG_INFO(F("Obtained IPv4 address %s/%s and gateway %s"),
uuid::printable_to_string(IPAddress(info.got_ip.ip_info.ip.addr)).c_str(),
uuid::printable_to_string(IPAddress(info.got_ip.ip_info.netmask.addr)).c_str(),
uuid::printable_to_string(IPAddress(info.got_ip.ip_info.gw.addr)).c_str());
uuid::printable_to_string(IPAddress(info.got_ip.ip_info.ip.addr)).c_str(),
uuid::printable_to_string(IPAddress(info.got_ip.ip_info.netmask.addr)).c_str(),
uuid::printable_to_string(IPAddress(info.got_ip.ip_info.gw.addr)).c_str());
}
#endif
@@ -148,11 +148,16 @@ void Network::connect() {
#ifndef EMSESP_STANDALONE
// WiFi.mode(WIFI_STA);
if (!settings.hostname().empty()) {
#if defined(ESP8266)
// experiment with fixed IP
// IPAddress ip(10, 10, 10, 140);
// IPAddress gateway(10, 10, 10, 1);
// IPAddress subnet(255, 255, 255, 0);
// WiFi.config(ip, gateway, subnet);
WiFi.config(INADDR_ANY, INADDR_ANY, INADDR_ANY);
WiFi.hostname(settings.hostname().c_str());
#elif defined(ESP32)
WiFi.config(INADDR_NONE, INADDR_NONE, INADDR_NONE);
@@ -205,9 +210,11 @@ void Network::ota_setup() {
ota_->onStart([this]() {
LOG_DEBUG(F("OTA starting (send type %d)..."), ota_->getCommand());
// turn off stuff to stop interference
// turn off UART stuff to stop interference on an ESP8266 only
#if defined(ESP8266)
EMSuart::stop(); // UART stop
in_ota_ = true; // set flag so all other services stop
#endif
in_ota_ = true; // set flag so all other services stop
});
ota_->onEnd([this]() { LOG_DEBUG(F("OTA done, automatically restarting")); });

View File

@@ -254,9 +254,9 @@ void Settings::show_settings(uuid::console::Shell & shell) {
// format the FS. Wipes everything.
void Settings::format(uuid::console::Shell & shell) {
EMSuart::stop();
#ifndef EMSESP_STANDALONE
#if defined(ESP8266)
EMSuart::stop();
if (EMSESP_FS.begin()) {
#elif defined(ESP32)
if (EMSESP_FS.begin(true)) {
@@ -275,8 +275,10 @@ void Settings::format(uuid::console::Shell & shell) {
auto msg = F("Unable to mount filesystem");
shell.logger().alert(msg);
}
#if defined(ESP8266)
EMSuart::restart();
#endif
#endif
}
void Settings::syslog_host(const std::string & syslog_host) {

View File

@@ -45,8 +45,6 @@ uuid::log::Logger System::logger_{F_(logger_name), uuid::log::Facility::KERN};
uuid::syslog::SyslogService System::syslog_;
#endif
EMSuart System::emsuart_;
#if defined(ESP8266)
RTCVars System::state_;
#endif
@@ -87,7 +85,6 @@ void System::mqtt_commands(const char * message) {
// restart EMS-ESP
// mode = safe mode. true to enable on next boot
void System::restart(bool mode) {
EMSuart::stop();
// check for safe mode
if (mode) {
@@ -171,7 +168,7 @@ void System::start() {
if (safe_mode()) {
} else {
save_safe_mode(false); // next time boot up in normal mode
emsuart_.start(settings.ems_tx_mode());
EMSuart::start(settings.ems_tx_mode());
}
#endif
}

View File

@@ -107,8 +107,6 @@ class System {
static uint32_t heap_start_;
static int reset_counter_;
static EMSuart emsuart_;
#if defined(ESP8266)
static RTCVars state_;
#endif

View File

@@ -43,6 +43,7 @@ bool EMSbus::bus_connected_ = false; // start assuming the bus
uint8_t EMSbus::ems_mask_ = EMS_MASK_UNSET; // unset so its triggered when booting, the its 0x00=buderus, 0x80=junker/ht3
uint8_t EMSbus::ems_bus_id_ = EMSESP_DEFAULT_BUS_ID;
bool EMSbus::tx_waiting_ = false;
bool EMSbus::tx_active_ = false;
uuid::log::Logger EMSbus::logger_{F_(logger_name), uuid::log::Facility::CONSOLE};
@@ -278,7 +279,7 @@ void RxService::add(uint8_t * data, uint8_t length) {
// EMS 2.0 / EMS+
if (data[2] == 0xFF) {
// check for empty data
// special broadcast telegrams on ems+ have no data values, some even don't have a type ID
// special broadcast telegrams on ems+ have no data values, some even don't have a type ID, e.g. "21 0B FF 00"
if (length <= 7) {
message_data = data; // bogus pointer, will not be used
message_length = 0;
@@ -355,8 +356,8 @@ void TxService::loop() {
#ifndef EMSESP_STANDALONE
if ((uuid::get_uptime() - last_tx_check_) > TX_LOOP_WAIT) {
last_tx_check_ = uuid::get_uptime();
if ((tx_telegrams_.size() >= MAX_TX_TELEGRAMS - 1) && (EMSbus::bus_connected())) {
LOG_ERROR(F("Tx buffer full. Looks like Tx is not working?"));
if (!tx_active_ && (EMSbus::bus_connected())) {
LOG_ERROR(F("Tx is not active. Please check connection."));
}
}
#endif

View File

@@ -139,8 +139,15 @@ class EMSbus {
return tx_waiting_;
}
static bool tx_active_; // whether Tx is active or not
static void tx_waiting(bool tx_waiting) {
tx_waiting_ = tx_waiting;
// if false, then it's been reset which means we have an active Tx
if (!tx_waiting) {
tx_active_ = true;
}
}
static uint8_t calculate_crc(const uint8_t * data, const uint8_t length);
@@ -150,14 +157,14 @@ class EMSbus {
static uint32_t last_bus_activity_; // timestamp of last time a valid Rx came in
static bool bus_connected_; // start assuming the bus hasn't been connected
static uint8_t ems_mask_; // unset 0x00 buderus 0x80 junker/ht3
static uint8_t ems_mask_; // unset 0x00 buderus 0x80 junkers/ht3
static uint8_t ems_bus_id_; // the bus id, which configurable and stored in settings
static bool tx_waiting_; // state of the Tx queue (idle, waiting for ack)
};
class RxService : public EMSbus {
public:
static constexpr size_t MAX_RX_TELEGRAMS = 10;
static constexpr size_t MAX_RX_TELEGRAMS = 20;
RxService() = default;
~RxService() = default;
@@ -213,7 +220,7 @@ class RxService : public EMSbus {
class TxService : public EMSbus {
public:
static constexpr size_t MAX_TX_TELEGRAMS = 30;
static constexpr size_t MAX_TX_TELEGRAMS = 40; // size of Tx queue
static constexpr uint8_t TX_WRITE_FAIL = 4;
static constexpr uint8_t TX_WRITE_SUCCESS = 1;

View File

@@ -35,7 +35,7 @@ uuid::log::Logger Thermostat::logger_{F_(logger_name), uuid::log::Facility::CONS
Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_id, const std::string & version, const std::string & name, uint8_t flags, uint8_t brand)
: EMSdevice(device_type, device_id, product_id, version, name, flags, brand) {
// telegram handlers
// common telegram handlers
register_telegram_type(EMS_TYPE_RCOutdoorTemp, F("RCOutdoorTemp"), false, std::bind(&Thermostat::process_RCOutdoorTemp, this, _1));
register_telegram_type(EMS_TYPE_RCTime, F("RCTime"), true, std::bind(&Thermostat::process_RCTime, this, _1)); // 0x06
@@ -44,8 +44,8 @@ Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_i
monitor_typeids = {0xB1};
set_typeids = {0xB0};
for (uint8_t i = 0; i < monitor_typeids.size(); i++) {
register_telegram_type(monitor_typeids[i], F("RC10Monitor"), true, std::bind(&Thermostat::process_RC10Monitor, this, _1));
register_telegram_type(set_typeids[i], F("RC10Set"), true, std::bind(&Thermostat::process_RC10Set, this, _1));
register_telegram_type(monitor_typeids[i], F("RC10Monitor"), false, std::bind(&Thermostat::process_RC10Monitor, this, _1));
register_telegram_type(set_typeids[i], F("RC10Set"), false, std::bind(&Thermostat::process_RC10Set, this, _1));
}
// RC35
@@ -53,8 +53,8 @@ Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_i
monitor_typeids = {0x3E, 0x48, 0x52, 0x5C};
set_typeids = {0x3D, 0x47, 0x51, 0x5B};
for (uint8_t i = 0; i < monitor_typeids.size(); i++) {
register_telegram_type(monitor_typeids[i], F("RC35Monitor"), true, std::bind(&Thermostat::process_RC35Monitor, this, _1));
register_telegram_type(set_typeids[i], F("RC35Set"), true, std::bind(&Thermostat::process_RC35Set, 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(EMS_TYPE_IBASettings, F("IBASettings"), true, std::bind(&Thermostat::process_IBASettings, this, _1));
@@ -63,8 +63,8 @@ Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_i
monitor_typeids = {0x91};
set_typeids = {0xA8};
for (uint8_t i = 0; i < monitor_typeids.size(); i++) {
register_telegram_type(monitor_typeids[i], F("RC20Monitor"), true, std::bind(&Thermostat::process_RC20Monitor, this, _1));
register_telegram_type(set_typeids[i], F("RC20Set"), true, std::bind(&Thermostat::process_RC20Set, this, _1));
register_telegram_type(monitor_typeids[i], F("RC20Monitor"), false, std::bind(&Thermostat::process_RC20Monitor, this, _1));
register_telegram_type(set_typeids[i], F("RC20Set"), false, std::bind(&Thermostat::process_RC20Set, this, _1));
}
// RC20 newer
@@ -72,8 +72,8 @@ Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_i
monitor_typeids = {0xAE};
set_typeids = {0xAD};
for (uint8_t i = 0; i < monitor_typeids.size(); i++) {
register_telegram_type(monitor_typeids[i], F("RC20Monitor"), true, std::bind(&Thermostat::process_RC20Monitor_2, this, _1));
register_telegram_type(set_typeids[i], F("RC20Set"), true, std::bind(&Thermostat::process_RC20Set_2, this, _1));
register_telegram_type(monitor_typeids[i], F("RC20Monitor"), false, std::bind(&Thermostat::process_RC20Monitor_2, this, _1));
register_telegram_type(set_typeids[i], F("RC20Set"), false, std::bind(&Thermostat::process_RC20Set_2, this, _1));
}
// RC30
@@ -81,23 +81,23 @@ Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_i
monitor_typeids = {0x41};
set_typeids = {0xA7};
for (uint8_t i = 0; i < monitor_typeids.size(); i++) {
register_telegram_type(monitor_typeids[i], F("RC30Monitor"), true, std::bind(&Thermostat::process_RC30Monitor, this, _1));
register_telegram_type(set_typeids[i], F("RC30Set"), true, std::bind(&Thermostat::process_RC30Set, this, _1));
register_telegram_type(monitor_typeids[i], F("RC30Monitor"), false, std::bind(&Thermostat::process_RC30Monitor, this, _1));
register_telegram_type(set_typeids[i], F("RC30Set"), false, std::bind(&Thermostat::process_RC30Set, this, _1));
}
// EASY
} else if (flags == EMSdevice::EMS_DEVICE_FLAG_EASY) {
monitor_typeids = {0x0A};
set_typeids = {};
register_telegram_type(monitor_typeids[0], F("EasyMonitor"), true, std::bind(&Thermostat::process_EasyMonitor, this, _1));
register_telegram_type(monitor_typeids[0], F("EasyMonitor"), false, std::bind(&Thermostat::process_EasyMonitor, this, _1));
// RC300/RC100
} else if ((flags == EMSdevice::EMS_DEVICE_FLAG_RC300) || (flags == EMSdevice::EMS_DEVICE_FLAG_RC100)) {
monitor_typeids = {0x02A5, 0x02A6, 0x02A7, 0x02A8};
set_typeids = {0x02B9, 0x02BA, 0x02BB, 0x02BC};
for (uint8_t i = 0; i < monitor_typeids.size(); i++) {
register_telegram_type(monitor_typeids[i], F("RC300Monitor"), true, std::bind(&Thermostat::process_RC300Monitor, this, _1));
register_telegram_type(set_typeids[i], F("RC300Set"), true, std::bind(&Thermostat::process_RC300Set, this, _1));
register_telegram_type(monitor_typeids[i], F("RC300Monitor"), false, std::bind(&Thermostat::process_RC300Monitor, this, _1));
register_telegram_type(set_typeids[i], F("RC300Set"), false, std::bind(&Thermostat::process_RC300Set, this, _1));
}
// JUNKERS/HT3
@@ -105,16 +105,16 @@ Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_i
monitor_typeids = {0x6F, 0x70, 0x71, 0x72};
set_typeids = {0x65, 0x66, 0x67, 0x68};
for (uint8_t i = 0; i < monitor_typeids.size(); i++) {
register_telegram_type(monitor_typeids[i], F("JunkersMonitor"), true, std::bind(&Thermostat::process_JunkersMonitor, this, _1));
register_telegram_type(set_typeids[i], F("JunkersSet"), true, std::bind(&Thermostat::process_JunkersSet, this, _1));
register_telegram_type(monitor_typeids[i], F("JunkersMonitor"), false, std::bind(&Thermostat::process_JunkersMonitor, this, _1));
register_telegram_type(set_typeids[i], F("JunkersSet"), false, std::bind(&Thermostat::process_JunkersSet, this, _1));
}
} else if (flags == (EMSdevice::EMS_DEVICE_FLAG_JUNKERS | EMSdevice::EMS_DEVICE_FLAG_JUNKERS_2)) {
monitor_typeids = {0x6F, 0x70, 0x71, 0x72};
set_typeids = {0x79, 0x7A, 0x7B, 0x7C};
for (uint8_t i = 0; i < monitor_typeids.size(); i++) {
register_telegram_type(monitor_typeids[i], F("JunkersMonitor"), true, std::bind(&Thermostat::process_JunkersMonitor, this, _1));
register_telegram_type(set_typeids[i], F("JunkersSet"), true, std::bind(&Thermostat::process_JunkersSet, this, _1));
register_telegram_type(monitor_typeids[i], F("JunkersMonitor"), false, std::bind(&Thermostat::process_JunkersMonitor, this, _1));
register_telegram_type(set_typeids[i], F("JunkersSet"), false, std::bind(&Thermostat::process_JunkersSet, this, _1));
}
}
@@ -510,6 +510,7 @@ std::shared_ptr<Thermostat::HeatingCircuit> Thermostat::heating_circuit(const ui
// determine which heating circuit the type ID is referring too
// returns pointer to the HeatingCircuit or nullptr if it can't be found
// if its a new one, the object will be created and also the fetch flags set
std::shared_ptr<Thermostat::HeatingCircuit> Thermostat::heating_circuit(std::shared_ptr<const Telegram> telegram) {
// look through the Monitor and Set arrays to see if there is a match
uint8_t hc_num = 0;
@@ -545,8 +546,12 @@ std::shared_ptr<Thermostat::HeatingCircuit> Thermostat::heating_circuit(std::sha
}
// create a new heating circuit object
// TODO do we need to create a new object if using emplace_back?
heating_circuits_.emplace_back(new HeatingCircuit(hc_num, monitor_typeids[hc_num - 1], set_typeids[hc_num - 1]));
// set the flag saying we want its data during the next auto fetch
toggle_fetch(monitor_typeids[hc_num - 1], true);
toggle_fetch(set_typeids[hc_num - 1], true);
return heating_circuits_.back();
}
@@ -667,17 +672,16 @@ std::string Thermostat::mode_tostring(uint8_t mode) const {
void Thermostat::show_values(uuid::console::Shell & shell) {
EMSdevice::show_values(shell); // always call this to show header
char buffer[10]; // for formatting only
char buffer[10]; // for formatting only
uint8_t flags = (this->flags() & 0x0F); // specific thermostat characteristics, strip the option bits
if (datetime_.size()) {
shell.printfln(F(" Clock: %s"), datetime_.c_str());
if (ibaClockOffset != EMS_VALUE_UINT_NOTSET) {
if (ibaClockOffset != EMS_VALUE_UINT_NOTSET && flags == EMS_DEVICE_FLAG_RC30_1) {
print_value(shell, 2, F("Offset clock"), Helpers::render_value(buffer, ibaClockOffset, 1)); // offset (in sec) to clock, 0xff = -1 s, 0x02 = 2 s
}
}
uint8_t flags = (this->flags() & 0x0F); // specific thermostat characteristics, strip the option bits
if (flags == EMS_DEVICE_FLAG_RC35) {
print_value(shell, 2, F("Damped Outdoor temperature"), F_(degrees), Helpers::render_value(buffer, dampedoutdoortemp, 1));
print_value(shell, 2, F("Tempsensor 1"), F_(degrees), Helpers::render_value(buffer, tempsensor1, 10));
@@ -719,7 +723,7 @@ void Thermostat::show_values(uuid::console::Shell & shell) {
}
}
}
if (flags == EMS_DEVICE_FLAG_RC35 ||flags == EMS_DEVICE_FLAG_RC30_1) {
if (flags == EMS_DEVICE_FLAG_RC35 || flags == EMS_DEVICE_FLAG_RC30_1) {
if (ibaCalIntTemperature != EMS_VALUE_INT_NOTSET) {
print_value(shell, 2, F("Offset int. temperature"), F_(degrees), Helpers::render_value(buffer, ibaCalIntTemperature, 2));

View File

@@ -29,15 +29,14 @@
namespace emsesp {
static intr_handle_t uart_handle;
static RingbufHandle_t buf_handle = NULL;
static uint8_t rxbuf[UART_FIFO_LEN];
static uint8_t rxlen;
bool drop_first_rx = true;
static RingbufHandle_t buf_handle = NULL;
static bool drop_first_rx = true;
static uint8_t tx_mode_ = 0xFF;
/*
* Task to handle the incoming data
*/
void EMSuart::emsuart_recvTask(void * param) {
void EMSuart::emsuart_recvTask(void * para) {
while (1) {
size_t item_size;
uint8_t * telegram = (uint8_t *)xRingbufferReceive(buf_handle, &item_size, portMAX_DELAY);
@@ -52,24 +51,36 @@ void EMSuart::emsuart_recvTask(void * param) {
/*
* UART interrupt, on break read the fifo and put the whole telegram to ringbuffer
*/
void IRAM_ATTR EMSuart::uart_intr_handle(void * arg) {
void IRAM_ATTR EMSuart::emsuart_rx_intr_handler(void * para) {
static uint8_t rxbuf[EMS_MAXBUFFERSIZE];
static uint8_t length;
if (EMS_UART.int_st.brk_det) {
for (uint8_t rxlen = 0; EMS_UART.status.rxfifo_cnt > 0; rxlen++) {
rxbuf[rxlen] = EMS_UART.fifo.rw_byte; // read all bytes into buffer
}
if (!drop_first_rx && (rxlen == 2) || ((rxlen > 4) && (rxlen <= EMS_MAXBUFFERSIZE))) {
int baseType = 0;
xRingbufferSendFromISR(buf_handle, rxbuf, rxlen - 1, &baseType);
}
drop_first_rx = false;
EMS_UART.int_clr.brk_det = 1; // clear flag
EMS_UART.conf0.txd_brk = 0; // if it was break from sending, clear bit
length = 0;
while (EMS_UART.status.rxfifo_cnt) {
uint8_t rx = EMS_UART.fifo.rw_byte; // read all bytes into buffer
if (length < EMS_MAXBUFFERSIZE) {
rxbuf[length++] = rx;
}
}
if ((!drop_first_rx) && ((length == 2) || ((length > 4)))) {
int baseType = 0;
xRingbufferSendFromISR(buf_handle, rxbuf, length - 1, &baseType);
}
drop_first_rx = false;
}
}
/*
* init UART driver
*/
void EMSuart::start(uint8_t tx_mode) {
if (tx_mode_ != 0xFF) { // uart already initialized
restart();
return;
}
tx_mode_ = tx_mode;
uart_config_t uart_config = {
.baud_rate = EMSUART_BAUD,
.data_bits = UART_DATA_8_BITS,
@@ -80,12 +91,13 @@ void EMSuart::start(uint8_t tx_mode) {
ESP_ERROR_CHECK(uart_param_config(EMSUART_UART, &uart_config));
ESP_ERROR_CHECK(uart_set_pin(EMSUART_UART, EMSUART_TXPIN, EMSUART_RXPIN, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE));
EMS_UART.int_ena.val = 0; // disable all intr.
EMS_UART.int_clr.val = 0xFFFFFFFF; // clear all intr. flags
buf_handle = xRingbufferCreate(128, RINGBUF_TYPE_NOSPLIT);
ESP_ERROR_CHECK(uart_isr_register(EMSUART_UART, uart_intr_handle, NULL, ESP_INTR_FLAG_IRAM, &uart_handle));
EMS_UART.int_ena.val = 0; // disable all intr.
EMS_UART.int_clr.val = 0xFFFFFFFF; // clear all intr. flags
EMS_UART.idle_conf.tx_brk_num = 11; // breaklength 11 bit
drop_first_rx = true;
buf_handle = xRingbufferCreate(128, RINGBUF_TYPE_NOSPLIT);
ESP_ERROR_CHECK(uart_isr_register(EMSUART_UART, emsuart_rx_intr_handler, NULL, ESP_INTR_FLAG_IRAM, &uart_handle));
xTaskCreate(emsuart_recvTask, "emsuart_recvTask", 2048, NULL, 12, NULL);
drop_first_rx = true;
EMS_UART.int_ena.brk_det = 1; // activate only break
}
@@ -100,8 +112,8 @@ void EMSuart::stop() {
* Restart Interrupt
*/
void EMSuart::restart() {
if (EMS_UART.int_st.brk_det) {
EMS_UART.int.clr.brk_det = 1; // clear break if happend
if (EMS_UART.int_raw.brk_det) {
EMS_UART.int_clr.brk_det = 1; // clear flag
drop_first_rx = true; // and drop first frame
}
EMS_UART.int_ena.brk_det = 1; // activate only break
@@ -113,7 +125,7 @@ void EMSuart::restart() {
void EMSuart::send_poll(uint8_t data) {
EMS_UART.conf0.txd_brk = 0; // just to make sure the bit is cleared
EMS_UART.fifo.rw_byte = data;
EMS_UART.idle_conf.tx_brk_num = 11; // breaklength 11 bit
//EMS_UART.idle_conf.tx_brk_num = 11; // breaklength 11 bit
EMS_UART.conf0.txd_brk = 1; // sending ends in a break
}
@@ -129,7 +141,7 @@ EMSUART_STATUS EMSuart::transmit(uint8_t * buf, uint8_t len) {
EMS_UART.fifo.rw_byte = buf[i];
}
//uart_tx_chars(EMSUART_UART, (const char *)buf, len);
EMS_UART.idle_conf.tx_brk_num = 11; // breaklength 11 bit
//EMS_UART.idle_conf.tx_brk_num = 11; // breaklength 11 bit
EMS_UART.conf0.txd_brk = 1; // sending ends in a break
}
return EMS_TX_STATUS_OK;

View File

@@ -27,7 +27,7 @@
#include "freertos/queue.h"
#include <driver/uart.h>
#define EMS_MAXBUFFERSIZE 33 // max size of the buffer. EMS packets are max 32 bytes, plus extra 2 for BRKs
#define EMS_MAXBUFFERSIZE 33 // max size of the buffer. EMS packets are max 32 bytes, plus extra for BRK
#define EMSUART_UART UART_NUM_2 // on the ESP32 we're using UART2
#define EMS_UART UART2 // for intr setting
@@ -57,7 +57,7 @@ class EMSuart {
static EMSUART_STATUS transmit(uint8_t * buf, uint8_t len);
private:
static void emsuart_recvTask(void * param);
static void emsuart_recvTask(void * para);
static void IRAM_ATTR emsuart_rx_intr_handler(void * para);
};

View File

@@ -30,7 +30,7 @@ EMSuart::EMSRxBuf_t * pEMSRxBuf;
EMSuart::EMSRxBuf_t * paEMSRxBuf[EMS_MAXBUFFERS];
uint8_t emsRxBufIdx = 0;
uint8_t phantomBreak = 0;
uint8_t tx_mode_ = EMS_TXMODE_DEFAULT;
uint8_t tx_mode_ = 0xFF;
bool drop_first_rx = true;
//
@@ -127,8 +127,12 @@ void ICACHE_FLASH_ATTR EMSuart::emsuart_flush_fifos() {
* init UART0 driver
*/
void ICACHE_FLASH_ATTR EMSuart::start(uint8_t tx_mode) {
if (tx_mode_ != 0xFF) { // it's a restart no need to configure rx
tx_mode_ = tx_mode;
restart();
return;
}
tx_mode_ = tx_mode;
// allocate and preset EMS Receive buffers
for (int i = 0; i < EMS_MAXBUFFERS; i++) {
EMSRxBuf_t * p = (EMSRxBuf_t *)malloc(sizeof(EMSRxBuf_t));
@@ -205,6 +209,7 @@ void ICACHE_FLASH_ATTR EMSuart::restart() {
drop_first_rx = true;
}
ETS_UART_INTR_ENABLE();
// emsuart_flush_fifos();
}
/*

View File

@@ -1 +1 @@
#define EMSESP_APP_VERSION "2.0.0a9"
#define EMSESP_APP_VERSION "2.0.0a10"