cogito/esphome_dev/esphome/components/micronova/micronova.cpp

148 lines
5.2 KiB
C++

#include "micronova.h"
#include "esphome/core/log.h"
namespace esphome {
namespace micronova {
void MicroNova::setup() {
if (this->enable_rx_pin_ != nullptr) {
this->enable_rx_pin_->setup();
this->enable_rx_pin_->pin_mode(gpio::FLAG_OUTPUT);
this->enable_rx_pin_->digital_write(false);
}
this->current_transmission_.request_transmission_time = millis();
this->current_transmission_.memory_location = 0;
this->current_transmission_.memory_address = 0;
this->current_transmission_.reply_pending = false;
this->current_transmission_.initiating_listener = nullptr;
}
void MicroNova::dump_config() {
ESP_LOGCONFIG(TAG, "MicroNova:");
if (this->enable_rx_pin_ != nullptr) {
LOG_PIN(" Enable RX Pin: ", this->enable_rx_pin_);
}
for (auto &mv_sensor : this->micronova_listeners_) {
mv_sensor->dump_config();
ESP_LOGCONFIG(TAG, " sensor location:%02X, address:%02X", mv_sensor->get_memory_location(),
mv_sensor->get_memory_address());
}
}
void MicroNova::update() {
ESP_LOGD(TAG, "Schedule sensor update");
for (auto &mv_listener : this->micronova_listeners_) {
mv_listener->set_needs_update(true);
}
}
void MicroNova::loop() {
// Only read one sensor that needs update per loop
// If STOVE_REPLY_DELAY time has passed since last loop()
// check for a reply from the stove
if ((this->current_transmission_.reply_pending) &&
(millis() - this->current_transmission_.request_transmission_time > STOVE_REPLY_DELAY)) {
int stove_reply_value = this->read_stove_reply();
if (this->current_transmission_.initiating_listener != nullptr) {
this->current_transmission_.initiating_listener->process_value_from_stove(stove_reply_value);
this->current_transmission_.initiating_listener = nullptr;
}
this->current_transmission_.reply_pending = false;
return;
} else if (!this->current_transmission_.reply_pending) {
for (auto &mv_listener : this->micronova_listeners_) {
if (mv_listener->get_needs_update()) {
mv_listener->set_needs_update(false);
this->current_transmission_.initiating_listener = mv_listener;
mv_listener->request_value_from_stove();
return;
}
}
}
}
void MicroNova::request_address(uint8_t location, uint8_t address, MicroNovaSensorListener *listener) {
uint8_t write_data[2] = {0, 0};
uint8_t trash_rx;
if (this->reply_pending_mutex_.try_lock()) {
// clear rx buffer.
// Stove hickups may cause late replies in the rx
while (this->available()) {
this->read_byte(&trash_rx);
ESP_LOGW(TAG, "Reading excess byte 0x%02X", trash_rx);
}
write_data[0] = location;
write_data[1] = address;
ESP_LOGV(TAG, "Request from stove [%02X,%02X]", write_data[0], write_data[1]);
this->enable_rx_pin_->digital_write(true);
this->write_array(write_data, 2);
this->flush();
this->enable_rx_pin_->digital_write(false);
this->current_transmission_.request_transmission_time = millis();
this->current_transmission_.memory_location = location;
this->current_transmission_.memory_address = address;
this->current_transmission_.reply_pending = true;
this->current_transmission_.initiating_listener = listener;
} else {
ESP_LOGE(TAG, "Reply is pending, skipping read request");
}
}
int MicroNova::read_stove_reply() {
uint8_t reply_data[2] = {0, 0};
uint8_t checksum = 0;
// assert enable_rx_pin is false
this->read_array(reply_data, 2);
this->reply_pending_mutex_.unlock();
ESP_LOGV(TAG, "Reply from stove [%02X,%02X]", reply_data[0], reply_data[1]);
checksum = ((uint16_t) this->current_transmission_.memory_location +
(uint16_t) this->current_transmission_.memory_address + (uint16_t) reply_data[1]) &
0xFF;
if (reply_data[0] != checksum) {
ESP_LOGE(TAG, "Checksum missmatch! From [0x%02X:0x%02X] received [0x%02X,0x%02X]. Expected 0x%02X, got 0x%02X",
this->current_transmission_.memory_location, this->current_transmission_.memory_address, reply_data[0],
reply_data[1], checksum, reply_data[0]);
return -1;
}
return ((int) reply_data[1]);
}
void MicroNova::write_address(uint8_t location, uint8_t address, uint8_t data) {
uint8_t write_data[4] = {0, 0, 0, 0};
uint16_t checksum = 0;
if (this->reply_pending_mutex_.try_lock()) {
write_data[0] = location;
write_data[1] = address;
write_data[2] = data;
checksum = ((uint16_t) write_data[0] + (uint16_t) write_data[1] + (uint16_t) write_data[2]) & 0xFF;
write_data[3] = checksum;
ESP_LOGV(TAG, "Write 4 bytes [%02X,%02X,%02X,%02X]", write_data[0], write_data[1], write_data[2], write_data[3]);
this->enable_rx_pin_->digital_write(true);
this->write_array(write_data, 4);
this->flush();
this->enable_rx_pin_->digital_write(false);
this->current_transmission_.request_transmission_time = millis();
this->current_transmission_.memory_location = location;
this->current_transmission_.memory_address = address;
this->current_transmission_.reply_pending = true;
this->current_transmission_.initiating_listener = nullptr;
} else {
ESP_LOGE(TAG, "Reply is pending, skipping write");
}
}
} // namespace micronova
} // namespace esphome