ran clang-format

This commit is contained in:
Guido Schreuder 2024-02-19 13:57:24 +01:00
parent 241f4363f5
commit e1a8f60ddb
8 changed files with 270 additions and 359 deletions

View file

@ -47,9 +47,7 @@ uint8_t Ebus::uart_send_char(uint8_t cr, bool esc, bool run_crc, uint8_t crc_ini
return Elf::crc8_calc(buffer[1], crc); return Elf::crc8_calc(buffer[1], crc);
} }
void Ebus::uart_send_char(uint8_t cr, bool esc) { void Ebus::uart_send_char(uint8_t cr, bool esc) { this->uart_send_char(cr, esc, false, 0); }
this->uart_send_char(cr, esc, false, 0);
}
void Ebus::uart_send_remaining_request_part(SendCommand &command) { void Ebus::uart_send_remaining_request_part(SendCommand &command) {
this->uart_send_char(command.getZZ()); this->uart_send_char(command.getZZ());
@ -57,7 +55,7 @@ void Ebus::uart_send_remaining_request_part(SendCommand &command) {
this->uart_send_char(command.getSB()); this->uart_send_char(command.getSB());
this->uart_send_char(command.getNN()); this->uart_send_char(command.getNN());
for (int i = 0; i < command.getNN(); i++) { for (int i = 0; i < command.getNN(); i++) {
this->uart_send_char((uint8_t)command.get_request_byte(i)); this->uart_send_char((uint8_t) command.get_request_byte(i));
} }
this->uart_send_char(command.get_crc()); this->uart_send_char(command.get_crc());
} }
@ -92,121 +90,131 @@ void Ebus::process_received_char(unsigned char received_byte) {
} }
switch (this->receiving_telegram_.get_state()) { switch (this->receiving_telegram_.get_state()) {
case TelegramState::waitForSyn: case TelegramState::waitForSyn:
if (received_byte == SYN) { if (received_byte == SYN) {
this->receiving_telegram_.set_state(TelegramState::waitForArbitration); this->receiving_telegram_.set_state(TelegramState::waitForArbitration);
} }
break; break;
case TelegramState::waitForArbitration: case TelegramState::waitForArbitration:
if (received_byte != SYN) { if (received_byte != SYN) {
this->receiving_telegram_.push_req_data(received_byte); this->receiving_telegram_.push_req_data(received_byte);
this->receiving_telegram_.set_state(TelegramState::waitForRequestData); this->receiving_telegram_.set_state(TelegramState::waitForRequestData);
} }
break; break;
case TelegramState::waitForRequestData: case TelegramState::waitForRequestData:
if (received_byte == SYN) { if (received_byte == SYN) {
if (this->receiving_telegram_.getZZ() == ESC) { if (this->receiving_telegram_.getZZ() == ESC) {
this->receiving_telegram_.set_state(TelegramState::endArbitration); this->receiving_telegram_.set_state(TelegramState::endArbitration);
} else {
this->receiving_telegram_.set_state(TelegramState::endErrorUnexpectedSyn);
}
} else { } else {
this->receiving_telegram_.push_req_data(received_byte);
if (this->receiving_telegram_.is_request_complete()) {
this->receiving_telegram_.set_state(this->receiving_telegram_.is_ack_expected()
? TelegramState::waitForRequestAck
: TelegramState::endCompleted);
}
}
break;
case TelegramState::waitForRequestAck:
switch (received_byte) {
case ACK:
this->receiving_telegram_.set_state(this->receiving_telegram_.is_response_expected()
? TelegramState::waitForResponseData
: TelegramState::endCompleted);
break;
case NACK:
this->receiving_telegram_.set_state(TelegramState::endErrorRequestNackReceived);
break;
default:
this->receiving_telegram_.set_state(TelegramState::endErrorRequestNoAck);
}
break;
case TelegramState::waitForResponseData:
if (received_byte == SYN) {
this->receiving_telegram_.set_state(TelegramState::endErrorUnexpectedSyn); this->receiving_telegram_.set_state(TelegramState::endErrorUnexpectedSyn);
} else {
this->receiving_telegram_.push_response_data(received_byte);
if (this->receiving_telegram_.is_response_complete()) {
this->receiving_telegram_.set_state(TelegramState::waitForResponseAck);
}
} }
} else {
this->receiving_telegram_.push_req_data(received_byte);
if (this->receiving_telegram_.is_request_complete()) {
this->receiving_telegram_.set_state(this->receiving_telegram_.is_ack_expected() ? TelegramState::waitForRequestAck : TelegramState::endCompleted);
}
}
break;
case TelegramState::waitForRequestAck:
switch (received_byte) {
case ACK:
this->receiving_telegram_.set_state(this->receiving_telegram_.is_response_expected() ? TelegramState::waitForResponseData : TelegramState::endCompleted);
break; break;
case NACK: case TelegramState::waitForResponseAck:
this->receiving_telegram_.set_state(TelegramState::endErrorRequestNackReceived); switch (received_byte) {
case ACK:
this->receiving_telegram_.set_state(TelegramState::endCompleted);
break;
case NACK:
this->receiving_telegram_.set_state(TelegramState::endErrorResponseNackReceived);
break;
default:
this->receiving_telegram_.set_state(TelegramState::endErrorResponseNoAck);
}
break; break;
default: default:
this->receiving_telegram_.set_state(TelegramState::endErrorRequestNoAck);
}
break;
case TelegramState::waitForResponseData:
if (received_byte == SYN) {
this->receiving_telegram_.set_state(TelegramState::endErrorUnexpectedSyn);
} else {
this->receiving_telegram_.push_response_data(received_byte);
if (this->receiving_telegram_.is_response_complete()) {
this->receiving_telegram_.set_state(TelegramState::waitForResponseAck);
}
}
break;
case TelegramState::waitForResponseAck:
switch (received_byte) {
case ACK:
this->receiving_telegram_.set_state(TelegramState::endCompleted);
break; break;
case NACK:
this->receiving_telegram_.set_state(TelegramState::endErrorResponseNackReceived);
break;
default:
this->receiving_telegram_.set_state(TelegramState::endErrorResponseNoAck);
}
break;
default:
break;
} }
switch (this->active_command_.get_state()) { switch (this->active_command_.get_state()) {
case TelegramState::waitForSend: case TelegramState::waitForSend:
if (received_byte == SYN && state == EbusState::normal && this->lock_counter_ == 0) { if (received_byte == SYN && state == EbusState::normal && this->lock_counter_ == 0) {
this->active_command_.set_state(TelegramState::waitForArbitration); this->active_command_.set_state(TelegramState::waitForArbitration);
this->uart_send_char(this->active_command_.getQQ()); this->uart_send_char(this->active_command_.getQQ());
} }
break; break;
case TelegramState::waitForArbitration: case TelegramState::waitForArbitration:
if (received_byte == this->active_command_.getQQ()) { if (received_byte == this->active_command_.getQQ()) {
// we won arbitration // we won arbitration
this->uart_send_remaining_request_part(this->active_command_); this->uart_send_remaining_request_part(this->active_command_);
if (this->active_command_.is_ack_expected()) { if (this->active_command_.is_ack_expected()) {
this->active_command_.set_state(TelegramState::waitForCommandAck); this->active_command_.set_state(TelegramState::waitForCommandAck);
} else {
this->active_command_.set_state(TelegramState::endCompleted);
this->lock_counter_ = this->max_lock_counter_;
}
} else if (Elf::get_priority_class(received_byte) == Elf::get_priority_class(this->active_command_.getQQ())) {
// eligible for round 2
this->active_command_.set_state(TelegramState::waitForArbitration2nd);
} else { } else {
// lost arbitration, try again later if retries left
this->active_command_.set_state(this->active_command_.can_retry(this->max_tries_)
? TelegramState::waitForSend
: TelegramState::endSendFailed);
}
break;
case TelegramState::waitForArbitration2nd:
if (received_byte == SYN) {
this->uart_send_char(this->active_command_.getQQ());
} else if (received_byte == this->active_command_.getQQ()) {
// won round 2
this->uart_send_remaining_request_part(this->active_command_);
if (this->active_command_.is_ack_expected()) {
this->active_command_.set_state(TelegramState::waitForCommandAck);
} else {
this->active_command_.set_state(TelegramState::endCompleted);
this->lock_counter_ = this->max_lock_counter_;
}
} else {
// try again later if retries left
this->active_command_.set_state(this->active_command_.can_retry(this->max_tries_)
? TelegramState::waitForSend
: TelegramState::endSendFailed);
}
break;
case TelegramState::waitForCommandAck:
if (received_byte == ACK) {
this->active_command_.set_state(TelegramState::endCompleted); this->active_command_.set_state(TelegramState::endCompleted);
this->lock_counter_ = this->max_lock_counter_; this->lock_counter_ = this->max_lock_counter_;
} else if (received_byte == SYN) { // timeout waiting for ACK signaled by AUTO-SYN
this->active_command_.set_state(this->active_command_.can_retry(this->max_tries_)
? TelegramState::waitForSend
: TelegramState::endSendFailed);
} }
} else if (Elf::get_priority_class(received_byte) == Elf::get_priority_class(this->active_command_.getQQ())) { break;
// eligible for round 2 default:
this->active_command_.set_state(TelegramState::waitForArbitration2nd); break;
} else {
// lost arbitration, try again later if retries left
this->active_command_.set_state(this->active_command_.can_retry(this->max_tries_) ? TelegramState::waitForSend : TelegramState::endSendFailed);
}
break;
case TelegramState::waitForArbitration2nd:
if (received_byte == SYN) {
this->uart_send_char(this->active_command_.getQQ());
} else if (received_byte == this->active_command_.getQQ()) {
// won round 2
this->uart_send_remaining_request_part(this->active_command_);
if (this->active_command_.is_ack_expected()) {
this->active_command_.set_state(TelegramState::waitForCommandAck);
} else {
this->active_command_.set_state(TelegramState::endCompleted);
this->lock_counter_ = this->max_lock_counter_;
}
} else {
// try again later if retries left
this->active_command_.set_state(this->active_command_.can_retry(this->max_tries_) ? TelegramState::waitForSend : TelegramState::endSendFailed);
}
break;
case TelegramState::waitForCommandAck:
if (received_byte == ACK) {
this->active_command_.set_state(TelegramState::endCompleted);
this->lock_counter_ = this->max_lock_counter_;
} else if (received_byte == SYN) { // timeout waiting for ACK signaled by AUTO-SYN
this->active_command_.set_state(this->active_command_.can_retry(this->max_tries_) ? TelegramState::waitForSend : TelegramState::endSendFailed);
}
break;
default:
break;
} }
// responses to our commands are stored in receiving_telegram_ // responses to our commands are stored in receiving_telegram_
@ -223,7 +231,6 @@ void Ebus::process_received_char(unsigned char received_byte) {
// Handle our responses // Handle our responses
this->handle_response(this->receiving_telegram_); this->handle_response(this->receiving_telegram_);
} }
void Ebus::add_send_response_handler(std::function<uint8_t(Telegram &, uint8_t *)> send_response_handler) { void Ebus::add_send_response_handler(std::function<uint8_t(Telegram &, uint8_t *)> send_response_handler) {
@ -245,7 +252,7 @@ void Ebus::handle_response(Telegram &telegram) {
int len = 0; int len = 0;
// find response // find response
for (auto const& handler : send_response_handlers_) { for (auto const &handler : send_response_handlers_) {
len = handler(telegram, buf); len = handler(telegram, buf);
if (len != 0) { if (len != 0) {
break; break;
@ -274,23 +281,23 @@ unsigned char Elf::crc8_calc(unsigned char data, unsigned char crc_init) {
crc = crc_init; crc = crc_init;
for (int i = 0; i < 8; i++) { for (int i = 0; i < 8; i++) {
if (crc & 0x80) { if (crc & 0x80) {
polynom = (unsigned char)0x9B; polynom = (unsigned char) 0x9B;
} else { } else {
polynom = (unsigned char)0; polynom = (unsigned char) 0;
} }
crc = (unsigned char)((crc & ~0x80) << 1); crc = (unsigned char) ((crc & ~0x80) << 1);
if (data & 0x80) { if (data & 0x80) {
crc = (unsigned char)(crc | 1); crc = (unsigned char) (crc | 1);
} }
crc = (unsigned char)(crc ^ polynom); crc = (unsigned char) (crc ^ polynom);
data = (unsigned char)(data << 1); data = (unsigned char) (data << 1);
} }
return (crc); return (crc);
} }
unsigned char Elf::crc8_array(unsigned char data[], unsigned int length) { unsigned char Elf::crc8_array(unsigned char data[], unsigned int length) {
unsigned char uc_crc; unsigned char uc_crc;
uc_crc = (unsigned char)0; uc_crc = (unsigned char) 0;
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
uc_crc = crc8_calc(data[i], uc_crc); uc_crc = crc8_calc(data[i], uc_crc);
} }
@ -304,24 +311,20 @@ bool Elf::is_primary(uint8_t address) {
int Elf::is_primary_nibble(uint8_t nibble) { int Elf::is_primary_nibble(uint8_t nibble) {
switch (nibble) { switch (nibble) {
case 0b0000: case 0b0000:
case 0b0001: case 0b0001:
case 0b0011: case 0b0011:
case 0b0111: case 0b0111:
case 0b1111: case 0b1111:
return true; return true;
default: default:
return false; return false;
} }
} }
uint8_t Elf::get_priority_class(uint8_t address) { uint8_t Elf::get_priority_class(uint8_t address) { return (address & 0x0F); }
return (address & 0x0F);
}
uint8_t Elf::get_sub_address(uint8_t address) { uint8_t Elf::get_sub_address(uint8_t address) { return (address >> 4); }
return (address >> 4);
}
uint8_t Elf::to_secondary(uint8_t address) { uint8_t Elf::to_secondary(uint8_t address) {
if (is_primary(address)) { if (is_primary(address)) {

View file

@ -15,9 +15,8 @@ typedef struct {
uint8_t max_lock_counter; uint8_t max_lock_counter;
} ebus_config_t; } ebus_config_t;
class Elf { class Elf {
public: public:
static unsigned char crc8_calc(unsigned char data, unsigned char crc_init); static unsigned char crc8_calc(unsigned char data, unsigned char crc_init);
static unsigned char crc8_array(unsigned char data[], unsigned int length); static unsigned char crc8_array(unsigned char data[], unsigned int length);
static bool is_primary(uint8_t address); static bool is_primary(uint8_t address);
@ -27,9 +26,8 @@ public:
static uint8_t to_secondary(uint8_t address); static uint8_t to_secondary(uint8_t address);
}; };
class Ebus { class Ebus {
public: public:
explicit Ebus(ebus_config_t &config); explicit Ebus(ebus_config_t &config);
void set_uart_send_function(std::function<void(const char *, int16_t)> uart_send); void set_uart_send_function(std::function<void(const char *, int16_t)> uart_send);
void set_queue_received_telegram_function(std::function<void(Telegram &telegram)> queue_received_telegram); void set_queue_received_telegram_function(std::function<void(Telegram &telegram)> queue_received_telegram);
@ -37,7 +35,7 @@ public:
void process_received_char(unsigned char receivedByte); void process_received_char(unsigned char receivedByte);
void add_send_response_handler(std::function<uint8_t(Telegram &, uint8_t *)>); void add_send_response_handler(std::function<uint8_t(Telegram &, uint8_t *)>);
protected: protected:
uint8_t primary_address_; uint8_t primary_address_;
uint8_t max_tries_; uint8_t max_tries_;
uint8_t max_lock_counter_; uint8_t max_lock_counter_;
@ -50,12 +48,11 @@ protected:
std::function<void(const char *, int16_t)> uart_send_; std::function<void(const char *, int16_t)> uart_send_;
std::function<void(Telegram &)> queue_received_telegram_; std::function<void(Telegram &)> queue_received_telegram_;
std::function<bool(void *const&)> dequeue_command_; std::function<bool(void *const &)> dequeue_command_;
uint8_t uart_send_char(uint8_t cr, bool esc, bool run_crc, uint8_t crc_init); uint8_t uart_send_char(uint8_t cr, bool esc, bool run_crc, uint8_t crc_init);
void uart_send_char(uint8_t cr, bool esc = true); void uart_send_char(uint8_t cr, bool esc = true);
void uart_send_remaining_request_part(SendCommand &command); void uart_send_remaining_request_part(SendCommand &command);
void handle_response(Telegram &telegram); void handle_response(Telegram &telegram);
}; };
} // namespace ebus } // namespace ebus

View file

@ -25,24 +25,12 @@ void EbusComponent::setup() {
this->setup_tasks(); this->setup_tasks();
} }
void EbusComponent::set_primary_address(uint8_t primary_address) { void EbusComponent::set_primary_address(uint8_t primary_address) { this->primary_address_ = primary_address; }
this->primary_address_ = primary_address; void EbusComponent::set_max_tries(uint8_t max_tries) { this->max_tries_ = max_tries; }
} void EbusComponent::set_max_lock_counter(uint8_t max_lock_counter) { this->max_lock_counter_ = max_lock_counter; }
void EbusComponent::set_max_tries(uint8_t max_tries) { void EbusComponent::set_uart_num(uint8_t uart_num) { this->uart_num_ = uart_num; }
this->max_tries_ = max_tries; void EbusComponent::set_uart_tx_pin(uint8_t uart_tx_pin) { this->uart_tx_pin_ = uart_tx_pin; }
} void EbusComponent::set_uart_rx_pin(uint8_t uart_rx_pin) { this->uart_rx_pin_ = uart_rx_pin; }
void EbusComponent::set_max_lock_counter(uint8_t max_lock_counter) {
this->max_lock_counter_ = max_lock_counter;
}
void EbusComponent::set_uart_num(uint8_t uart_num) {
this->uart_num_ = uart_num;
}
void EbusComponent::set_uart_tx_pin(uint8_t uart_tx_pin) {
this->uart_tx_pin_ = uart_tx_pin;
}
void EbusComponent::set_uart_rx_pin(uint8_t uart_rx_pin) {
this->uart_rx_pin_ = uart_rx_pin;
}
void EbusComponent::set_history_queue_size(uint8_t history_queue_size) { void EbusComponent::set_history_queue_size(uint8_t history_queue_size) {
this->history_queue_size_ = history_queue_size; this->history_queue_size_ = history_queue_size;
} }
@ -54,36 +42,33 @@ void EbusComponent::add_sender(EbusSender *sender) {
sender->set_primary_address(this->primary_address_); sender->set_primary_address(this->primary_address_);
this->senders_.push_back(sender); this->senders_.push_back(sender);
} }
void EbusComponent::add_receiver(EbusReceiver *receiver) { void EbusComponent::add_receiver(EbusReceiver *receiver) { this->receivers_.push_back(receiver); }
this->receivers_.push_back(receiver);
}
void EbusComponent::setup_queues() { void EbusComponent::setup_queues() {
this->history_queue_ = xQueueCreate(this->history_queue_size_, sizeof(Telegram)); this->history_queue_ = xQueueCreate(this->history_queue_size_, sizeof(Telegram));
this->command_queue_ = xQueueCreate(this->command_queue_size_, sizeof(Telegram)); this->command_queue_ = xQueueCreate(this->command_queue_size_, sizeof(Telegram));
} }
void EbusComponent::setup_ebus() { void EbusComponent::setup_ebus() {
ebus_config_t ebus_config = ebus_config_t { ebus_config_t ebus_config = ebus_config_t{
.primary_address = this->primary_address_, .primary_address = this->primary_address_,
.max_tries = this->max_tries_, .max_tries = this->max_tries_,
.max_lock_counter = this->max_lock_counter_, .max_lock_counter = this->max_lock_counter_,
}; };
this->ebus = new Ebus(ebus_config); this->ebus = new Ebus(ebus_config);
this->ebus->set_uart_send_function( [&](const char * buffer, int16_t length) { this->ebus->set_uart_send_function(
return uart_write_bytes(this->uart_num_, buffer, length); [&](const char *buffer, int16_t length) { return uart_write_bytes(this->uart_num_, buffer, length); });
} );
this->ebus->set_queue_received_telegram_function( [&](Telegram &telegram) { this->ebus->set_queue_received_telegram_function([&](Telegram &telegram) {
BaseType_t xHigherPriorityTaskWoken; BaseType_t xHigherPriorityTaskWoken;
xHigherPriorityTaskWoken = pdFALSE; xHigherPriorityTaskWoken = pdFALSE;
xQueueSendToBackFromISR(this->history_queue_, &telegram, &xHigherPriorityTaskWoken); xQueueSendToBackFromISR(this->history_queue_, &telegram, &xHigherPriorityTaskWoken);
if (xHigherPriorityTaskWoken) { if (xHigherPriorityTaskWoken) {
portYIELD_FROM_ISR(); portYIELD_FROM_ISR();
} }
} ); });
this->ebus->set_dequeue_command_function( [&](void *const command) { this->ebus->set_dequeue_command_function([&](void *const command) {
BaseType_t xHigherPriorityTaskWoken = pdFALSE; BaseType_t xHigherPriorityTaskWoken = pdFALSE;
if (xQueueReceiveFromISR(this->command_queue_, command, &xHigherPriorityTaskWoken)) { if (xQueueReceiveFromISR(this->command_queue_, command, &xHigherPriorityTaskWoken)) {
if (xHigherPriorityTaskWoken) { if (xHigherPriorityTaskWoken) {
@ -92,8 +77,7 @@ void EbusComponent::setup_ebus() {
return true; return true;
} }
return false; return false;
} ); });
} }
void EbusComponent::setup_uart() { void EbusComponent::setup_uart() {
@ -101,23 +85,19 @@ void EbusComponent::setup_uart() {
portENTER_CRITICAL(&mux); portENTER_CRITICAL(&mux);
uart_config_t uart_config = { uart_config_t uart_config = {
.baud_rate = 2400, .baud_rate = 2400,
.data_bits = UART_DATA_8_BITS, .data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE, .parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1, .stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE, .flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
.rx_flow_ctrl_thresh = 2, .rx_flow_ctrl_thresh = 2,
.use_ref_tick = true, .use_ref_tick = true,
}; };
ESP_ERROR_CHECK(uart_param_config(this->uart_num_, &uart_config)); ESP_ERROR_CHECK(uart_param_config(this->uart_num_, &uart_config));
ESP_ERROR_CHECK(uart_set_pin( ESP_ERROR_CHECK(
this->uart_num_, uart_set_pin(this->uart_num_, this->uart_tx_pin_, this->uart_rx_pin_, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE));
this->uart_tx_pin_,
this->uart_rx_pin_,
UART_PIN_NO_CHANGE,
UART_PIN_NO_CHANGE));
ESP_ERROR_CHECK(uart_driver_install(this->uart_num_, 256, 0, 0, NULL, 0)); ESP_ERROR_CHECK(uart_driver_install(this->uart_num_, 256, 0, 0, NULL, 0));
@ -125,12 +105,12 @@ void EbusComponent::setup_uart() {
} }
void EbusComponent::setup_tasks() { void EbusComponent::setup_tasks() {
xTaskCreate(&process_received_bytes, "ebus_process_received_bytes", 2048, (void*) this, 10, NULL); xTaskCreate(&process_received_bytes, "ebus_process_received_bytes", 2048, (void *) this, 10, NULL);
xTaskCreate(&process_received_messages, "ebus_process_received_messages", 2560, (void*) this, 5, NULL); xTaskCreate(&process_received_messages, "ebus_process_received_messages", 2560, (void *) this, 5, NULL);
} }
void EbusComponent::process_received_bytes(void *pvParameter) { void EbusComponent::process_received_bytes(void *pvParameter) {
EbusComponent* instance = static_cast<EbusComponent*>(pvParameter); EbusComponent *instance = static_cast<EbusComponent *>(pvParameter);
while (1) { while (1) {
uint8_t receivedByte; uint8_t receivedByte;
@ -143,14 +123,15 @@ void EbusComponent::process_received_bytes(void *pvParameter) {
} }
void EbusComponent::process_received_messages(void *pvParameter) { void EbusComponent::process_received_messages(void *pvParameter) {
EbusComponent* instance = static_cast<EbusComponent*>(pvParameter); EbusComponent *instance = static_cast<EbusComponent *>(pvParameter);
Telegram telegram; Telegram telegram;
while (1) { while (1) {
if (xQueueReceive(instance->history_queue_, &telegram, pdMS_TO_TICKS(1000))) { if (xQueueReceive(instance->history_queue_, &telegram, pdMS_TO_TICKS(1000))) {
instance->handle_message(telegram); instance->handle_message(telegram);
// TODO: this comment is kept as reference on how to debug stack overflows. Could be generalized. // TODO: this comment is kept as reference on how to debug stack overflows. Could be generalized.
// ESP_LOGD(TAG, "Task: %s, Stack Highwater Mark: %d", pcTaskGetTaskName(NULL), uxTaskGetStackHighWaterMark(NULL)); // ESP_LOGD(TAG, "Task: %s, Stack Highwater Mark: %d", pcTaskGetTaskName(NULL),
// uxTaskGetStackHighWaterMark(NULL));
taskYIELD(); taskYIELD();
} }
} }
@ -159,28 +140,23 @@ void EbusComponent::process_received_messages(void *pvParameter) {
void EbusComponent::handle_message(Telegram &telegram) { void EbusComponent::handle_message(Telegram &telegram) {
if (telegram.get_state() != TelegramState::endCompleted) { if (telegram.get_state() != TelegramState::endCompleted) {
ESP_LOGD(TAG, "Message received with invalid state: %s, QQ:%02X, ZZ:%02X, Command:%02X%02X", ESP_LOGD(TAG, "Message received with invalid state: %s, QQ:%02X, ZZ:%02X, Command:%02X%02X",
telegram.get_state_string(), telegram.get_state_string(), telegram.getQQ(), telegram.getZZ(), telegram.getPB(), telegram.getSB());
telegram.getQQ(),
telegram.getZZ(),
telegram.getPB(),
telegram.getSB());
return; return;
} }
for (auto const& receiver : this->receivers_) { for (auto const &receiver : this->receivers_) {
receiver->process_received(telegram); receiver->process_received(telegram);
} }
} }
void EbusComponent::update() { void EbusComponent::update() {
for (auto const& sender : this->senders_) { for (auto const &sender : this->senders_) {
optional<SendCommand> command = sender->prepare_command(); optional<SendCommand> command = sender->prepare_command();
if (command.has_value()) { if (command.has_value()) {
xQueueSendToBack(this->command_queue_, &command.value(), portMAX_DELAY); xQueueSendToBack(this->command_queue_, &command.value(), portMAX_DELAY);
} }
} }
} }
} // namespace ebus } // namespace ebus
} // namespace esphome } // namespace esphome

View file

@ -8,29 +8,27 @@
#include <driver/uart.h> #include <driver/uart.h>
#include <soc/uart_reg.h> #include <soc/uart_reg.h>
namespace esphome { namespace esphome {
namespace ebus { namespace ebus {
static const char *const TAG = "ebus"; static const char *const TAG = "ebus";
class EbusReceiver { class EbusReceiver {
public: public:
EbusReceiver() {} EbusReceiver() {}
virtual void process_received(Telegram) = 0; virtual void process_received(Telegram) = 0;
}; };
class EbusSender { class EbusSender {
public: public:
EbusSender() {} EbusSender() {}
virtual void set_primary_address(uint8_t) = 0; virtual void set_primary_address(uint8_t) = 0;
virtual optional<SendCommand> prepare_command() = 0; virtual optional<SendCommand> prepare_command() = 0;
}; };
class EbusComponent : public PollingComponent { class EbusComponent : public PollingComponent {
public: public:
EbusComponent() { EbusComponent() {}
}
void dump_config() override; void dump_config() override;
void setup() override; void setup() override;
@ -49,7 +47,7 @@ public:
void update(); void update();
protected: protected:
uint8_t primary_address_; uint8_t primary_address_;
uint8_t max_tries_; uint8_t max_tries_;
uint8_t max_lock_counter_; uint8_t max_lock_counter_;
@ -65,7 +63,7 @@ protected:
std::list<EbusSender *> senders_; std::list<EbusSender *> senders_;
std::list<EbusReceiver *> receivers_; std::list<EbusReceiver *> receivers_;
Ebus* ebus; Ebus *ebus;
void setup_queues(); void setup_queues();
void setup_ebus(); void setup_ebus();
@ -75,8 +73,7 @@ protected:
static void process_received_bytes(void *); static void process_received_bytes(void *);
static void process_received_messages(void *); static void process_received_messages(void *);
void handle_message(Telegram &); void handle_message(Telegram &);
}; };
} // namespace ebus } // namespace ebus
} // namespace esphome } // namespace esphome

View file

@ -23,41 +23,21 @@ void EbusSensor::dump_config() {
ESP_LOGCONFIG(TAG, " command: 0x%04x", this->command_); ESP_LOGCONFIG(TAG, " command: 0x%04x", this->command_);
}; };
void EbusSensor::set_primary_address(uint8_t primary_address) { void EbusSensor::set_primary_address(uint8_t primary_address) { this->primary_address_ = primary_address; }
this->primary_address_ = primary_address; void EbusSensor::set_source(uint8_t source) { this->source_ = source; }
} void EbusSensor::set_destination(uint8_t destination) { this->destination_ = destination; }
void EbusSensor::set_source(uint8_t source) { void EbusSensor::set_command(uint16_t command) { this->command_ = command; }
this->source_ = source; void EbusSensor::set_payload(const std::vector<uint8_t> &payload) { this->payload_ = payload; }
} void EbusSensor::set_response_read_position(uint8_t response_position) { this->response_position_ = response_position; }
void EbusSensor::set_destination(uint8_t destination) { void EbusSensor::set_response_read_bytes(uint8_t response_bytes) { this->response_bytes_ = response_bytes; }
this->destination_ = destination; void EbusSensor::set_response_read_divider(float response_divider) { this->response_divider_ = response_divider; }
}
void EbusSensor::set_command(uint16_t command) {
this->command_ = command;
}
void EbusSensor::set_payload(const std::vector<uint8_t> &payload) {
this->payload_ = payload;
}
void EbusSensor::set_response_read_position(uint8_t response_position) {
this->response_position_ = response_position;
}
void EbusSensor::set_response_read_bytes(uint8_t response_bytes) {
this->response_bytes_ = response_bytes;
}
void EbusSensor::set_response_read_divider(float response_divider) {
this->response_divider_ = response_divider;
}
optional<SendCommand> EbusSensor::prepare_command() { optional<SendCommand> EbusSensor::prepare_command() {
optional<SendCommand> command; optional<SendCommand> command;
if (this->destination_ != SYN) { if (this->destination_ != SYN) {
command = SendCommand( // command = SendCommand( //
this->primary_address_, this->primary_address_, Elf::to_secondary(this->destination_), GET_BYTE(this->command_, 1),
Elf::to_secondary(this->destination_), GET_BYTE(this->command_, 0), this->payload_.size(), &this->payload_[0]);
GET_BYTE(this->command_, 1),
GET_BYTE(this->command_, 0),
this->payload_.size(),
&this->payload_[0]);
} }
return command; return command;
} }

View file

@ -7,9 +7,8 @@ namespace esphome {
namespace ebus { namespace ebus {
class EbusSensor : public EbusReceiver, public EbusSender, public sensor::Sensor, public Component { class EbusSensor : public EbusReceiver, public EbusSender, public sensor::Sensor, public Component {
public: public:
EbusSensor() { EbusSensor() {}
}
void dump_config() override; void dump_config() override;
@ -31,7 +30,7 @@ public:
float to_float(Telegram &telegram, uint8_t start, uint8_t length, float divider); float to_float(Telegram &telegram, uint8_t start, uint8_t length, float divider);
bool is_mine(Telegram &telegram); bool is_mine(Telegram &telegram);
protected: protected:
uint8_t primary_address_; uint8_t primary_address_;
uint8_t source_ = SYN; uint8_t source_ = SYN;
uint8_t destination_ = SYN; uint8_t destination_ = SYN;

View file

@ -3,20 +3,17 @@
namespace esphome { namespace esphome {
namespace ebus { namespace ebus {
TelegramBase::TelegramBase() { TelegramBase::TelegramBase() {}
}
void TelegramBase::set_state(TelegramState new_state) { void TelegramBase::set_state(TelegramState new_state) { this->state = new_state; }
this->state = new_state;
}
TelegramState TelegramBase::get_state() { TelegramState TelegramBase::get_state() { return this->state; }
return this->state;
}
#define X(name, int) case int: return ""#name""; #define X(name, int) \
const char * TelegramBase::get_state_string() { case int: \
switch((int8_t) this->state) { return "" #name "";
const char *TelegramBase::get_state_string() {
switch ((int8_t) this->state) {
TELEGRAM_STATE_TABLE TELEGRAM_STATE_TABLE
default: default:
return "[INVALID STATE]"; return "[INVALID STATE]";
@ -24,7 +21,6 @@ const char * TelegramBase::get_state_string() {
} }
#undef X #undef X
void TelegramBase::push_buffer(uint8_t cr, uint8_t *buffer, uint8_t *pos, uint8_t *crc, int max_pos) { void TelegramBase::push_buffer(uint8_t cr, uint8_t *buffer, uint8_t *pos, uint8_t *crc, int max_pos) {
if (*pos < max_pos) { if (*pos < max_pos) {
*crc = Elf::crc8_calc(cr, *crc); *crc = Elf::crc8_calc(cr, *crc);
@ -58,30 +54,19 @@ int16_t TelegramBase::get_request_byte(uint8_t pos) {
return this->request_buffer[OFFSET_DATA + pos]; return this->request_buffer[OFFSET_DATA + pos];
} }
uint8_t TelegramBase::get_request_crc() { uint8_t TelegramBase::get_request_crc() { return this->request_buffer[OFFSET_DATA + this->getNN()]; }
return this->request_buffer[OFFSET_DATA + this->getNN()];
}
void TelegramBase::push_req_data(uint8_t cr) { void TelegramBase::push_req_data(uint8_t cr) {
this->push_buffer(cr, request_buffer, &request_buffer_pos, &request_rolling_crc, OFFSET_DATA + getNN()); this->push_buffer(cr, request_buffer, &request_buffer_pos, &request_rolling_crc, OFFSET_DATA + getNN());
} }
bool TelegramBase::is_ack_expected() { bool TelegramBase::is_ack_expected() { return (this->get_type() != TelegramType::Broadcast); }
return (this->get_type() != TelegramType::Broadcast);
}
bool TelegramBase::is_response_expected() { bool TelegramBase::is_response_expected() { return (this->get_type() == TelegramType::PrimarySecondary); }
return (this->get_type() == TelegramType::PrimarySecondary);
}
bool TelegramBase::is_finished() { bool TelegramBase::is_finished() { return this->state < TelegramState::unknown; }
return this->state < TelegramState::unknown;
}
Telegram::Telegram() { this->state = TelegramState::waitForSyn; }
Telegram::Telegram() {
this->state = TelegramState::waitForSyn;
}
int16_t Telegram::get_response_byte(uint8_t pos) { int16_t Telegram::get_response_byte(uint8_t pos) {
if (pos > this->getResponseNN() || pos >= MAX_DATA_LENGTH) { if (pos > this->getResponseNN() || pos >= MAX_DATA_LENGTH) {
@ -90,19 +75,17 @@ int16_t Telegram::get_response_byte(uint8_t pos) {
return this->response_buffer[RESPONSE_OFFSET + pos]; return this->response_buffer[RESPONSE_OFFSET + pos];
} }
uint8_t Telegram::get_response_crc() { uint8_t Telegram::get_response_crc() { return this->response_buffer[RESPONSE_OFFSET + this->getResponseNN()]; }
return this->response_buffer[RESPONSE_OFFSET + this->getResponseNN()];
}
void Telegram::push_response_data(uint8_t cr) { void Telegram::push_response_data(uint8_t cr) {
this->push_buffer(cr, response_buffer, &response_buffer_pos, &response_rolling_crc, RESPONSE_OFFSET + getResponseNN()); this->push_buffer(cr, response_buffer, &response_buffer_pos, &response_rolling_crc,
RESPONSE_OFFSET + getResponseNN());
} }
bool Telegram::is_response_complete() { bool Telegram::is_response_complete() {
return (this->state > TelegramState::waitForSyn || this->state == TelegramState::endCompleted) && return (this->state > TelegramState::waitForSyn || this->state == TelegramState::endCompleted) &&
(this->response_buffer_pos > RESPONSE_OFFSET) && (this->response_buffer_pos > RESPONSE_OFFSET) &&
(this->response_buffer_pos == (RESPONSE_OFFSET + this->getResponseNN() + 1)) && (this->response_buffer_pos == (RESPONSE_OFFSET + this->getResponseNN() + 1)) && !this->wait_for_escaped_char_;
!this->wait_for_escaped_char_;
} }
bool Telegram::is_response_valid() { bool Telegram::is_response_valid() {
@ -111,17 +94,14 @@ bool Telegram::is_response_valid() {
bool Telegram::is_request_complete() { bool Telegram::is_request_complete() {
return (this->state > TelegramState::waitForSyn || this->state == TelegramState::endCompleted) && return (this->state > TelegramState::waitForSyn || this->state == TelegramState::endCompleted) &&
(this->request_buffer_pos > OFFSET_DATA) && (this->request_buffer_pos > OFFSET_DATA) && (this->request_buffer_pos == (OFFSET_DATA + this->getNN() + 1)) &&
(this->request_buffer_pos == (OFFSET_DATA + this->getNN() + 1)) && !this->wait_for_escaped_char_; !this->wait_for_escaped_char_;
} }
bool Telegram::is_request_valid() { bool Telegram::is_request_valid() {
return this->is_request_complete() && this->get_request_crc() == this->request_rolling_crc; return this->is_request_complete() && this->get_request_crc() == this->request_rolling_crc;
} }
SendCommand::SendCommand() { this->state = TelegramState::endCompleted; }
SendCommand::SendCommand() {
this->state = TelegramState::endCompleted;
}
SendCommand::SendCommand(uint8_t QQ, uint8_t ZZ, uint8_t PB, uint8_t SB, uint8_t NN, uint8_t *data) { SendCommand::SendCommand(uint8_t QQ, uint8_t ZZ, uint8_t PB, uint8_t SB, uint8_t NN, uint8_t *data) {
this->state = TelegramState::waitForSend; this->state = TelegramState::waitForSend;
@ -136,13 +116,9 @@ SendCommand::SendCommand(uint8_t QQ, uint8_t ZZ, uint8_t PB, uint8_t SB, uint8_t
this->push_req_data(this->request_rolling_crc); this->push_req_data(this->request_rolling_crc);
} }
bool SendCommand::can_retry(int8_t max_tries) { bool SendCommand::can_retry(int8_t max_tries) { return this->tries_count_++ < max_tries; }
return this->tries_count_++ < max_tries;
}
uint8_t SendCommand::get_crc() { uint8_t SendCommand::get_crc() { return this->request_rolling_crc; }
return this->request_rolling_crc;
}
} // namespace ebus } // namespace ebus
} // namespace esphome } // namespace esphome

View file

@ -16,75 +16,62 @@ enum TelegramType : int8_t {
}; };
#define TELEGRAM_STATE_TABLE \ #define TELEGRAM_STATE_TABLE \
X(waitForSyn, 1) \ X(waitForSyn, 1) \
X(waitForSend, 2) \ X(waitForSend, 2) \
X(waitForRequestData, 3) \ X(waitForRequestData, 3) \
X(waitForRequestAck, 4) \ X(waitForRequestAck, 4) \
X(waitForResponseData, 5) \ X(waitForResponseData, 5) \
X(waitForResponseAck, 6) \ X(waitForResponseAck, 6) \
X(waitForArbitration, 7) \ X(waitForArbitration, 7) \
X(waitForArbitration2nd, 8) \ X(waitForArbitration2nd, 8) \
X(waitForCommandAck, 9) \ X(waitForCommandAck, 9) \
X(unknown, 0) \ X(unknown, 0) \
X(endErrorUnexpectedSyn, -1) \ X(endErrorUnexpectedSyn, -1) \
X(endErrorRequestNackReceived, -2) \ X(endErrorRequestNackReceived, -2) \
X(endErrorResponseNackReceived, -3) \ X(endErrorResponseNackReceived, -3) \
X(endErrorResponseNoAck, -4) \ X(endErrorResponseNoAck, -4) \
X(endErrorRequestNoAck, -5) \ X(endErrorRequestNoAck, -5) \
X(endArbitration, -6) \ X(endArbitration, -6) \
X(endCompleted, -16) \ X(endCompleted, -16) \
X(endSendFailed, -17) X(endSendFailed, -17)
#define X(name, int) name = int, #define X(name, int) name = int,
enum TelegramState : int8_t { enum TelegramState : int8_t { TELEGRAM_STATE_TABLE };
TELEGRAM_STATE_TABLE
};
#undef X #undef X
const uint8_t SYN = 0xAA; const uint8_t SYN = 0xAA;
const uint8_t ESC = 0xA9; const uint8_t ESC = 0xA9;
const uint8_t ACK = 0x00; const uint8_t ACK = 0x00;
const uint8_t NACK = 0xFF; const uint8_t NACK = 0xFF;
const uint8_t BROADCAST_ADDRESS = 0xFE; const uint8_t BROADCAST_ADDRESS = 0xFE;
/* Specification says:
1. In primary and secondary telegram part, standardised commands must be limited to 10 used data bytes.
2. In primary and secondary telegram part, the sum of mfr.-specific telegram used data bytes must not exceed 14.
We use 16 to be on the safe side for now.
*/
const uint8_t MAX_DATA_LENGTH = 16;
const uint8_t OFFSET_QQ = 0;
const uint8_t OFFSET_ZZ = 1;
const uint8_t OFFSET_PB = 2;
const uint8_t OFFSET_SB = 3;
const uint8_t OFFSET_NN = 4;
const uint8_t OFFSET_DATA = 5;
const uint8_t REQUEST_BUFFER_SIZE = (OFFSET_DATA + MAX_DATA_LENGTH + 1);
const uint8_t RESPONSE_BUFFER_SIZE = (MAX_DATA_LENGTH + 2);
const uint8_t RESPONSE_OFFSET = 1;
const uint8_t INVALID_RESPONSE_BYTE = -1;
/* Specification says:
1. In primary and secondary telegram part, standardised commands must be limited to 10 used data bytes.
2. In primary and secondary telegram part, the sum of mfr.-specific telegram used data bytes must not exceed 14.
We use 16 to be on the safe side for now.
*/
const uint8_t MAX_DATA_LENGTH = 16;
const uint8_t OFFSET_QQ = 0;
const uint8_t OFFSET_ZZ = 1;
const uint8_t OFFSET_PB = 2;
const uint8_t OFFSET_SB = 3;
const uint8_t OFFSET_NN = 4;
const uint8_t OFFSET_DATA = 5;
const uint8_t REQUEST_BUFFER_SIZE = (OFFSET_DATA + MAX_DATA_LENGTH + 1);
const uint8_t RESPONSE_BUFFER_SIZE = (MAX_DATA_LENGTH + 2);
const uint8_t RESPONSE_OFFSET = 1;
const uint8_t INVALID_RESPONSE_BYTE = -1;
class TelegramBase { class TelegramBase {
public: public:
TelegramBase(); TelegramBase();
uint8_t getQQ() { uint8_t getQQ() { return this->request_buffer[OFFSET_QQ]; }
return this->request_buffer[OFFSET_QQ]; uint8_t getZZ() { return this->request_buffer[OFFSET_ZZ]; }
} uint8_t getPB() { return this->request_buffer[OFFSET_PB]; }
uint8_t getZZ() { uint8_t getSB() { return this->request_buffer[OFFSET_SB]; }
return this->request_buffer[OFFSET_ZZ]; uint16_t getCommand() { return ((uint16_t) getPB()) << 8 | getSB(); }
}
uint8_t getPB() {
return this->request_buffer[OFFSET_PB];
}
uint8_t getSB() {
return this->request_buffer[OFFSET_SB];
}
uint16_t getCommand() {
return ((uint16_t) getPB()) << 8 | getSB();
}
uint8_t getNN() { uint8_t getNN() {
uint8_t nn = this->request_buffer[OFFSET_NN]; uint8_t nn = this->request_buffer[OFFSET_NN];
if (nn >= MAX_DATA_LENGTH) { if (nn >= MAX_DATA_LENGTH) {
@ -95,7 +82,7 @@ public:
void set_state(TelegramState new_state); void set_state(TelegramState new_state);
TelegramState get_state(); TelegramState get_state();
const char * get_state_string(); const char *get_state_string();
TelegramType get_type(); TelegramType get_type();
int16_t get_request_byte(uint8_t pos); int16_t get_request_byte(uint8_t pos);
@ -105,19 +92,18 @@ public:
bool is_response_expected(); bool is_response_expected();
bool is_finished(); bool is_finished();
protected: protected:
TelegramState state; TelegramState state;
uint8_t request_buffer[REQUEST_BUFFER_SIZE] = {ESC, ESC}; // initialize QQ and ZZ with ESC char to distinguish from valid primary 0 uint8_t request_buffer[REQUEST_BUFFER_SIZE] = {
ESC, ESC}; // initialize QQ and ZZ with ESC char to distinguish from valid primary 0
uint8_t request_buffer_pos = 0; uint8_t request_buffer_pos = 0;
uint8_t request_rolling_crc = 0; uint8_t request_rolling_crc = 0;
bool wait_for_escaped_char_ = false; bool wait_for_escaped_char_ = false;
void push_buffer(uint8_t cr, uint8_t *buffer, uint8_t *pos, uint8_t *crc, int max_pos); void push_buffer(uint8_t cr, uint8_t *buffer, uint8_t *pos, uint8_t *crc, int max_pos);
}; };
class Telegram : public TelegramBase { class Telegram : public TelegramBase {
public: public:
Telegram(); Telegram();
uint8_t getResponseNN() { uint8_t getResponseNN() {
@ -137,25 +123,22 @@ public:
bool is_request_complete(); bool is_request_complete();
bool is_request_valid(); bool is_request_valid();
protected: protected:
uint8_t response_buffer[RESPONSE_BUFFER_SIZE] = {0}; uint8_t response_buffer[RESPONSE_BUFFER_SIZE] = {0};
uint8_t response_buffer_pos = 0; uint8_t response_buffer_pos = 0;
uint8_t response_rolling_crc = 0; uint8_t response_rolling_crc = 0;
}; };
class SendCommand : public TelegramBase { class SendCommand : public TelegramBase {
public: public:
SendCommand(); SendCommand();
SendCommand(uint8_t QQ, uint8_t ZZ, uint8_t PB, uint8_t SB, uint8_t NN, uint8_t *data); SendCommand(uint8_t QQ, uint8_t ZZ, uint8_t PB, uint8_t SB, uint8_t NN, uint8_t *data);
bool can_retry(int8_t max_tries); bool can_retry(int8_t max_tries);
uint8_t get_crc(); uint8_t get_crc();
protected: protected:
uint8_t tries_count_ = 0; uint8_t tries_count_ = 0;
}; };
} // namespace ebus } // namespace ebus
} // namespace esphome } // namespace esphome