This commit is contained in:
MichaelDvP
2020-06-19 12:12:40 +02:00
8 changed files with 98 additions and 80 deletions

View File

@@ -571,35 +571,35 @@ void EMSESP::incoming_telegram(uint8_t * data, const uint8_t length) {
if (((first_value & 0x7F) == txservice_.ems_bus_id()) && (length > 1)) { if (((first_value & 0x7F) == txservice_.ems_bus_id()) && (length > 1)) {
// 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 // get_uptime is only updated once per loop, does not give the right time
LOG_DEBUG(F("[DEBUG] Echo after %d ms: %s"), ::millis() - tx_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
} }
// are we waiting for a response from a recent Tx Read or Write? // are we waiting for a response from a recent Tx Read or Write?
bool tx_successful = false; uint8_t op = EMSbus::tx_waiting();
if (EMSbus::tx_waiting()) { if (op != Telegram::Operation::NONE) {
EMSbus::tx_waiting(false); // reset Tx wait state bool tx_successful = false;
EMSbus::tx_waiting(Telegram::Operation::NONE); // reset Tx wait state
// if it's a single byte 1 or 4 then its maybe a response from the last write action // if we're waiting on a Write operation, we want a single byte 1 or 4
if (length == 1) { if ((op == Telegram::Operation::TX_WRITE) && (length == 1)) {
if (first_value == TxService::TX_WRITE_SUCCESS) { if (first_value == TxService::TX_WRITE_SUCCESS) {
LOG_DEBUG(F("Last Tx write successful. Sending read request.")); LOG_DEBUG(F("Last Tx write successful"));
txservice_.increment_telegram_write_count(); // last tx/write was confirmed ok txservice_.increment_telegram_write_count(); // last tx/write was confirmed ok
txservice_.send_poll(); // close the bus txservice_.send_poll(); // close the bus
txservice_.post_send_query(); // follow up with any post-read txservice_.post_send_query(); // follow up with any post-read
tx_successful = true;
txservice_.reset_retry_count(); txservice_.reset_retry_count();
tx_successful = true;
} else if (first_value == TxService::TX_WRITE_FAIL) { } else if (first_value == TxService::TX_WRITE_FAIL) {
LOG_ERROR(F("Last Tx write rejected by host")); LOG_ERROR(F("Last Tx write rejected by host"));
txservice_.send_poll(); // close the bus txservice_.send_poll(); // close the bus
txservice_.reset_retry_count(); txservice_.reset_retry_count();
} }
} else { } else if (op == Telegram::Operation::TX_READ) {
// got a telegram with data in it. See if the src/dest matches that from the last one we sent // got a telegram with data in it. See if the src/dest matches that from the last one we sent and continue to process it
// and continue to process it
uint8_t src = data[0]; uint8_t src = data[0];
uint8_t dest = data[1]; uint8_t dest = data[1];
if (txservice_.is_last_tx(src, dest)) { if (txservice_.is_last_tx(src, dest)) {
@@ -613,17 +613,19 @@ void EMSESP::incoming_telegram(uint8_t * data, const uint8_t length) {
// if Tx wasn't successful, retry or give up // if Tx wasn't successful, retry or give up
if (!tx_successful) { if (!tx_successful) {
// the telegram we got wasn't what we had requested // the telegram we got wasn't what we had requested, so re-send the last Tx and increment retry count
// So re-send the last Tx and increment retry count
uint8_t retries = txservice_.retry_tx(); // returns 0 if exceeded count uint8_t retries = txservice_.retry_tx(); // returns 0 if exceeded count
#ifdef EMSESP_DEBUG #ifdef EMSESP_DEBUG
LOG_DEBUG(F("[DEBUG] Last Tx operation failed. Retry #%d. Sent: %s, received: %s"), LOG_DEBUG(F("[DEBUG] Last Tx %s operation failed. Retry #%d. Sent: %s, received: %s"),
(op == Telegram::Operation::TX_WRITE) ? F("Write") : F("Read"),
retries, retries,
txservice_.last_tx_to_string().c_str(), txservice_.last_tx_to_string().c_str(),
Helpers::data_to_hex(data, length).c_str()); Helpers::data_to_hex(data, length).c_str());
#endif #endif
if (!retries) { if (!retries) {
LOG_ERROR(F("Last Tx operation failed after %d retries. Ignoring request."), txservice_.MAXIMUM_TX_RETRIES); LOG_ERROR(F("Last Tx %s operation failed after %d retries. Ignoring request."),
(op == Telegram::Operation::TX_WRITE) ? F("Write") : F("Read"),
txservice_.MAXIMUM_TX_RETRIES);
} }
return; return;

View File

@@ -42,7 +42,7 @@ uint32_t EMSbus::last_bus_activity_ = 0; // timestamp of last time
bool EMSbus::bus_connected_ = false; // start assuming the bus hasn't been connected bool EMSbus::bus_connected_ = false; // start assuming the bus hasn't been connected
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_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; uint8_t EMSbus::ems_bus_id_ = EMSESP_DEFAULT_BUS_ID;
bool EMSbus::tx_waiting_ = false; uint8_t EMSbus::tx_waiting_ = Telegram::Operation::NONE;
bool EMSbus::tx_active_ = false; bool EMSbus::tx_active_ = false;
uuid::log::Logger EMSbus::logger_{F_(logger_name), uuid::log::Facility::CONSOLE}; uuid::log::Logger EMSbus::logger_{F_(logger_name), uuid::log::Facility::CONSOLE};
@@ -271,7 +271,8 @@ void RxService::add(uint8_t * data, uint8_t length) {
// work out depending on the type, where the data message block starts and the message length // work out depending on the type, where the data message block starts and the message length
// EMS 1 has type_id always in data[2], if it gets a ems+ inquiery it will reply with FF but short length // EMS 1 has type_id always in data[2], if it gets a ems+ inquiery it will reply with FF but short length
// i.e. sending 0b A1 FF 00 01 D8 20 to a MM10 Mixer (ems1.0) he replys with 21 0B FF 00 // i.e. sending 0B A1 FF 00 01 D8 20 CRC to a MM10 Mixer (ems1.0), the reply is 21 0B FF 00 CRC
// see: https://github.com/proddy/EMS-ESP/issues/380#issuecomment-633663007
if (data[2] < 0xF0 || length < 6) { if (data[2] < 0xF0 || length < 6) {
// EMS 1.0 // EMS 1.0
type_id = data[2]; type_id = data[2];
@@ -350,7 +351,7 @@ void TxService::loop() {
#ifndef EMSESP_STANDALONE #ifndef EMSESP_STANDALONE
if ((uuid::get_uptime() - last_tx_check_) > TX_LOOP_WAIT) { if ((uuid::get_uptime() - last_tx_check_) > TX_LOOP_WAIT) {
last_tx_check_ = uuid::get_uptime(); last_tx_check_ = uuid::get_uptime();
if (!tx_active_ && (EMSbus::bus_connected())) { if (!tx_active() && (EMSbus::bus_connected())) {
LOG_ERROR(F("Tx is not active. Please check connection.")); LOG_ERROR(F("Tx is not active. Please check connection."));
} }
} }
@@ -445,7 +446,7 @@ void TxService::send_telegram(const QueuedTxTelegram & tx_telegram) {
uint8_t length = message_p; uint8_t length = message_p;
remember_tx(telegram_raw, length); // make a copy of it in case we want to re-send it, without the CRC remember_tx(telegram->operation, telegram_raw, length); // make a copy of it in case we want to re-send it, without the CRC
telegram_raw[length] = calculate_crc(telegram_raw, length); // generate and append CRC to the end telegram_raw[length] = calculate_crc(telegram_raw, length); // generate and append CRC to the end
@@ -475,12 +476,12 @@ void TxService::send_telegram(const QueuedTxTelegram & tx_telegram) {
if (status == EMS_TX_STATUS_ERR) { if (status == EMS_TX_STATUS_ERR) {
LOG_ERROR(F("Failed to transmit Tx via UART.")); LOG_ERROR(F("Failed to transmit Tx via UART."));
increment_telegram_fail_count(); // another Tx fail increment_telegram_fail_count(); // another Tx fail
tx_waiting(false); // nothing send, tx not in wait state tx_waiting(Telegram::Operation::NONE); // nothing send, tx not in wait state
return; return;
} }
tx_waiting(true); // tx now in a wait state tx_waiting(telegram->operation); // tx now in a wait state
} }
// send an array of bytes as a telegram // send an array of bytes as a telegram
@@ -494,7 +495,7 @@ void TxService::send_telegram(const uint8_t * data, const uint8_t length) {
} }
telegram_raw[length] = calculate_crc(telegram_raw, length); // apppend CRC telegram_raw[length] = calculate_crc(telegram_raw, length); // apppend CRC
tx_waiting(false); // no post validation tx_waiting(Telegram::Operation::NONE); // no post validation needed
// send the telegram to the UART Tx // send the telegram to the UART Tx
uint16_t status = EMSuart::transmit(telegram_raw, length); uint16_t status = EMSuart::transmit(telegram_raw, length);
@@ -521,11 +522,12 @@ void TxService::add(const uint8_t operation, const uint8_t dest, const uint16_t
tx_telegrams_.emplace_back(tx_telegram_id_++, std::move(telegram)); tx_telegrams_.emplace_back(tx_telegram_id_++, std::move(telegram));
} }
// builds a Tx telegram and adds to queue, using only raw data // 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
// 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 // length is the length of the whole telegram data
// front = true if adding to the front of queue, e.g. with an Tx retry. Default is false. // front = true if adding to the front of queue, e.g. with an Tx retry. Default is false.
void TxService::add(uint8_t * data, const uint8_t length, bool front) { void TxService::add(uint8_t operation, uint8_t * data, const uint8_t length, bool front) {
if (length < 5) { if (length < 5) {
LOG_ERROR(F("Tx telegram too short (telegram length is %d)"), length); LOG_ERROR(F("Tx telegram too short (telegram length is %d)"), length);
return; return;
@@ -540,7 +542,7 @@ void TxService::add(uint8_t * data, const uint8_t length, bool front) {
uint8_t offset = data[3]; uint8_t offset = data[3];
uint8_t * message_data = data + 4; uint8_t * message_data = data + 4;
auto telegram = std::make_shared<Telegram>(Telegram::Operation::TX_RAW, src, dest, type_id, offset, message_data, message_length); auto telegram = std::make_shared<Telegram>(operation, src, dest, type_id, offset, message_data, message_length); // operation is TX_WRITE or TX_READ
// if the queue is full, make room but removing the last one // if the queue is full, make room but removing the last one
if (tx_telegrams_.size() >= MAX_TX_TELEGRAMS) { if (tx_telegrams_.size() >= MAX_TX_TELEGRAMS) {
@@ -601,15 +603,18 @@ void TxService::send_raw(const char * telegram_data) {
return; // nothing to send return; // nothing to send
} }
add(data, count + 1); // add to Tx queue add(Telegram::Operation::TX_RAW, data, count + 1); // add to Tx queue
} }
// save the last Tx sent, only the telegram, excluding the CRC // save the last Tx sent, only the telegram, excluding the CRC
void TxService::remember_tx(const uint8_t * data, const uint8_t length) { void TxService::remember_tx(const uint8_t operation, const uint8_t * data, const uint8_t length) {
for (uint8_t i = 0; i < length; i++) { for (uint8_t i = 0; i < length; i++) {
telegram_last_[i] = data[i]; telegram_last_[i] = data[i];
} }
telegram_last_length_ = length; telegram_last_length_ = length;
telegram_last_op_ = operation;
if (ems_mask() != EMS_MASK_UNSET) { if (ems_mask() != EMS_MASK_UNSET) {
telegram_last_[0] ^= ems_mask(); telegram_last_[0] ^= ems_mask();
} }
@@ -624,7 +629,7 @@ uint8_t TxService::retry_tx() {
return 0; return 0;
} }
add(telegram_last_, telegram_last_length_, true); // add the last Tx telegram to the front of the tx queue, at the top add(telegram_last_op_, telegram_last_, telegram_last_length_, true); // add the last Tx telegram to the front of the tx queue, at the top
return retry_count_; return retry_count_;
} }

View File

@@ -76,6 +76,7 @@ class Telegram {
std::string to_string(const uint8_t * telegram, uint8_t length) const; std::string to_string(const uint8_t * telegram, uint8_t length) const;
enum Operation : uint8_t { enum Operation : uint8_t {
NONE = 0,
RX, RX,
TX_RAW, TX_RAW,
TX_READ, TX_READ,
@@ -144,17 +145,23 @@ class EMSbus {
bus_connected_ = true; bus_connected_ = true;
} }
static bool tx_waiting() {
return tx_waiting_;
static bool tx_active() {
return tx_active_;
}
static void tx_active(bool tx_active) {
tx_active_ = tx_active;
} }
static bool tx_active_; // whether Tx is active or not static uint8_t tx_waiting() {
return tx_waiting_;
static void tx_waiting(bool tx_waiting) { }
static void tx_waiting(uint8_t tx_waiting) {
tx_waiting_ = tx_waiting; tx_waiting_ = tx_waiting;
// if false, then it's been reset which means we have an active Tx // if NONE, then it's been reset which means we have an active Tx
if (!tx_waiting) { if ((tx_waiting == Telegram::Operation::NONE) && !(tx_active_)) {
tx_active_ = true; tx_active_ = true;
} }
} }
@@ -168,7 +175,8 @@ class EMSbus {
static bool bus_connected_; // start assuming the bus hasn't been connected static bool bus_connected_; // start assuming the bus hasn't been connected
static uint8_t ems_mask_; // unset 0x00 buderus 0x80 junkers/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 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) static uint8_t tx_waiting_; // state of the Tx line (NONE or waiting on a TX_READ or TX_WRITE)
static bool tx_active_; // is true is we have a working Tx connection
}; };
class RxService : public EMSbus { class RxService : public EMSbus {
@@ -240,7 +248,7 @@ class TxService : public EMSbus {
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);
void add(uint8_t * data, const uint8_t length, bool front = false); void add(const uint8_t operation, uint8_t * data, const uint8_t length, 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);
@@ -250,7 +258,7 @@ class TxService : public EMSbus {
void flush_tx_queue(); void flush_tx_queue();
void remember_tx(const uint8_t * data, const uint8_t length); void remember_tx(const uint8_t operation, const uint8_t * data, const uint8_t length);
uint8_t retry_tx(); uint8_t retry_tx();
@@ -319,16 +327,17 @@ class TxService : public EMSbus {
std::deque<QueuedTxTelegram> tx_telegrams_; std::deque<QueuedTxTelegram> tx_telegrams_;
uint16_t telegram_read_count_ = 0; // # Tx successful reads
uint16_t telegram_write_count_ = 0; // # Tx successful writes
uint16_t telegram_fail_count_ = 0; // # Tx unsuccessful transmits
const std::shared_ptr<const Telegram> telegram_last;
uint8_t telegram_last_[EMS_MAX_TELEGRAM_LENGTH]; // copy of last telegram uint8_t telegram_last_[EMS_MAX_TELEGRAM_LENGTH]; // copy of last telegram
uint8_t telegram_last_length_; // and its length uint8_t telegram_last_length_; // and its length
uint16_t telegram_last_post_send_query_; // which type ID to query after a successful send, to read back the values just written uint16_t telegram_last_post_send_query_; // which type ID to query after a successful send, to read back the values just written
uint8_t telegram_last_op_; // TX_WRITE or TX_READ
const std::shared_ptr<const Telegram> telegram_last; // copy of last telegram uint8_t retry_count_ = 0; // count for # Tx retries
uint16_t telegram_read_count_ = 0; // # Tx successful reads
uint16_t telegram_write_count_ = 0; // # Tx successful writes
uint16_t telegram_fail_count_ = 0; // # Tx unsuccessful transmits
uint8_t retry_count_ = 0; // count for # Tx retries
void send_telegram(const QueuedTxTelegram & tx_telegram); void send_telegram(const QueuedTxTelegram & tx_telegram);
void send_telegram(const uint8_t * data, const uint8_t length); void send_telegram(const uint8_t * data, const uint8_t length);

View File

@@ -64,7 +64,7 @@ void IRAM_ATTR EMSuart::emsuart_rx_intr_handler(void * para) {
EMS_UART.int_clr.rxfifo_full = 1; EMS_UART.int_clr.rxfifo_full = 1;
emsTxBufIdx++; emsTxBufIdx++;
if (emsTxBufIdx < emsTxBufLen) { if (emsTxBufIdx < emsTxBufLen) {
EMS_UART.conf1.rxfifo_full_thrhd = emsTxBufId + 1; EMS_UART.conf1.rxfifo_full_thrhd = emsTxBufIdx + 1;
EMS_UART.fifo.rw_byte = emsTxBuf[emsTxBufIdx]; EMS_UART.fifo.rw_byte = emsTxBuf[emsTxBufIdx];
} else if (emsTxBufIdx == emsTxBufLen) { } else if (emsTxBufIdx == emsTxBufLen) {
EMS_UART.conf0.txd_brk = 1; // <brk> after send EMS_UART.conf0.txd_brk = 1; // <brk> after send
@@ -187,7 +187,6 @@ void EMSuart::send_poll(uint8_t data) {
emsTxBufLen = 1; emsTxBufLen = 1;
EMS_UART.conf1.rxfifo_full_thrhd = 1; EMS_UART.conf1.rxfifo_full_thrhd = 1;
EMS_UART.int_ena.rxfifo_full = 1; EMS_UART.int_ena.rxfifo_full = 1;
return EMS_TX_STATUS_OK;
} else if (tx_mode_ == EMS_TXMODE_NEW) { } else if (tx_mode_ == EMS_TXMODE_NEW) {
EMS_UART.fifo.rw_byte = data; EMS_UART.fifo.rw_byte = data;
EMS_UART.conf0.txd_brk = 1; // <brk> after send EMS_UART.conf0.txd_brk = 1; // <brk> after send
@@ -206,7 +205,7 @@ void EMSuart::send_poll(uint8_t data) {
} else { } else {
volatile uint8_t _usrxc = EMS_UART.status.rxfifo_cnt; volatile uint8_t _usrxc = EMS_UART.status.rxfifo_cnt;
EMS_UART.fifo.rw_byte = data; EMS_UART.fifo.rw_byte = data;
uint8_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...
} }
@@ -280,7 +279,7 @@ uint16_t EMSuart::transmit(uint8_t * buf, uint8_t len) {
for (uint8_t i = 0; i < len; i++) { for (uint8_t i = 0; i < len; 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
uint8_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...
} }

View File

@@ -50,7 +50,7 @@
// EMS 1.0 // EMS 1.0
#define EMSUART_TX_BUSY_WAIT (EMSUART_TX_BIT_TIME / 8) // 13 #define EMSUART_TX_BUSY_WAIT (EMSUART_TX_BIT_TIME / 8) // 13
#define EMSUART_TX_TIMEOUT (22 * EMSUART_TX_BIT_TIME / EMSUART_TX_BUSY_WAIT) // 176 #define EMSUART_TX_TIMEOUT (32 * EMSUART_TX_BIT_TIME / EMSUART_TX_BUSY_WAIT) // 256
// HT3/Junkers - Time to send one Byte (8 Bits, 1 Start Bit, 1 Stop Bit) plus 7 bit delay. The -8 is for lag compensation. // HT3/Junkers - Time to send one Byte (8 Bits, 1 Start Bit, 1 Stop Bit) plus 7 bit delay. The -8 is for lag compensation.
// since we use a faster processor the lag is negligible // since we use a faster processor the lag is negligible

View File

@@ -35,7 +35,6 @@ uint8_t emsTxBufIdx;
uint8_t emsTxBufLen; uint8_t emsTxBufLen;
uint32_t emsTxWait; uint32_t emsTxWait;
// //
// Main interrupt handler // Main interrupt handler
// Important: must not use ICACHE_FLASH_ATTR // Important: must not use ICACHE_FLASH_ATTR
@@ -45,24 +44,24 @@ void ICACHE_RAM_ATTR EMSuart::emsuart_rx_intr_handler(void * para) {
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 if (USIS(EMSUART_UART) & ((1 << UIFF))) { // Fifo full, sending in Mode 5
USIC(EMSUART_UART) |= (1 << UIFF); // INT clear fifo interrupt USIC(EMSUART_UART) |= (1 << UIFF); // clear fifo interrupt
emsTxBufIdx++; emsTxBufIdx++;
if (emsTxBufIdx < emsTxBufLen) { if (emsTxBufIdx < emsTxBufLen) {
USF(EMSUART_UART) = emsTxBuf[emsTxBufIdx]; // send next byte USF(EMSUART_UART) = emsTxBuf[emsTxBufIdx]; // send next byte
USC1(EMSUART_UART) = ((emsTxBufIdx + 1) << UCFFT); // increase fifo full USC1(EMSUART_UART) = ((emsTxBufIdx + 1) << UCFFT); // increase fifo full
} else if (emsTxBufIdx == emsTxBufLen) { } else if (emsTxBufIdx == emsTxBufLen) {
USC0(EMSUART_UART) |= (1 << UCBRK); // set <BRK> USC0(EMSUART_UART) |= (1 << UCBRK); // set <BRK>
USIE(EMSUART_UART) &= ~(1 << UIFF); // disable fifo-full irq USIE(EMSUART_UART) &= ~(1 << UIFF); // disable fifo-full irq
USC1(EMSUART_UART) = (0x7F << UCFFT); // fifo full to max 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) { // 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
} }
USIC(EMSUART_UART) = (1 << UIBD); // INT clear the BREAK detect interrupt USIC(EMSUART_UART) = (1 << UIBD); // INT clear the BREAK detect interrupt
USIE(EMSUART_UART) &= ~(1 << UIFF); // disable fifo-full irq USIE(EMSUART_UART) &= ~(1 << UIFF); // disable fifo-full irq
length = 0; length = 0;
while ((USS(EMSUART_UART) >> USRXC) & 0x0FF) { // read fifo into buffer while ((USS(EMSUART_UART) >> USRXC) & 0x0FF) { // read fifo into buffer
@@ -120,6 +119,7 @@ void ICACHE_RAM_ATTR EMSuart::emsuart_tx_timer_intr_handler() {
USC0(EMSUART_UART) |= (1 << UCBRK); // set <BRK> USC0(EMSUART_UART) |= (1 << UCBRK); // set <BRK>
} }
} }
/* /*
* init UART0 driver * init UART0 driver
*/ */
@@ -190,7 +190,6 @@ void ICACHE_FLASH_ATTR EMSuart::start(uint8_t tx_mode) {
ETS_UART_INTR_ATTACH(emsuart_rx_intr_handler, nullptr); ETS_UART_INTR_ATTACH(emsuart_rx_intr_handler, nullptr);
ETS_UART_INTR_ENABLE(); ETS_UART_INTR_ENABLE();
drop_next_rx = true; 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 // for sending with large delay in EMS+ mode we use a timer interrupt
timer1_attachInterrupt(emsuart_tx_timer_intr_handler); // Add ISR Function timer1_attachInterrupt(emsuart_tx_timer_intr_handler); // Add ISR Function
@@ -225,7 +224,6 @@ void ICACHE_FLASH_ATTR EMSuart::restart() {
* Which is a 11-bit set of zero's (11 cycles) * Which is a 11-bit set of zero's (11 cycles)
*/ */
void ICACHE_FLASH_ATTR EMSuart::tx_brk() { void ICACHE_FLASH_ATTR EMSuart::tx_brk() {
// make sure Tx FIFO is empty // make sure Tx FIFO is empty
while (((USS(EMSUART_UART) >> USTXC) & 0xFF)) { while (((USS(EMSUART_UART) >> USTXC) & 0xFF)) {
} }
@@ -235,8 +233,8 @@ void ICACHE_FLASH_ATTR EMSuart::tx_brk() {
ETS_UART_INTR_DISABLE(); ETS_UART_INTR_DISABLE();
USC0(EMSUART_UART) |= (1 << UCBRK); // set bit USC0(EMSUART_UART) |= (1 << UCBRK); // set bit
// also for EMS+ there is no need to wait longer, we are finished and can free the bus. // also for EMS+ there is no need to wait longer, we are finished and can free the bus.
delayMicroseconds(EMSUART_TX_WAIT_BRK); // 1144 delayMicroseconds(EMSUART_TX_WAIT_BRK); // 1144
USC0(EMSUART_UART) &= ~(1 << UCBRK); // clear BRK bit USC0(EMSUART_UART) &= ~(1 << UCBRK); // clear BRK bit
ETS_UART_INTR_ENABLE(); ETS_UART_INTR_ENABLE();
@@ -256,10 +254,11 @@ void EMSuart::send_poll(uint8_t data) {
emsTxBufLen = 1; emsTxBufLen = 1;
timer1_write(emsTxWait); timer1_write(emsTxWait);
} else if (tx_mode_ == 5) { // reload sendbuffer in irq } else if (tx_mode_ == 5) { // reload sendbuffer in irq
USIC(EMSUART_UART) |= (1 << UIFF); // clear fifo-full irq
USC1(EMSUART_UART) = (0x01 << UCFFT); // fifo full to 1 USC1(EMSUART_UART) = (0x01 << UCFFT); // fifo full to 1
USF(EMSUART_UART) = data; USF(EMSUART_UART) = data;
emsTxBufIdx = 0; emsTxBufIdx = 0;
emsTxBufLen = 1; emsTxBufLen = 1;
USIE(EMSUART_UART) |= (1 << UIFF); // enable fifo-full irq USIE(EMSUART_UART) |= (1 << UIFF); // enable fifo-full irq
} 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;
@@ -272,7 +271,9 @@ void EMSuart::send_poll(uint8_t data) {
USF(EMSUART_UART) = data; USF(EMSUART_UART) = data;
delayMicroseconds(EMSUART_TX_WAIT_PLUS); delayMicroseconds(EMSUART_TX_WAIT_PLUS);
tx_brk(); // send <BRK> tx_brk(); // send <BRK>
} else { // EMS1.0, same logic as in transmit } else {
// tx_mode 1
// EMS1.0, same logic as in transmit
ETS_UART_INTR_DISABLE(); ETS_UART_INTR_DISABLE();
volatile uint8_t _usrxc = (USS(EMSUART_UART) >> USRXC) & 0xFF; volatile uint8_t _usrxc = (USS(EMSUART_UART) >> USRXC) & 0xFF;
USF(EMSUART_UART) = data; USF(EMSUART_UART) = data;
@@ -299,7 +300,7 @@ uint16_t ICACHE_FLASH_ATTR EMSuart::transmit(uint8_t * buf, uint8_t len) {
if (len == 0 || len >= EMS_MAXBUFFERSIZE) { if (len == 0 || len >= EMS_MAXBUFFERSIZE) {
return EMS_TX_STATUS_ERR; // nothing or to much to send return EMS_TX_STATUS_ERR; // nothing or to much to send
} }
// reset tx-brk, just in case it is accidentally set // reset tx-brk, just in case it is accidentally set
USC0(EMSUART_UART) &= ~(1 << UCBRK); USC0(EMSUART_UART) &= ~(1 << UCBRK);
@@ -314,10 +315,12 @@ uint16_t ICACHE_FLASH_ATTR EMSuart::transmit(uint8_t * buf, uint8_t len) {
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
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];
} }
USIC(EMSUART_UART) |= (1 << UIFF); // clear fifo-full irq
emsTxBufIdx = 0; emsTxBufIdx = 0;
emsTxBufLen = len; emsTxBufLen = len;
USF(EMSUART_UART) = buf[0]; USF(EMSUART_UART) = buf[0];
@@ -336,7 +339,7 @@ uint16_t ICACHE_FLASH_ATTR EMSuart::transmit(uint8_t * buf, uint8_t len) {
} }
// EMS+ https://github.com/proddy/EMS-ESP/issues/23# // EMS+ https://github.com/proddy/EMS-ESP/issues/23#
if (tx_mode_ == EMS_TXMODE_EMSPLUS) { // With extra tx delay for EMS+ if (tx_mode_ == EMS_TXMODE_EMSPLUS) { // tx_mode 2, With extra tx delay for EMS+
for (uint8_t i = 0; i < len; i++) { for (uint8_t i = 0; i < len; i++) {
USF(EMSUART_UART) = buf[i]; USF(EMSUART_UART) = buf[i];
delayMicroseconds(EMSUART_TX_WAIT_PLUS); // 2070 delayMicroseconds(EMSUART_TX_WAIT_PLUS); // 2070
@@ -345,7 +348,7 @@ uint16_t ICACHE_FLASH_ATTR EMSuart::transmit(uint8_t * buf, uint8_t len) {
return EMS_TX_STATUS_OK; return EMS_TX_STATUS_OK;
} }
// Junkers logic by @philrich // Junkers logic by @philrich, tx_mode 3
if (tx_mode_ == EMS_TXMODE_HT3) { if (tx_mode_ == EMS_TXMODE_HT3) {
for (uint8_t i = 0; i < len; i++) { for (uint8_t i = 0; i < len; i++) {
USF(EMSUART_UART) = buf[i]; USF(EMSUART_UART) = buf[i];
@@ -391,9 +394,9 @@ uint16_t ICACHE_FLASH_ATTR EMSuart::transmit(uint8_t * buf, uint8_t len) {
// send the bytes along the serial line // send the bytes along the serial line
for (uint8_t i = 0; i < len; i++) { for (uint8_t i = 0; i < len; i++) {
volatile uint8_t _usrxc = (USS(EMSUART_UART) >> USRXC) & 0xFF; volatile uint8_t _usrxc = (USS(EMSUART_UART) >> USRXC) & 0xFF;
uint16_t timeoutcnt = EMSUART_TX_TIMEOUT; uint16_t timeoutcnt = EMSUART_TX_TIMEOUT;
USF(EMSUART_UART) = buf[i]; // send each Tx byte USF(EMSUART_UART) = buf[i]; // send each Tx byte
// wait for echo // wait for echo
while ((((USS(EMSUART_UART) >> USRXC) & 0xFF) == _usrxc) && (--timeoutcnt > 0)) { while ((((USS(EMSUART_UART) >> USRXC) & 0xFF) == _usrxc) && (--timeoutcnt > 0)) {
delayMicroseconds(EMSUART_TX_BUSY_WAIT); // burn CPU cycles... delayMicroseconds(EMSUART_TX_BUSY_WAIT); // burn CPU cycles...

View File

@@ -23,7 +23,6 @@
#include <Arduino.h> #include <Arduino.h>
#include <user_interface.h> #include <user_interface.h>
#include <uuid/log.h>
#define EMSUART_UART 0 // UART 0 #define EMSUART_UART 0 // UART 0
#define EMSUART_CONFIG 0x1C // 8N1 (8 bits, no parity, 1 stop bit) #define EMSUART_CONFIG 0x1C // 8N1 (8 bits, no parity, 1 stop bit)
@@ -41,12 +40,13 @@
#define EMS_TXMODE_NEW 4 // for michael's testing #define EMS_TXMODE_NEW 4 // for michael's testing
// LEGACY // LEGACY
#define EMSUART_TX_BIT_TIME 104 // bit time @9600 baud #define EMSUART_TX_BIT_TIME 104 // bit time @9600 baud
#define EMSUART_TX_WAIT_BRK (EMSUART_TX_BIT_TIME * 11) // 1144 #define EMSUART_TX_WAIT_BRK (EMSUART_TX_BIT_TIME * 11) // 1144
// EMS 1.0 // EMS 1.0
#define EMSUART_TX_BUSY_WAIT (EMSUART_TX_BIT_TIME / 8) // 13 #define EMSUART_TX_BUSY_WAIT (EMSUART_TX_BIT_TIME / 8) // 13
#define EMSUART_TX_TIMEOUT (32 * EMSUART_TX_BIT_TIME / EMSUART_TX_BUSY_WAIT) // equivaltent to 32 bittimes // #define EMSUART_TX_TIMEOUT (22 * EMSUART_TX_BIT_TIME / EMSUART_TX_BUSY_WAIT) // 176
#define EMSUART_TX_TIMEOUT (32 * 8) // 256 for tx_mode 1 - see https://github.com/proddy/EMS-ESP/issues/398#issuecomment-645886277
// HT3/Junkers - Time to send one Byte (8 Bits, 1 Start Bit, 1 Stop Bit) plus 7 bit delay. The -8 is for lag compensation. // HT3/Junkers - Time to send one Byte (8 Bits, 1 Start Bit, 1 Stop Bit) plus 7 bit delay. The -8 is for lag compensation.
// since we use a faster processor the lag is negligible // since we use a faster processor the lag is negligible

View File

@@ -1 +1 @@
#define EMSESP_APP_VERSION "2.0.0a22" #define EMSESP_APP_VERSION "2.0.0a23"