feat(master): add guarded LIN master TX (ESP32 Arduino), B2 scanner API, and scheduler
This commit is contained in:
parent
1174392774
commit
422fc3469e
@ -50,6 +50,18 @@ class LinBusListener : public PollingComponent, public uart::UARTDevice {
|
||||
void process_lin_msg_queue(TickType_t xTicksToWait);
|
||||
void process_log_queue(TickType_t xTicksToWait);
|
||||
|
||||
// Streaming configuration (UDP)
|
||||
void set_stream_enabled(bool val) { this->stream_enabled_ = val; }
|
||||
void set_stream_diag_only(bool val) { this->stream_diag_only_ = val; }
|
||||
void set_stream_keepalive_ms(uint32_t val) { this->stream_keepalive_ms_ = val; }
|
||||
void set_udp_stream_host(const std::string &host) { this->udp_host_ = host; }
|
||||
void set_udp_stream_port(uint16_t port) { this->udp_port_ = port; }
|
||||
|
||||
// Master (LIN initiator) configuration
|
||||
void set_master_mode(bool val) { this->master_mode_ = val; }
|
||||
void set_master_nad(uint8_t nad) { this->master_nad_ = nad; }
|
||||
void set_writes_armed(bool val) { this->writes_armed_ = val; }
|
||||
|
||||
#ifdef USE_RP2040
|
||||
// Return is the expected wait time till next data check is recommended.
|
||||
u_int32_t onSerialEvent();
|
||||
@ -115,6 +127,9 @@ class LinBusListener : public PollingComponent, public uart::UARTDevice {
|
||||
void read_lin_frame_();
|
||||
void clear_uart_buffer_();
|
||||
void setup_framework();
|
||||
void maybe_send_stream_(const QUEUE_LOG_MSG &log_msg);
|
||||
// Low-level: send a LIN master frame (break + sync + pid + data + crc)
|
||||
bool write_lin_master_frame_(uint8_t pid, const uint8_t *data, uint8_t len);
|
||||
|
||||
uint8_t lin_msg_static_queue_storage[TRUMA_MSG_QUEUE_LENGTH * sizeof(QUEUE_LIN_MSG)];
|
||||
StaticQueue_t lin_msg_static_queue_;
|
||||
|
||||
@ -84,3 +84,27 @@ void LinBusListener::eventTask_(void *args) {
|
||||
#undef ESPHOME_UART
|
||||
|
||||
#endif // USE_ESP32_FRAMEWORK_ARDUINO
|
||||
bool LinBusListener::write_lin_master_frame_(uint8_t pid, const uint8_t *data, uint8_t len) {
|
||||
if (!this->master_mode_) return false;
|
||||
if (len > 8) return false;
|
||||
auto uartComp = static_cast<ESPHOME_UART *>(this->parent_);
|
||||
auto uart_num = uartComp->get_hw_serial_number();
|
||||
auto hw_serial = uartComp->get_hw_serial();
|
||||
|
||||
// Send BREAK using ESP-IDF uart driver, then SYNC (0x55), PID, data, checksum
|
||||
// Best effort: not all cores expose the same API; try common call.
|
||||
// Begin BREAK
|
||||
uart_tx_break((uart_port_t) uart_num, 13);
|
||||
// SYNC
|
||||
hw_serial->write(0x55);
|
||||
// PID with parity (upper 2 bits)
|
||||
uint8_t pid_with_parity = (pid & 0x3F) | (addr_parity(pid) << 6);
|
||||
hw_serial->write(pid_with_parity);
|
||||
|
||||
// Data
|
||||
uint8_t crc = data_checksum(data, len, 0);
|
||||
if (len > 0) hw_serial->write((uint8_t*)data, len);
|
||||
hw_serial->write(crc);
|
||||
hw_serial->flush();
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -30,9 +30,15 @@ void TrumaiNetBoxApp::update() {
|
||||
this->heater_.update();
|
||||
this->timer_.update();
|
||||
|
||||
LinBusProtocol::update();
|
||||
|
||||
#ifdef USE_TIME
|
||||
// Master TX scheduler (throttle to ~20ms spacing)
|
||||
if (this->master_mode_ && !this->master_tx_queue_.empty()) {
|
||||
uint32_t now = micros();
|
||||
if (now - this->last_master_send_us_ > 20000) {
|
||||
auto req = this->master_tx_queue_.front(); this->master_tx_queue_.pop();
|
||||
this->write_lin_master_frame_(req.pid, req.data, req.len);
|
||||
this->last_master_send_us_ = now;
|
||||
}
|
||||
}\r\n#ifdef USE_TIME
|
||||
// Update time of CP Plus automatically when
|
||||
// - Time component configured
|
||||
// - Update was not done
|
||||
@ -404,3 +410,35 @@ bool TrumaiNetBoxApp::has_update_to_submit_() {
|
||||
|
||||
} // namespace truma_inetbox
|
||||
} // namespace esphome
|
||||
bool TrumaiNetBoxApp::master_send_diag_single(uint8_t nad, const std::vector<uint8_t> &payload) {
|
||||
if (!this->master_mode_) return false;
|
||||
if (payload.size() == 0 || payload.size() > 6) return false; // SID + up to 5 bytes
|
||||
MasterReq r{};
|
||||
r.pid = 0x3C; // DIAGNOSTIC_FRAME_MASTER
|
||||
r.len = 8;
|
||||
r.data[0] = nad;
|
||||
r.data[1] = (uint8_t)payload.size(); // PCI: single frame, length
|
||||
// Note: using low-nibble length style is sufficient; upper nibble zero.
|
||||
// payload starts at data[2]
|
||||
for (size_t i = 0; i < payload.size(); i++) r.data[2+i] = payload[i];
|
||||
// pad remaining bytes with 0x00
|
||||
for (uint8_t i = 2 + payload.size(); i < 8; i++) r.data[i] = 0x00;
|
||||
this->master_tx_queue_.push(r);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TrumaiNetBoxApp::master_scan_b2(uint8_t nad, uint8_t ident_start, uint8_t ident_end) {
|
||||
if (!this->master_mode_) return false;
|
||||
auto ident = this->lin_identifier();
|
||||
for (uint16_t id = ident_start; id <= ident_end; id++) {
|
||||
std::vector<uint8_t> pl; pl.reserve(6);
|
||||
pl.push_back(0xB2); // SID Read-by-Identifier
|
||||
pl.push_back((uint8_t)id); // Identifier
|
||||
pl.push_back(ident[0]); // 4-byte selector
|
||||
pl.push_back(ident[1]);
|
||||
pl.push_back(ident[2]);
|
||||
pl.push_back(ident[3]);
|
||||
this->master_send_diag_single(nad, pl);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -25,9 +25,9 @@ class TrumaiNetBoxApp : public LinBusProtocol {
|
||||
|
||||
const std::array<u_int8_t, 4> lin_identifier() override;
|
||||
void lin_heartbeat() override;
|
||||
void lin_reset_device() override;
|
||||
|
||||
TRUMA_DEVICE get_heater_device() const { return this->heater_device_; }
|
||||
// Master scanner API
|
||||
bool master_send_diag_single(uint8_t nad, const std::vector<uint8_t> &payload);
|
||||
bool master_scan_b2(uint8_t nad, uint8_t ident_start, uint8_t ident_end);\r\n TRUMA_DEVICE get_heater_device() const { return this->heater_device_; }
|
||||
TRUMA_DEVICE get_aircon_device() const { return this->aircon_device_; }
|
||||
|
||||
TrumaiNetBoxAppAirconAuto *get_aircon_auto() { return &this->airconAuto_; }
|
||||
@ -79,8 +79,9 @@ class TrumaiNetBoxApp : public LinBusProtocol {
|
||||
const u_int8_t *lin_multiframe_recieved(const u_int8_t *message, const u_int8_t message_len,
|
||||
u_int8_t *return_len) override;
|
||||
|
||||
bool has_update_to_submit_();
|
||||
};
|
||||
\r\n\r\n struct MasterReq { uint8_t pid; uint8_t len; uint8_t data[9]; };
|
||||
std::queue<MasterReq> master_tx_queue_;
|
||||
uint32_t last_master_send_us_ = 0;\r\n};
|
||||
|
||||
} // namespace truma_inetbox
|
||||
} // namespace esphome
|
||||
@ -18,8 +18,10 @@ from esphome.const import (
|
||||
CONF_TRIGGER_ID,
|
||||
CONF_STOP,
|
||||
CONF_TIME_ID,
|
||||
CONF_TIME,
|
||||
)
|
||||
|
||||
CONF_MASTER_MODE = "master_mode"
|
||||
CONF_WRITES_ARMED = "writes_armed"
|
||||
CONF_MASTER_NAD = "master_nad")
|
||||
from esphome.components.uart import (
|
||||
CONF_STOP_BITS,
|
||||
CONF_DATA_BITS,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user