Test new tx_mode 2, small changes to MM100, SM100 and RC300, see #397

This commit is contained in:
MichaelDvP
2020-06-13 10:29:03 +02:00
parent ee29a39140
commit b75eea44a1
16 changed files with 250 additions and 101 deletions

View File

@@ -49,8 +49,9 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const
LOG_DEBUG(F("Registering new Boiler with device ID 0x%02X"), device_id);
// the telegram handlers...
register_telegram_type(0x10, F("UBAErrorMessage1"), false, nullptr);
register_telegram_type(0x11, F("UBAErrorMessage2"), false, nullptr);
register_telegram_type(0x10, F("UBAErrorMessage1"), false, std::bind(&Boiler::process_UBAErrorMessage, this, _1));
register_telegram_type(0x11, F("UBAErrorMessage2"), false, std::bind(&Boiler::process_UBAErrorMessage, this, _1));
register_telegram_type(0x12, F("UBAErrorMessage3"), false, std::bind(&Boiler::process_UBAErrorMessage, this, _1));
register_telegram_type(0x18, F("UBAMonitorFast"), false, std::bind(&Boiler::process_UBAMonitorFast, this, _1));
register_telegram_type(0x19, F("UBAMonitorSlow"), true, std::bind(&Boiler::process_UBAMonitorSlow, this, _1));
register_telegram_type(0x34, F("UBAMonitorWW"), false, std::bind(&Boiler::process_UBAMonitorWW, this, _1));
@@ -679,6 +680,12 @@ void Boiler::process_UBAMaintenanceStatus(std::shared_ptr<const Telegram> telegr
void Boiler::process_UBAMaintenanceSettings(std::shared_ptr<const Telegram> telegram) {
}
// 0x10, 0x11, 0x12
// not yet implemented
void Boiler::process_UBAErrorMessage(std::shared_ptr<const Telegram> telegram) {
// data: displaycode(2), errornumner(2), year, month, hour, day, minute, duration(2), src-addr
}
#pragma GCC diagnostic pop
// Set the warm water temperature 0x33

View File

@@ -141,6 +141,7 @@ class Boiler : public EMSdevice {
void process_MC10Status(std::shared_ptr<const Telegram> telegram);
void process_UBAMaintenanceStatus(std::shared_ptr<const Telegram> telegram);
void process_UBAMaintenanceSettings(std::shared_ptr<const Telegram> telegram);
void process_UBAErrorMessage(std::shared_ptr<const Telegram> telegram);
void process_UBADHWStatus(std::shared_ptr<const Telegram> telegram);
void process_HPMonitor1(std::shared_ptr<const Telegram> telegram);

View File

@@ -40,9 +40,9 @@ Mixing::Mixing(uint8_t device_type, uint8_t device_id, uint8_t product_id, const
}
// EMS 1.0
if (flags == EMSdevice::EMS_DEVICE_FLAG_MM10) {
register_telegram_type(0x00AA, F("MMConfigMessage"), false, nullptr);
register_telegram_type(0x00AA, F("MMConfigMessage"), false, std::bind(&Mixing::process_MMConfigMessage, this, _1));
register_telegram_type(0x00AB, F("MMStatusMessage"), true, std::bind(&Mixing::process_MMStatusMessage, this, _1));
register_telegram_type(0x00AC, F("MMSetMessage"), false, nullptr);
register_telegram_type(0x00AC, F("MMSetMessage"), false, std::bind(&Mixing::process_MMSetMessage, this, _1));
}
// MQTT callbacks
@@ -131,8 +131,9 @@ void Mixing::process_MMPLUSStatusMessage_HC(std::shared_ptr<const Telegram> tele
type_ = Type::HC;
hc_ = telegram->type_id - 0x02D7 + 1; // determine which circuit this is
telegram->read_value(flowTemp_, 3); // is * 10
telegram->read_value(pumpMod_, 5);
telegram->read_value(status_, 2); // valve status
telegram->read_value(flowSetTemp_, 5);
telegram->read_value(pumpMod_, 2);
telegram->read_value(status_, 1); // valve status
}
// Mixing module warm water loading/DHW - 0x0331, 0x0332
@@ -161,4 +162,19 @@ void Mixing::process_MMStatusMessage(std::shared_ptr<const Telegram> telegram) {
telegram->read_value(flowSetTemp_, 0);
}
// Mixing on a MM10 - 0xAA
// e.g. Thermostat -> Mixing Module, type 0xAA, telegram: 10 21 AA 00 FF 0C 0A 11 0A 32 xx
void Mixing::process_MMConfigMessage(std::shared_ptr<const Telegram> telegram) {
hc_ = device_id() - 0x20 + 1;
// pos 0: active FF = on
// pos 1: valve runtime 0C = 120 sec in units of 10 sec
}
// Mixing on a MM10 - 0xAC
// e.g. Thermostat -> Mixing Module, type 0xAC, telegram: 10 21 AC 00 1E 64 01 AB
void Mixing::process_MMSetMessage(std::shared_ptr<const Telegram> telegram) {
hc_ = device_id() - 0x20 + 1;
// pos 0: flowtemp setpoint 1E = 30°C
// pos 1: position in %
}
} // namespace emsesp

View File

@@ -49,6 +49,8 @@ class Mixing : public EMSdevice {
void process_MMPLUSStatusMessage_HC(std::shared_ptr<const Telegram> telegram);
void process_MMPLUSStatusMessage_WWC(std::shared_ptr<const Telegram> telegram);
void process_MMStatusMessage(std::shared_ptr<const Telegram> telegram);
void process_MMConfigMessage(std::shared_ptr<const Telegram> telegram);
void process_MMSetMessage(std::shared_ptr<const Telegram> telegram);
enum class Type {
NONE,

View File

@@ -37,9 +37,9 @@ Solar::Solar(uint8_t device_type, uint8_t device_id, uint8_t product_id, const s
register_telegram_type(0x0362, F("SM100Monitor"), true, std::bind(&Solar::process_SM100Monitor, this, _1));
register_telegram_type(0x0364, F("SM100Status"), false, std::bind(&Solar::process_SM100Status, this, _1));
register_telegram_type(0x036A, F("SM100Status2"), false, std::bind(&Solar::process_SM100Status2, this, _1));
register_telegram_type(0x038E, F("SM100Energy"), false, std::bind(&Solar::process_SM100Energy, this, _1));
register_telegram_type(0x0003, F("ISM1StatusMessage"), true, std::bind(&Solar::process_ISM1StatusMessage, this, _1));
register_telegram_type(0x0001, F("ISM1Set"), false, std::bind(&Solar::process_ISM1Set, this, _1));
register_telegram_type(0x038E, F("SM100Energy"), true, std::bind(&Solar::process_SM100Energy, this, _1));
register_telegram_type(0x0103, F("ISM1StatusMessage"), true, std::bind(&Solar::process_ISM1StatusMessage, this, _1));
register_telegram_type(0x0101, F("ISM1Set"), false, std::bind(&Solar::process_ISM1Set, this, _1));
// MQTT callbacks
// register_mqtt_topic("cmd", std::bind(&Solar::cmd, this, _1));
@@ -130,10 +130,11 @@ void Solar::process_SM10Monitor(std::shared_ptr<const Telegram> telegram) {
telegram->read_value(bottomTemp_, 5); // bottom temp from SM10, is *10
telegram->read_value(pumpModulation_, 4); // modulation solar pump
telegram->read_value(pump_, 7, 1);
telegram->read_value(pumpWorkMin_, 8);
}
/*
* SM100Monitor - type 0x0162 EMS+ - for SM100 and SM200
* SM100Monitor - type 0x0262 EMS+ - for SM100 and SM200
* e.g. B0 0B FF 00 02 62 00 44 02 7A 80 00 80 00 80 00 80 00 80 00 80 00 00 7C 80 00 80 00 80 00 80
* e.g, 30 00 FF 00 02 62 01 AC
* 30 00 FF 18 02 62 80 00

View File

@@ -31,7 +31,6 @@ MAKE_PSTR(master_thermostat_fmt, "Master Thermostat device ID = %s")
namespace emsesp {
REGISTER_FACTORY(Thermostat, EMSdevice::DeviceType::THERMOSTAT);
MAKE_PSTR(logger_name, "thermostat")
uuid::log::Logger Thermostat::logger_{F_(logger_name), uuid::log::Facility::CONSOLE};
@@ -239,7 +238,6 @@ void Thermostat::thermostat_cmd(const char * message) {
strlcpy(hc_name, "hc", 6);
uint8_t hc_num = hc->hc_num();
strlcat(hc_name, Helpers::itoa(s, hc_num), 6);
if (nullptr != doc[hc_name]["mode"]) {
std::string mode = doc[hc_name]["mode"]; // first check mode
set_mode(mode, hc_num);
@@ -279,29 +277,29 @@ void Thermostat::thermostat_cmd(const char * message) {
uint8_t ctrl = doc[hc_name]["control"];
set_control(ctrl, hc_num);
}
if (float ct = doc["calinttemp"]) {
set_settings_calinttemp((int8_t)(ct * 10));
}
if (nullptr != doc["minexttemp"]) {
int8_t mt = doc["minexttemp"];
set_settings_minexttemp(mt);
}
if (nullptr != doc["building"]) {
uint8_t bd = doc["building"];
set_settings_building(bd);
}
if (nullptr != doc["language"]) {
uint8_t lg = doc["language"];
set_settings_language(lg);
}
if (nullptr != doc["display"]) {
uint8_t dp = doc["display"];
set_settings_display(dp);
}
if (nullptr != doc["clockoffset"]) {
int8_t co = doc["clockoffset"];
set_settings_clockoffset(co);
}
}
if (float ct = doc["calinttemp"]) {
set_settings_calinttemp((int8_t)(ct * 10));
}
if (nullptr != doc["minexttemp"]) {
int8_t mt = doc["minexttemp"];
set_settings_minexttemp(mt);
}
if (nullptr != doc["building"]) {
uint8_t bd = doc["building"];
set_settings_building(bd);
}
if (nullptr != doc["language"]) {
uint8_t lg = doc["language"];
set_settings_language(lg);
}
if (nullptr != doc["display"]) {
uint8_t dp = doc["display"];
set_settings_display(dp);
}
if (nullptr != doc["clockoffset"]) {
int8_t co = doc["clockoffset"];
set_settings_clockoffset(co);
}
const char * command = doc["cmd"];
@@ -1023,17 +1021,17 @@ void Thermostat::process_JunkersMonitor(std::shared_ptr<const Telegram> telegram
// type 0x02A5 - data from the Nefit RC1010/3000 thermostat (0x18) and RC300/310s on 0x10
void Thermostat::process_RC300Monitor(std::shared_ptr<const Telegram> telegram) {
if (telegram->message_data[2] == 0x00) {
return;
}
std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(telegram);
telegram->read_value(hc->curr_roomTemp, 0); // is * 10
telegram->read_value(hc->mode_type, 10, 1);
telegram->read_value(hc->mode, 10, 0); // bit 1, mode (auto=1 or manual=0)
// setpoint is in offset 3 and also 7. We're sticking to 3 for now.
// also ignore if its 0 - see https://github.com/proddy/EMS-ESP/issues/256#issuecomment-585171426
if (telegram->message_data[3] != 0) {
telegram->read_value8(hc->setpoint_roomTemp, 3); // is * 2, force as single byte
}
telegram->read_value8(hc->setpoint_roomTemp, 3); // is * 2, force as single byte
}
// type 0x02B9 EMS+ for reading from RC300/RC310 thermostat
@@ -1044,11 +1042,12 @@ void Thermostat::process_RC300Set(std::shared_ptr<const Telegram> telegram) {
// manual is position 10
// comfort is position 2
// I think auto is position 8?
telegram->read_value8(hc->setpoint_roomTemp, 8); // single byte conversion, value is * 2 - auto?
telegram->read_value8(hc->setpoint_roomTemp, 10); // single byte conversion, value is * 2 - manual
// actual setpoint taken from RC300Monitor (Michael 12.06.2020)
// telegram->read_value8(hc->setpoint_roomTemp, 8); // single byte conversion, value is * 2 - auto?
// telegram->read_value8(hc->setpoint_roomTemp, 10); // single byte conversion, value is * 2 - manual
// check why mode is both in the Monitor and Set for the RC300. It'll be read twice!
telegram->read_value(hc->mode, 0); // Auto = xFF, Manual = x00 eg. 10 00 FF 08 01 B9 FF
// telegram->read_value(hc->mode, 0); // Auto = xFF, Manual = x00 eg. 10 00 FF 08 01 B9 FF
telegram->read_value(hc->daytemp, 2); // is * 2
telegram->read_value(hc->nighttemp, 4); // is * 2
@@ -1182,7 +1181,7 @@ void Thermostat::set_settings_building(const uint8_t bg) {
// 0xA5 Set the language settings
void Thermostat::set_settings_language(const uint8_t lg) {
if ((flags() & 0x0F) == EMS_DEVICE_FLAG_RC30_1) {
LOG_INFO(F("Setting building to %d"), lg);
LOG_INFO(F("Setting language to %d"), lg);
write_command(EMS_TYPE_IBASettings, 1, lg);
}
}
@@ -1199,8 +1198,10 @@ void Thermostat::set_control(const uint8_t ctrl, const uint8_t hc_num) {
return;
}
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);
} else {
LOG_INFO(F("Setting circuit-control not possible"));
}
}

View File

@@ -29,7 +29,6 @@
#include "emsesp.h"
#include "helpers.h"
#include "mqtt.h"
#include "roomcontrol.h"
#include <vector>

View File

@@ -562,14 +562,14 @@ void EMSESP::send_write_request(const uint16_t type_id,
// this is main entry point when data is received on the Rx line, via emsuart library
// we check if its a complete telegram or just a single byte (which could be a poll or a return status)
void EMSESP::incoming_telegram(uint8_t * data, const uint8_t length) {
// LOG_DEBUG(F("Rx: %s"), Helpers::data_to_hex(data, length).c_str());
// check first for echo
//LOG_TRACE(F("Rx: %s"), Helpers::data_to_hex(data, length).c_str());
uint8_t first_value = data[0];
if (((first_value & 0x7F) == txservice_.ems_bus_id()) && (length > 1)) {
// if we ask ourself at roomcontrol for version e.g. 0B 98 02 ...
// if we ask ourself at roomcontrol for version e.g. 0B 98 02 00 20
Roomctrl::check((data[1] ^ 0x80 ^ rxservice_.ems_mask()), data);
#ifdef EMSESP_DEBUG
rxservice_.add(data, length); // just for logging, if compiled with additional debugging
LOG_DEBUG(F("Echo: %s"), Helpers::data_to_hex(data, length).c_str());
#endif
return; // it's an echo
}

View File

@@ -233,7 +233,7 @@ char * Helpers::render_value(char * result, const uint32_t value, const uint8_t
strlcat(result, ltoa(value, s, 10), 20);
} else {
strlcat(result, ltoa(value / format, s, 10), 20);
strlcat(result, ".", 2);
strlcat(result, ".", 20);
strlcat(result, ltoa(value % format, s, 10), 20);
}

View File

@@ -20,21 +20,23 @@
namespace emsesp {
uint32_t rc_time_ = 0;
uint16_t hc_ = EMS_VALUE_USHORT_NOTSET;
int16_t remotetemp[4] = {EMS_VALUE_SHORT_NOTSET, EMS_VALUE_SHORT_NOTSET, EMS_VALUE_SHORT_NOTSET, EMS_VALUE_SHORT_NOTSET};
static uint32_t rc_time_ = 0;
static int16_t remotetemp[4] = {EMS_VALUE_SHORT_NOTSET, EMS_VALUE_SHORT_NOTSET, EMS_VALUE_SHORT_NOTSET, EMS_VALUE_SHORT_NOTSET};
/**
* set the temperature,
*/
void Roomctrl::set_remotetemp(uint8_t hc, int16_t temp) {
void Roomctrl::set_remotetemp(const uint8_t hc, const int16_t temp) {
if (hc > 3) {
return;
}
remotetemp[hc] = temp;
}
/**
* if remote control is active send the temperature every minute
*/
void Roomctrl::send(uint8_t addr) {
void Roomctrl::send(const uint8_t addr) {
uint8_t hc_ = addr - ADDR;
// check address, reply only on addresses 0x18..0x1B
if (hc_ > 3) {
@@ -48,7 +50,7 @@ void Roomctrl::send(uint8_t addr) {
rc_time_ = uuid::get_uptime(); // use EMS-ESP's millis() to prevent overhead
temperature(addr, 0x00); // send to all
} else {
// acknowledge every poll, otherwise the master shows error A11-822
// acknowledge every poll, otherwise the master shows error A22-816
EMSuart::send_poll(addr);
}
}
@@ -56,19 +58,22 @@ void Roomctrl::send(uint8_t addr) {
/**
* check if there is a message for the remote room controller
*/
void Roomctrl::check(uint8_t addr, uint8_t * data) {
uint8_t hc_num = addr - ADDR;
void Roomctrl::check(const uint8_t addr, const uint8_t * data) {
uint8_t hc_ = (addr & 0x7F) - ADDR;
// check address, reply only on addresses 0x18..0x1B
if (hc_num > 3) {
if (hc_ > 3) {
return;
}
// no reply if the temperature is not set
if (remotetemp[hc_num] == EMS_VALUE_SHORT_NOTSET) {
if (remotetemp[hc_] == EMS_VALUE_SHORT_NOTSET) {
return;
}
// reply to writes with write nack byte
if(addr & 0x80) { // it's a write to us
nack_write(); // we don't accept writes.
return;
}
// for now we only reply to version and remote temperature
if (data[2] == 0x02) {
version(addr, data[0]);
@@ -124,5 +129,13 @@ void Roomctrl::temperature(uint8_t addr, uint8_t dst) {
data[7] = EMSbus::calculate_crc(data, 7); // apppend CRC
EMSuart::transmit(data, 8);
}
/**
* send a nack if someone want to write to us.
*/
void Roomctrl::nack_write() {
uint8_t data[1];
data[0] = TxService::TX_WRITE_FAIL;
EMSuart::transmit(data, 1);
}
} // namespace emsesp

View File

@@ -20,17 +20,14 @@
#define EMSESP_ROOMCONTROL_H
#include "emsesp.h"
#include "telegram.h"
#include "uart/emsuart_esp8266.h"
#include "uart/emsuart_esp32.h"
namespace emsesp {
class Roomctrl {
public:
static void send(uint8_t addr);
static void check(uint8_t addr, uint8_t * data);
static void set_remotetemp(uint8_t hc, int16_t temp);
static void send(const uint8_t addr);
static void check(const uint8_t addr, const uint8_t * data);
static void set_remotetemp(const uint8_t hc, const int16_t temp);
private:
static constexpr uint8_t ADDR = 0x18;
@@ -39,6 +36,8 @@ class Roomctrl {
static void version(uint8_t addr, uint8_t dst);
static void unknown(uint8_t addr, uint8_t dst, uint8_t type, uint8_t offset);
static void temperature(uint8_t addr, uint8_t dst);
static void nack_write();
};
} // namespace emsesp

View File

@@ -62,23 +62,72 @@ void System::mqtt_commands(const char * message) {
LOG_DEBUG(F("MQTT error: payload %s, error %s"), message, error.c_str());
return;
}
// restart EMS-ESP
if (strcmp(message, "restart") == 0) {
LOG_INFO(F("Restart command received"));
restart();
}
if (doc["send"] != nullptr) {
const char * data = doc["send"];
EMSESP::send_raw_telegram(data);
LOG_INFO(F("Sending raw: %s"),data);
}
#if defined(ESP8266)
const uint8_t d0_ = 16;
const uint8_t d1_ = 5;
const uint8_t d2_ = 4;
const uint8_t d3_ = 0;
#elif defined(ESP32)
const uint8_t d0_ = 26;
const uint8_t d1_ = 22;
const uint8_t d2_ = 21;
const uint8_t d3_ = 17;
#endif
if(doc["D0"] != nullptr) {
const int8_t set = doc["D0"];
pinMode(d0_, OUTPUT);
if (set == 1) digitalWrite(d0_, HIGH);
else if (set == 0) digitalWrite(d0_, LOW);
LOG_INFO(F("Port D0 set to %d"),set);
}
if(doc["D1"] != nullptr) {
const int8_t set = doc["D1"];
pinMode(d1_, OUTPUT);
if (set == 1) digitalWrite(d1_, HIGH);
else if (set == 0) digitalWrite(d1_, LOW);
LOG_INFO(F("Port D1 set to %d"),set);
}
if(doc["D2"] != nullptr) {
const int8_t set = doc["D2"];
pinMode(d2_, OUTPUT);
if (set == 1) digitalWrite(d2_, HIGH);
else if (set == 0) digitalWrite(d2_, LOW);
LOG_INFO(F("Port D2 set to %d"),set);
}
if(doc["D3"] != nullptr) {
const int8_t set = doc["D3"];
pinMode(d3_, OUTPUT);
if (set == 1) digitalWrite(d3_, HIGH);
else if (set == 0) digitalWrite(d3_, LOW);
LOG_INFO(F("Port D3 set to %d"),set);
}
const char * command = doc["cmd"];
if (command == nullptr) {
return;
}
// restart EMS-ESP
if (strcmp(message, "restart") == 0) {
restart();
}
// boiler ww comfort setting
// send raw command
if (strcmp(command, "send") == 0) {
const char * data = doc["data"];
if (data == nullptr) {
return;
}
EMSESP::send_raw_telegram(data);
LOG_INFO(F("Sending raw: %s"),data);
return;
}
}

View File

@@ -177,7 +177,7 @@ void Telegram::read_value32(uint32_t & param, const uint8_t index) const {
return;
}
param = (uint32_t)((message_data[pos] << 24) + (message_data[pos] << 16) + (message_data[pos + 1] << 8) + (message_data[pos + 2]));
param = (uint32_t)((message_data[pos] << 24) + (message_data[pos + 1] << 16) + (message_data[pos + 2] << 8) + (message_data[pos + 3]));
}
// bit from an unsigned byte
@@ -294,12 +294,13 @@ void RxService::add(uint8_t * data, uint8_t length) {
type_id = (data[4] << 8) + data[5] + 256;
}
} else {
type_id = (data[4] << 8) + data[5] + 256;
message_length = length - 7; // remove 6 byte header plus CRC
message_data = data + 6; // message block starts at 7th position
}
} else {
// its F9 or F7
uint8_t shift = (data[4] != 0xFF); // true (1) if 5th byte is not 0xFF, then telegram is 1 byte longer
uint8_t shift = (data[4] != 0xFF) ? 1 : 0; // true (1) if 5th byte is not 0xFF, then telegram is 1 byte longer
type_id = (data[5 + shift] << 8) + data[6 + shift] + 256;
message_data = data + 6 + shift; // there is a special byte after the typeID which we ignore for now
if (length <= (9 + shift)) {
@@ -611,6 +612,10 @@ void TxService::remember_tx(const uint8_t * data, const uint8_t length) {
telegram_last_[i] = data[i];
}
telegram_last_length_ = length;
if (ems_mask() != EMS_MASK_UNSET) {
telegram_last_[0] ^= ems_mask();
}
}
// add last Tx to tx queue and increment count
@@ -621,8 +626,25 @@ uint8_t TxService::retry_tx() {
increment_telegram_fail_count(); // another Tx fail
return 0;
}
// if the queue is full, throw away
if (tx_telegrams_.size() >= MAX_TX_TELEGRAMS) {
reset_retry_count(); // give up
increment_telegram_fail_count(); // another Tx fail
return 0;
}
add(telegram_last_, telegram_last_length_); // add the last Tx telegram to the tx queue, at the top
uint8_t message_length = telegram_last_length_ - 4;
// build header
uint8_t src = telegram_last_[0];
uint8_t dest = telegram_last_[1];
uint8_t type_id = telegram_last_[2];
uint8_t offset = telegram_last_[3];
uint8_t * message_data = telegram_last_ + 4;
auto telegram = std::make_shared<Telegram>(Telegram::Operation::TX_RAW, src, dest, type_id, offset, message_data, message_length);
tx_telegrams_.emplace_front(tx_telegram_id_++, std::move(telegram));
return retry_count_;
}

View File

@@ -20,6 +20,7 @@
/*
* ESP32 UART port by @ArwedL and improved by @MichaelDvP. See https://github.com/proddy/EMS-ESP/issues/380
*/
#if defined(ESP32)
#ifndef EMSESP_EMSUART_H
#define EMSESP_EMSUART_H
@@ -74,3 +75,4 @@ class EMSuart {
} // namespace emsesp
#endif
#endif

View File

@@ -35,6 +35,11 @@ uint8_t phantomBreak = 0;
uint8_t tx_mode_ = 0xFF;
bool drop_next_rx = true;
uint32_t emsRxTime;
uint8_t emsTxBuf[EMS_MAXBUFFERSIZE];
uint8_t emsTxBufIdx;
uint8_t emsTxBufLen;
uint32_t emsTxWait;
//
// Main interrupt handler
@@ -45,6 +50,12 @@ void ICACHE_RAM_ATTR EMSuart::emsuart_rx_intr_handler(void * para) {
static uint8_t uart_buffer[EMS_MAXBUFFERSIZE + 2];
if (USIS(EMSUART_UART) & ((1 << UIBD))) { // BREAK detection = End of EMS data block
USC0(EMSUART_UART) &= ~(1 << UCBRK); // reset tx-brk
// while((USS(EMSUART_UART) >> USRXD) == 0); // wait for idle state of pin
// if((USS(EMSUART_UART) >> USRXD) == 0) { // if rx is not idle wait one bittime
// delayMicroseconds(EMSUART_BIT_TIME);
// }
USIC(EMSUART_UART) = (1 << UIBD); // INT clear the BREAK detect interrupt
length = 0;
while ((USS(EMSUART_UART) >> USRXC) & 0x0FF) { // read fifo into buffer
uint8_t rx = USF(EMSUART_UART);
@@ -54,8 +65,6 @@ void ICACHE_RAM_ATTR EMSuart::emsuart_rx_intr_handler(void * para) {
drop_next_rx = true;
}
}
USIC(EMSUART_UART) = (1 << UIBD); // INT clear the BREAK detect interrupt
USC0(EMSUART_UART) &= ~(1 << UCBRK); // reset tx-brk
if (!drop_next_rx) {
pEMSRxBuf->length = length;
os_memcpy((void *)pEMSRxBuf->buffer, (void *)&uart_buffer, pEMSRxBuf->length); // copy data into transfer buffer, including the BRK 0x00 at the end
@@ -105,6 +114,19 @@ void ICACHE_FLASH_ATTR EMSuart::emsuart_flush_fifos() {
USC0(EMSUART_UART) &= ~(tmp); // clear bits
}
// ISR to Fire when Timer is triggered
void ICACHE_RAM_ATTR EMSuart::emsuart_tx_timer_intr_handler() {
emsTxBufIdx++;
if (emsTxBufIdx < emsTxBufLen) {
USF(EMSUART_UART) = emsTxBuf[emsTxBufIdx];
timer1_write(emsTxWait);
} else if (emsTxBufIdx == emsTxBufLen) {
USC0(EMSUART_UART) |= (1 << UCBRK); // set <BRK>
// timer1_write(emsTxWait);
// } else {
// USC0(EMSUART_UART) &= ~(1 << UCBRK); // clear <BRK>
}
}
/*
* init UART0 driver
*/
@@ -146,8 +168,8 @@ void ICACHE_FLASH_ATTR EMSuart::start(uint8_t tx_mode) {
// change: we set UCFFT to 1 to get an immediate indicator about incoming traffic.
// Otherwise, we're only noticed by UCTOT or RxBRK!
// change: don't care, we do not use these interrupts
//USC1(EMSUART_UART) = 0; // reset config first
//USC1(EMSUART_UART) = (0x01 << UCFFT) | (0x01 << UCTOT) | (0 << UCTOE); // enable interupts
// USC1(EMSUART_UART) = 0; // reset config first
// USC1(EMSUART_UART) = (0x7F << UCFFT) | (0x04 << UCTOT) | (1 << UCTOE); // enable interupts
// set interrupts for triggers
USIC(EMSUART_UART) = 0xFFFF; // clear all interupts
@@ -172,6 +194,11 @@ void ICACHE_FLASH_ATTR EMSuart::start(uint8_t tx_mode) {
ETS_UART_INTR_ENABLE();
drop_next_rx = true;
// LOG_INFO(F("UART service for Rx/Tx started"));
// for sending with large delay in EMS+ mode we use a timer interrupt
timer1_attachInterrupt(emsuart_tx_timer_intr_handler); // Add ISR Function
timer1_enable(TIM_DIV16, TIM_EDGE, TIM_SINGLE); // 5 MHz timer
emsTxWait = 5 * EMSUART_BIT_TIME * 20; // 20 bittimes for tx_mode 2
}
/*
@@ -180,6 +207,7 @@ void ICACHE_FLASH_ATTR EMSuart::start(uint8_t tx_mode) {
*/
void ICACHE_FLASH_ATTR EMSuart::stop() {
ETS_UART_INTR_DISABLE();
timer1_disable();
}
/*
@@ -191,6 +219,9 @@ void ICACHE_FLASH_ATTR EMSuart::restart() {
drop_next_rx = true;
}
ETS_UART_INTR_ENABLE();
emsTxBufIdx = 0;
emsTxBufLen = 0;
timer1_enable(TIM_DIV16, TIM_EDGE, TIM_SINGLE);
}
/*
@@ -227,17 +258,20 @@ void ICACHE_FLASH_ATTR EMSuart::tx_brk() {
* It's a bit dirty. there is no special wait logic per tx_mode type, fifo flushes or error checking
*/
void EMSuart::send_poll(uint8_t data) {
noInterrupts();
if (tx_mode_ == EMS_TXMODE_NEW) {
USC0(EMSUART_UART) &= ~(1 << UCBRK); // reset tx-brk
USF(EMSUART_UART) = data;
USC0(EMSUART_UART) |= (1 << UCBRK); // send <BRK> at the end
} else if (tx_mode_ == EMS_TXMODE_EMSPLUS) {
USF(EMSUART_UART) = data;
emsTxBufIdx = 0;
emsTxBufLen = 1;
timer1_write(emsTxWait);
} else {
USF(EMSUART_UART) = data;
delayMicroseconds(EMSUART_TX_BRK_WAIT);
tx_brk(); // send <BRK>
}
interrupts();
}
/*
@@ -259,30 +293,30 @@ EMSUART_STATUS ICACHE_FLASH_ATTR EMSuart::transmit(uint8_t * buf, uint8_t len) {
// new code from Michael. See https://github.com/proddy/EMS-ESP/issues/380
if (tx_mode_ == EMS_TXMODE_NEW) {
USC0(EMSUART_UART) &= ~(1 << UCBRK); // reset tx-brk
noInterrupts();
for (uint8_t i = 0; i < len; i++) {
USF(EMSUART_UART) = buf[i];
}
USC0(EMSUART_UART) |= (1 << UCBRK); // send <BRK> at the end
interrupts();
return EMS_TX_STATUS_OK;
}
// EMS+ https://github.com/proddy/EMS-ESP/issues/23#
if (tx_mode_ == EMS_TXMODE_EMSPLUS) { // With extra tx delay for EMS+
noInterrupts();
for (uint8_t i = 0; i < len; i++) {
USF(EMSUART_UART) = buf[i];
delayMicroseconds(EMSUART_TX_BRK_WAIT); // 2070
emsTxBuf[i] = buf[i];
// USF(EMSUART_UART) = buf[i];
// delayMicroseconds(EMSUART_TX_BRK_WAIT); // 2070
}
tx_brk(); // send <BRK>
interrupts();
emsTxBufIdx = 0;
emsTxBufLen = len;
USF(EMSUART_UART) = buf[0];
timer1_write(emsTxWait);
// tx_brk(); // send <BRK>
return EMS_TX_STATUS_OK;
}
// Junkers logic by @philrich
if (tx_mode_ == EMS_TXMODE_HT3) {
noInterrupts();
for (uint8_t i = 0; i < len; i++) {
USF(EMSUART_UART) = buf[i];
@@ -294,7 +328,6 @@ EMSUART_STATUS ICACHE_FLASH_ATTR EMSuart::transmit(uint8_t * buf, uint8_t len) {
delayMicroseconds(EMSUART_TX_WAIT_BYTE - EMSUART_TX_LAG + EMSUART_TX_WAIT_GAP); // 1760
}
tx_brk(); // send <BRK>
interrupts();
return EMS_TX_STATUS_OK;
}
@@ -325,8 +358,8 @@ EMSUART_STATUS ICACHE_FLASH_ATTR EMSuart::transmit(uint8_t * buf, uint8_t len) {
// disable rx interrupt
// clear Rx status register, resetting the Rx FIFO and flush it
noInterrupts();
// ETS_UART_INTR_DISABLE();
// noInterrupts();
ETS_UART_INTR_DISABLE();
// USC0(EMSUART_UART) |= (1 << UCRXRST); // reset uart rx fifo
emsuart_flush_fifos();
@@ -339,14 +372,14 @@ EMSUART_STATUS ICACHE_FLASH_ATTR EMSuart::transmit(uint8_t * buf, uint8_t len) {
while (((USS(EMSUART_UART) >> USRXC) & 0xFF) == _usrxc) {
delayMicroseconds(EMSUART_BUSY_WAIT); // burn CPU cycles...
if (--wdc == 0) {
interrupts();
// ETS_UART_INTR_ENABLE();
// interrupts();
ETS_UART_INTR_ENABLE();
return EMS_TX_WTD_TIMEOUT;
}
if (USIR(EMSUART_UART) & (1 << UIBD)) {
USIC(EMSUART_UART) = (1 << UIBD); // clear BRK detect IRQ
interrupts();
// ETS_UART_INTR_ENABLE();
// interrupts();
ETS_UART_INTR_ENABLE();
return EMS_TX_BRK_DETECT;
}
}
@@ -371,8 +404,8 @@ EMSUART_STATUS ICACHE_FLASH_ATTR EMSuart::transmit(uint8_t * buf, uint8_t len) {
phantomBreak = 1;
}
interrupts();
// ETS_UART_INTR_ENABLE(); // open up the FIFO again to start receiving
// interrupts();
ETS_UART_INTR_ENABLE(); // open up the FIFO again to start receiving
return EMS_TX_STATUS_OK; // send the Tx ok status back
}

View File

@@ -15,6 +15,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#if defined(ESP8266)
#ifndef EMSESP_EMSUART_H
#define EMSESP_EMSUART_H
@@ -81,8 +82,11 @@ class EMSuart {
static void ICACHE_FLASH_ATTR emsuart_recvTask(os_event_t * events);
static void ICACHE_FLASH_ATTR emsuart_flush_fifos();
static void ICACHE_FLASH_ATTR tx_brk();
static void ICACHE_RAM_ATTR emsuart_tx_timer_intr_handler();
};
} // namespace emsesp
#endif
#endif