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/uart/* @esphome/core | ||||
| esphome/components/uart/button/* @ssieb | ||||
| esphome/components/uart/packet_transport/* @clydebarrow | ||||
| esphome/components/udp/* @clydebarrow | ||||
| esphome/components/ufire_ec/* @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 | ||||
|     parity: EVEN | ||||
|     stop_bits: 2 | ||||
|  | ||||
| packet_transport: | ||||
|   - platform: uart | ||||
|   | ||||
		Reference in New Issue
	
	Block a user