From aafaf474d337641e35c8b522b53198300089a19d Mon Sep 17 00:00:00 2001 From: Your Name Date: Sun, 12 Feb 2023 18:54:47 +0100 Subject: [PATCH] Split platform files. Reading via interrupt --- components/truma_inetbox/LinBusListener.cpp | 284 +++++------------- components/truma_inetbox/LinBusListener.h | 24 +- .../LinBusListener_esp32_arduino.cpp | 85 ++++++ .../truma_inetbox/LinBusListener_esp_idf.cpp | 31 ++ .../truma_inetbox/LinBusListener_rp2040.cpp | 18 ++ components/truma_inetbox/LinBusProtocol.cpp | 236 +++++++-------- components/truma_inetbox/LinBusProtocol.h | 10 +- components/truma_inetbox/__init__.py | 5 + 8 files changed, 342 insertions(+), 351 deletions(-) create mode 100644 components/truma_inetbox/LinBusListener_esp32_arduino.cpp create mode 100644 components/truma_inetbox/LinBusListener_esp_idf.cpp create mode 100644 components/truma_inetbox/LinBusListener_rp2040.cpp diff --git a/components/truma_inetbox/LinBusListener.cpp b/components/truma_inetbox/LinBusListener.cpp index fc2d448..0c526bb 100644 --- a/components/truma_inetbox/LinBusListener.cpp +++ b/components/truma_inetbox/LinBusListener.cpp @@ -3,33 +3,6 @@ #include "esphome/core/log.h" #include "helpers.h" -#ifdef USE_ESP32 -#include "driver/uart.h" -#include "soc/uart_struct.h" -#include "soc/uart_reg.h" -#endif - -#ifdef USE_ESP8266 -#include "esphome/components/uart/uart_component_esp8266.h" -#endif -#ifdef USE_ESP32_FRAMEWORK_ARDUINO -#include "esphome/components/uart/truma_uart_component_esp32_arduino.h" -#include "esphome/components/uart/uart_component_esp32_arduino.h" -#endif -#ifdef USE_ESP32_FRAMEWORK_ESP_IDF -#include "esphome/components/uart/truma_uart_component_esp_idf.h" -#include "esphome/components/uart/uart_component_esp_idf.h" -#endif -#ifdef USE_RP2040 -#include "esphome/components/uart/truma_uart_component_rp2040.h" -#include "esphome/components/uart/uart_component_rp2040.h" -#endif - -#ifdef USE_ESP32_FRAMEWORK_ARDUINO -// For method `xTaskCreateUniversal` -#include -#endif - namespace esphome { namespace truma_inetbox { @@ -54,52 +27,8 @@ void LinBusListener::setup() { this->time_per_first_byte_ = this->time_per_baud_ * this->frame_length_ * 3.0; this->time_per_byte_ = this->time_per_baud_ * this->frame_length_ * 1.1; -#ifdef USE_ESP32_FRAMEWORK_ARDUINO - auto uartComp = static_cast(this->parent_); - auto uart_num = uartComp->get_hw_serial_number(); - - // Tweak the fifo settings so data is available as soon as the first byte is recieved. - // If not it will wait either until fifo is filled or a certain time has passed. - uart_intr_config_t uart_intr; - uart_intr.intr_enable_mask = - UART_RXFIFO_FULL_INT_ENA_M | UART_RXFIFO_TOUT_INT_ENA_M; // only these IRQs - no BREAK, PARITY or OVERFLOW - // UART_RXFIFO_FULL_INT_ENA_M | UART_RXFIFO_TOUT_INT_ENA_M | UART_FRM_ERR_INT_ENA_M | - // UART_RXFIFO_OVF_INT_ENA_M | UART_BRK_DET_INT_ENA_M | UART_PARITY_ERR_INT_ENA_M; - uart_intr.rxfifo_full_thresh = - 1; // UART_FULL_THRESH_DEFAULT, //120 default!! aghh! need receive 120 chars before we see them - uart_intr.rx_timeout_thresh = - 10; // UART_TOUT_THRESH_DEFAULT, //10 works well for my short messages I need send/receive - uart_intr.txfifo_empty_intr_thresh = 10; // UART_EMPTY_THRESH_DEFAULT - uart_intr_config(uart_num, &uart_intr); -#elif USE_ESP32_FRAMEWORK_ESP_IDF - - // uartSetFastReading - auto uartComp = ((*uart::truma_IDFUARTComponent) this->parent_); - - // Tweak the fifo settings so data is available as soon as the first byte is recieved. - // If not it will wait either until fifo is filled or a certain time has passed. - uart_intr_config_t uart_intr; - uart_intr.intr_enable_mask = 0; // UART_RXFIFO_FULL_INT_ENA_M | UART_RXFIFO_TOUT_INT_ENA_M | UART_FRM_ERR_INT_ENA_M | - // UART_RXFIFO_OVF_INT_ENA_M | UART_BRK_DET_INT_ENA_M | UART_PARITY_ERR_INT_ENA_M; - uart_intr.rxfifo_full_thresh = - 1; // UART_FULL_THRESH_DEFAULT, //120 default!! aghh! need receive 120 chars before we see them - uart_intr.rx_timeout_thresh = - 1; // UART_TOUT_THRESH_DEFAULT, //10 works well for my short messages I need send/receive - uart_intr.txfifo_empty_intr_thresh = 10; // UART_EMPTY_THRESH_DEFAULT - uart_intr_config(uartComp->get_hw_serial_number(), &uart_intr); -#else -// truma_RP2040UartComponent -#error Only ESP32 Arduino is supported. -#endif - - xTaskCreateUniversal(LinBusListener::read_task, - "read_task", // name - 4096, // stack size (in words) - this, // input params - 1, // priority - &this->read_task_handle, // handle - 0 // core - ); + // call device specific function + this->setup_framework(); if (this->cs_pin_ != nullptr) { this->cs_pin_->digital_write(true); @@ -117,19 +46,6 @@ void LinBusListener::write_lin_answer_(const u_int8_t *data, size_t len) { return; } - int64_t wait_time = 0; - // Was data read from FIFO and the master is awaiting an answer. - if (this->total_wait_ > 1000) { - // I am up to date and should not answer too quickly. - auto current = esp_timer_get_time(); - auto wait_time_in_us = (int64_t) this->time_per_baud_ - (current - this->last_data_recieved_); - wait_time = wait_time_in_us; - if (wait_time_in_us > 1000 || wait_time_in_us < 0) { - wait_time_in_us = 0; - } - delayMicroseconds(wait_time_in_us); - } - u_int8_t data_CRC = 0; if (this->lin_checksum_ == LIN_CHECKSUM::LIN_CHECKSUM_VERSION_1 || this->current_PID_ == DIAGNOSTIC_FRAME_SLAVE) { // LIN checksum V1 @@ -144,128 +60,81 @@ void LinBusListener::write_lin_answer_(const u_int8_t *data, size_t len) { this->write(data_CRC); this->flush(); } - ESP_LOGV(TAG, "RESPONSE %02x %s %02x T %lli", this->current_PID_, format_hex_pretty(data, len).c_str(), data_CRC, - wait_time); -} - -void LinBusListener::read_task(void *params) { - LinBusListener *instance = (LinBusListener *) params; - - while (true) { - // Check if Lin Bus is faulty. - if (instance->fault_pin_ != nullptr) { - if (!instance->fault_pin_->digital_read()) { - if (!instance->fault_on_lin_bus_reported_) { - instance->fault_on_lin_bus_reported_ = true; - ESP_LOGE(TAG, "Fault on LIN BUS detected."); - } - // Ignore any data present in buffer - instance->clear_uart_buffer_(); - } else if (instance->fault_on_lin_bus_reported_) { - instance->fault_on_lin_bus_reported_ = false; - ESP_LOGI(TAG, "Fault on LIN BUS fixed."); - } - } - - if (!instance->fault_on_lin_bus_reported_) { - while (instance->available()) { - instance->read_lin_frame_(); - } - } - - // Check if CP Plus is inactive mode. In inactive mode it checks the bus every ~15 seconds for ~5 seconds. At the - // start it send a Break to notify devices to wake up. - auto time_since_last_activity = esp_timer_get_time() - instance->last_data_recieved_; - if (time_since_last_activity > 100 * 1000 /* 100 ms*/) { - // CP Plus is inactive. - delay(500); // NOLINT - } else { - // CP Plus is active. - // 1'000'000 ns / 9600 baud = 104 ns/baud * (8 bit + start bit + 2 stop bit) = 1144 ns/byte * 3 (BREAK,SYNC,PID) = - // ~3.5ms per preamble till I should answer. It is still working with 50ms. But thats the upper limit. CP Plus - // waits 50ms when ordering for an answer. With higher polling the number of CRC errors increases and I cannot - // answer lin orders. - delay(10); // NOLINT - } - } + ESP_LOGV(TAG, "RESPONSE %02x %s %02x", this->current_PID_, format_hex_pretty(data, len).c_str(), data_CRC); } void LinBusListener::read_lin_frame_() { u_int8_t buf; - bool dataRecieved; - u_int8_t data_length, data_CRC, data_CRC_master, data_CRC_slave; - bool message_source_know, message_from_master; + switch (this->current_state_) { + case READ_STATE_BREAK: + // Check if there was an unanswered message before break. + if (this->current_PID_with_parity_ != 0x00 && this->current_PID_ != 0x00 && this->current_data_valid && + this->current_data_count_ == 0) { + ESP_LOGV(TAG, "PID %02x (%02x) order no answer", this->current_PID_, this->current_PID_with_parity_); + } - // Reset current state - { - this->current_PID_with_parity_ = 0x00; - this->current_PID_ = 0x00; - this->current_data_valid = true; - this->current_data_count_ = 0; - memset(this->current_data_, 0, sizeof(this->current_data_)); - this->total_wait_ = 0; - } + // Reset current state + { + this->current_PID_with_parity_ = 0x00; + this->current_PID_ = 0x00; + this->current_data_valid = true; + this->current_data_count_ = 0; + memset(this->current_data_, 0, sizeof(this->current_data_)); + } - // First is Break expected - if (!this->read_byte(&buf) || buf != LIN_BREAK) { - // Update I recieved garbage - this->last_data_recieved_ = esp_timer_get_time(); - ESP_LOGVV(TAG, "Expected BREAK not received."); - return; - } + // First is Break expected + if (!this->read_byte(&buf) || buf != LIN_BREAK) { + ESP_LOGVV(TAG, "Expected BREAK not received."); + } else { + this->current_state_ = READ_STATE_SYNC; + } + break; + case READ_STATE_SYNC: + // Second is Sync expected + if (!this->read_byte(&buf) || buf != LIN_SYNC) { + ESP_LOGVV(TAG, "Expected SYNC not found."); + this->current_state_ = READ_STATE_BREAK; + } else { + this->current_state_ = READ_STATE_SID; + } + break; + case READ_STATE_SID: + this->read_byte(&(this->current_PID_with_parity_)); + this->current_PID_ = this->current_PID_with_parity_ & 0x3F; + if (this->lin_checksum_ == LIN_CHECKSUM::LIN_CHECKSUM_VERSION_2) { + if (this->current_PID_with_parity_ != (this->current_PID_ | (addr_parity(this->current_PID_) << 6))) { + ESP_LOGW(TAG, "LIN CRC error on SID."); + this->current_data_valid = false; + } + } - // Update I recieved a break - this->last_data_recieved_ = esp_timer_get_time(); + if (this->current_data_valid) { + this->can_write_lin_answer_ = true; + // Should I response to this PID order? Ask the handling class. + this->answer_lin_order_(this->current_PID_); + this->can_write_lin_answer_ = false; + } - if (!this->wait_for_data_available_with_timeout_(this->time_per_lin_break_)) { - ESP_LOGV(TAG, "Timeout waiting for Sync"); - return; - } - - // Second is Sync expected - if (!this->read_byte(&buf) || buf != LIN_SYNC) { - // No data present on UART - ESP_LOGVV(TAG, "Expected SYNC not found."); - return; - } - - if (!this->wait_for_data_available_with_timeout_(this->time_per_pid_)) { - ESP_LOGVV(TAG, "Timeout waiting for PID."); - return; - } - - this->read_byte(&(this->current_PID_with_parity_)); - this->current_PID_ = this->current_PID_with_parity_ & 0x3F; - if (this->lin_checksum_ == LIN_CHECKSUM::LIN_CHECKSUM_VERSION_2) { - if (this->current_PID_with_parity_ != (this->current_PID_ | (addr_parity(this->current_PID_) << 6))) { - ESP_LOGW(TAG, "LIN CRC error"); - this->current_data_valid = false; - } - } - - this->can_write_lin_answer_ = true; - // Should I response to this PID order? Ask the handling class. - this->answer_lin_order_(this->current_PID_); - this->can_write_lin_answer_ = false; - - dataRecieved = wait_for_data_available_with_timeout_(this->time_per_first_byte_); - while (dataRecieved) { - this->read_byte(&buf); - if (this->current_data_count_ < sizeof(this->current_data_)) { + // Even on error read data. + this->current_state_ = READ_STATE_DATA; + break; + case READ_STATE_DATA: + this->read_byte(&buf); this->current_data_[this->current_data_count_] = buf; this->current_data_count_++; - dataRecieved = wait_for_data_available_with_timeout_(this->time_per_byte_); - } else { - // end of data reached. There cannot be more than 9 bytes in a LIN frame. - dataRecieved = false; - } + + if (this->current_data_count_ >= sizeof(this->current_data_)) { + // End of data reached. There cannot be more than 9 bytes in a LIN frame. + this->current_state_ = READ_STATE_ACT; + } + break; } - if (this->current_data_count_ > 1) { - data_length = this->current_data_count_ - 1; - data_CRC = this->current_data_[this->current_data_count_ - 1]; - message_source_know = false; - message_from_master = true; + if (this->current_state_ == READ_STATE_ACT && this->current_data_count_ > 1) { + u_int8_t data_length = this->current_data_count_ - 1; + u_int8_t data_CRC = this->current_data_[this->current_data_count_ - 1]; + bool message_source_know = false; + bool message_from_master = true; if (this->lin_checksum_ == LIN_CHECKSUM::LIN_CHECKSUM_VERSION_1 || (this->current_PID_ == DIAGNOSTIC_FRAME_MASTER || this->current_PID_ == DIAGNOSTIC_FRAME_SLAVE)) { @@ -281,8 +150,8 @@ void LinBusListener::read_lin_frame_() { message_from_master = false; } } else { - data_CRC_master = data_checksum(this->current_data_, data_length, this->current_PID_); - data_CRC_slave = data_checksum(this->current_data_, data_length, this->current_PID_with_parity_); + u_int8_t data_CRC_master = data_checksum(this->current_data_, data_length, this->current_PID_); + u_int8_t data_CRC_slave = data_checksum(this->current_data_, data_length, this->current_PID_with_parity_); if (data_CRC != data_CRC_master && data_CRC != data_CRC_slave) { ESP_LOGW(TAG, "LIN v2 CRC error"); this->current_data_valid = false; @@ -309,8 +178,7 @@ void LinBusListener::read_lin_frame_() { if (this->current_data_valid && message_from_master) { this->lin_message_recieved_(this->current_PID_, this->current_data_, data_length); } - } else { - ESP_LOGV(TAG, "PID %02x (%02x) order no answer", this->current_PID_, this->current_PID_with_parity_); + this->current_state_ = READ_STATE_BREAK; } } @@ -320,21 +188,5 @@ void LinBusListener::clear_uart_buffer_() { } } -bool LinBusListener::wait_for_data_available_with_timeout_(u_int32_t timeout) { - int64_t start = esp_timer_get_time(); - int64_t current = esp_timer_get_time(); - int64_t latest_end = start + timeout; - while (current < latest_end) { - current = esp_timer_get_time(); - if (this->available()) { - this->total_wait_ += current - start; - this->last_data_recieved_ = current; - return true; - } - NOP(); - } - return false; -} - } // namespace truma_inetbox } // namespace esphome diff --git a/components/truma_inetbox/LinBusListener.h b/components/truma_inetbox/LinBusListener.h index bec479f..a8e3918 100644 --- a/components/truma_inetbox/LinBusListener.h +++ b/components/truma_inetbox/LinBusListener.h @@ -4,11 +4,6 @@ #include "esphome/core/component.h" #include "esphome/components/uart/uart.h" -#ifdef USE_ESP32 -#include -#include -#endif - namespace esphome { namespace truma_inetbox { @@ -56,23 +51,26 @@ class LinBusListener : public PollingComponent, public uart::UARTDevice { bool fault_on_lin_bus_reported_ = false; bool can_write_lin_answer_ = false; + enum read_state { + READ_STATE_BREAK, + READ_STATE_SYNC, + READ_STATE_SID, + READ_STATE_DATA, + READ_STATE_ACT, + }; + read_state current_state_ = READ_STATE_BREAK; u_int8_t current_PID_with_parity_ = 0x00; u_int8_t current_PID_ = 0x00; bool current_data_valid = true; u_int8_t current_data_count_ = 0; // up to 8 byte data frame + CRC u_int8_t current_data_[9] = {}; - // Total wait time for this LIN Frame (Break, SYNC, Data, CRC) - u_int32_t total_wait_; - // Time when the last LIN data was available. - int64_t last_data_recieved_; - - TaskHandle_t read_task_handle = NULL; - static void read_task(void *params); + // // Time when the last LIN data was available. + // int64_t last_data_recieved_; void read_lin_frame_(); void clear_uart_buffer_(); - bool wait_for_data_available_with_timeout_(u_int32_t timeout); + void setup_framework(); }; } // namespace truma_inetbox diff --git a/components/truma_inetbox/LinBusListener_esp32_arduino.cpp b/components/truma_inetbox/LinBusListener_esp32_arduino.cpp new file mode 100644 index 0000000..7f2fcf3 --- /dev/null +++ b/components/truma_inetbox/LinBusListener_esp32_arduino.cpp @@ -0,0 +1,85 @@ +#ifdef USE_ESP32_FRAMEWORK_ARDUINO +#include "LinBusListener.h" +#include "esphome/core/log.h" +#include "driver/uart.h" +#include "soc/uart_struct.h" +#include "soc/uart_reg.h" +#include "esphome/components/uart/truma_uart_component_esp32_arduino.h" +#include "esphome/components/uart/uart_component_esp32_arduino.h" + +namespace esphome { +namespace truma_inetbox { + +static const char *const TAG = "truma_inetbox.LinBusListener"; + +void LinBusListener::setup_framework() { + auto uartComp = static_cast(this->parent_); + + auto uart_num = uartComp->get_hw_serial_number(); + auto hwSerial = uartComp->get_hw_serial(); + + // Extract from `uartSetFastReading` - Can't call it because I don't have access to `uart_t` object. + + // Tweak the fifo settings so data is available as soon as the first byte is recieved. + // If not it will wait either until fifo is filled or a certain time has passed. + uart_intr_config_t uart_intr; + uart_intr.intr_enable_mask = + UART_RXFIFO_FULL_INT_ENA_M | UART_RXFIFO_TOUT_INT_ENA_M; // only these IRQs - no BREAK, PARITY or OVERFLOW + // UART_RXFIFO_FULL_INT_ENA_M | UART_RXFIFO_TOUT_INT_ENA_M | UART_FRM_ERR_INT_ENA_M | + // UART_RXFIFO_OVF_INT_ENA_M | UART_BRK_DET_INT_ENA_M | UART_PARITY_ERR_INT_ENA_M; + uart_intr.rxfifo_full_thresh = + 1; // UART_FULL_THRESH_DEFAULT, //120 default!! aghh! need receive 120 chars before we see them + uart_intr.rx_timeout_thresh = + 10; // UART_TOUT_THRESH_DEFAULT, //10 works well for my short messages I need send/receive + uart_intr.txfifo_empty_intr_thresh = 10; // UART_EMPTY_THRESH_DEFAULT + uart_intr_config(uart_num, &uart_intr); + + hwSerial->onReceive( + [this]() { + // Check if Lin Bus is faulty. + if (this->fault_pin_ != nullptr) { + if (!this->fault_pin_->digital_read()) { + if (!this->fault_on_lin_bus_reported_) { + this->fault_on_lin_bus_reported_ = true; + ESP_LOGE(TAG, "Fault on LIN BUS detected."); + } + // Ignore any data present in buffer + this->clear_uart_buffer_(); + } else if (this->fault_on_lin_bus_reported_) { + this->fault_on_lin_bus_reported_ = false; + ESP_LOGI(TAG, "Fault on LIN BUS fixed."); + } + } + + if (!this->fault_on_lin_bus_reported_) { + while (this->available()) { + // this->last_data_recieved_ = esp_timer_get_time(); + this->read_lin_frame_(); + } + } + }, + false); + hwSerial->onReceiveError([this](hardwareSerial_error_t val) { + if (val == UART_BREAK_ERROR) { + // If the break is valid the `onReceive` is called first and the break is handeld. Therfore the expectation is + // that the state should be in waiting for `SYNC`. + if (this->current_state_ != READ_STATE_SYNC) { + this->current_state_ = READ_STATE_BREAK; + } + return; + } else if (val == UART_BUFFER_FULL_ERROR) { + ESP_LOGW(TAG, "UART_BUFFER_FULL_ERROR"); + } else if (val == UART_FIFO_OVF_ERROR) { + ESP_LOGW(TAG, "UART_FIFO_OVF_ERROR"); + } else if (val == UART_FRAME_ERROR) { + ESP_LOGW(TAG, "UART_FRAME_ERROR"); + } else if (val == UART_PARITY_ERROR) { + ESP_LOGW(TAG, "UART_PARITY_ERROR"); + } + }); +} + +} // namespace truma_inetbox +} // namespace esphome + +#endif // USE_ESP32_FRAMEWORK_ARDUINO \ No newline at end of file diff --git a/components/truma_inetbox/LinBusListener_esp_idf.cpp b/components/truma_inetbox/LinBusListener_esp_idf.cpp new file mode 100644 index 0000000..8b842d0 --- /dev/null +++ b/components/truma_inetbox/LinBusListener_esp_idf.cpp @@ -0,0 +1,31 @@ +#ifdef USE_ESP32_FRAMEWORK_ESP_IDF +#include "LinBusListener.h" +#include "esphome/core/log.h" +#include "esphome/components/uart/truma_uart_component_esp_idf.h" +#include "esphome/components/uart/uart_component_esp_idf.h" + +namespace esphome { +namespace truma_inetbox { + +static const char *const TAG = "truma_inetbox.LinBusListener"; + +void LinBusListener::setup_framework() { + // uartSetFastReading + auto uartComp = ((*uart::truma_IDFUARTComponent) this->parent_); + + // Tweak the fifo settings so data is available as soon as the first byte is recieved. + // If not it will wait either until fifo is filled or a certain time has passed. + uart_intr_config_t uart_intr; + uart_intr.intr_enable_mask = 0; // UART_RXFIFO_FULL_INT_ENA_M | UART_RXFIFO_TOUT_INT_ENA_M | UART_FRM_ERR_INT_ENA_M | + // UART_RXFIFO_OVF_INT_ENA_M | UART_BRK_DET_INT_ENA_M | UART_PARITY_ERR_INT_ENA_M; + uart_intr.rxfifo_full_thresh = + 1; // UART_FULL_THRESH_DEFAULT, //120 default!! aghh! need receive 120 chars before we see them + uart_intr.rx_timeout_thresh = + 1; // UART_TOUT_THRESH_DEFAULT, //10 works well for my short messages I need send/receive + uart_intr.txfifo_empty_intr_thresh = 10; // UART_EMPTY_THRESH_DEFAULT + uart_intr_config(uartComp->get_hw_serial_number(), &uart_intr); +} +} // namespace truma_inetbox +} // namespace esphome + +#endif // USE_ESP32_FRAMEWORK_ESP_IDF \ No newline at end of file diff --git a/components/truma_inetbox/LinBusListener_rp2040.cpp b/components/truma_inetbox/LinBusListener_rp2040.cpp new file mode 100644 index 0000000..99b2840 --- /dev/null +++ b/components/truma_inetbox/LinBusListener_rp2040.cpp @@ -0,0 +1,18 @@ +#ifdef USE_RP2040 +#include "LinBusListener.h" +#include "esphome/core/log.h" +#include "esphome/components/uart/truma_uart_component_rp2040.h" +#include "esphome/components/uart/uart_component_rp2040.h" + +namespace esphome { +namespace truma_inetbox { + +static const char *const TAG = "truma_inetbox.LinBusListener"; + +void LinBusListener::setup_framework() { + // truma_RP2040UartComponent +} +} // namespace truma_inetbox +} // namespace esphome + +#endif // USE_RP2040 diff --git a/components/truma_inetbox/LinBusProtocol.cpp b/components/truma_inetbox/LinBusProtocol.cpp index 4436961..dde3af7 100644 --- a/components/truma_inetbox/LinBusProtocol.cpp +++ b/components/truma_inetbox/LinBusProtocol.cpp @@ -54,89 +54,57 @@ void LinBusProtocol::lin_message_recieved_(const u_int8_t pid, const u_int8_t *m // this->prepare_update_msg_(response); // } - this->lin_message_recieved_diagnostic_(message, length); + { + // auto node_address = message[0]; + bool my_node_address = message[0] == this->lin_node_address_; + bool broadcast_address = message[0] == LIN_NAD_BROADCAST; + if (!my_node_address && !broadcast_address) { + return; + } + } + u_int8_t protocol_control_information = message[1]; + if ((protocol_control_information & 0xF0) == 0x00) { + // Single Frame mode + { + // End any open Multi frame mode message + this->multi_pdu_message_expected_size_ = 0; + this->multi_pdu_message_len_ = 0; + this->multi_pdu_message_frame_counter_ = 0; + } + this->lin_msg_diag_single_(message, length); + } else if ((protocol_control_information & 0xF0) == 0x10) { + // First Frame of multi PDU message + this->lin_msg_diag_first_(message, length); + } else if ((protocol_control_information & 0xF0) == 0x20) { + // Consecutive Frames + this->lin_msg_diag_consecutive_(message, length); + // Check if this was the last consecutive message. + if (this->multi_pdu_message_len_ == this->multi_pdu_message_expected_size_) { + this->lin_msg_diag_multi_(); + } + } } else if (pid == this->lin_node_address_) { ESP_LOGW(TAG, "Unhandled message for me."); } } -void LinBusProtocol::prepare_update_msg_(const std::array message) { - this->updates_to_send_.push(message); -} - bool LinBusProtocol::is_matching_identifier_(const u_int8_t *message) { auto lin_identifier = this->lin_identifier(); return message[0] == lin_identifier[0] && message[1] == lin_identifier[1] && message[2] == lin_identifier[2] && message[3] == lin_identifier[3]; } -void LinBusProtocol::lin_message_recieved_diagnostic_(const u_int8_t *message, u_int8_t length) { - u_int8_t node_address = message[0]; - bool my_node_address = node_address == this->lin_node_address_; - bool broadcast_address = node_address == LIN_NAD_BROADCAST; - if (!my_node_address && !broadcast_address) { - return; - } - u_int8_t protocol_control_information = message[1]; - u_int16_t message_length = 0; - u_int8_t service_identifier = 0; - if ((protocol_control_information & 0xF0) == 0x00) { - // Single Frame mode - { - // End any open Multi frame mode message - this->multi_pdu_message_expected_size_ = 0; - this->multi_pdu_message_len_ = 0; - this->multi_pdu_message_frame_counter_ = 0; - } - message_length = protocol_control_information; - service_identifier = message[2]; - if (message_length > 6) { - ESP_LOGE(TAG, "LIN Protocol issue: Single frame message too long."); - // ignore invalid message - return; - } - } else if ((protocol_control_information & 0xF0) == 0x10) { - // First Frame of multi PDU message - message_length = (protocol_control_information & 0x0F << 8) + message[2]; - service_identifier = message[3]; - if (message_length < 7) { - ESP_LOGE(TAG, "LIN Protocol issue: Multi frame message too short."); - // ignore invalid message - return; - } - if (message_length > sizeof(this->multi_pdu_message_)) { - ESP_LOGE(TAG, "LIN Protocol issue: Multi frame message too long."); - // ignore invalid message - return; - } - this->multi_pdu_message_expected_size_ = message_length; - this->multi_pdu_message_len_ = 0; - this->multi_pdu_message_frame_counter_ = 1; - for (size_t i = 3; i < 8; i++) { - this->multi_pdu_message_[this->multi_pdu_message_len_++] = message[i]; - } - // Message is handeld - return; - } else if ((protocol_control_information & 0xF0) == 0x20) { - // Consecutive Frames - if (this->multi_pdu_message_len_ >= this->multi_pdu_message_expected_size_) { - // ignore, because i don't await a consecutive frame - return; - } - u_int8_t frame_counter = protocol_control_information & 0x0F; - if (frame_counter != this->multi_pdu_message_frame_counter_) { - // ignore, because i don't await this consecutive frame - return; - } - this->multi_pdu_message_frame_counter_++; - if (this->multi_pdu_message_frame_counter_ > 0x0F) { - // Frame counter has only 4 bit and wraps around. - this->multi_pdu_message_frame_counter_ = 0x00; - } +void LinBusProtocol::lin_msg_diag_single_(const u_int8_t *message, u_int8_t length) { + // auto node_address = message[0]; + bool my_node_address = message[0] == this->lin_node_address_; + bool broadcast_address = message[0] == LIN_NAD_BROADCAST; - this->lin_message_recieved_diagnostic_multi_(message, length, protocol_control_information); - // Message is handeld + u_int8_t message_length = message[1]; + u_int8_t service_identifier = message[2]; + if (message_length > 6) { + ESP_LOGE(TAG, "LIN Protocol issue: Single frame message too long."); + // ignore invalid message return; } @@ -201,69 +169,103 @@ void LinBusProtocol::lin_message_recieved_diagnostic_(const u_int8_t *message, u } } -void LinBusProtocol::lin_message_recieved_diagnostic_multi_(const u_int8_t *message, u_int8_t length, - u_int8_t protocol_control_information) { +void LinBusProtocol::lin_msg_diag_first_(const u_int8_t *message, u_int8_t length) { + u_int8_t protocol_control_information = message[1]; + u_int16_t message_length = (protocol_control_information & 0x0F << 8) + message[2]; + if (message_length < 7) { + ESP_LOGE(TAG, "LIN Protocol issue: Multi frame message too short."); + // ignore invalid message + return; + } + if (message_length > sizeof(this->multi_pdu_message_)) { + ESP_LOGE(TAG, "LIN Protocol issue: Multi frame message too long."); + // ignore invalid message + return; + } + this->multi_pdu_message_expected_size_ = message_length; + this->multi_pdu_message_len_ = 0; + this->multi_pdu_message_frame_counter_ = 1; + + // Copy recieved message over to `multi_pdu_message_` buffer. + for (size_t i = 3; i < 8; i++) { + this->multi_pdu_message_[this->multi_pdu_message_len_++] = message[i]; + } +} + +void LinBusProtocol::lin_msg_diag_consecutive_(const u_int8_t *message, u_int8_t length) { + if (this->multi_pdu_message_len_ >= this->multi_pdu_message_expected_size_) { + // ignore, because i don't await a consecutive frame + return; + } + u_int8_t protocol_control_information = message[1]; + u_int8_t frame_counter = protocol_control_information & 0x0F; + if (frame_counter != this->multi_pdu_message_frame_counter_) { + // ignore, because i don't await this consecutive frame + return; + } + this->multi_pdu_message_frame_counter_++; + if (this->multi_pdu_message_frame_counter_ > 0x0F) { + // Frame counter has only 4 bit and wraps around. + this->multi_pdu_message_frame_counter_ = 0x00; + } + // Copy recieved message over to `multi_pdu_message_` buffer. for (u_int8_t i = 2; i < 8; i++) { if (this->multi_pdu_message_len_ < this->multi_pdu_message_expected_size_) { this->multi_pdu_message_[this->multi_pdu_message_len_++] = message[i]; } } +} - if (this->multi_pdu_message_len_ == this->multi_pdu_message_expected_size_) { - ESP_LOGD(TAG, "Multi package request %s", - format_hex_pretty(this->multi_pdu_message_, this->multi_pdu_message_len_).c_str()); +void LinBusProtocol::lin_msg_diag_multi_() { + ESP_LOGD(TAG, "Multi package request %s", + format_hex_pretty(this->multi_pdu_message_, this->multi_pdu_message_len_).c_str()); - u_int8_t answer_len = 0; - // Ask handling class what to answer to this request. - auto answer = this->lin_multiframe_recieved(this->multi_pdu_message_, this->multi_pdu_message_len_, &answer_len); - if (answer_len > 0) { - ESP_LOGD(TAG, "Multi package response %s", format_hex_pretty(answer, answer_len).c_str()); + u_int8_t answer_len = 0; + // Ask handling class what to answer to this request. + auto answer = this->lin_multiframe_recieved(this->multi_pdu_message_, this->multi_pdu_message_len_, &answer_len); + if (answer_len > 0) { + ESP_LOGD(TAG, "Multi package response %s", format_hex_pretty(answer, answer_len).c_str()); - std::array response = this->lin_empty_response_; - if (answer_len <= 6) { - // Single Frame response - first frame + std::array response = this->lin_empty_response_; + if (answer_len <= 6) { + // Single Frame response - first frame + response[0] = this->lin_node_address_; + response[1] = answer_len; /* bytes length */ + response[2] = answer[0] | LIN_SID_RESPONSE; + for (u_int8_t i = 1; i < answer_len; i++) { + response[i + 2] = answer[i]; + } + this->prepare_update_msg_(response); + } else { + // Multi Frame response + response[0] = this->lin_node_address_; + response[1] = 0x10 | ((answer_len >> 8) & 0x0F); + response[2] = answer_len & 0xFF; + response[3] = answer[0] | LIN_SID_RESPONSE; + for (u_int8_t i = 1; i < 5; i++) { + response[i + 3] = answer[i]; + } + this->prepare_update_msg_(response); + + // Multi Frame response - consecutive frame + u_int16_t answer_position = 5; // The first 5 bytes are sent in First frame of multi frame response. + u_int8_t answer_frame_counter = 0; // Each answer frame can contain 6 bytes + while (answer_position < answer_len) { + response = this->lin_empty_response_; response[0] = this->lin_node_address_; - response[1] = answer_len; /* bytes length */ - response[2] = answer[0] | LIN_SID_RESPONSE; - for (u_int8_t i = 1; i < answer_len; i++) { - response[i + 2] = answer[i]; - } - this->prepare_update_msg_(response); - } else { - // Multi Frame response - response[0] = this->lin_node_address_; - response[1] = 0x10 | ((answer_len >> 8) & 0x0F); - response[2] = answer_len & 0xFF; - response[3] = answer[0] | LIN_SID_RESPONSE; - for (u_int8_t i = 1; i < 5; i++) { - response[i + 3] = answer[i]; - } - this->prepare_update_msg_(response); - - // Multi Frame response - consecutive frame - u_int16_t answer_position = 5; // The first 5 bytes are sent in First frame of multi frame response. - u_int8_t answer_frame_counter = 0; // Each answer frame can contain 6 bytes - while (answer_position < answer_len) { - response = this->lin_empty_response_; - response[0] = this->lin_node_address_; - response[1] = ((answer_frame_counter + 1) & 0x0F) | 0x20; - for (u_int8_t i = 0; i < 6; i++) { - if (answer_position < answer_len) { - response[i + 2] = answer[answer_position++]; - } + response[1] = ((answer_frame_counter + 1) & 0x0F) | 0x20; + for (u_int8_t i = 0; i < 6; i++) { + if (answer_position < answer_len) { + response[i + 2] = answer[answer_position++]; } - this->prepare_update_msg_(response); - answer_frame_counter++; } + this->prepare_update_msg_(response); + answer_frame_counter++; } } } } -void LinBusProtocol::lin_message_recieved_diagnostic_single_(const u_int8_t *message, u_int8_t length) { - // TODO: Split up `lin_message_recieved_diagnostic_` method. -} - } // namespace truma_inetbox } // namespace esphome \ No newline at end of file diff --git a/components/truma_inetbox/LinBusProtocol.h b/components/truma_inetbox/LinBusProtocol.h index 969c44b..007146f 100644 --- a/components/truma_inetbox/LinBusProtocol.h +++ b/components/truma_inetbox/LinBusProtocol.h @@ -26,17 +26,17 @@ class LinBusProtocol : public LinBusListener { private: u_int8_t lin_node_address_ = /*LIN initial node address*/ 0x03; - void prepare_update_msg_(const std::array message); + void prepare_update_msg_(const std::array message) { this->updates_to_send_.push(std::move(message)); } bool is_matching_identifier_(const u_int8_t *message); u_int16_t multi_pdu_message_expected_size_ = 0; u_int8_t multi_pdu_message_len_ = 0; u_int8_t multi_pdu_message_frame_counter_ = 0; u_int8_t multi_pdu_message_[64]; - void lin_message_recieved_diagnostic_(const u_int8_t *message, u_int8_t length); - void lin_message_recieved_diagnostic_multi_(const u_int8_t *message, u_int8_t length, - u_int8_t protocol_control_information); - void lin_message_recieved_diagnostic_single_(const u_int8_t *message, u_int8_t length); + void lin_msg_diag_single_(const u_int8_t *message, u_int8_t length); + void lin_msg_diag_first_(const u_int8_t *message, u_int8_t length); + void lin_msg_diag_consecutive_(const u_int8_t *message, u_int8_t length); + void lin_msg_diag_multi_(); }; } // namespace truma_inetbox diff --git a/components/truma_inetbox/__init__.py b/components/truma_inetbox/__init__.py index fab3bda..515940e 100644 --- a/components/truma_inetbox/__init__.py +++ b/components/truma_inetbox/__init__.py @@ -325,6 +325,11 @@ async def truma_inetbox_timer_disable_to_code(config, action_id, template_arg, a ), ) async def truma_inetbox_timer_activate_to_code(config, action_id, template_arg, args): + # Run interrupt on core 0. ESP Home runs on core 1. + cg.add_build_flag("-DARDUINO_SERIAL_EVENT_TASK_RUNNING_CORE=0") + # Default Stack Size is 2048. Not enough for my operation. + cg.add_build_flag("-DARDUINO_SERIAL_EVENT_TASK_STACK_SIZE=4096") + var = cg.new_Pvariable(action_id, template_arg) await cg.register_parented(var, config[CONF_ID])