Split platform files. Reading via interrupt
This commit is contained in:
parent
e3f2ca70dc
commit
aafaf474d3
@ -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 <esp32-hal.h>
|
||||
#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<esphome::uart::truma_ESP32ArduinoUARTComponent *>(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
|
||||
|
||||
@ -4,11 +4,6 @@
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/components/uart/uart.h"
|
||||
|
||||
#ifdef USE_ESP32
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/task.h>
|
||||
#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
|
||||
|
||||
85
components/truma_inetbox/LinBusListener_esp32_arduino.cpp
Normal file
85
components/truma_inetbox/LinBusListener_esp32_arduino.cpp
Normal file
@ -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<esphome::uart::truma_ESP32ArduinoUARTComponent *>(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
|
||||
31
components/truma_inetbox/LinBusListener_esp_idf.cpp
Normal file
31
components/truma_inetbox/LinBusListener_esp_idf.cpp
Normal file
@ -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
|
||||
18
components/truma_inetbox/LinBusListener_rp2040.cpp
Normal file
18
components/truma_inetbox/LinBusListener_rp2040.cpp
Normal file
@ -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
|
||||
@ -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<u_int8_t, 8> 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<u_int8_t, 8> response = this->lin_empty_response_;
|
||||
if (answer_len <= 6) {
|
||||
// Single Frame response - first frame
|
||||
std::array<u_int8_t, 8> 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
|
||||
@ -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<u_int8_t, 8> message);
|
||||
void prepare_update_msg_(const std::array<u_int8_t, 8> 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
|
||||
|
||||
@ -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])
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user