mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-30 22:53:59 +00:00 
			
		
		
		
	[uart] Add packet_transport platform (#8214)
Co-authored-by: Faidon Liambotis <paravoid@debian.org> Co-authored-by: clydeps <U5yx99dok9> Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
This commit is contained in:
		| @@ -468,6 +468,7 @@ esphome/components/tuya/switch/* @jesserockz | |||||||
| esphome/components/tuya/text_sensor/* @dentra | esphome/components/tuya/text_sensor/* @dentra | ||||||
| esphome/components/uart/* @esphome/core | esphome/components/uart/* @esphome/core | ||||||
| esphome/components/uart/button/* @ssieb | esphome/components/uart/button/* @ssieb | ||||||
|  | esphome/components/uart/packet_transport/* @clydebarrow | ||||||
| esphome/components/udp/* @clydebarrow | esphome/components/udp/* @clydebarrow | ||||||
| esphome/components/ufire_ec/* @pvizeli | esphome/components/ufire_ec/* @pvizeli | ||||||
| esphome/components/ufire_ise/* @pvizeli | esphome/components/ufire_ise/* @pvizeli | ||||||
|   | |||||||
							
								
								
									
										20
									
								
								esphome/components/uart/packet_transport/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								esphome/components/uart/packet_transport/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | |||||||
|  | from esphome.components.packet_transport import ( | ||||||
|  |     PacketTransport, | ||||||
|  |     new_packet_transport, | ||||||
|  |     transport_schema, | ||||||
|  | ) | ||||||
|  | from esphome.cpp_types import PollingComponent | ||||||
|  |  | ||||||
|  | from .. import UART_DEVICE_SCHEMA, register_uart_device, uart_ns | ||||||
|  |  | ||||||
|  | CODEOWNERS = ["@clydebarrow"] | ||||||
|  | DEPENDENCIES = ["uart"] | ||||||
|  |  | ||||||
|  | UARTTransport = uart_ns.class_("UARTTransport", PacketTransport, PollingComponent) | ||||||
|  |  | ||||||
|  | CONFIG_SCHEMA = transport_schema(UARTTransport).extend(UART_DEVICE_SCHEMA) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | async def to_code(config): | ||||||
|  |     var, _ = await new_packet_transport(config) | ||||||
|  |     await register_uart_device(var, config) | ||||||
							
								
								
									
										88
									
								
								esphome/components/uart/packet_transport/uart_transport.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								esphome/components/uart/packet_transport/uart_transport.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,88 @@ | |||||||
|  | #include "esphome/core/log.h" | ||||||
|  | #include "esphome/core/application.h" | ||||||
|  | #include "uart_transport.h" | ||||||
|  |  | ||||||
|  | namespace esphome { | ||||||
|  | namespace uart { | ||||||
|  |  | ||||||
|  | static const char *const TAG = "uart_transport"; | ||||||
|  |  | ||||||
|  | void UARTTransport::loop() { | ||||||
|  |   PacketTransport::loop(); | ||||||
|  |  | ||||||
|  |   while (this->parent_->available()) { | ||||||
|  |     uint8_t byte; | ||||||
|  |     if (!this->parent_->read_byte(&byte)) { | ||||||
|  |       ESP_LOGW(TAG, "Failed to read byte from UART"); | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |     if (byte == FLAG_BYTE) { | ||||||
|  |       if (this->rx_started_ && this->receive_buffer_.size() > 6) { | ||||||
|  |         auto len = this->receive_buffer_.size(); | ||||||
|  |         auto crc = crc16(this->receive_buffer_.data(), len - 2); | ||||||
|  |         if (crc != (this->receive_buffer_[len - 2] | (this->receive_buffer_[len - 1] << 8))) { | ||||||
|  |           ESP_LOGD(TAG, "CRC mismatch, discarding packet"); | ||||||
|  |           this->rx_started_ = false; | ||||||
|  |           this->receive_buffer_.clear(); | ||||||
|  |           continue; | ||||||
|  |         } | ||||||
|  |         this->receive_buffer_.resize(len - 2); | ||||||
|  |         this->process_(this->receive_buffer_); | ||||||
|  |         this->rx_started_ = false; | ||||||
|  |       } else { | ||||||
|  |         this->rx_started_ = true; | ||||||
|  |       } | ||||||
|  |       this->receive_buffer_.clear(); | ||||||
|  |       this->rx_control_ = false; | ||||||
|  |       continue; | ||||||
|  |     } | ||||||
|  |     if (!this->rx_started_) | ||||||
|  |       continue; | ||||||
|  |     if (byte == CONTROL_BYTE) { | ||||||
|  |       this->rx_control_ = true; | ||||||
|  |       continue; | ||||||
|  |     } | ||||||
|  |     if (this->rx_control_) { | ||||||
|  |       byte ^= 0x20; | ||||||
|  |       this->rx_control_ = false; | ||||||
|  |     } | ||||||
|  |     if (this->receive_buffer_.size() == MAX_PACKET_SIZE) { | ||||||
|  |       ESP_LOGD(TAG, "Packet too large, discarding"); | ||||||
|  |       this->rx_started_ = false; | ||||||
|  |       this->receive_buffer_.clear(); | ||||||
|  |       continue; | ||||||
|  |     } | ||||||
|  |     this->receive_buffer_.push_back(byte); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void UARTTransport::update() { | ||||||
|  |   this->updated_ = true; | ||||||
|  |   this->resend_data_ = true; | ||||||
|  |   PacketTransport::update(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Write a byte to the UART bus. If the byte is a flag or control byte, it will be escaped. | ||||||
|  |  * @param byte The byte to write. | ||||||
|  |  */ | ||||||
|  | void UARTTransport::write_byte_(uint8_t byte) const { | ||||||
|  |   if (byte == FLAG_BYTE || byte == CONTROL_BYTE) { | ||||||
|  |     this->parent_->write_byte(CONTROL_BYTE); | ||||||
|  |     byte ^= 0x20; | ||||||
|  |   } | ||||||
|  |   this->parent_->write_byte(byte); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void UARTTransport::send_packet(std::vector<uint8_t> &buf) const { | ||||||
|  |   this->parent_->write_byte(FLAG_BYTE); | ||||||
|  |   for (uint8_t byte : buf) { | ||||||
|  |     this->write_byte_(byte); | ||||||
|  |   } | ||||||
|  |   auto crc = crc16(buf.data(), buf.size()); | ||||||
|  |   this->write_byte_(crc & 0xFF); | ||||||
|  |   this->write_byte_(crc >> 8); | ||||||
|  |   this->parent_->write_byte(FLAG_BYTE); | ||||||
|  | } | ||||||
|  | }  // namespace uart | ||||||
|  | }  // namespace esphome | ||||||
							
								
								
									
										41
									
								
								esphome/components/uart/packet_transport/uart_transport.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								esphome/components/uart/packet_transport/uart_transport.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,41 @@ | |||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include "esphome/core/component.h" | ||||||
|  | #include "esphome/components/packet_transport/packet_transport.h" | ||||||
|  | #include <vector> | ||||||
|  | #include "../uart.h" | ||||||
|  |  | ||||||
|  | namespace esphome { | ||||||
|  | namespace uart { | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * A transport protocol for sending and receiving packets over a UART connection. | ||||||
|  |  * The protocol is based on Asynchronous HDLC framing. (https://en.wikipedia.org/wiki/High-Level_Data_Link_Control) | ||||||
|  |  * There are two special bytes: FLAG_BYTE and CONTROL_BYTE. | ||||||
|  |  * A 16-bit CRC is appended to the packet, then | ||||||
|  |  * the protocol wraps the resulting data between FLAG_BYTEs. | ||||||
|  |  * Any occurrence of FLAG_BYTE or CONTROL_BYTE in the data is escaped by emitting CONTROL_BYTE followed by the byte | ||||||
|  |  * XORed with 0x20. | ||||||
|  |  */ | ||||||
|  | static const uint16_t MAX_PACKET_SIZE = 508; | ||||||
|  | static const uint8_t FLAG_BYTE = 0x7E; | ||||||
|  | static const uint8_t CONTROL_BYTE = 0x7D; | ||||||
|  |  | ||||||
|  | class UARTTransport : public packet_transport::PacketTransport, public UARTDevice { | ||||||
|  |  public: | ||||||
|  |   void loop() override; | ||||||
|  |   void update() override; | ||||||
|  |   float get_setup_priority() const override { return setup_priority::PROCESSOR; } | ||||||
|  |  | ||||||
|  |  protected: | ||||||
|  |   void write_byte_(uint8_t byte) const; | ||||||
|  |   void send_packet(std::vector<uint8_t> &buf) const override; | ||||||
|  |   bool should_send() override { return true; }; | ||||||
|  |   size_t get_max_packet_size() override { return MAX_PACKET_SIZE; } | ||||||
|  |   std::vector<uint8_t> receive_buffer_{}; | ||||||
|  |   bool rx_started_{}; | ||||||
|  |   bool rx_control_{}; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | }  // namespace uart | ||||||
|  | }  // namespace esphome | ||||||
| @@ -13,3 +13,6 @@ uart: | |||||||
|     rx_buffer_size: 512 |     rx_buffer_size: 512 | ||||||
|     parity: EVEN |     parity: EVEN | ||||||
|     stop_bits: 2 |     stop_bits: 2 | ||||||
|  |  | ||||||
|  | packet_transport: | ||||||
|  |   - platform: uart | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user