mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-30 22:53:59 +00:00 
			
		
		
		
	Add the WeiKai SPI/I2C UART/IO Expander components to esphome (#5218)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
This commit is contained in:
		
				
					committed by
					
						 GitHub
						GitHub
					
				
			
			
				
	
			
			
			
						parent
						
							f9ce35c894
						
					
				
				
					commit
					f8cdb087fc
				
			
							
								
								
									
										11
									
								
								CODEOWNERS
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								CODEOWNERS
									
									
									
									
									
								
							| @@ -400,10 +400,21 @@ esphome/components/wake_on_lan/* @willwill2will54 | |||||||
| esphome/components/waveshare_epaper/* @clydebarrow | esphome/components/waveshare_epaper/* @clydebarrow | ||||||
| esphome/components/web_server_base/* @OttoWinter | esphome/components/web_server_base/* @OttoWinter | ||||||
| esphome/components/web_server_idf/* @dentra | esphome/components/web_server_idf/* @dentra | ||||||
|  | esphome/components/weikai/* @DrCoolZic | ||||||
|  | esphome/components/weikai_i2c/* @DrCoolZic | ||||||
|  | esphome/components/weikai_spi/* @DrCoolZic | ||||||
| esphome/components/whirlpool/* @glmnet | esphome/components/whirlpool/* @glmnet | ||||||
| esphome/components/whynter/* @aeonsablaze | esphome/components/whynter/* @aeonsablaze | ||||||
| esphome/components/wiegand/* @ssieb | esphome/components/wiegand/* @ssieb | ||||||
| esphome/components/wireguard/* @droscy @lhoracek @thomas0bernard | esphome/components/wireguard/* @droscy @lhoracek @thomas0bernard | ||||||
|  | esphome/components/wk2132_i2c/* @DrCoolZic | ||||||
|  | esphome/components/wk2132_spi/* @DrCoolZic | ||||||
|  | esphome/components/wk2168_i2c/* @DrCoolZic | ||||||
|  | esphome/components/wk2168_spi/* @DrCoolZic | ||||||
|  | esphome/components/wk2204_i2c/* @DrCoolZic | ||||||
|  | esphome/components/wk2204_spi/* @DrCoolZic | ||||||
|  | esphome/components/wk2212_i2c/* @DrCoolZic | ||||||
|  | esphome/components/wk2212_spi/* @DrCoolZic | ||||||
| esphome/components/wl_134/* @hobbypunk90 | esphome/components/wl_134/* @hobbypunk90 | ||||||
| esphome/components/x9c/* @EtienneMD | esphome/components/x9c/* @EtienneMD | ||||||
| esphome/components/xgzp68xx/* @gcormier | esphome/components/xgzp68xx/* @gcormier | ||||||
|   | |||||||
							
								
								
									
										108
									
								
								esphome/components/weikai/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										108
									
								
								esphome/components/weikai/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,108 @@ | |||||||
|  | import esphome.codegen as cg | ||||||
|  | import esphome.config_validation as cv | ||||||
|  | from esphome.components import uart | ||||||
|  | from esphome.const import ( | ||||||
|  |     CONF_BAUD_RATE, | ||||||
|  |     CONF_CHANNEL, | ||||||
|  |     CONF_ID, | ||||||
|  |     CONF_INPUT, | ||||||
|  |     CONF_INVERTED, | ||||||
|  |     CONF_MODE, | ||||||
|  |     CONF_NUMBER, | ||||||
|  |     CONF_OUTPUT, | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | CODEOWNERS = ["@DrCoolZic"] | ||||||
|  | AUTO_LOAD = ["uart"] | ||||||
|  |  | ||||||
|  | MULTI_CONF = True | ||||||
|  | CONF_STOP_BITS = "stop_bits" | ||||||
|  | CONF_PARITY = "parity" | ||||||
|  | CONF_CRYSTAL = "crystal" | ||||||
|  | CONF_UART = "uart" | ||||||
|  | CONF_TEST_MODE = "test_mode" | ||||||
|  |  | ||||||
|  | weikai_ns = cg.esphome_ns.namespace("weikai") | ||||||
|  | WeikaiComponent = weikai_ns.class_("WeikaiComponent", cg.Component) | ||||||
|  | WeikaiChannel = weikai_ns.class_("WeikaiChannel", uart.UARTComponent) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def check_channel_max(value, max): | ||||||
|  |     channel_uniq = [] | ||||||
|  |     channel_dup = [] | ||||||
|  |     for x in value[CONF_UART]: | ||||||
|  |         if x[CONF_CHANNEL] > max - 1: | ||||||
|  |             raise cv.Invalid(f"Invalid channel number: {x[CONF_CHANNEL]}") | ||||||
|  |         if x[CONF_CHANNEL] not in channel_uniq: | ||||||
|  |             channel_uniq.append(x[CONF_CHANNEL]) | ||||||
|  |         else: | ||||||
|  |             channel_dup.append(x[CONF_CHANNEL]) | ||||||
|  |     if len(channel_dup) > 0: | ||||||
|  |         raise cv.Invalid(f"Duplicate channel list: {channel_dup}") | ||||||
|  |     return value | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def check_channel_max_4(value): | ||||||
|  |     return check_channel_max(value, 4) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def check_channel_max_2(value): | ||||||
|  |     return check_channel_max(value, 2) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | WKBASE_SCHEMA = cv.Schema( | ||||||
|  |     { | ||||||
|  |         cv.GenerateID(): cv.declare_id(WeikaiComponent), | ||||||
|  |         cv.Optional(CONF_CRYSTAL, default=14745600): cv.int_, | ||||||
|  |         cv.Optional(CONF_TEST_MODE, default=0): cv.int_, | ||||||
|  |         cv.Required(CONF_UART): cv.ensure_list( | ||||||
|  |             { | ||||||
|  |                 cv.Required(CONF_ID): cv.declare_id(WeikaiChannel), | ||||||
|  |                 cv.Optional(CONF_CHANNEL, default=0): cv.int_range(min=0, max=3), | ||||||
|  |                 cv.Required(CONF_BAUD_RATE): cv.int_range(min=1), | ||||||
|  |                 cv.Optional(CONF_STOP_BITS, default=1): cv.one_of(1, 2, int=True), | ||||||
|  |                 cv.Optional(CONF_PARITY, default="NONE"): cv.enum( | ||||||
|  |                     uart.UART_PARITY_OPTIONS, upper=True | ||||||
|  |                 ), | ||||||
|  |             } | ||||||
|  |         ), | ||||||
|  |     } | ||||||
|  | ).extend(cv.COMPONENT_SCHEMA) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | async def register_weikai(var, config): | ||||||
|  |     """Register an weikai device with the given config.""" | ||||||
|  |     cg.add(var.set_crystal(config[CONF_CRYSTAL])) | ||||||
|  |     cg.add(var.set_test_mode(config[CONF_TEST_MODE])) | ||||||
|  |     await cg.register_component(var, config) | ||||||
|  |     for uart_elem in config[CONF_UART]: | ||||||
|  |         chan = cg.new_Pvariable(uart_elem[CONF_ID]) | ||||||
|  |         cg.add(chan.set_channel_name(str(uart_elem[CONF_ID]))) | ||||||
|  |         cg.add(chan.set_parent(var)) | ||||||
|  |         cg.add(chan.set_channel(uart_elem[CONF_CHANNEL])) | ||||||
|  |         cg.add(chan.set_baud_rate(uart_elem[CONF_BAUD_RATE])) | ||||||
|  |         cg.add(chan.set_stop_bits(uart_elem[CONF_STOP_BITS])) | ||||||
|  |         cg.add(chan.set_parity(uart_elem[CONF_PARITY])) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def validate_pin_mode(value): | ||||||
|  |     """Checks input/output mode inconsistency""" | ||||||
|  |     if not (value[CONF_MODE][CONF_INPUT] or value[CONF_MODE][CONF_OUTPUT]): | ||||||
|  |         raise cv.Invalid("Mode must be either input or output") | ||||||
|  |     if value[CONF_MODE][CONF_INPUT] and value[CONF_MODE][CONF_OUTPUT]: | ||||||
|  |         raise cv.Invalid("Mode must be either input or output") | ||||||
|  |     return value | ||||||
|  |  | ||||||
|  |  | ||||||
|  | WEIKAI_PIN_SCHEMA = cv.Schema( | ||||||
|  |     { | ||||||
|  |         cv.Required(CONF_NUMBER): cv.int_range(min=0, max=7), | ||||||
|  |         cv.Optional(CONF_MODE, default={}): cv.All( | ||||||
|  |             { | ||||||
|  |                 cv.Optional(CONF_INPUT, default=False): cv.boolean, | ||||||
|  |                 cv.Optional(CONF_OUTPUT, default=False): cv.boolean, | ||||||
|  |             }, | ||||||
|  |         ), | ||||||
|  |         cv.Optional(CONF_INVERTED, default=False): cv.boolean, | ||||||
|  |     } | ||||||
|  | ) | ||||||
							
								
								
									
										615
									
								
								esphome/components/weikai/weikai.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										615
									
								
								esphome/components/weikai/weikai.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,615 @@ | |||||||
|  | /// @file weikai.cpp | ||||||
|  | /// @brief  WeiKai component family - classes implementation | ||||||
|  | /// @date Last Modified: 2024/04/06 15:13:11 | ||||||
|  | /// @details The classes declared in this file can be used by the Weikai family | ||||||
|  |  | ||||||
|  | #include "weikai.h" | ||||||
|  |  | ||||||
|  | namespace esphome { | ||||||
|  | namespace weikai { | ||||||
|  |  | ||||||
|  | /*! @mainpage Weikai source code documentation | ||||||
|  |  This documentation provides information about the implementation of the family of WeiKai Components in ESPHome. | ||||||
|  |  Here is the class diagram related to Weikai family of components: | ||||||
|  |  @image html weikai_class.png | ||||||
|  |  | ||||||
|  |   @section WKRingBuffer_ The WKRingBuffer template class | ||||||
|  | The WKRingBuffer template class has it names implies implement a simple ring buffer helper class. This straightforward | ||||||
|  | container implements FIFO functionality, enabling bytes to be pushed into one side and popped from the other in the | ||||||
|  | order of entry. Implementation is classic and therefore not described in any details. | ||||||
|  |  | ||||||
|  |   @section WeikaiRegister_ The WeikaiRegister class | ||||||
|  |  The WeikaiRegister helper class creates objects that act as proxies to the device registers. | ||||||
|  |  @details This is an abstract virtual class (interface) that provides all the necessary access to registers while hiding | ||||||
|  |  the actual implementation. The access to the registers can be made through an I²C bus in for example for wk2168_i2c | ||||||
|  |  component or through a SPI bus for example in the case of the wk2168_spi component. Derived classes will actually | ||||||
|  |  performs the specific bus operations. | ||||||
|  |  | ||||||
|  |  @section WeikaiRegisterI2C_ WeikaiRegisterI2C | ||||||
|  |  The weikai_i2c::WeikaiRegisterI2C class implements the virtual methods of the WeikaiRegister class for an I2C bus. | ||||||
|  |  | ||||||
|  |   @section WeikaiRegisterSPI_ WeikaiRegisterSPI | ||||||
|  |  The weikai_spi::WeikaiRegisterSPI class implements the virtual methods of the WeikaiRegister class for an SPI bus. | ||||||
|  |  | ||||||
|  |  @section WeikaiComponent_ The WeikaiComponent class | ||||||
|  | The WeikaiComponent class stores the information global to a WeiKai family component and provides methods to set/access | ||||||
|  | this information. It also serves as a container for WeikaiChannel instances. This is done by maintaining an array of | ||||||
|  | references these WeikaiChannel instances. This class derives from the esphome::Component classes. This class override | ||||||
|  | esphome::Component::loop() method to facilitate the seamless transfer of accumulated bytes from the receive | ||||||
|  | FIFO into the ring buffer. This process ensures quick access to the stored bytes, enhancing the overall efficiency of | ||||||
|  | the component. | ||||||
|  |  | ||||||
|  |  @section WeikaiComponentI2C_ WeikaiComponentI2C | ||||||
|  |  The weikai_i2c::WeikaiComponentI2C class implements the virtual methods of the WeikaiComponent class for an I2C bus. | ||||||
|  |  | ||||||
|  |   @section WeikaiComponentSPI_ WeikaiComponentSPI | ||||||
|  |  The weikai_spi::WeikaiComponentSPI class implements the virtual methods of the WeikaiComponent class for an SPI bus. | ||||||
|  |  | ||||||
|  |  @section WeikaiGPIOPin_ WeikaiGPIOPin class | ||||||
|  |  The WeikaiGPIOPin class is an helper class to expose the GPIO pins of WK family components as if they were internal | ||||||
|  |  GPIO pins. It also provides the setup() and dump_summary() methods. | ||||||
|  |  | ||||||
|  |  @section WeikaiChannel_ The WeikaiChannel class | ||||||
|  |  The WeikaiChannel class is used to implement all the virtual methods of the ESPHome uart::UARTComponent class. An | ||||||
|  |  individual instance of this class is created for each UART channel. It has a link back to the WeikaiComponent object it | ||||||
|  |  belongs to. This class derives from the uart::UARTComponent class. It collaborates through an aggregation with | ||||||
|  |  WeikaiComponent. This implies that WeikaiComponent acts as a container, housing several WeikaiChannel instances. | ||||||
|  |  Furthermore, the WeikaiChannel class derives from the ESPHome uart::UARTComponent class, it also has an association | ||||||
|  |  relationship with the WKRingBuffer and WeikaiRegister helper classes. Consequently, when a WeikaiChannel instance is | ||||||
|  |  destroyed, the associated WKRingBuffer instance is also destroyed. | ||||||
|  |  | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | static const char *const TAG = "weikai"; | ||||||
|  |  | ||||||
|  | /// @brief convert an int to binary representation as C++ std::string | ||||||
|  | /// @param val integer to convert | ||||||
|  | /// @return a std::string | ||||||
|  | inline std::string i2s(uint8_t val) { return std::bitset<8>(val).to_string(); } | ||||||
|  | /// Convert std::string to C string | ||||||
|  | #define I2S2CS(val) (i2s(val).c_str()) | ||||||
|  |  | ||||||
|  | /// @brief measure the time elapsed between two calls | ||||||
|  | /// @param last_time time of the previous call | ||||||
|  | /// @return the elapsed time in milliseconds | ||||||
|  | uint32_t elapsed_ms(uint32_t &last_time) { | ||||||
|  |   uint32_t e = millis() - last_time; | ||||||
|  |   last_time = millis(); | ||||||
|  |   return e; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | /// @brief Converts the parity enum value to a C string | ||||||
|  | /// @param parity enum | ||||||
|  | /// @return the string | ||||||
|  | const char *p2s(uart::UARTParityOptions parity) { | ||||||
|  |   using namespace uart; | ||||||
|  |   switch (parity) { | ||||||
|  |     case UART_CONFIG_PARITY_NONE: | ||||||
|  |       return "NONE"; | ||||||
|  |     case UART_CONFIG_PARITY_EVEN: | ||||||
|  |       return "EVEN"; | ||||||
|  |     case UART_CONFIG_PARITY_ODD: | ||||||
|  |       return "ODD"; | ||||||
|  |     default: | ||||||
|  |       return "UNKNOWN"; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /// @brief Display a buffer in hexadecimal format (32 hex values / line) for debug | ||||||
|  | void print_buffer(const uint8_t *data, size_t length) { | ||||||
|  |   char hex_buffer[100]; | ||||||
|  |   hex_buffer[(3 * 32) + 1] = 0; | ||||||
|  |   for (size_t i = 0; i < length; i++) { | ||||||
|  |     snprintf(&hex_buffer[3 * (i % 32)], sizeof(hex_buffer), "%02X ", data[i]); | ||||||
|  |     if (i % 32 == 31) { | ||||||
|  |       ESP_LOGVV(TAG, "   %s", hex_buffer); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   if (length % 32) { | ||||||
|  |     // null terminate if incomplete line | ||||||
|  |     hex_buffer[3 * (length % 32) + 2] = 0; | ||||||
|  |     ESP_LOGVV(TAG, "   %s", hex_buffer); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static const char *const REG_TO_STR_P0[16] = {"GENA", "GRST",  "GMUT",  "SPAGE", "SCR", "LCR",  "FCR",  "SIER", | ||||||
|  |                                               "SIFR", "TFCNT", "RFCNT", "FSR",   "LSR", "FDAT", "FWCR", "RS485"}; | ||||||
|  | static const char *const REG_TO_STR_P1[16] = {"GENA", "GRST", "GMUT", "SPAGE", "BAUD1", "BAUD0", "PRES", "RFTL", | ||||||
|  |                                               "TFTL", "FWTH", "FWTL", "XON1",  "XOFF1", "SADR",  "SAEN", "RTSDLY"}; | ||||||
|  |  | ||||||
|  | // method to print a register value as text: used in the log messages ... | ||||||
|  | const char *reg_to_str(int reg, bool page1) { | ||||||
|  |   if (reg == WKREG_GPDAT) { | ||||||
|  |     return "GPDAT"; | ||||||
|  |   } else if (reg == WKREG_GPDIR) { | ||||||
|  |     return "GPDIR"; | ||||||
|  |   } else { | ||||||
|  |     return page1 ? REG_TO_STR_P1[reg & 0x0F] : REG_TO_STR_P0[reg & 0x0F]; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | enum RegType { REG = 0, FIFO = 1 };  ///< Register or FIFO | ||||||
|  |  | ||||||
|  | /////////////////////////////////////////////////////////////////////////////// | ||||||
|  | // The WeikaiRegister methods | ||||||
|  | /////////////////////////////////////////////////////////////////////////////// | ||||||
|  | WeikaiRegister &WeikaiRegister::operator=(uint8_t value) { | ||||||
|  |   write_reg(value); | ||||||
|  |   return *this; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | WeikaiRegister &WeikaiRegister::operator&=(uint8_t value) { | ||||||
|  |   value &= read_reg(); | ||||||
|  |   write_reg(value); | ||||||
|  |   return *this; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | WeikaiRegister &WeikaiRegister::operator|=(uint8_t value) { | ||||||
|  |   value |= read_reg(); | ||||||
|  |   write_reg(value); | ||||||
|  |   return *this; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /////////////////////////////////////////////////////////////////////////////// | ||||||
|  | // The WeikaiComponent methods | ||||||
|  | /////////////////////////////////////////////////////////////////////////////// | ||||||
|  | void WeikaiComponent::loop() { | ||||||
|  |   if ((this->component_state_ & COMPONENT_STATE_MASK) != COMPONENT_STATE_LOOP) | ||||||
|  |     return; | ||||||
|  |  | ||||||
|  |   // If there are some bytes in the receive FIFO we transfers them to the ring buffers | ||||||
|  |   size_t transferred = 0; | ||||||
|  |   for (auto *child : this->children_) { | ||||||
|  |     // we look if some characters has been received in the fifo | ||||||
|  |     transferred += child->xfer_fifo_to_buffer_(); | ||||||
|  |   } | ||||||
|  |   if (transferred > 0) { | ||||||
|  |     ESP_LOGV(TAG, "we transferred %d bytes from fifo to buffer...", transferred); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  | #ifdef TEST_COMPONENT | ||||||
|  |   static uint32_t loop_time = 0; | ||||||
|  |   static uint32_t loop_count = 0; | ||||||
|  |   uint32_t time = 0; | ||||||
|  |  | ||||||
|  |   if (test_mode_ == 1) {  // test component in loopback | ||||||
|  |     ESP_LOGI(TAG, "Component loop %" PRIu32 " for %s : %" PRIu32 " ms since last call ...", loop_count++, | ||||||
|  |              this->get_name(), millis() - loop_time); | ||||||
|  |     loop_time = millis(); | ||||||
|  |     char message[64]; | ||||||
|  |     elapsed_ms(time);  // set time to now | ||||||
|  |     for (int i = 0; i < this->children_.size(); i++) { | ||||||
|  |       if (i != ((loop_count - 1) % this->children_.size()))  // we do only one per loop | ||||||
|  |         continue; | ||||||
|  |       snprintf(message, sizeof(message), "%s:%s", this->get_name(), children_[i]->get_channel_name()); | ||||||
|  |       children_[i]->uart_send_test_(message); | ||||||
|  |       uint32_t const start_time = millis(); | ||||||
|  |       while (children_[i]->tx_fifo_is_not_empty_()) {  // wait until buffer empty | ||||||
|  |         if (millis() - start_time > 1500) { | ||||||
|  |           ESP_LOGE(TAG, "timeout while flushing - %d bytes left in buffer...", children_[i]->tx_in_fifo_()); | ||||||
|  |           break; | ||||||
|  |         } | ||||||
|  |         yield();  // reschedule our thread to avoid blocking | ||||||
|  |       } | ||||||
|  |       bool status = children_[i]->uart_receive_test_(message); | ||||||
|  |       ESP_LOGI(TAG, "Test %s => send/received %u bytes %s - execution time %" PRIu32 " ms...", message, | ||||||
|  |                RING_BUFFER_SIZE, status ? "correctly" : "with error", elapsed_ms(time)); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if (this->test_mode_ == 2) {  // test component in echo mode | ||||||
|  |     for (auto *child : this->children_) { | ||||||
|  |       uint8_t data = 0; | ||||||
|  |       if (child->available()) { | ||||||
|  |         child->read_byte(&data); | ||||||
|  |         ESP_LOGI(TAG, "echo mode: read -> send %02X", data); | ||||||
|  |         child->write_byte(data); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   if (test_mode_ == 3) { | ||||||
|  |     test_gpio_input_(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if (test_mode_ == 4) { | ||||||
|  |     test_gpio_output_(); | ||||||
|  |   } | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #if defined(TEST_COMPONENT) | ||||||
|  | void WeikaiComponent::test_gpio_input_() { | ||||||
|  |   static bool init_input{false}; | ||||||
|  |   static uint8_t state{0}; | ||||||
|  |   uint8_t value; | ||||||
|  |   if (!init_input) { | ||||||
|  |     init_input = true; | ||||||
|  |     // set all pins in input mode | ||||||
|  |     this->reg(WKREG_GPDIR, 0) = 0x00; | ||||||
|  |     ESP_LOGI(TAG, "initializing all pins to input mode"); | ||||||
|  |     state = this->reg(WKREG_GPDAT, 0); | ||||||
|  |     ESP_LOGI(TAG, "initial input data state = %02X (%s)", state, I2S2CS(state)); | ||||||
|  |   } | ||||||
|  |   value = this->reg(WKREG_GPDAT, 0); | ||||||
|  |   if (value != state) { | ||||||
|  |     ESP_LOGI(TAG, "Input data changed from %02X to %02X (%s)", state, value, I2S2CS(value)); | ||||||
|  |     state = value; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void WeikaiComponent::test_gpio_output_() { | ||||||
|  |   static bool init_output{false}; | ||||||
|  |   static uint8_t state{0}; | ||||||
|  |   if (!init_output) { | ||||||
|  |     init_output = true; | ||||||
|  |     // set all pins in output mode | ||||||
|  |     this->reg(WKREG_GPDIR, 0) = 0xFF; | ||||||
|  |     ESP_LOGI(TAG, "initializing all pins to output mode"); | ||||||
|  |     this->reg(WKREG_GPDAT, 0) = state; | ||||||
|  |     ESP_LOGI(TAG, "setting all outputs to 0"); | ||||||
|  |   } | ||||||
|  |   state = ~state; | ||||||
|  |   this->reg(WKREG_GPDAT, 0) = state; | ||||||
|  |   ESP_LOGI(TAG, "Flipping all outputs to %02X (%s)", state, I2S2CS(state)); | ||||||
|  |   delay(100);  // NOLINT | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | /////////////////////////////////////////////////////////////////////////////// | ||||||
|  | // The WeikaiGPIOPin methods | ||||||
|  | /////////////////////////////////////////////////////////////////////////////// | ||||||
|  | bool WeikaiComponent::read_pin_val_(uint8_t pin) { | ||||||
|  |   this->input_state_ = this->reg(WKREG_GPDAT, 0); | ||||||
|  |   ESP_LOGVV(TAG, "reading input pin %u = %u in_state %s", pin, this->input_state_ & (1 << pin), I2S2CS(input_state_)); | ||||||
|  |   return this->input_state_ & (1 << pin); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void WeikaiComponent::write_pin_val_(uint8_t pin, bool value) { | ||||||
|  |   if (value) { | ||||||
|  |     this->output_state_ |= (1 << pin); | ||||||
|  |   } else { | ||||||
|  |     this->output_state_ &= ~(1 << pin); | ||||||
|  |   } | ||||||
|  |   ESP_LOGVV(TAG, "writing output pin %d with %d out_state %s", pin, uint8_t(value), I2S2CS(this->output_state_)); | ||||||
|  |   this->reg(WKREG_GPDAT, 0) = this->output_state_; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void WeikaiComponent::set_pin_direction_(uint8_t pin, gpio::Flags flags) { | ||||||
|  |   if (flags == gpio::FLAG_INPUT) { | ||||||
|  |     this->pin_config_ &= ~(1 << pin);  // clear bit (input mode) | ||||||
|  |   } else { | ||||||
|  |     if (flags == gpio::FLAG_OUTPUT) { | ||||||
|  |       this->pin_config_ |= 1 << pin;  // set bit (output mode) | ||||||
|  |     } else { | ||||||
|  |       ESP_LOGE(TAG, "pin %d direction invalid", pin); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   ESP_LOGVV(TAG, "setting pin %d direction to %d pin_config=%s", pin, flags, I2S2CS(this->pin_config_)); | ||||||
|  |   this->reg(WKREG_GPDIR, 0) = this->pin_config_;  // TODO check ~ | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void WeikaiGPIOPin::setup() { | ||||||
|  |   ESP_LOGCONFIG(TAG, "Setting GPIO pin %d mode to %s", this->pin_, | ||||||
|  |                 flags_ == gpio::FLAG_INPUT          ? "Input" | ||||||
|  |                 : this->flags_ == gpio::FLAG_OUTPUT ? "Output" | ||||||
|  |                                                     : "NOT SPECIFIED"); | ||||||
|  |   // ESP_LOGCONFIG(TAG, "Setting GPIO pins mode to '%s' %02X", I2S2CS(this->flags_), this->flags_); | ||||||
|  |   this->pin_mode(this->flags_); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | std::string WeikaiGPIOPin::dump_summary() const { | ||||||
|  |   char buffer[32]; | ||||||
|  |   snprintf(buffer, sizeof(buffer), "%u via WeiKai %s", this->pin_, this->parent_->get_name()); | ||||||
|  |   return buffer; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /////////////////////////////////////////////////////////////////////////////// | ||||||
|  | // The WeikaiChannel methods | ||||||
|  | /////////////////////////////////////////////////////////////////////////////// | ||||||
|  | void WeikaiChannel::setup_channel() { | ||||||
|  |   ESP_LOGCONFIG(TAG, "  Setting up UART %s:%s ...", this->parent_->get_name(), this->get_channel_name()); | ||||||
|  |   // we enable transmit and receive on this channel | ||||||
|  |   if (this->check_channel_down()) { | ||||||
|  |     ESP_LOGCONFIG(TAG, "  Error channel %s not working...", this->get_channel_name()); | ||||||
|  |   } | ||||||
|  |   this->reset_fifo_(); | ||||||
|  |   this->receive_buffer_.clear(); | ||||||
|  |   this->set_line_param_(); | ||||||
|  |   this->set_baudrate_(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void WeikaiChannel::dump_channel() { | ||||||
|  |   ESP_LOGCONFIG(TAG, "  UART %s ...", this->get_channel_name()); | ||||||
|  |   ESP_LOGCONFIG(TAG, "    Baud rate: %" PRIu32 " Bd", this->baud_rate_); | ||||||
|  |   ESP_LOGCONFIG(TAG, "    Data bits: %u", this->data_bits_); | ||||||
|  |   ESP_LOGCONFIG(TAG, "    Stop bits: %u", this->stop_bits_); | ||||||
|  |   ESP_LOGCONFIG(TAG, "    Parity: %s", p2s(this->parity_)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void WeikaiChannel::reset_fifo_() { | ||||||
|  |   // enable transmission and reception | ||||||
|  |   this->reg(WKREG_SCR) = SCR_RXEN | SCR_TXEN; | ||||||
|  |   // we reset and enable transmit and receive FIFO | ||||||
|  |   this->reg(WKREG_FCR) = FCR_TFEN | FCR_RFEN | FCR_TFRST | FCR_RFRST; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void WeikaiChannel::set_line_param_() { | ||||||
|  |   this->data_bits_ = 8;  // always equal to 8 for WeiKai (cant be changed) | ||||||
|  |   uint8_t lcr = 0; | ||||||
|  |   if (this->stop_bits_ == 2) | ||||||
|  |     lcr |= LCR_STPL; | ||||||
|  |   switch (this->parity_) {  // parity selection settings | ||||||
|  |     case uart::UART_CONFIG_PARITY_ODD: | ||||||
|  |       lcr |= (LCR_PAEN | LCR_PAR_ODD); | ||||||
|  |       break; | ||||||
|  |     case uart::UART_CONFIG_PARITY_EVEN: | ||||||
|  |       lcr |= (LCR_PAEN | LCR_PAR_EVEN); | ||||||
|  |       break; | ||||||
|  |     default: | ||||||
|  |       break;  // no parity 000x | ||||||
|  |   } | ||||||
|  |   this->reg(WKREG_LCR) = lcr;  // write LCR | ||||||
|  |   ESP_LOGV(TAG, "    line config: %d data_bits, %d stop_bits, parity %s register [%s]", this->data_bits_, | ||||||
|  |            this->stop_bits_, p2s(this->parity_), I2S2CS(lcr)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void WeikaiChannel::set_baudrate_() { | ||||||
|  |   if (this->baud_rate_ > this->parent_->crystal_ / 16) { | ||||||
|  |     baud_rate_ = this->parent_->crystal_ / 16; | ||||||
|  |     ESP_LOGE(TAG, " Requested baudrate too high for crystal=%" PRIu32 " Hz. Has been reduced to %" PRIu32 " Bd", | ||||||
|  |              this->parent_->crystal_, this->baud_rate_); | ||||||
|  |   }; | ||||||
|  |   uint16_t const val_int = this->parent_->crystal_ / (this->baud_rate_ * 16) - 1; | ||||||
|  |   uint16_t val_dec = (this->parent_->crystal_ % (this->baud_rate_ * 16)) / (this->baud_rate_ * 16); | ||||||
|  |   uint8_t const baud_high = (uint8_t) (val_int >> 8); | ||||||
|  |   uint8_t const baud_low = (uint8_t) (val_int & 0xFF); | ||||||
|  |   while (val_dec > 0x0A) | ||||||
|  |     val_dec /= 0x0A; | ||||||
|  |   uint8_t const baud_dec = (uint8_t) (val_dec); | ||||||
|  |  | ||||||
|  |   this->parent_->page1_ = true;  // switch to page 1 | ||||||
|  |   this->reg(WKREG_SPAGE) = 1; | ||||||
|  |   this->reg(WKREG_BRH) = baud_high; | ||||||
|  |   this->reg(WKREG_BRL) = baud_low; | ||||||
|  |   this->reg(WKREG_BRD) = baud_dec; | ||||||
|  |   this->parent_->page1_ = false;  // switch back to page 0 | ||||||
|  |   this->reg(WKREG_SPAGE) = 0; | ||||||
|  |  | ||||||
|  |   ESP_LOGV(TAG, "    Crystal=%d baudrate=%d => registers [%d %d %d]", this->parent_->crystal_, this->baud_rate_, | ||||||
|  |            baud_high, baud_low, baud_dec); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | inline bool WeikaiChannel::tx_fifo_is_not_empty_() { return this->reg(WKREG_FSR) & FSR_TFDAT; } | ||||||
|  |  | ||||||
|  | size_t WeikaiChannel::tx_in_fifo_() { | ||||||
|  |   size_t tfcnt = this->reg(WKREG_TFCNT); | ||||||
|  |   if (tfcnt == 0) { | ||||||
|  |     uint8_t const fsr = this->reg(WKREG_FSR); | ||||||
|  |     if (fsr & FSR_TFFULL) { | ||||||
|  |       ESP_LOGVV(TAG, "tx FIFO full FSR=%s", I2S2CS(fsr)); | ||||||
|  |       tfcnt = FIFO_SIZE; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   ESP_LOGVV(TAG, "tx FIFO contains %d bytes", tfcnt); | ||||||
|  |   return tfcnt; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | size_t WeikaiChannel::rx_in_fifo_() { | ||||||
|  |   size_t available = this->reg(WKREG_RFCNT); | ||||||
|  |   uint8_t const fsr = this->reg(WKREG_FSR); | ||||||
|  |   if (fsr & (FSR_RFOE | FSR_RFLB | FSR_RFFE | FSR_RFPE)) { | ||||||
|  |     if (fsr & FSR_RFOE) | ||||||
|  |       ESP_LOGE(TAG, "Receive data overflow FSR=%s", I2S2CS(fsr)); | ||||||
|  |     if (fsr & FSR_RFLB) | ||||||
|  |       ESP_LOGE(TAG, "Receive line break FSR=%s", I2S2CS(fsr)); | ||||||
|  |     if (fsr & FSR_RFFE) | ||||||
|  |       ESP_LOGE(TAG, "Receive frame error FSR=%s", I2S2CS(fsr)); | ||||||
|  |     if (fsr & FSR_RFPE) | ||||||
|  |       ESP_LOGE(TAG, "Receive parity error FSR=%s", I2S2CS(fsr)); | ||||||
|  |   } | ||||||
|  |   if ((available == 0) && (fsr & FSR_RFDAT)) { | ||||||
|  |     // here we should be very careful because we can have something like this: | ||||||
|  |     // -  at time t0 we read RFCNT=0 because nothing yet received | ||||||
|  |     // -  at time t0+delta we might read FIFO not empty because one byte has just been received | ||||||
|  |     // -  so to be sure we need to do another read of RFCNT and if it is still zero -> buffer full | ||||||
|  |     available = this->reg(WKREG_RFCNT); | ||||||
|  |     if (available == 0) {  // still zero ? | ||||||
|  |       ESP_LOGV(TAG, "rx FIFO is full FSR=%s", I2S2CS(fsr)); | ||||||
|  |       available = FIFO_SIZE; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   ESP_LOGVV(TAG, "rx FIFO contain %d bytes - FSR status=%s", available, I2S2CS(fsr)); | ||||||
|  |   return available; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool WeikaiChannel::check_channel_down() { | ||||||
|  |   // to check if we channel is up we write to the LCR W/R register | ||||||
|  |   // note that this will put a break on the tx line for few ms | ||||||
|  |   WeikaiRegister &lcr = this->reg(WKREG_LCR); | ||||||
|  |   lcr = 0x3F; | ||||||
|  |   uint8_t val = lcr; | ||||||
|  |   if (val != 0x3F) { | ||||||
|  |     ESP_LOGE(TAG, "R/W of register failed expected 0x3F received 0x%02X", val); | ||||||
|  |     return true; | ||||||
|  |   } | ||||||
|  |   lcr = 0; | ||||||
|  |   val = lcr; | ||||||
|  |   if (val != 0x00) { | ||||||
|  |     ESP_LOGE(TAG, "R/W of register failed expected 0x00 received 0x%02X", val); | ||||||
|  |     return true; | ||||||
|  |   } | ||||||
|  |   return false; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool WeikaiChannel::peek_byte(uint8_t *buffer) { | ||||||
|  |   auto available = this->receive_buffer_.count(); | ||||||
|  |   if (!available) | ||||||
|  |     xfer_fifo_to_buffer_(); | ||||||
|  |   return this->receive_buffer_.peek(*buffer); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int WeikaiChannel::available() { | ||||||
|  |   size_t available = this->receive_buffer_.count(); | ||||||
|  |   if (!available) | ||||||
|  |     available = xfer_fifo_to_buffer_(); | ||||||
|  |   return available; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool WeikaiChannel::read_array(uint8_t *buffer, size_t length) { | ||||||
|  |   bool status = true; | ||||||
|  |   auto available = this->receive_buffer_.count(); | ||||||
|  |   if (length > available) { | ||||||
|  |     ESP_LOGW(TAG, "read_array: buffer underflow requested %d bytes only %d bytes available...", length, available); | ||||||
|  |     length = available; | ||||||
|  |     status = false; | ||||||
|  |   } | ||||||
|  |   // retrieve the bytes from ring buffer | ||||||
|  |   for (size_t i = 0; i < length; i++) { | ||||||
|  |     this->receive_buffer_.pop(buffer[i]); | ||||||
|  |   } | ||||||
|  |   ESP_LOGVV(TAG, "read_array(ch=%d buffer[0]=%02X, length=%d): status %s", this->channel_, *buffer, length, | ||||||
|  |             status ? "OK" : "ERROR"); | ||||||
|  |   return status; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void WeikaiChannel::write_array(const uint8_t *buffer, size_t length) { | ||||||
|  |   if (length > XFER_MAX_SIZE) { | ||||||
|  |     ESP_LOGE(TAG, "Write_array: invalid call - requested %d bytes but max size %d ...", length, XFER_MAX_SIZE); | ||||||
|  |     length = XFER_MAX_SIZE; | ||||||
|  |   } | ||||||
|  |   this->reg(0).write_fifo(const_cast<uint8_t *>(buffer), length); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void WeikaiChannel::flush() { | ||||||
|  |   uint32_t const start_time = millis(); | ||||||
|  |   while (this->tx_fifo_is_not_empty_()) {  // wait until buffer empty | ||||||
|  |     if (millis() - start_time > 200) { | ||||||
|  |       ESP_LOGW(TAG, "WARNING flush timeout - still %d bytes not sent after 200 ms...", this->tx_in_fifo_()); | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |     yield();  // reschedule our thread to avoid blocking | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | size_t WeikaiChannel::xfer_fifo_to_buffer_() { | ||||||
|  |   size_t to_transfer; | ||||||
|  |   size_t free; | ||||||
|  |   while ((to_transfer = this->rx_in_fifo_()) && (free = this->receive_buffer_.free())) { | ||||||
|  |     // while bytes in fifo and some room in the buffer we transfer | ||||||
|  |     if (to_transfer > XFER_MAX_SIZE) | ||||||
|  |       to_transfer = XFER_MAX_SIZE;  // we can only do so much | ||||||
|  |     if (to_transfer > free) | ||||||
|  |       to_transfer = free;  // we'll do the rest next time | ||||||
|  |     if (to_transfer) { | ||||||
|  |       uint8_t data[to_transfer]; | ||||||
|  |       this->reg(0).read_fifo(data, to_transfer); | ||||||
|  |       for (size_t i = 0; i < to_transfer; i++) | ||||||
|  |         this->receive_buffer_.push(data[i]); | ||||||
|  |     } | ||||||
|  |   }  // while work to do | ||||||
|  |   return to_transfer; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /// | ||||||
|  | // TEST COMPONENT | ||||||
|  | // | ||||||
|  | #ifdef TEST_COMPONENT | ||||||
|  | /// @addtogroup test_ Test component information | ||||||
|  | /// @{ | ||||||
|  |  | ||||||
|  | /// @brief An increment "Functor" (i.e. a class object that acts like a method with state!) | ||||||
|  | /// | ||||||
|  | /// Functors are objects that can be treated as though they are a function or function pointer. | ||||||
|  | class Increment { | ||||||
|  |  public: | ||||||
|  |   /// @brief constructor: initialize current value to 0 | ||||||
|  |   Increment() : i_(0) {} | ||||||
|  |   /// @brief overload of the parenthesis operator. | ||||||
|  |   /// Returns the current value and auto increment it | ||||||
|  |   /// @return the current value. | ||||||
|  |   uint8_t operator()() { return i_++; } | ||||||
|  |  | ||||||
|  |  private: | ||||||
|  |   uint8_t i_; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | /// @brief Hex converter to print/display a buffer in hexadecimal format (32 hex values / line). | ||||||
|  | /// @param buffer contains the values to display | ||||||
|  | void print_buffer(std::vector<uint8_t> buffer) { | ||||||
|  |   char hex_buffer[100]; | ||||||
|  |   hex_buffer[(3 * 32) + 1] = 0; | ||||||
|  |   for (size_t i = 0; i < buffer.size(); i++) { | ||||||
|  |     snprintf(&hex_buffer[3 * (i % 32)], sizeof(hex_buffer), "%02X ", buffer[i]); | ||||||
|  |     if (i % 32 == 31) | ||||||
|  |       ESP_LOGI(TAG, "   %s", hex_buffer); | ||||||
|  |   } | ||||||
|  |   if (buffer.size() % 32) { | ||||||
|  |     // null terminate if incomplete line | ||||||
|  |     hex_buffer[3 * (buffer.size() % 32) + 1] = 0; | ||||||
|  |     ESP_LOGI(TAG, "   %s", hex_buffer); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /// @brief test the write_array method | ||||||
|  | void WeikaiChannel::uart_send_test_(char *message) { | ||||||
|  |   auto start_exec = micros(); | ||||||
|  |   std::vector<uint8_t> output_buffer(XFER_MAX_SIZE); | ||||||
|  |   generate(output_buffer.begin(), output_buffer.end(), Increment());  // fill with incrementing number | ||||||
|  |   size_t to_send = RING_BUFFER_SIZE; | ||||||
|  |   while (to_send) { | ||||||
|  |     this->write_array(&output_buffer[0], XFER_MAX_SIZE);  // we send the buffer | ||||||
|  |     this->flush(); | ||||||
|  |     to_send -= XFER_MAX_SIZE; | ||||||
|  |   } | ||||||
|  |   ESP_LOGV(TAG, "%s => sent %d bytes - exec time %d µs ...", message, RING_BUFFER_SIZE, micros() - start_exec); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /// @brief test read_array method | ||||||
|  | bool WeikaiChannel::uart_receive_test_(char *message) { | ||||||
|  |   auto start_exec = micros(); | ||||||
|  |   bool status = true; | ||||||
|  |   size_t received = 0; | ||||||
|  |   std::vector<uint8_t> buffer(RING_BUFFER_SIZE); | ||||||
|  |  | ||||||
|  |   // we wait until we have received all the bytes | ||||||
|  |   uint32_t const start_time = millis(); | ||||||
|  |   status = true; | ||||||
|  |   while (received < RING_BUFFER_SIZE) { | ||||||
|  |     while (XFER_MAX_SIZE > this->available()) { | ||||||
|  |       this->xfer_fifo_to_buffer_(); | ||||||
|  |       if (millis() - start_time > 1500) { | ||||||
|  |         ESP_LOGE(TAG, "uart_receive_test_() timeout: only %d bytes received...", this->available()); | ||||||
|  |         break; | ||||||
|  |       } | ||||||
|  |       yield();  // reschedule our thread to avoid blocking | ||||||
|  |     } | ||||||
|  |     status = this->read_array(&buffer[received], XFER_MAX_SIZE) && status; | ||||||
|  |     received += XFER_MAX_SIZE; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   uint8_t peek_value = 0; | ||||||
|  |   this->peek_byte(&peek_value); | ||||||
|  |   if (peek_value != 0) { | ||||||
|  |     ESP_LOGE(TAG, "Peek first byte value error..."); | ||||||
|  |     status = false; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   for (size_t i = 0; i < RING_BUFFER_SIZE; i++) { | ||||||
|  |     if (buffer[i] != i % XFER_MAX_SIZE) { | ||||||
|  |       ESP_LOGE(TAG, "Read buffer contains error...b=%x i=%x", buffer[i], i % XFER_MAX_SIZE); | ||||||
|  |       print_buffer(buffer); | ||||||
|  |       status = false; | ||||||
|  |       break; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   ESP_LOGV(TAG, "%s => received %d bytes  status %s - exec time %d µs ...", message, received, status ? "OK" : "ERROR", | ||||||
|  |            micros() - start_exec); | ||||||
|  |   return status; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /// @} | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | }  // namespace weikai | ||||||
|  | }  // namespace esphome | ||||||
							
								
								
									
										443
									
								
								esphome/components/weikai/weikai.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										443
									
								
								esphome/components/weikai/weikai.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,443 @@ | |||||||
|  | /// @file weikai.h | ||||||
|  | /// @author DrCoolZic | ||||||
|  | /// @brief  WeiKai component family - classes declaration | ||||||
|  | /// @date Last Modified: 2024/04/06 14:44:17 | ||||||
|  | /// @details The classes declared in this file can be used by the Weikai family | ||||||
|  | /// of UART and GPIO expander components. As of today it provides support for | ||||||
|  | ///     wk2124_spi, wk2132_spi, wk2168_spi, wk2204_spi, wk2212_spi, | ||||||
|  | ///                 wk2132_i2c, wk2168_i2c, wk2204_i2c, wk2212_i2c | ||||||
|  |  | ||||||
|  | #pragma once | ||||||
|  | #include <bitset> | ||||||
|  | #include <memory> | ||||||
|  | #include <cinttypes> | ||||||
|  | #include "esphome/core/component.h" | ||||||
|  | #include "esphome/components/uart/uart.h" | ||||||
|  | #include "wk_reg_def.h" | ||||||
|  |  | ||||||
|  | /// When the TEST_COMPONENT flag is defined we include some auto-test methods. Used to test the software during | ||||||
|  | /// development but can also be used in situ to test if the component is working correctly. For release we do | ||||||
|  | /// not set it by default but you can set it by using the following lines in you configuration file: | ||||||
|  | /// @code | ||||||
|  | /// esphome: | ||||||
|  | ///   platformio_options: | ||||||
|  | ///     build_flags: | ||||||
|  | ///       - -DTEST_COMPONENT | ||||||
|  | /// @endcode | ||||||
|  | // #define TEST_COMPONENT | ||||||
|  |  | ||||||
|  | namespace esphome { | ||||||
|  | namespace weikai { | ||||||
|  |  | ||||||
|  | /// @brief XFER_MAX_SIZE defines the maximum number of bytes allowed during one transfer. | ||||||
|  | #if defined(I2C_BUFFER_LENGTH) | ||||||
|  | constexpr size_t XFER_MAX_SIZE = I2C_BUFFER_LENGTH; | ||||||
|  | #else | ||||||
|  | constexpr size_t XFER_MAX_SIZE = 128; | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | /// @brief size of the internal WeiKai FIFO | ||||||
|  | constexpr size_t FIFO_SIZE = 256; | ||||||
|  |  | ||||||
|  | /// @brief size of the ring buffer set to size of the FIFO | ||||||
|  | constexpr size_t RING_BUFFER_SIZE = FIFO_SIZE; | ||||||
|  |  | ||||||
|  | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | /// @brief This is an helper class that provides a simple ring buffers that works as a FIFO | ||||||
|  | /// @details This ring buffer is used to buffer the bytes received in the FIFO of the Weika device. The best way to read | ||||||
|  | /// characters from the device FIFO, is to first check how many bytes were received and then read them all at once. | ||||||
|  | /// Unfortunately in all the code I have reviewed the characters are read one by one in a while loop by checking if | ||||||
|  | /// bytes are available then reading the byte until no more byte available. This is pretty inefficient for two reasons: | ||||||
|  | /// - Fist you need to perform a test for each byte to read | ||||||
|  | /// - and second you call the read byte method for each character. | ||||||
|  | /// . | ||||||
|  | /// Assuming you need to read 100 bytes that results into 200 calls. This is to compare to 2 calls (one to find the | ||||||
|  | /// number of bytes available plus one to read all the bytes) in the best case! If the registers you read are located on | ||||||
|  | /// the micro-controller this is acceptable because the registers can be accessed fast. But when the registers are | ||||||
|  | /// located on a remote device accessing them requires several cycles on a slow bus. As it it not possible to fix this | ||||||
|  | /// problem by asking users to rewrite their code, I have implemented this ring buffer that store the bytes received | ||||||
|  | /// locally. | ||||||
|  | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | template<typename T, size_t SIZE> class WKRingBuffer { | ||||||
|  |  public: | ||||||
|  |   /// @brief pushes an item at the tail of the fifo | ||||||
|  |   /// @param item item to push | ||||||
|  |   /// @return true if item has been pushed, false il item could not pushed (buffer full) | ||||||
|  |   bool push(const T item) { | ||||||
|  |     if (is_full()) | ||||||
|  |       return false; | ||||||
|  |     this->rb_[this->head_] = item; | ||||||
|  |     this->head_ = (this->head_ + 1) % SIZE; | ||||||
|  |     this->count_++; | ||||||
|  |     return true; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /// @brief return and remove the item at head of the fifo | ||||||
|  |   /// @param item item read | ||||||
|  |   /// @return true if an item has been retrieved, false il no item available (buffer empty) | ||||||
|  |   bool pop(T &item) { | ||||||
|  |     if (is_empty()) | ||||||
|  |       return false; | ||||||
|  |     item = this->rb_[this->tail_]; | ||||||
|  |     this->tail_ = (this->tail_ + 1) % SIZE; | ||||||
|  |     this->count_--; | ||||||
|  |     return true; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /// @brief return the value of the item at fifo's head without removing it | ||||||
|  |   /// @param item pointer to item to return | ||||||
|  |   /// @return true if item has been retrieved, false il no item available (buffer empty) | ||||||
|  |   bool peek(T &item) { | ||||||
|  |     if (is_empty()) | ||||||
|  |       return false; | ||||||
|  |     item = this->rb_[this->tail_]; | ||||||
|  |     return true; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /// @brief test is the Ring Buffer is empty ? | ||||||
|  |   /// @return true if empty | ||||||
|  |   inline bool is_empty() { return (this->count_ == 0); } | ||||||
|  |  | ||||||
|  |   /// @brief test is the ring buffer is full ? | ||||||
|  |   /// @return true if full | ||||||
|  |   inline bool is_full() { return (this->count_ == SIZE); } | ||||||
|  |  | ||||||
|  |   /// @brief return the number of item in the ring buffer | ||||||
|  |   /// @return the number of items | ||||||
|  |   inline size_t count() { return this->count_; } | ||||||
|  |  | ||||||
|  |   /// @brief returns the number of free positions in the buffer | ||||||
|  |   /// @return how many items can be added | ||||||
|  |   inline size_t free() { return SIZE - this->count_; } | ||||||
|  |  | ||||||
|  |   /// @brief clear the buffer content | ||||||
|  |   inline void clear() { this->head_ = this->tail_ = this->count_ = 0; } | ||||||
|  |  | ||||||
|  |  protected: | ||||||
|  |   std::array<T, SIZE> rb_{0};  ///< the ring buffer | ||||||
|  |   int tail_{0};                ///< position of the next element to read | ||||||
|  |   int head_{0};                ///< position of the next element to write | ||||||
|  |   size_t count_{0};            ///< count number of element in the buffer | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | class WeikaiComponent; | ||||||
|  | // class WeikaiComponentSPI; | ||||||
|  | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | /// @brief WeikaiRegister objects acts as proxies to access remote register independently of the bus type. | ||||||
|  | /// @details This is an abstract interface class that provides many operations to access to registers while hiding | ||||||
|  | /// the actual implementation. This allow to accesses the registers in the Weikai component abstract class independently | ||||||
|  | /// of the actual bus (I2C, SPI). The derived classes will actually implements the specific bus operations dependant of | ||||||
|  | /// the bus used. | ||||||
|  | /// @n typical usage of WeikaiRegister: | ||||||
|  | /// @code | ||||||
|  | ///   WeikaiRegister reg_X {&WeikaiComponent, ADDR_REGISTER_X, CHANNEL_NUM}  // declaration | ||||||
|  | ///   reg_X |= 0x01;    // set bit 0 of the weikai register | ||||||
|  | ///   reg_X &= ~0x01;   // reset bit 0 of the weikai register | ||||||
|  | ///   reg_X = 10;       // Set the value of weikai register | ||||||
|  | ///   uint val = reg_X; // get the value of weikai register | ||||||
|  | /// @endcode | ||||||
|  | class WeikaiRegister { | ||||||
|  |  public: | ||||||
|  |   /// @brief WeikaiRegister constructor. | ||||||
|  |   /// @param comp our parent WeikaiComponent | ||||||
|  |   /// @param reg address of the register | ||||||
|  |   /// @param channel the channel of this register | ||||||
|  |   WeikaiRegister(WeikaiComponent *const comp, uint8_t reg, uint8_t channel) | ||||||
|  |       : comp_(comp), register_(reg), channel_(channel) {} | ||||||
|  |   virtual ~WeikaiRegister() {} | ||||||
|  |  | ||||||
|  |   /// @brief overloads the = operator. This is used to set a value into the weikai register | ||||||
|  |   /// @param value to be set | ||||||
|  |   /// @return this object | ||||||
|  |   WeikaiRegister &operator=(uint8_t value); | ||||||
|  |  | ||||||
|  |   /// @brief overloads the compound &= operator. This is often used to reset bits in the weikai register | ||||||
|  |   /// @param value performs an & operation with value and store the result | ||||||
|  |   /// @return this object | ||||||
|  |   WeikaiRegister &operator&=(uint8_t value); | ||||||
|  |  | ||||||
|  |   /// @brief overloads the compound |= operator. This is often used to set bits in the weikai register | ||||||
|  |   /// @param value performs an | operation with value and store the result | ||||||
|  |   /// @return this object | ||||||
|  |   WeikaiRegister &operator|=(uint8_t value); | ||||||
|  |  | ||||||
|  |   /// @brief cast operator that returns the content of the weikai register | ||||||
|  |   operator uint8_t() const { return read_reg(); } | ||||||
|  |  | ||||||
|  |   /// @brief reads the register | ||||||
|  |   /// @return the value read from the register | ||||||
|  |   virtual uint8_t read_reg() const = 0; | ||||||
|  |  | ||||||
|  |   /// @brief writes the register | ||||||
|  |   /// @param value to write in the register | ||||||
|  |   virtual void write_reg(uint8_t value) = 0; | ||||||
|  |  | ||||||
|  |   /// @brief read an array of bytes from the receiver fifo | ||||||
|  |   /// @param data pointer to data buffer | ||||||
|  |   /// @param length number of bytes to read | ||||||
|  |   virtual void read_fifo(uint8_t *data, size_t length) const = 0; | ||||||
|  |  | ||||||
|  |   /// @brief write an array of bytes to the transmitter fifo | ||||||
|  |   /// @param data pointer to data buffer | ||||||
|  |   /// @param length number of bytes to write | ||||||
|  |   virtual void write_fifo(uint8_t *data, size_t length) = 0; | ||||||
|  |  | ||||||
|  |   WeikaiComponent *const comp_;  ///< pointer to our parent (aggregation) | ||||||
|  |   uint8_t register_;             ///< address of the register | ||||||
|  |   uint8_t channel_;              ///< channel for this register | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | class WeikaiChannel;  // forward declaration | ||||||
|  | //////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | /// @brief The WeikaiComponent class stores the information global to the WeiKai component | ||||||
|  | /// and provides methods to set/access this information. It is also the container of | ||||||
|  | /// the WeikaiChannel children objects. This class is derived from esphome::Component | ||||||
|  | /// class. | ||||||
|  | //////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | class WeikaiComponent : public Component { | ||||||
|  |  public: | ||||||
|  |   /// @brief virtual destructor | ||||||
|  |   virtual ~WeikaiComponent() {} | ||||||
|  |  | ||||||
|  |   /// @brief store crystal frequency | ||||||
|  |   /// @param crystal frequency | ||||||
|  |   void set_crystal(uint32_t crystal) { this->crystal_ = crystal; } | ||||||
|  |  | ||||||
|  |   /// @brief store if the component is in test mode | ||||||
|  |   /// @param test_mode 0=normal mode any other values mean component in test mode | ||||||
|  |   void set_test_mode(int test_mode) { this->test_mode_ = test_mode; } | ||||||
|  |  | ||||||
|  |   /// @brief store the name for the component | ||||||
|  |   /// @param name the name as defined by the python code generator | ||||||
|  |   void set_name(std::string name) { this->name_ = std::move(name); } | ||||||
|  |  | ||||||
|  |   /// @brief Get the name of the component | ||||||
|  |   /// @return the name | ||||||
|  |   const char *get_name() { return this->name_.c_str(); } | ||||||
|  |  | ||||||
|  |   /// @brief override the Component loop() | ||||||
|  |   void loop() override; | ||||||
|  |  | ||||||
|  |   bool page1() { return page1_; } | ||||||
|  |  | ||||||
|  |   /// @brief Factory method to create a Register object | ||||||
|  |   /// @param reg address of the register | ||||||
|  |   /// @param channel channel associated with this register | ||||||
|  |   /// @return a reference to WeikaiRegister | ||||||
|  |   virtual WeikaiRegister ®(uint8_t reg, uint8_t channel) = 0; | ||||||
|  |  | ||||||
|  |  protected: | ||||||
|  |   friend class WeikaiChannel; | ||||||
|  |  | ||||||
|  |   /// @brief Get the priority of the component | ||||||
|  |   /// @return the priority | ||||||
|  |   /// @details The priority is set  below setup_priority::BUS because we use | ||||||
|  |   /// the spi/i2c busses (which has a priority of BUS) to communicate and the WeiKai | ||||||
|  |   /// therefore it is seen by our client almost as if it was a bus. | ||||||
|  |   float get_setup_priority() const override { return setup_priority::BUS - 0.1F; } | ||||||
|  |  | ||||||
|  |   friend class WeikaiGPIOPin; | ||||||
|  |   /// Helper method to read the value of a pin. | ||||||
|  |   bool read_pin_val_(uint8_t pin); | ||||||
|  |  | ||||||
|  |   /// Helper method to write the value of a pin. | ||||||
|  |   void write_pin_val_(uint8_t pin, bool value); | ||||||
|  |  | ||||||
|  |   /// Helper method to set the pin mode of a pin. | ||||||
|  |   void set_pin_direction_(uint8_t pin, gpio::Flags flags); | ||||||
|  |  | ||||||
|  | #ifdef TEST_COMPONENT | ||||||
|  |   /// @defgroup test_ Test component information | ||||||
|  |   /// @brief Contains information about the auto-tests of the component | ||||||
|  |   /// @{ | ||||||
|  |   void test_gpio_input_(); | ||||||
|  |   void test_gpio_output_(); | ||||||
|  |   /// @} | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  |   uint8_t pin_config_{0x00};                 ///< pin config mask: 1 means OUTPUT, 0 means INPUT | ||||||
|  |   uint8_t output_state_{0x00};               ///< output state: 1 means HIGH, 0 means LOW | ||||||
|  |   uint8_t input_state_{0x00};                ///< input pin states: 1 means HIGH, 0 means LOW | ||||||
|  |   uint32_t crystal_;                         ///< crystal value; | ||||||
|  |   int test_mode_;                            ///< test mode value (0 -> no tests) | ||||||
|  |   bool page1_{false};                        ///< set to true when in "page1 mode" | ||||||
|  |   std::vector<WeikaiChannel *> children_{};  ///< the list of WeikaiChannel UART children | ||||||
|  |   std::string name_;                         ///< name of entity | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | /////////////////////////////////////////////////////////////////////////////// | ||||||
|  | /// @brief Helper class to expose a WeiKai family IO pin as an internal GPIO pin. | ||||||
|  | /////////////////////////////////////////////////////////////////////////////// | ||||||
|  | class WeikaiGPIOPin : public GPIOPin { | ||||||
|  |  public: | ||||||
|  |   void set_parent(WeikaiComponent *parent) { this->parent_ = parent; } | ||||||
|  |   void set_pin(uint8_t pin) { this->pin_ = pin; } | ||||||
|  |   void set_inverted(bool inverted) { this->inverted_ = inverted; } | ||||||
|  |   void set_flags(gpio::Flags flags) { this->flags_ = flags; } | ||||||
|  |  | ||||||
|  |   void setup() override; | ||||||
|  |   std::string dump_summary() const override; | ||||||
|  |   void pin_mode(gpio::Flags flags) override { this->parent_->set_pin_direction_(this->pin_, flags); } | ||||||
|  |   bool digital_read() override { return this->parent_->read_pin_val_(this->pin_) != this->inverted_; } | ||||||
|  |   void digital_write(bool value) override { this->parent_->write_pin_val_(this->pin_, value != this->inverted_); } | ||||||
|  |  | ||||||
|  |  protected: | ||||||
|  |   WeikaiComponent *parent_{nullptr}; | ||||||
|  |   uint8_t pin_; | ||||||
|  |   bool inverted_; | ||||||
|  |   gpio::Flags flags_; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | /////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | /// @brief The WeikaiChannel class is used to implement all the virtual methods of the ESPHome | ||||||
|  | /// uart::UARTComponent virtual class. This class is common to the different members of the Weikai | ||||||
|  | /// components family and therefore avoid code duplication. | ||||||
|  | /////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | class WeikaiChannel : public uart::UARTComponent { | ||||||
|  |  public: | ||||||
|  |   /// @brief We belongs to this WeikaiComponent | ||||||
|  |   /// @param parent pointer to the component we belongs to | ||||||
|  |   void set_parent(WeikaiComponent *parent) { | ||||||
|  |     this->parent_ = parent; | ||||||
|  |     this->parent_->children_.push_back(this);  // add ourself to the list (vector) | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /// @brief Sets the channel number | ||||||
|  |   /// @param channel number | ||||||
|  |   void set_channel(uint8_t channel) { this->channel_ = channel; } | ||||||
|  |  | ||||||
|  |   /// @brief The name as generated by the Python code generator | ||||||
|  |   /// @param name of the channel | ||||||
|  |   void set_channel_name(std::string name) { this->name_ = std::move(name); } | ||||||
|  |  | ||||||
|  |   /// @brief Get the channel name | ||||||
|  |   /// @return the name | ||||||
|  |   const char *get_channel_name() { return this->name_.c_str(); } | ||||||
|  |  | ||||||
|  |   /// @brief Setup the channel | ||||||
|  |   void virtual setup_channel(); | ||||||
|  |  | ||||||
|  |   /// @brief dump channel information | ||||||
|  |   void virtual dump_channel(); | ||||||
|  |  | ||||||
|  |   /// @brief Factory method to create a WeikaiRegister proxy object | ||||||
|  |   /// @param reg address of the register | ||||||
|  |   /// @return a reference to WeikaiRegister | ||||||
|  |   WeikaiRegister ®(uint8_t reg) { return this->parent_->reg(reg, channel_); } | ||||||
|  |  | ||||||
|  |   // | ||||||
|  |   // we implements/overrides the virtual class from UARTComponent | ||||||
|  |   // | ||||||
|  |  | ||||||
|  |   /// @brief Writes a specified number of bytes to a serial port | ||||||
|  |   /// @param buffer pointer to the buffer | ||||||
|  |   /// @param length number of bytes to write | ||||||
|  |   /// @details This method sends 'length' characters from the buffer to the serial line. Unfortunately (unlike the | ||||||
|  |   /// Arduino equivalent) this method does not return any flag and therefore it is not possible to know if any/all bytes | ||||||
|  |   /// have been transmitted correctly. Another problem is that it is not possible to know ahead of time how many bytes | ||||||
|  |   /// we can safely send as there is no tx_available() method provided! To avoid overrun when using the write method you | ||||||
|  |   /// can use the flush() method to wait until the transmit fifo is empty. | ||||||
|  |   /// @n Typical usage could be: | ||||||
|  |   /// @code | ||||||
|  |   ///   // ... | ||||||
|  |   ///   uint8_t buffer[128]; | ||||||
|  |   ///   // ... | ||||||
|  |   ///   write_array(&buffer, length); | ||||||
|  |   ///   flush(); | ||||||
|  |   ///   // ... | ||||||
|  |   /// @endcode | ||||||
|  |   void write_array(const uint8_t *buffer, size_t length) override; | ||||||
|  |  | ||||||
|  |   /// @brief Reads a specified number of bytes from a serial port | ||||||
|  |   /// @param buffer buffer to store the bytes | ||||||
|  |   /// @param length number of bytes to read | ||||||
|  |   /// @return true if succeed, false otherwise | ||||||
|  |   /// @details Typical usage: | ||||||
|  |   /// @code | ||||||
|  |   ///   // ... | ||||||
|  |   ///   auto length = available(); | ||||||
|  |   ///   uint8_t buffer[128]; | ||||||
|  |   ///   if (length > 0) { | ||||||
|  |   ///     auto status = read_array(&buffer, length) | ||||||
|  |   ///     // test status ... | ||||||
|  |   ///   } | ||||||
|  |   /// @endcode | ||||||
|  |   bool read_array(uint8_t *buffer, size_t length) override; | ||||||
|  |  | ||||||
|  |   /// @brief Reads the first byte in FIFO without removing it | ||||||
|  |   /// @param buffer pointer to the byte | ||||||
|  |   /// @return true if succeed reading one byte, false if no character available | ||||||
|  |   /// @details This method returns the next byte from receiving buffer without removing it from the internal fifo. It | ||||||
|  |   /// returns true if a character is available and has been read, false otherwise.\n | ||||||
|  |   bool peek_byte(uint8_t *buffer) override; | ||||||
|  |  | ||||||
|  |   /// @brief Returns the number of bytes in the receive buffer | ||||||
|  |   /// @return the number of bytes available in the receiver fifo | ||||||
|  |   int available() override; | ||||||
|  |  | ||||||
|  |   /// @brief Flush the output fifo. | ||||||
|  |   /// @details If we refer to Serial.flush() in Arduino it says: ** Waits for the transmission of outgoing serial data | ||||||
|  |   /// to complete. (Prior to Arduino 1.0, this the method was removing any buffered incoming serial data.). ** Therefore | ||||||
|  |   /// we wait until all bytes are gone with a timeout of 100 ms | ||||||
|  |   void flush() override; | ||||||
|  |  | ||||||
|  |  protected: | ||||||
|  |   friend class WeikaiComponent; | ||||||
|  |  | ||||||
|  |   /// @brief this cannot happen with external uart therefore we do nothing | ||||||
|  |   void check_logger_conflict() override {} | ||||||
|  |  | ||||||
|  |   /// @brief reset the weikai internal FIFO | ||||||
|  |   void reset_fifo_(); | ||||||
|  |  | ||||||
|  |   /// @brief set the line parameters | ||||||
|  |   void set_line_param_(); | ||||||
|  |  | ||||||
|  |   /// @brief set the baud rate | ||||||
|  |   void set_baudrate_(); | ||||||
|  |  | ||||||
|  |   /// @brief Returns the number of bytes in the receive fifo | ||||||
|  |   /// @return the number of bytes in the fifo | ||||||
|  |   size_t rx_in_fifo_(); | ||||||
|  |  | ||||||
|  |   /// @brief Returns the number of bytes in the transmit fifo | ||||||
|  |   /// @return the number of bytes in the fifo | ||||||
|  |   size_t tx_in_fifo_(); | ||||||
|  |  | ||||||
|  |   /// @brief test if transmit buffer is not empty in the status register (optimization) | ||||||
|  |   /// @return true if not emptygroup test_ | ||||||
|  |   bool tx_fifo_is_not_empty_(); | ||||||
|  |  | ||||||
|  |   /// @brief transfer bytes from the weikai internal FIFO to the buffer (if any) | ||||||
|  |   /// @return number of bytes transferred | ||||||
|  |   size_t xfer_fifo_to_buffer_(); | ||||||
|  |  | ||||||
|  |   /// @brief check if channel is alive | ||||||
|  |   /// @return true if OK | ||||||
|  |   bool virtual check_channel_down(); | ||||||
|  |  | ||||||
|  | #ifdef TEST_COMPONENT | ||||||
|  |   /// @ingroup test_ | ||||||
|  |   /// @{ | ||||||
|  |  | ||||||
|  |   /// @brief Test the write_array() method | ||||||
|  |   /// @param message to display | ||||||
|  |   void uart_send_test_(char *message); | ||||||
|  |  | ||||||
|  |   /// @brief Test the read_array() method | ||||||
|  |   /// @param message to display | ||||||
|  |   /// @return true if success | ||||||
|  |   bool uart_receive_test_(char *message); | ||||||
|  |   /// @} | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  |   /// @brief the buffer where we store temporarily the bytes received | ||||||
|  |   WKRingBuffer<uint8_t, RING_BUFFER_SIZE> receive_buffer_; | ||||||
|  |   WeikaiComponent *parent_;  ///< our WK2168component parent | ||||||
|  |   uint8_t channel_;          ///< our Channel number | ||||||
|  |   uint8_t data_;             ///< a one byte buffer for register read storage | ||||||
|  |   std::string name_;         ///< name of the entity | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | }  // namespace weikai | ||||||
|  | }  // namespace esphome | ||||||
							
								
								
									
										304
									
								
								esphome/components/weikai/wk_reg_def.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										304
									
								
								esphome/components/weikai/wk_reg_def.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,304 @@ | |||||||
|  | /// @file wk_reg_def.h | ||||||
|  | /// @author DrCoolZic | ||||||
|  | /// @brief  WeiKai component family - registers' definition | ||||||
|  | /// @date Last Modified: 2024/02/18 15:49:18 | ||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | namespace esphome { | ||||||
|  | namespace weikai { | ||||||
|  |  | ||||||
|  | //////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | /// Definition of the WeiKai registers | ||||||
|  | //////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  |  | ||||||
|  | /// @defgroup wk2168_gr_ WeiKai Global Registers | ||||||
|  | /// This section groups all **Global Registers**: these registers are global to the | ||||||
|  | /// the WeiKai chip (i.e. independent of the UART channel used) | ||||||
|  | /// @note only registers and parameters used have been fully documented | ||||||
|  | /// @{ | ||||||
|  |  | ||||||
|  | /// @brief Global Control Register - 00 0000 | ||||||
|  | /// @details @code | ||||||
|  | ///  ------------------------------------------------------------------------- | ||||||
|  | ///  |   b7   |   b6   |   b5   |   b4   |   b3   |   b2   |   b1   |   b0   | bit | ||||||
|  | ///  ------------------------------------------------------------------------- | ||||||
|  | ///  |   M0   |   M1   |       RSV       |  C4EN  |  C3EN  |  C2EN  |  C1EN  | name | ||||||
|  | ///  ------------------------------------------------------------------------- | ||||||
|  | ///  |    R   |    R   |    R   |    R   |   W/R  |   W/R  |   W/R  |   W/R  | type | ||||||
|  | ///  ------------------------------------------------------------------------- | ||||||
|  | ///  |    1   |    1   |    1   |    1   |    0   |    0   |    0   |    0   | reset | ||||||
|  | ///  ------------------------------------------------------------------------- | ||||||
|  | /// @endcode | ||||||
|  | constexpr uint8_t WKREG_GENA = 0x00; | ||||||
|  | /// @brief Channel 4 enable clock (0: disable, 1: enable) | ||||||
|  | constexpr uint8_t GENA_C4EN = 1 << 3; | ||||||
|  | /// @brief Channel 3 enable clock (0: disable, 1: enable) | ||||||
|  | constexpr uint8_t GENA_C3EN = 1 << 2; | ||||||
|  | /// @brief Channel 2 enable clock (0: disable, 1: enable) | ||||||
|  | constexpr uint8_t GENA_C2EN = 1 << 1; | ||||||
|  | /// @brief Channel 1 enable clock (0: disable, 1: enable) | ||||||
|  | constexpr uint8_t GENA_C1EN = 1 << 0; | ||||||
|  |  | ||||||
|  | /// @brief Global Reset Register - 00 0001 | ||||||
|  | /// @details @code | ||||||
|  | ///  ------------------------------------------------------------------------- | ||||||
|  | ///  |   b7   |   b6   |   b5   |   b4   |   b3   |   b2   |   b1   |   b0   | bit | ||||||
|  | ///  ------------------------------------------------------------------------- | ||||||
|  | ///  | C4SLEEP| C3SLEEP| C2SLEEP| C1SLEEP|  C4RST |  C3RST |  C2RST |  C1RST | name | ||||||
|  | ///  ------------------------------------------------------------------------- | ||||||
|  | ///  |    R   |    R   |    R   |    R   |  W1/R0 |  W1/R0 |  W1/R0 |  W1/R0 | type | ||||||
|  | ///  ------------------------------------------------------------------------- | ||||||
|  | ///  |    0   |    0   |    0   |    0   |    0   |    0   |    0   |    0   | reset | ||||||
|  | ///  ------------------------------------------------------------------------- | ||||||
|  | /// @endcode | ||||||
|  | constexpr uint8_t WKREG_GRST = 0x01; | ||||||
|  | /// @brief Channel 4 soft reset (0: not reset, 1: reset) | ||||||
|  | constexpr uint8_t GRST_C4RST = 1 << 3; | ||||||
|  | /// @brief Channel 3 soft reset (0: not reset, 1: reset) | ||||||
|  | constexpr uint8_t GRST_C3RST = 1 << 2; | ||||||
|  | /// @brief Channel 2 soft reset (0: not reset, 1: reset) | ||||||
|  | constexpr uint8_t GRST_C2RST = 1 << 1; | ||||||
|  | /// @brief Channel 1 soft reset (0: not reset, 1: reset) | ||||||
|  | constexpr uint8_t GRST_C1RST = 1 << 0; | ||||||
|  |  | ||||||
|  | /// @brief Global Master channel control register (not used) - 000010 | ||||||
|  | constexpr uint8_t WKREG_GMUT = 0x02; | ||||||
|  |  | ||||||
|  | /// Global interrupt register (not used) - 01 0000 | ||||||
|  | constexpr uint8_t WKREG_GIER = 0x10; | ||||||
|  |  | ||||||
|  | /// Global interrupt flag register (not used) 01 0001 | ||||||
|  | constexpr uint8_t WKREG_GIFR = 0x11; | ||||||
|  |  | ||||||
|  | /// @brief Global GPIO direction register - 10 0001 | ||||||
|  | /// @details @code | ||||||
|  | ///  ------------------------------------------------------------------------- | ||||||
|  | ///  |   b7   |   b6   |   b5   |   b4   |   b3   |   b2   |   b1   |   b0   | bit | ||||||
|  | ///  ------------------------------------------------------------------------- | ||||||
|  | ///  |   PD7  |   PD6  |   PD5  |   PD4  |   PD3  |   PD2  |   PD1  |   PD0  | name | ||||||
|  | ///  ------------------------------------------------------------------------- | ||||||
|  | ///  |   W/R  |   W/R  |   W/R  |   W/R  |   W/R  |   W/R  |   W/R  |   W/R  | type | ||||||
|  | ///  ------------------------------------------------------------------------- | ||||||
|  | ///  |    0   |    0   |    0   |    0   |    0   |    0   |    0   |    0   | reset | ||||||
|  | ///  ------------------------------------------------------------------------- | ||||||
|  | /// @endcode | ||||||
|  | constexpr uint8_t WKREG_GPDIR = 0x21; | ||||||
|  |  | ||||||
|  | /// @brief Global GPIO data register - 11 0001 | ||||||
|  | /// @details @code | ||||||
|  | ///  ------------------------------------------------------------------------- | ||||||
|  | ///  |   b7   |   b6   |   b5   |   b4   |   b3   |   b2   |   b1   |   b0   | bit | ||||||
|  | ///  ------------------------------------------------------------------------- | ||||||
|  | ///  |   PV7  |   PV6  |   PV5  |   PV4  |   PV3  |   PV2  |   PV1  |   PV0  | name | ||||||
|  | ///  ------------------------------------------------------------------------- | ||||||
|  | ///  |   W/R  |   W/R  |   W/R  |   W/R  |   W/R  |   W/R  |   W/R  |   W/R  | type | ||||||
|  | ///  ------------------------------------------------------------------------- | ||||||
|  | ///  |    0   |    0   |    0   |    0   |    0   |    0   |    0   |    0   | reset | ||||||
|  | ///  ------------------------------------------------------------------------- | ||||||
|  | /// @endcode | ||||||
|  | constexpr uint8_t WKREG_GPDAT = 0x31; | ||||||
|  |  | ||||||
|  | /// @} | ||||||
|  | /// @defgroup WeiKai_cr_ WeiKai Channel Registers | ||||||
|  | /// @brief Definition of the register linked to a particular channel | ||||||
|  | /// @details This topic groups all the **Channel Registers**: these registers are specific | ||||||
|  | /// to the a specific channel i.e. each channel has its own set of registers | ||||||
|  | /// @note only registers and parameters used have been documented | ||||||
|  | /// @{ | ||||||
|  |  | ||||||
|  | /// @defgroup cr_p0 Channel registers when SPAGE=0 | ||||||
|  | /// @brief Definition of the register linked to a particular channel when SPAGE=0 | ||||||
|  | /// @details The channel registers are further splitted into two groups. | ||||||
|  | /// This first group is defined when the Global register WKREG_SPAGE is 0 | ||||||
|  | /// @{ | ||||||
|  |  | ||||||
|  | /// @brief Global Page register c0/c1 0011 | ||||||
|  | /// @details @code | ||||||
|  | /// ------------------------------------------------------------------------- | ||||||
|  | /// |   b7   |   b6   |   b5   |   b4   |   b3   |   b2   |   b1   |   b0   | bit | ||||||
|  | /// ------------------------------------------------------------------------- | ||||||
|  | /// |                             RSV                              |  PAGE  | name | ||||||
|  | /// ------------------------------------------------------------------------- | ||||||
|  | /// |    R   |    R   |    R   |    R   |    R   |    R   |    R   |   W/R  | type | ||||||
|  | /// ------------------------------------------------------------------------- | ||||||
|  | /// |    0   |    0   |    0   |    0   |    0   |    0   |    0   |    0   | reset | ||||||
|  | /// ------------------------------------------------------------------------- | ||||||
|  | /// @endcode | ||||||
|  | constexpr uint8_t WKREG_SPAGE = 0x03; | ||||||
|  |  | ||||||
|  | /// @brief Serial Control Register - c0/c1 0100 | ||||||
|  | /// @details @code | ||||||
|  | ///  ------------------------------------------------------------------------- | ||||||
|  | ///  |   b7   |   b6   |   b5   |   b4   |   b3   |   b2   |   b1   |   b0   | bit | ||||||
|  | ///  ------------------------------------------------------------------------- | ||||||
|  | ///  |                     RSV                    | SLPEN  |  TXEN  |  RXEN  | name | ||||||
|  | ///  ------------------------------------------------------------------------- | ||||||
|  | ///  |    R   |    R   |    R   |    R   |    R   |   R/W  |   R/W  |   W/R  | type | ||||||
|  | ///  ------------------------------------------------------------------------- | ||||||
|  | ///  |    0   |    0   |    0   |    0   |    0   |    0   |    0   |    0   | reset | ||||||
|  | ///  ------------------------------------------------------------------------- | ||||||
|  | /// @endcode | ||||||
|  | constexpr uint8_t WKREG_SCR = 0x04; | ||||||
|  | /// @brief transmission control (0: enable, 1: disable) | ||||||
|  | constexpr uint8_t SCR_TXEN = 1 << 1; | ||||||
|  | /// @brief receiving control (0: enable, 1: disable) | ||||||
|  | constexpr uint8_t SCR_RXEN = 1 << 0; | ||||||
|  |  | ||||||
|  | /// @brief Line Configuration Register - c0/c1 0101 | ||||||
|  | /// @details @code | ||||||
|  | ///  ------------------------------------------------------------------------- | ||||||
|  | ///  |   b7   |   b6   |   b5   |   b4   |   b3   |   b2   |   b1   |   b0   | bit | ||||||
|  | ///  ------------------------------------------------------------------------- | ||||||
|  | ///  |        RSV      |  BREAK |  IREN  |  PAEN  |      PARITY     |  STPL  | name | ||||||
|  | ///  ------------------------------------------------------------------------- | ||||||
|  | ///  |   W/R  |   W/R  |   W/R  |   W/R  |   W/R  |   W/R  |   W/R  |   W/R  | type | ||||||
|  | ///  ------------------------------------------------------------------------- | ||||||
|  | ///  |    0   |    0   |    0   |    0   |    0   |    0   |    0   |    0   | reset | ||||||
|  | ///  ------------------------------------------------------------------------- | ||||||
|  | /// @endcode | ||||||
|  | constexpr uint8_t WKREG_LCR = 0x05; | ||||||
|  | /// @brief Parity enable (0: no check, 1: check) | ||||||
|  | constexpr uint8_t LCR_PAEN = 1 << 3; | ||||||
|  | /// @brief Parity force 0 | ||||||
|  | constexpr uint8_t LCR_PAR_F0 = 0 << 1; | ||||||
|  | /// @brief Parity odd | ||||||
|  | constexpr uint8_t LCR_PAR_ODD = 1 << 1; | ||||||
|  | /// @brief Parity even | ||||||
|  | constexpr uint8_t LCR_PAR_EVEN = 2 << 1; | ||||||
|  | /// @brief Parity force 1 | ||||||
|  | constexpr uint8_t LCR_PAR_F1 = 3 << 1; | ||||||
|  | /// @brief Stop length (0: 1 bit, 1: 2 bits) | ||||||
|  | constexpr uint8_t LCR_STPL = 1 << 0; | ||||||
|  |  | ||||||
|  | /// @brief FIFO Control Register - c0/c1 0110 | ||||||
|  | /// @details @code | ||||||
|  | /// ------------------------------------------------------------------------- | ||||||
|  | /// |   b7   |   b6   |   b5   |   b4   |   b3   |   b2   |   b1   |   b0   | bit | ||||||
|  | /// ------------------------------------------------------------------------- | ||||||
|  | /// |      TFTRIG     |      RFTRIG     |  TFEN  |  RFEN  |  TFRST |  RFRST | name | ||||||
|  | /// ------------------------------------------------------------------------- | ||||||
|  | /// |   W/R  |   W/R  |   W/R  |   W/R  |   W/R  |   W/R  |   W/R  |   W/R  | type | ||||||
|  | /// ------------------------------------------------------------------------- | ||||||
|  | /// |    0   |    0   |    0   |    0   |    0   |    0   |    0   |    0   | reset | ||||||
|  | /// ------------------------------------------------------------------------- | ||||||
|  | /// @endcode | ||||||
|  | constexpr uint8_t WKREG_FCR = 0x06; | ||||||
|  | /// @brief Transmitter FIFO enable | ||||||
|  | constexpr uint8_t FCR_TFEN = 1 << 3; | ||||||
|  | /// @brief Receiver FIFO enable | ||||||
|  | constexpr uint8_t FCR_RFEN = 1 << 2; | ||||||
|  | /// @brief Transmitter FIFO reset | ||||||
|  | constexpr uint8_t FCR_TFRST = 1 << 1; | ||||||
|  | /// @brief Receiver FIFO reset | ||||||
|  | constexpr uint8_t FCR_RFRST = 1 << 0; | ||||||
|  |  | ||||||
|  | /// @brief Serial Interrupt Enable Register (not used)  - c0/c1 0111 | ||||||
|  | constexpr uint8_t WKREG_SIER = 0x07; | ||||||
|  |  | ||||||
|  | /// @brief Serial Interrupt Flag Register (not used) - c0/c1 1000 | ||||||
|  | constexpr uint8_t WKREG_SIFR = 0x08; | ||||||
|  |  | ||||||
|  | /// @brief Transmitter FIFO Count - c0/c1 1001 | ||||||
|  | /// @details @code | ||||||
|  | /// ------------------------------------------------------------------------- | ||||||
|  | /// |   b7   |   b6   |   b5   |   b4   |   b3   |   b2   |   b1   |   b0   | | ||||||
|  | /// ------------------------------------------------------------------------- | ||||||
|  | /// |                  NUMBER OF DATA IN TRANSMITTER FIFO                   | | ||||||
|  | /// ------------------------------------------------------------------------- | ||||||
|  | /// @endcode | ||||||
|  | constexpr uint8_t WKREG_TFCNT = 0x09; | ||||||
|  |  | ||||||
|  | /// @brief Receiver FIFO count - c0/c1 1010 | ||||||
|  | /// @details @code | ||||||
|  | /// ------------------------------------------------------------------------- | ||||||
|  | /// |   b7   |   b6   |   b5   |   b4   |   b3   |   b2   |   b1   |   b0   | | ||||||
|  | /// ------------------------------------------------------------------------- | ||||||
|  | /// |                    NUMBER OF DATA IN RECEIVER FIFO                    | | ||||||
|  | /// ------------------------------------------------------------------------- | ||||||
|  | /// @endcode | ||||||
|  | constexpr uint8_t WKREG_RFCNT = 0x0A; | ||||||
|  |  | ||||||
|  | /// @brief FIFO Status Register - c0/c1 1011 | ||||||
|  | /// @details @code | ||||||
|  | /// ------------------------------------------------------------------------- | ||||||
|  | /// |   b7   |   b6   |   b5   |   b4   |   b3   |   b2   |   b1   |   b0   | bit | ||||||
|  | /// ------------------------------------------------------------------------- | ||||||
|  | /// |  RFOE  |  RFLB  |  RFFE  |  RFPE  | RFDAT  | TFDAT  | TFFULL |  TBUSY | name | ||||||
|  | /// ------------------------------------------------------------------------- | ||||||
|  | /// |    R   |   W/R  |   W/R  |   W/R  |   W/R  |   W/R  |   W/R  |   W/R  | type | ||||||
|  | /// ------------------------------------------------------------------------- | ||||||
|  | /// |    0   |    0   |    0   |    0   |    0   |    0   |    0   |    0   | reset | ||||||
|  | /// ------------------------------------------------------------------------- | ||||||
|  | /// @endcode | ||||||
|  | /// @warning The received buffer can hold 256 bytes. However, as the RFCNT reg | ||||||
|  | /// is 8 bits, if we have 256 byte in the register this is reported as 0 ! Therefore | ||||||
|  | /// RFCNT=0 can indicate that there are 0 **or** 256 bytes in the buffer. If we | ||||||
|  | /// have RFDAT = 1 and RFCNT = 0 it should be interpreted as 256 bytes in the FIFO. | ||||||
|  | /// @note Note that in case of overflow the RFOE goes to one **but** as soon as you read | ||||||
|  | /// the FSR this bit is cleared. Therefore Overflow can be read only once. | ||||||
|  | /// @n The same problem applies to the transmit buffer but here we have to check the | ||||||
|  | /// TFFULL flag. So if TFFULL is set and TFCNT is 0 this should be interpreted as 256 | ||||||
|  | constexpr uint8_t WKREG_FSR = 0x0B; | ||||||
|  | /// @brief Receiver FIFO Overflow Error (0: no OE, 1: OE) | ||||||
|  | constexpr uint8_t FSR_RFOE = 1 << 7; | ||||||
|  | /// @brief Receiver FIFO Line Break (0: no LB, 1: LB) | ||||||
|  | constexpr uint8_t FSR_RFLB = 1 << 6; | ||||||
|  | /// @brief Receiver FIFO Frame Error (0: no FE, 1: FE) | ||||||
|  | constexpr uint8_t FSR_RFFE = 1 << 5; | ||||||
|  | /// @brief Receiver Parity Error (0: no PE, 1: PE) | ||||||
|  | constexpr uint8_t FSR_RFPE = 1 << 4; | ||||||
|  | /// @brief Receiver FIFO count (0: empty, 1: not empty) | ||||||
|  | constexpr uint8_t FSR_RFDAT = 1 << 3; | ||||||
|  | /// @brief Transmitter FIFO count (0: empty, 1: not empty) | ||||||
|  | constexpr uint8_t FSR_TFDAT = 1 << 2; | ||||||
|  | /// @brief Transmitter FIFO full (0: not full, 1: full) | ||||||
|  | constexpr uint8_t FSR_TFFULL = 1 << 1; | ||||||
|  | /// @brief Transmitter busy (0 nothing to transmit, 1: transmitter busy sending) | ||||||
|  | constexpr uint8_t FSR_TBUSY = 1 << 0; | ||||||
|  |  | ||||||
|  | /// @brief Line Status Register (not used - using FIFO) | ||||||
|  | constexpr uint8_t WKREG_LSR = 0x0C; | ||||||
|  |  | ||||||
|  | /// @brief FIFO Data Register (not used - does not seems to work) | ||||||
|  | constexpr uint8_t WKREG_FDAT = 0x0D; | ||||||
|  |  | ||||||
|  | /// @} | ||||||
|  | /// @defgroup cr_p1 Channel registers for SPAGE=1 | ||||||
|  | /// @brief Definition of the register linked to a particular channel when SPAGE=1 | ||||||
|  | /// @details The channel registers are further splitted into two groups. | ||||||
|  | /// This second group is defined when the Global register WKREG_SPAGE is 1 | ||||||
|  | /// @{ | ||||||
|  |  | ||||||
|  | /// @brief Baud rate configuration register: high byte - c0/c1 0100 | ||||||
|  | /// @details @code | ||||||
|  | /// ------------------------------------------------------------------------- | ||||||
|  | /// |   b7   |   b6   |   b5   |   b4   |   b3   |   b2   |   b1   |   b0   | | ||||||
|  | /// ------------------------------------------------------------------------- | ||||||
|  | /// |                      High byte of the baud rate                       | | ||||||
|  | /// ------------------------------------------------------------------------- | ||||||
|  | /// @endcode | ||||||
|  | constexpr uint8_t WKREG_BRH = 0x04; | ||||||
|  |  | ||||||
|  | /// @brief Baud rate configuration register: low byte - c0/c1 0101 | ||||||
|  | /// @details @code | ||||||
|  | /// ------------------------------------------------------------------------- | ||||||
|  | /// |   b7   |   b6   |   b5   |   b4   |   b3   |   b2   |   b1   |   b0   | | ||||||
|  | /// ------------------------------------------------------------------------- | ||||||
|  | /// |                       Low byte of the baud rate                       | | ||||||
|  | /// ------------------------------------------------------------------------- | ||||||
|  | /// @endcode | ||||||
|  | constexpr uint8_t WKREG_BRL = 0x05; | ||||||
|  |  | ||||||
|  | /// @brief Baud rate configuration register decimal part - c0/c1 0110 | ||||||
|  | constexpr uint8_t WKREG_BRD = 0x06; | ||||||
|  |  | ||||||
|  | /// @brief Receive FIFO Interrupt trigger configuration (not used) - c0/c1 0111 | ||||||
|  | constexpr uint8_t WKREG_RFI = 0x07; | ||||||
|  |  | ||||||
|  | /// @brief Transmit FIFO interrupt trigger configuration (not used) - c0/c1 1000 | ||||||
|  | constexpr uint8_t WKREG_TFI = 0x08; | ||||||
|  |  | ||||||
|  | /// @} | ||||||
|  | /// @} | ||||||
|  | }  // namespace weikai | ||||||
|  | }  // namespace esphome | ||||||
							
								
								
									
										1
									
								
								esphome/components/weikai_i2c/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								esphome/components/weikai_i2c/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | CODEOWNERS = ["@DrCoolZic"] | ||||||
							
								
								
									
										177
									
								
								esphome/components/weikai_i2c/weikai_i2c.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										177
									
								
								esphome/components/weikai_i2c/weikai_i2c.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,177 @@ | |||||||
|  | /// @file weikai_i2c.cpp | ||||||
|  | /// @brief  WeiKai component family - classes implementation | ||||||
|  | /// @date Last Modified: 2024/04/06 14:43:31 | ||||||
|  | /// @details The classes declared in this file can be used by the Weikai family | ||||||
|  |  | ||||||
|  | #include "weikai_i2c.h" | ||||||
|  |  | ||||||
|  | namespace esphome { | ||||||
|  | namespace weikai_i2c { | ||||||
|  | static const char *const TAG = "weikai_i2c"; | ||||||
|  |  | ||||||
|  | /// @brief Display a buffer in hexadecimal format (32 hex values / line). | ||||||
|  | void print_buffer(const uint8_t *data, size_t length) { | ||||||
|  |   char hex_buffer[100]; | ||||||
|  |   hex_buffer[(3 * 32) + 1] = 0; | ||||||
|  |   for (size_t i = 0; i < length; i++) { | ||||||
|  |     snprintf(&hex_buffer[3 * (i % 32)], sizeof(hex_buffer), "%02X ", data[i]); | ||||||
|  |     if (i % 32 == 31) { | ||||||
|  |       ESP_LOGVV(TAG, "   %s", hex_buffer); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   if (length % 32) { | ||||||
|  |     // null terminate if incomplete line | ||||||
|  |     hex_buffer[3 * (length % 32) + 2] = 0; | ||||||
|  |     ESP_LOGVV(TAG, "   %s", hex_buffer); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static const char *const REG_TO_STR_P0[16] = {"GENA", "GRST",  "GMUT",  "SPAGE", "SCR", "LCR",  "FCR",  "SIER", | ||||||
|  |                                               "SIFR", "TFCNT", "RFCNT", "FSR",   "LSR", "FDAT", "FWCR", "RS485"}; | ||||||
|  | static const char *const REG_TO_STR_P1[16] = {"GENA", "GRST", "GMUT", "SPAGE", "BAUD1", "BAUD0", "PRES", "RFTL", | ||||||
|  |                                               "TFTL", "FWTH", "FWTL", "XON1",  "XOFF1", "SADR",  "SAEN", "RTSDLY"}; | ||||||
|  | using namespace weikai; | ||||||
|  | // method to print a register value as text: used in the log messages ... | ||||||
|  | const char *reg_to_str(int reg, bool page1) { | ||||||
|  |   if (reg == WKREG_GPDAT) { | ||||||
|  |     return "GPDAT"; | ||||||
|  |   } else if (reg == WKREG_GPDIR) { | ||||||
|  |     return "GPDIR"; | ||||||
|  |   } else { | ||||||
|  |     return page1 ? REG_TO_STR_P1[reg & 0x0F] : REG_TO_STR_P0[reg & 0x0F]; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | enum RegType { REG = 0, FIFO = 1 };  ///< Register or FIFO | ||||||
|  |  | ||||||
|  | /// @brief Computes the I²C bus's address used to access the component | ||||||
|  | /// @param base_address the base address of the component - set by the A1 A0 pins | ||||||
|  | /// @param channel (0-3) the UART channel | ||||||
|  | /// @param fifo (0-1) 0 = access to internal register, 1 = direct access to fifo | ||||||
|  | /// @return the i2c address to use | ||||||
|  | inline uint8_t i2c_address(uint8_t base_address, uint8_t channel, RegType fifo) { | ||||||
|  |   // the address of the device is: | ||||||
|  |   // +----+----+----+----+----+----+----+----+ | ||||||
|  |   // |  0 | A1 | A0 |  1 |  0 | C1 | C0 |  F | | ||||||
|  |   // +----+----+----+----+----+----+----+----+ | ||||||
|  |   // where: | ||||||
|  |   // - A1,A0 is the address read from A1,A0 switch | ||||||
|  |   // - C1,C0 is the channel number (in practice only 00 or 01) | ||||||
|  |   // - F is: 0 when accessing register, one when accessing FIFO | ||||||
|  |   uint8_t const addr = base_address | channel << 1 | fifo << 0; | ||||||
|  |   return addr; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /////////////////////////////////////////////////////////////////////////////// | ||||||
|  | // The WeikaiRegisterI2C methods | ||||||
|  | /////////////////////////////////////////////////////////////////////////////// | ||||||
|  | uint8_t WeikaiRegisterI2C::read_reg() const { | ||||||
|  |   uint8_t value = 0x00; | ||||||
|  |   WeikaiComponentI2C *comp_i2c = static_cast<WeikaiComponentI2C *>(this->comp_); | ||||||
|  |   uint8_t address = i2c_address(comp_i2c->base_address_, this->channel_, REG); | ||||||
|  |   comp_i2c->set_i2c_address(address); | ||||||
|  |   auto error = comp_i2c->read_register(this->register_, &value, 1); | ||||||
|  |   if (error == i2c::NO_ERROR) { | ||||||
|  |     this->comp_->status_clear_warning(); | ||||||
|  |     ESP_LOGVV(TAG, "WeikaiRegisterI2C::read_reg() @%02X reg=%s ch=%u I2C_code:%d, buf=%02X", address, | ||||||
|  |               reg_to_str(this->register_, comp_i2c->page1()), this->channel_, (int) error, value); | ||||||
|  |   } else {  // error | ||||||
|  |     this->comp_->status_set_warning(); | ||||||
|  |     ESP_LOGE(TAG, "WeikaiRegisterI2C::read_reg() @%02X reg=%s ch=%u I2C_code:%d, buf=%02X", address, | ||||||
|  |              reg_to_str(this->register_, comp_i2c->page1()), this->channel_, (int) error, value); | ||||||
|  |   } | ||||||
|  |   return value; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void WeikaiRegisterI2C::read_fifo(uint8_t *data, size_t length) const { | ||||||
|  |   WeikaiComponentI2C *comp_i2c = static_cast<WeikaiComponentI2C *>(this->comp_); | ||||||
|  |   uint8_t address = i2c_address(comp_i2c->base_address_, this->channel_, FIFO); | ||||||
|  |   comp_i2c->set_i2c_address(address); | ||||||
|  |   auto error = comp_i2c->read(data, length); | ||||||
|  |   if (error == i2c::NO_ERROR) { | ||||||
|  |     this->comp_->status_clear_warning(); | ||||||
|  | #ifdef ESPHOME_LOG_HAS_VERY_VERBOSE | ||||||
|  |     ESP_LOGVV(TAG, "WeikaiRegisterI2C::read_fifo() @%02X ch=%d I2C_code:%d len=%d buffer", address, this->channel_, | ||||||
|  |               (int) error, length); | ||||||
|  |     print_buffer(data, length); | ||||||
|  | #endif | ||||||
|  |   } else {  // error | ||||||
|  |     this->comp_->status_set_warning(); | ||||||
|  |     ESP_LOGE(TAG, "WeikaiRegisterI2C::read_fifo() @%02X reg=N/A ch=%d I2C_code:%d len=%d buf=%02X...", address, | ||||||
|  |              this->channel_, (int) error, length, data[0]); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void WeikaiRegisterI2C::write_reg(uint8_t value) { | ||||||
|  |   WeikaiComponentI2C *comp_i2c = static_cast<WeikaiComponentI2C *>(this->comp_); | ||||||
|  |   uint8_t address = i2c_address(comp_i2c->base_address_, this->channel_, REG);  // update the i2c bus | ||||||
|  |   comp_i2c->set_i2c_address(address); | ||||||
|  |   auto error = comp_i2c->write_register(this->register_, &value, 1); | ||||||
|  |   if (error == i2c::NO_ERROR) { | ||||||
|  |     this->comp_->status_clear_warning(); | ||||||
|  |     ESP_LOGVV(TAG, "WK2168Reg::write_reg() @%02X reg=%s ch=%d I2C_code:%d buf=%02X", address, | ||||||
|  |               reg_to_str(this->register_, comp_i2c->page1()), this->channel_, (int) error, value); | ||||||
|  |   } else {  // error | ||||||
|  |     this->comp_->status_set_warning(); | ||||||
|  |     ESP_LOGE(TAG, "WK2168Reg::write_reg() @%02X reg=%s ch=%d I2C_code:%d buf=%d", address, | ||||||
|  |              reg_to_str(this->register_, comp_i2c->page1()), this->channel_, (int) error, value); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void WeikaiRegisterI2C::write_fifo(uint8_t *data, size_t length) { | ||||||
|  |   WeikaiComponentI2C *comp_i2c = static_cast<WeikaiComponentI2C *>(this->comp_); | ||||||
|  |   uint8_t address = i2c_address(comp_i2c->base_address_, this->channel_, FIFO);  // set fifo flag | ||||||
|  |   comp_i2c->set_i2c_address(address); | ||||||
|  |   auto error = comp_i2c->write(data, length); | ||||||
|  |   if (error == i2c::NO_ERROR) { | ||||||
|  |     this->comp_->status_clear_warning(); | ||||||
|  | #ifdef ESPHOME_LOG_HAS_VERY_VERBOSE | ||||||
|  |     ESP_LOGVV(TAG, "WK2168Reg::write_fifo() @%02X ch=%d I2C_code:%d len=%d buffer", address, this->channel_, | ||||||
|  |               (int) error, length); | ||||||
|  |     print_buffer(data, length); | ||||||
|  | #endif | ||||||
|  |   } else {  // error | ||||||
|  |     this->comp_->status_set_warning(); | ||||||
|  |     ESP_LOGE(TAG, "WK2168Reg::write_fifo() @%02X reg=N/A, ch=%d I2C_code:%d len=%d, buf=%02X...", address, | ||||||
|  |              this->channel_, (int) error, length, data[0]); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /////////////////////////////////////////////////////////////////////////////// | ||||||
|  | // The WeikaiComponentI2C methods | ||||||
|  | /////////////////////////////////////////////////////////////////////////////// | ||||||
|  | void WeikaiComponentI2C::setup() { | ||||||
|  |   // before any manipulation we store the address to base_address_ for future use | ||||||
|  |   this->base_address_ = this->address_; | ||||||
|  |   ESP_LOGCONFIG(TAG, "Setting up wk2168_i2c: %s with %d UARTs at @%02X ...", this->get_name(), this->children_.size(), | ||||||
|  |                 this->base_address_); | ||||||
|  |  | ||||||
|  |   // enable all channels | ||||||
|  |   this->reg(WKREG_GENA, 0) = GENA_C1EN | GENA_C2EN | GENA_C3EN | GENA_C4EN; | ||||||
|  |   // reset all channels | ||||||
|  |   this->reg(WKREG_GRST, 0) = GRST_C1RST | GRST_C2RST | GRST_C3RST | GRST_C4RST; | ||||||
|  |   // initialize the spage register to page 0 | ||||||
|  |   this->reg(WKREG_SPAGE, 0) = 0; | ||||||
|  |   this->page1_ = false; | ||||||
|  |  | ||||||
|  |   // we setup our children channels | ||||||
|  |   for (auto *child : this->children_) { | ||||||
|  |     child->setup_channel(); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void WeikaiComponentI2C::dump_config() { | ||||||
|  |   ESP_LOGCONFIG(TAG, "Initialization of %s with %d UARTs completed", this->get_name(), this->children_.size()); | ||||||
|  |   ESP_LOGCONFIG(TAG, "  Crystal: %" PRIu32, this->crystal_); | ||||||
|  |   if (test_mode_) | ||||||
|  |     ESP_LOGCONFIG(TAG, "  Test mode: %d", test_mode_); | ||||||
|  |   ESP_LOGCONFIG(TAG, "  Transfer buffer size: %d", XFER_MAX_SIZE); | ||||||
|  |   this->address_ = this->base_address_;  // we restore the base_address before display (less confusing) | ||||||
|  |   LOG_I2C_DEVICE(this); | ||||||
|  |  | ||||||
|  |   for (auto *child : this->children_) { | ||||||
|  |     child->dump_channel(); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | }  // namespace weikai_i2c | ||||||
|  | }  // namespace esphome | ||||||
							
								
								
									
										61
									
								
								esphome/components/weikai_i2c/weikai_i2c.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								esphome/components/weikai_i2c/weikai_i2c.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,61 @@ | |||||||
|  | /// @file weikai_i2c.h | ||||||
|  | /// @author DrCoolZic | ||||||
|  | /// @brief  WeiKai component family - classes declaration | ||||||
|  | /// @date Last Modified: 2024/03/01 13:31:57 | ||||||
|  | /// @details The classes declared in this file can be used by the Weikai family | ||||||
|  | ///          wk2132_i2c, wk2168_i2c, wk2204_i2c, wk2212_i2c | ||||||
|  |  | ||||||
|  | #pragma once | ||||||
|  | #include <bitset> | ||||||
|  | #include <memory> | ||||||
|  | #include "esphome/core/component.h" | ||||||
|  | #include "esphome/components/uart/uart.h" | ||||||
|  | #include "esphome/components/i2c/i2c.h" | ||||||
|  | #include "esphome/components/weikai/weikai.h" | ||||||
|  |  | ||||||
|  | namespace esphome { | ||||||
|  | namespace weikai_i2c { | ||||||
|  |  | ||||||
|  | class WeikaiComponentI2C; | ||||||
|  |  | ||||||
|  | // using namespace weikai; | ||||||
|  | //////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | /// @brief WeikaiRegisterI2C objects acts as proxies to access remote register through an I2C Bus | ||||||
|  | //////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | class WeikaiRegisterI2C : public weikai::WeikaiRegister { | ||||||
|  |  public: | ||||||
|  |   uint8_t read_reg() const override; | ||||||
|  |   void write_reg(uint8_t value) override; | ||||||
|  |   void read_fifo(uint8_t *data, size_t length) const override; | ||||||
|  |   void write_fifo(uint8_t *data, size_t length) override; | ||||||
|  |  | ||||||
|  |  protected: | ||||||
|  |   friend WeikaiComponentI2C; | ||||||
|  |   WeikaiRegisterI2C(weikai::WeikaiComponent *const comp, uint8_t reg, uint8_t channel) | ||||||
|  |       : weikai::WeikaiRegister(comp, reg, channel) {} | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | //////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | /// @brief The WeikaiComponentI2C class stores the information to the WeiKai component | ||||||
|  | /// connected through an I2C bus. | ||||||
|  | //////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | class WeikaiComponentI2C : public weikai::WeikaiComponent, public i2c::I2CDevice { | ||||||
|  |  public: | ||||||
|  |   weikai::WeikaiRegister ®(uint8_t reg, uint8_t channel) override { | ||||||
|  |     reg_i2c_.register_ = reg; | ||||||
|  |     reg_i2c_.channel_ = channel; | ||||||
|  |     return reg_i2c_; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // | ||||||
|  |   // override Component methods | ||||||
|  |   // | ||||||
|  |   void setup() override; | ||||||
|  |   void dump_config() override; | ||||||
|  |  | ||||||
|  |   uint8_t base_address_;                   ///< base address of I2C device | ||||||
|  |   WeikaiRegisterI2C reg_i2c_{this, 0, 0};  ///< init to this component | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | }  // namespace weikai_i2c | ||||||
|  | }  // namespace esphome | ||||||
							
								
								
									
										1
									
								
								esphome/components/weikai_spi/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								esphome/components/weikai_spi/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | CODEOWNERS = ["@DrCoolZic"] | ||||||
							
								
								
									
										189
									
								
								esphome/components/weikai_spi/weikai_spi.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										189
									
								
								esphome/components/weikai_spi/weikai_spi.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,189 @@ | |||||||
|  | /// @file weikai_spi.cpp | ||||||
|  | /// @brief  WeiKai component family - classes implementation | ||||||
|  | /// @date Last Modified: 2024/04/06 14:46:09 | ||||||
|  | /// @details The classes declared in this file can be used by the Weikai family | ||||||
|  |  | ||||||
|  | #include "weikai_spi.h" | ||||||
|  |  | ||||||
|  | namespace esphome { | ||||||
|  | namespace weikai_spi { | ||||||
|  | using namespace weikai; | ||||||
|  | static const char *const TAG = "weikai_spi"; | ||||||
|  |  | ||||||
|  | /// @brief convert an int to binary representation as C++ std::string | ||||||
|  | /// @param val integer to convert | ||||||
|  | /// @return a std::string | ||||||
|  | inline std::string i2s(uint8_t val) { return std::bitset<8>(val).to_string(); } | ||||||
|  | /// Convert std::string to C string | ||||||
|  | #define I2S2CS(val) (i2s(val).c_str()) | ||||||
|  |  | ||||||
|  | /// @brief measure the time elapsed between two calls | ||||||
|  | /// @param last_time time of the previous call | ||||||
|  | /// @return the elapsed time in microseconds | ||||||
|  | uint32_t elapsed_ms(uint32_t &last_time) { | ||||||
|  |   uint32_t e = millis() - last_time; | ||||||
|  |   last_time = millis(); | ||||||
|  |   return e; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | /// @brief Converts the parity enum value to a C string | ||||||
|  | /// @param parity enum | ||||||
|  | /// @return the string | ||||||
|  | const char *p2s(uart::UARTParityOptions parity) { | ||||||
|  |   using namespace uart; | ||||||
|  |   switch (parity) { | ||||||
|  |     case UART_CONFIG_PARITY_NONE: | ||||||
|  |       return "NONE"; | ||||||
|  |     case UART_CONFIG_PARITY_EVEN: | ||||||
|  |       return "EVEN"; | ||||||
|  |     case UART_CONFIG_PARITY_ODD: | ||||||
|  |       return "ODD"; | ||||||
|  |     default: | ||||||
|  |       return "UNKNOWN"; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /// @brief Display a buffer in hexadecimal format (32 hex values / line). | ||||||
|  | void print_buffer(const uint8_t *data, size_t length) { | ||||||
|  |   char hex_buffer[100]; | ||||||
|  |   hex_buffer[(3 * 32) + 1] = 0; | ||||||
|  |   for (size_t i = 0; i < length; i++) { | ||||||
|  |     snprintf(&hex_buffer[3 * (i % 32)], sizeof(hex_buffer), "%02X ", data[i]); | ||||||
|  |     if (i % 32 == 31) { | ||||||
|  |       ESP_LOGVV(TAG, "   %s", hex_buffer); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   if (length % 32) { | ||||||
|  |     // null terminate if incomplete line | ||||||
|  |     hex_buffer[3 * (length % 32) + 2] = 0; | ||||||
|  |     ESP_LOGVV(TAG, "   %s", hex_buffer); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static const char *const REG_TO_STR_P0[16] = {"GENA", "GRST",  "GMUT",  "SPAGE", "SCR", "LCR",  "FCR",  "SIER", | ||||||
|  |                                               "SIFR", "TFCNT", "RFCNT", "FSR",   "LSR", "FDAT", "FWCR", "RS485"}; | ||||||
|  | static const char *const REG_TO_STR_P1[16] = {"GENA", "GRST", "GMUT", "SPAGE", "BAUD1", "BAUD0", "PRES", "RFTL", | ||||||
|  |                                               "TFTL", "FWTH", "FWTL", "XON1",  "XOFF1", "SADR",  "SAEN", "RTSDLY"}; | ||||||
|  |  | ||||||
|  | // method to print a register value as text: used in the log messages ... | ||||||
|  | const char *reg_to_str(int reg, bool page1) { | ||||||
|  |   if (reg == WKREG_GPDAT) { | ||||||
|  |     return "GPDAT"; | ||||||
|  |   } else if (reg == WKREG_GPDIR) { | ||||||
|  |     return "GPDIR"; | ||||||
|  |   } else { | ||||||
|  |     return page1 ? REG_TO_STR_P1[reg & 0x0F] : REG_TO_STR_P0[reg & 0x0F]; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | enum RegType { REG = 0, FIFO = 1 };            ///< Register or FIFO | ||||||
|  | enum CmdType { WRITE_CMD = 0, READ_CMD = 1 };  ///< Read or Write transfer | ||||||
|  |  | ||||||
|  | /// @brief Computes the SPI command byte | ||||||
|  | /// @param transfer_type read or write command | ||||||
|  | /// @param reg (0-15) the address of the register | ||||||
|  | /// @param channel (0-3) the UART channel | ||||||
|  | /// @param fifo (0-1) 0 = access to internal register, 1 = direct access to fifo | ||||||
|  | /// @return the spi command byte | ||||||
|  | /// @details | ||||||
|  | /// +------+------+------+------+------+------+------+------+ | ||||||
|  | /// | FIFO | R/W  |    C1-C0    |           A3-A0           | | ||||||
|  | /// +------+------+-------------+---------------------------+ | ||||||
|  | /// FIFO: 0 = register, 1 = FIFO | ||||||
|  | /// R/W: 0 = write, 1 = read | ||||||
|  | /// C1-C0: Channel (0-1) | ||||||
|  | /// A3-A0: Address (0-F) | ||||||
|  | inline static uint8_t cmd_byte(RegType fifo, CmdType transfer_type, uint8_t channel, uint8_t reg) { | ||||||
|  |   return (fifo << 7 | transfer_type << 6 | channel << 4 | reg << 0); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /////////////////////////////////////////////////////////////////////////////// | ||||||
|  | // The WeikaiRegisterSPI methods | ||||||
|  | /////////////////////////////////////////////////////////////////////////////// | ||||||
|  | uint8_t WeikaiRegisterSPI::read_reg() const { | ||||||
|  |   auto *spi_comp = static_cast<WeikaiComponentSPI *>(this->comp_); | ||||||
|  |   uint8_t cmd = cmd_byte(REG, READ_CMD, this->channel_, this->register_); | ||||||
|  |   spi_comp->enable(); | ||||||
|  |   spi_comp->write_byte(cmd); | ||||||
|  |   uint8_t val = spi_comp->read_byte(); | ||||||
|  |   spi_comp->disable(); | ||||||
|  |   ESP_LOGVV(TAG, "WeikaiRegisterSPI::read_reg() cmd=%s(%02X) reg=%s ch=%d buf=%02X", I2S2CS(cmd), cmd, | ||||||
|  |             reg_to_str(this->register_, this->comp_->page1()), this->channel_, val); | ||||||
|  |   return val; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void WeikaiRegisterSPI::read_fifo(uint8_t *data, size_t length) const { | ||||||
|  |   auto *spi_comp = static_cast<WeikaiComponentSPI *>(this->comp_); | ||||||
|  |   uint8_t cmd = cmd_byte(FIFO, READ_CMD, this->channel_, this->register_); | ||||||
|  |   spi_comp->enable(); | ||||||
|  |   spi_comp->write_byte(cmd); | ||||||
|  |   spi_comp->read_array(data, length); | ||||||
|  |   spi_comp->disable(); | ||||||
|  | #ifdef ESPHOME_LOG_HAS_VERY_VERBOSE | ||||||
|  |   ESP_LOGVV(TAG, "WeikaiRegisterSPI::read_fifo() cmd=%s(%02X) ch=%d len=%d buffer", I2S2CS(cmd), cmd, this->channel_, | ||||||
|  |             length); | ||||||
|  |   print_buffer(data, length); | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void WeikaiRegisterSPI::write_reg(uint8_t value) { | ||||||
|  |   auto *spi_comp = static_cast<WeikaiComponentSPI *>(this->comp_); | ||||||
|  |   uint8_t buf[2]{cmd_byte(REG, WRITE_CMD, this->channel_, this->register_), value}; | ||||||
|  |   spi_comp->enable(); | ||||||
|  |   spi_comp->write_array(buf, 2); | ||||||
|  |   spi_comp->disable(); | ||||||
|  |   ESP_LOGVV(TAG, "WeikaiRegisterSPI::write_reg() cmd=%s(%02X) reg=%s ch=%d buf=%02X", I2S2CS(buf[0]), buf[0], | ||||||
|  |             reg_to_str(this->register_, this->comp_->page1()), this->channel_, buf[1]); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void WeikaiRegisterSPI::write_fifo(uint8_t *data, size_t length) { | ||||||
|  |   auto *spi_comp = static_cast<WeikaiComponentSPI *>(this->comp_); | ||||||
|  |   uint8_t cmd = cmd_byte(FIFO, WRITE_CMD, this->channel_, this->register_); | ||||||
|  |   spi_comp->enable(); | ||||||
|  |   spi_comp->write_byte(cmd); | ||||||
|  |   spi_comp->write_array(data, length); | ||||||
|  |   spi_comp->disable(); | ||||||
|  |  | ||||||
|  | #ifdef ESPHOME_LOG_HAS_VERY_VERBOSE | ||||||
|  |   ESP_LOGVV(TAG, "WeikaiRegisterSPI::write_fifo() cmd=%s(%02X) ch=%d len=%d buffer", I2S2CS(cmd), cmd, this->channel_, | ||||||
|  |             length); | ||||||
|  |   print_buffer(data, length); | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /////////////////////////////////////////////////////////////////////////////// | ||||||
|  | // The WeikaiComponentSPI methods | ||||||
|  | /////////////////////////////////////////////////////////////////////////////// | ||||||
|  | void WeikaiComponentSPI::setup() { | ||||||
|  |   using namespace weikai; | ||||||
|  |   ESP_LOGCONFIG(TAG, "Setting up wk2168_spi: %s with %d UARTs...", this->get_name(), this->children_.size()); | ||||||
|  |   this->spi_setup(); | ||||||
|  |   // enable all channels | ||||||
|  |   this->reg(WKREG_GENA, 0) = GENA_C1EN | GENA_C2EN | GENA_C3EN | GENA_C4EN; | ||||||
|  |   // reset all channels | ||||||
|  |   this->reg(WKREG_GRST, 0) = GRST_C1RST | GRST_C2RST | GRST_C3RST | GRST_C4RST; | ||||||
|  |   // initialize the spage register to page 0 | ||||||
|  |   this->reg(WKREG_SPAGE, 0) = 0; | ||||||
|  |   this->page1_ = false; | ||||||
|  |  | ||||||
|  |   // we setup our children channels | ||||||
|  |   for (auto *child : this->children_) { | ||||||
|  |     child->setup_channel(); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void WeikaiComponentSPI::dump_config() { | ||||||
|  |   ESP_LOGCONFIG(TAG, "Initialization of %s with %d UARTs completed", this->get_name(), this->children_.size()); | ||||||
|  |   ESP_LOGCONFIG(TAG, "  Crystal: %" PRIu32 "", this->crystal_); | ||||||
|  |   if (test_mode_) | ||||||
|  |     ESP_LOGCONFIG(TAG, "  Test mode: %d", test_mode_); | ||||||
|  |   ESP_LOGCONFIG(TAG, "  Transfer buffer size: %d", XFER_MAX_SIZE); | ||||||
|  |   LOG_PIN("  CS Pin: ", this->cs_); | ||||||
|  |  | ||||||
|  |   for (auto *child : this->children_) { | ||||||
|  |     child->dump_channel(); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | }  // namespace weikai_spi | ||||||
|  | }  // namespace esphome | ||||||
							
								
								
									
										54
									
								
								esphome/components/weikai_spi/weikai_spi.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								esphome/components/weikai_spi/weikai_spi.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,54 @@ | |||||||
|  | /// @file weikai.h | ||||||
|  | /// @author DrCoolZic | ||||||
|  | /// @brief  WeiKai component family - classes declaration | ||||||
|  | /// @date Last Modified: 2024/02/29 17:20:32 | ||||||
|  | /// @details The classes declared in this file can be used by the Weikai family | ||||||
|  | ///          wk2124_spi, wk2132_spi, wk2168_spi, wk2204_spi, wk2212_spi, | ||||||
|  |  | ||||||
|  | #pragma once | ||||||
|  | #include <bitset> | ||||||
|  | #include <memory> | ||||||
|  | #include "esphome/core/component.h" | ||||||
|  | #include "esphome/components/uart/uart.h" | ||||||
|  | #include "esphome/components/spi/spi.h" | ||||||
|  | #include "esphome/components/weikai/weikai.h" | ||||||
|  |  | ||||||
|  | namespace esphome { | ||||||
|  | namespace weikai_spi { | ||||||
|  | //////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | /// @brief WeikaiRegisterSPI objects acts as proxies to access remote register through an SPI Bus | ||||||
|  | //////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | class WeikaiRegisterSPI : public weikai::WeikaiRegister { | ||||||
|  |  public: | ||||||
|  |   WeikaiRegisterSPI(weikai::WeikaiComponent *const comp, uint8_t reg, uint8_t channel) | ||||||
|  |       : weikai::WeikaiRegister(comp, reg, channel) {} | ||||||
|  |  | ||||||
|  |   uint8_t read_reg() const override; | ||||||
|  |   void write_reg(uint8_t value) override; | ||||||
|  |   void read_fifo(uint8_t *data, size_t length) const override; | ||||||
|  |   void write_fifo(uint8_t *data, size_t length) override; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | //////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | /// @brief The WeikaiComponentSPI class stores the information to the WeiKai component | ||||||
|  | /// connected through an SPI bus. | ||||||
|  | //////////////////////////////////////////////////////////////////////////////////// | ||||||
|  | class WeikaiComponentSPI : public weikai::WeikaiComponent, | ||||||
|  |                            public spi::SPIDevice<spi::BIT_ORDER_MSB_FIRST, spi::CLOCK_POLARITY_LOW, | ||||||
|  |                                                  spi::CLOCK_PHASE_LEADING, spi::DATA_RATE_1MHZ> { | ||||||
|  |  public: | ||||||
|  |   weikai::WeikaiRegister ®(uint8_t reg, uint8_t channel) override { | ||||||
|  |     reg_spi_.register_ = reg; | ||||||
|  |     reg_spi_.channel_ = channel; | ||||||
|  |     return reg_spi_; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   void setup() override; | ||||||
|  |   void dump_config() override; | ||||||
|  |  | ||||||
|  |  protected: | ||||||
|  |   WeikaiRegisterSPI reg_spi_{this, 0, 0};  ///< init to this component | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | }  // namespace weikai_spi | ||||||
|  | }  // namespace esphome | ||||||
							
								
								
									
										30
									
								
								esphome/components/wk2132_i2c/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								esphome/components/wk2132_i2c/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,30 @@ | |||||||
|  | import esphome.codegen as cg | ||||||
|  | import esphome.config_validation as cv | ||||||
|  | from esphome.components import i2c, weikai | ||||||
|  | from esphome.const import CONF_ID | ||||||
|  |  | ||||||
|  | CODEOWNERS = ["@DrCoolZic"] | ||||||
|  | DEPENDENCIES = ["i2c"] | ||||||
|  | AUTO_LOAD = ["weikai", "weikai_i2c"] | ||||||
|  | MULTI_CONF = True | ||||||
|  |  | ||||||
|  | weikai_i2c_ns = cg.esphome_ns.namespace("weikai_i2c") | ||||||
|  | WeikaiComponentI2C = weikai_i2c_ns.class_( | ||||||
|  |     "WeikaiComponentI2C", weikai.WeikaiComponent, i2c.I2CDevice | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | CONFIG_SCHEMA = cv.All( | ||||||
|  |     weikai.WKBASE_SCHEMA.extend( | ||||||
|  |         { | ||||||
|  |             cv.GenerateID(): cv.declare_id(WeikaiComponentI2C), | ||||||
|  |         } | ||||||
|  |     ).extend(i2c.i2c_device_schema(0x2C)), | ||||||
|  |     weikai.check_channel_max_2, | ||||||
|  | ) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | async def to_code(config): | ||||||
|  |     var = cg.new_Pvariable(config[CONF_ID]) | ||||||
|  |     cg.add(var.set_name(str(config[CONF_ID]))) | ||||||
|  |     await weikai.register_weikai(var, config) | ||||||
|  |     await i2c.register_i2c_device(var, config) | ||||||
							
								
								
									
										4
									
								
								esphome/components/wk2132_i2c/wk2132_i2c.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								esphome/components/wk2132_i2c/wk2132_i2c.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,4 @@ | |||||||
|  | /* compiling with esp-idf framework requires a .cpp file for some reason ? */ | ||||||
|  | namespace esphome { | ||||||
|  | namespace wk2132_i2c {} | ||||||
|  | }  // namespace esphome | ||||||
							
								
								
									
										31
									
								
								esphome/components/wk2132_spi/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								esphome/components/wk2132_spi/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,31 @@ | |||||||
|  | import esphome.codegen as cg | ||||||
|  | import esphome.config_validation as cv | ||||||
|  | from esphome.components import spi, weikai | ||||||
|  |  | ||||||
|  | from esphome.const import CONF_ID | ||||||
|  |  | ||||||
|  | CODEOWNERS = ["@DrCoolZic"] | ||||||
|  | DEPENDENCIES = ["spi"] | ||||||
|  | AUTO_LOAD = ["weikai", "weikai_spi"] | ||||||
|  | MULTI_CONF = True | ||||||
|  |  | ||||||
|  | weikai_spi_ns = cg.esphome_ns.namespace("weikai_spi") | ||||||
|  | WeikaiComponentSPI = weikai_spi_ns.class_( | ||||||
|  |     "WeikaiComponentSPI", weikai.WeikaiComponent, spi.SPIDevice | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | CONFIG_SCHEMA = cv.All( | ||||||
|  |     weikai.WKBASE_SCHEMA.extend( | ||||||
|  |         { | ||||||
|  |             cv.GenerateID(): cv.declare_id(WeikaiComponentSPI), | ||||||
|  |         } | ||||||
|  |     ).extend(spi.spi_device_schema()), | ||||||
|  |     weikai.check_channel_max_2, | ||||||
|  | ) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | async def to_code(config): | ||||||
|  |     var = cg.new_Pvariable(config[CONF_ID]) | ||||||
|  |     cg.add(var.set_name(str(config[CONF_ID]))) | ||||||
|  |     await weikai.register_weikai(var, config) | ||||||
|  |     await spi.register_spi_device(var, config) | ||||||
							
								
								
									
										64
									
								
								esphome/components/wk2168_i2c/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								esphome/components/wk2168_i2c/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,64 @@ | |||||||
|  | import esphome.codegen as cg | ||||||
|  | import esphome.config_validation as cv | ||||||
|  | from esphome import pins | ||||||
|  | from esphome.components import i2c, weikai | ||||||
|  | from esphome.const import ( | ||||||
|  |     CONF_ID, | ||||||
|  |     CONF_INVERTED, | ||||||
|  |     CONF_MODE, | ||||||
|  |     CONF_NUMBER, | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | CODEOWNERS = ["@DrCoolZic"] | ||||||
|  | DEPENDENCIES = ["i2c"] | ||||||
|  | AUTO_LOAD = ["weikai", "weikai_i2c"] | ||||||
|  | MULTI_CONF = True | ||||||
|  | CONF_WK2168_I2C = "wk2168_i2c" | ||||||
|  |  | ||||||
|  | weikai_ns = cg.esphome_ns.namespace("weikai") | ||||||
|  | weikai_i2c_ns = cg.esphome_ns.namespace("weikai_i2c") | ||||||
|  | WeikaiComponentI2C = weikai_i2c_ns.class_( | ||||||
|  |     "WeikaiComponentI2C", weikai.WeikaiComponent, i2c.I2CDevice | ||||||
|  | ) | ||||||
|  | WeikaiGPIOPin = weikai_ns.class_( | ||||||
|  |     "WeikaiGPIOPin", cg.GPIOPin, cg.Parented.template(WeikaiComponentI2C) | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | CONFIG_SCHEMA = cv.All( | ||||||
|  |     weikai.WKBASE_SCHEMA.extend( | ||||||
|  |         { | ||||||
|  |             cv.GenerateID(): cv.declare_id(WeikaiComponentI2C), | ||||||
|  |         } | ||||||
|  |     ).extend(i2c.i2c_device_schema(0x2C)), | ||||||
|  |     weikai.check_channel_max_4, | ||||||
|  | ) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | async def to_code(config): | ||||||
|  |     var = cg.new_Pvariable(config[CONF_ID]) | ||||||
|  |     cg.add(var.set_name(str(config[CONF_ID]))) | ||||||
|  |     await weikai.register_weikai(var, config) | ||||||
|  |     await i2c.register_i2c_device(var, config) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | WK2168_PIN_SCHEMA = cv.All( | ||||||
|  |     weikai.WEIKAI_PIN_SCHEMA.extend( | ||||||
|  |         { | ||||||
|  |             cv.GenerateID(): cv.declare_id(WeikaiGPIOPin), | ||||||
|  |             cv.Required(CONF_WK2168_I2C): cv.use_id(WeikaiComponentI2C), | ||||||
|  |         } | ||||||
|  |     ), | ||||||
|  |     weikai.validate_pin_mode, | ||||||
|  | ) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @pins.PIN_SCHEMA_REGISTRY.register(CONF_WK2168_I2C, WK2168_PIN_SCHEMA) | ||||||
|  | async def sc16is75x_pin_to_code(config): | ||||||
|  |     var = cg.new_Pvariable(config[CONF_ID]) | ||||||
|  |     parent = await cg.get_variable(config[CONF_WK2168_I2C]) | ||||||
|  |     cg.add(var.set_parent(parent)) | ||||||
|  |     num = config[CONF_NUMBER] | ||||||
|  |     cg.add(var.set_pin(num)) | ||||||
|  |     cg.add(var.set_inverted(config[CONF_INVERTED])) | ||||||
|  |     cg.add(var.set_flags(pins.gpio_flags_expr(config[CONF_MODE]))) | ||||||
|  |     return var | ||||||
							
								
								
									
										62
									
								
								esphome/components/wk2168_spi/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								esphome/components/wk2168_spi/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,62 @@ | |||||||
|  | import esphome.codegen as cg | ||||||
|  | import esphome.config_validation as cv | ||||||
|  | from esphome import pins | ||||||
|  | from esphome.components import spi, weikai | ||||||
|  | from esphome.const import ( | ||||||
|  |     CONF_ID, | ||||||
|  |     CONF_INVERTED, | ||||||
|  |     CONF_MODE, | ||||||
|  |     CONF_NUMBER, | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | CODEOWNERS = ["@DrCoolZic"] | ||||||
|  | DEPENDENCIES = ["spi"] | ||||||
|  | AUTO_LOAD = ["weikai", "weikai_spi"] | ||||||
|  | MULTI_CONF = True | ||||||
|  | CONF_WK2168_SPI = "wk2168_spi" | ||||||
|  |  | ||||||
|  | weikai_spi_ns = cg.esphome_ns.namespace("weikai_spi") | ||||||
|  | weikai_ns = cg.esphome_ns.namespace("weikai") | ||||||
|  | WeikaiComponentSPI = weikai_spi_ns.class_( | ||||||
|  |     "WeikaiComponentSPI", weikai.WeikaiComponent, spi.SPIDevice | ||||||
|  | ) | ||||||
|  | WeikaiGPIOPin = weikai_ns.class_( | ||||||
|  |     "WeikaiGPIOPin", cg.GPIOPin, cg.Parented.template(WeikaiComponentSPI) | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | CONFIG_SCHEMA = cv.All( | ||||||
|  |     weikai.WKBASE_SCHEMA.extend( | ||||||
|  |         {cv.GenerateID(): cv.declare_id(WeikaiComponentSPI)} | ||||||
|  |     ).extend(spi.spi_device_schema()), | ||||||
|  |     weikai.check_channel_max_4, | ||||||
|  | ) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | async def to_code(config): | ||||||
|  |     var = cg.new_Pvariable(config[CONF_ID]) | ||||||
|  |     cg.add(var.set_name(str(config[CONF_ID]))) | ||||||
|  |     await weikai.register_weikai(var, config) | ||||||
|  |     await spi.register_spi_device(var, config) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | WK2168_PIN_SCHEMA = cv.All( | ||||||
|  |     weikai.WEIKAI_PIN_SCHEMA.extend( | ||||||
|  |         { | ||||||
|  |             cv.GenerateID(): cv.declare_id(WeikaiGPIOPin), | ||||||
|  |             cv.Required(CONF_WK2168_SPI): cv.use_id(WeikaiComponentSPI), | ||||||
|  |         }, | ||||||
|  |     ), | ||||||
|  |     weikai.validate_pin_mode, | ||||||
|  | ) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @pins.PIN_SCHEMA_REGISTRY.register(CONF_WK2168_SPI, WK2168_PIN_SCHEMA) | ||||||
|  | async def sc16is75x_pin_to_code(config): | ||||||
|  |     var = cg.new_Pvariable(config[CONF_ID]) | ||||||
|  |     parent = await cg.get_variable(config[CONF_WK2168_SPI]) | ||||||
|  |     cg.add(var.set_parent(parent)) | ||||||
|  |     num = config[CONF_NUMBER] | ||||||
|  |     cg.add(var.set_pin(num)) | ||||||
|  |     cg.add(var.set_inverted(config[CONF_INVERTED])) | ||||||
|  |     cg.add(var.set_flags(pins.gpio_flags_expr(config[CONF_MODE]))) | ||||||
|  |     return var | ||||||
							
								
								
									
										30
									
								
								esphome/components/wk2204_i2c/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								esphome/components/wk2204_i2c/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,30 @@ | |||||||
|  | import esphome.codegen as cg | ||||||
|  | import esphome.config_validation as cv | ||||||
|  | from esphome.components import i2c, weikai | ||||||
|  | from esphome.const import CONF_ID | ||||||
|  |  | ||||||
|  | CODEOWNERS = ["@DrCoolZic"] | ||||||
|  | DEPENDENCIES = ["i2c"] | ||||||
|  | AUTO_LOAD = ["weikai", "weikai_i2c"] | ||||||
|  | MULTI_CONF = True | ||||||
|  |  | ||||||
|  | weikai_i2c_ns = cg.esphome_ns.namespace("weikai_i2c") | ||||||
|  | WeikaiComponentI2C = weikai_i2c_ns.class_( | ||||||
|  |     "WeikaiComponentI2C", weikai.WeikaiComponent, i2c.I2CDevice | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | CONFIG_SCHEMA = cv.All( | ||||||
|  |     weikai.WKBASE_SCHEMA.extend( | ||||||
|  |         { | ||||||
|  |             cv.GenerateID(): cv.declare_id(WeikaiComponentI2C), | ||||||
|  |         } | ||||||
|  |     ).extend(i2c.i2c_device_schema(0x2C)), | ||||||
|  |     weikai.check_channel_max_4, | ||||||
|  | ) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | async def to_code(config): | ||||||
|  |     var = cg.new_Pvariable(config[CONF_ID]) | ||||||
|  |     cg.add(var.set_name(str(config[CONF_ID]))) | ||||||
|  |     await weikai.register_weikai(var, config) | ||||||
|  |     await i2c.register_i2c_device(var, config) | ||||||
							
								
								
									
										30
									
								
								esphome/components/wk2204_spi/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								esphome/components/wk2204_spi/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,30 @@ | |||||||
|  | import esphome.codegen as cg | ||||||
|  | import esphome.config_validation as cv | ||||||
|  | from esphome.components import spi, weikai | ||||||
|  | from esphome.const import CONF_ID | ||||||
|  |  | ||||||
|  | CODEOWNERS = ["@DrCoolZic"] | ||||||
|  | DEPENDENCIES = ["spi"] | ||||||
|  | AUTO_LOAD = ["weikai", "weikai_spi"] | ||||||
|  | MULTI_CONF = True | ||||||
|  |  | ||||||
|  | weikai_spi_ns = cg.esphome_ns.namespace("weikai_spi") | ||||||
|  | WeikaiComponentSPI = weikai_spi_ns.class_( | ||||||
|  |     "WeikaiComponentSPI", weikai.WeikaiComponent, spi.SPIDevice | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | CONFIG_SCHEMA = cv.All( | ||||||
|  |     weikai.WKBASE_SCHEMA.extend( | ||||||
|  |         { | ||||||
|  |             cv.GenerateID(): cv.declare_id(WeikaiComponentSPI), | ||||||
|  |         } | ||||||
|  |     ).extend(spi.spi_device_schema()), | ||||||
|  |     weikai.check_channel_max_4, | ||||||
|  | ) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | async def to_code(config): | ||||||
|  |     var = cg.new_Pvariable(config[CONF_ID]) | ||||||
|  |     cg.add(var.set_name(str(config[CONF_ID]))) | ||||||
|  |     await weikai.register_weikai(var, config) | ||||||
|  |     await spi.register_spi_device(var, config) | ||||||
							
								
								
									
										64
									
								
								esphome/components/wk2212_i2c/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								esphome/components/wk2212_i2c/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,64 @@ | |||||||
|  | import esphome.codegen as cg | ||||||
|  | import esphome.config_validation as cv | ||||||
|  | from esphome import pins | ||||||
|  | from esphome.components import i2c, weikai | ||||||
|  | from esphome.const import ( | ||||||
|  |     CONF_ID, | ||||||
|  |     CONF_INVERTED, | ||||||
|  |     CONF_MODE, | ||||||
|  |     CONF_NUMBER, | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | CODEOWNERS = ["@DrCoolZic"] | ||||||
|  | DEPENDENCIES = ["i2c"] | ||||||
|  | AUTO_LOAD = ["weikai", "weikai_i2c"] | ||||||
|  | MULTI_CONF = True | ||||||
|  | CONF_WK2212_I2C = "wk2212_i2c" | ||||||
|  |  | ||||||
|  | weikai_ns = cg.esphome_ns.namespace("weikai") | ||||||
|  | weikai_i2c_ns = cg.esphome_ns.namespace("weikai_i2c") | ||||||
|  | WeikaiComponentI2C = weikai_i2c_ns.class_( | ||||||
|  |     "WeikaiComponentI2C", weikai.WeikaiComponent, i2c.I2CDevice | ||||||
|  | ) | ||||||
|  | WeikaiGPIOPin = weikai_ns.class_( | ||||||
|  |     "WeikaiGPIOPin", cg.GPIOPin, cg.Parented.template(WeikaiComponentI2C) | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | CONFIG_SCHEMA = cv.All( | ||||||
|  |     weikai.WKBASE_SCHEMA.extend( | ||||||
|  |         { | ||||||
|  |             cv.GenerateID(): cv.declare_id(WeikaiComponentI2C), | ||||||
|  |         } | ||||||
|  |     ).extend(i2c.i2c_device_schema(0x2C)), | ||||||
|  |     weikai.check_channel_max_2, | ||||||
|  | ) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | async def to_code(config): | ||||||
|  |     var = cg.new_Pvariable(config[CONF_ID]) | ||||||
|  |     cg.add(var.set_name(str(config[CONF_ID]))) | ||||||
|  |     await weikai.register_weikai(var, config) | ||||||
|  |     await i2c.register_i2c_device(var, config) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | WK2212_PIN_SCHEMA = cv.All( | ||||||
|  |     weikai.WEIKAI_PIN_SCHEMA.extend( | ||||||
|  |         { | ||||||
|  |             cv.GenerateID(): cv.declare_id(WeikaiGPIOPin), | ||||||
|  |             cv.Required(CONF_WK2212_I2C): cv.use_id(WeikaiComponentI2C), | ||||||
|  |         } | ||||||
|  |     ), | ||||||
|  |     weikai.validate_pin_mode, | ||||||
|  | ) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @pins.PIN_SCHEMA_REGISTRY.register(CONF_WK2212_I2C, WK2212_PIN_SCHEMA) | ||||||
|  | async def sc16is75x_pin_to_code(config): | ||||||
|  |     var = cg.new_Pvariable(config[CONF_ID]) | ||||||
|  |     parent = await cg.get_variable(config[CONF_WK2212_I2C]) | ||||||
|  |     cg.add(var.set_parent(parent)) | ||||||
|  |     num = config[CONF_NUMBER] | ||||||
|  |     cg.add(var.set_pin(num)) | ||||||
|  |     cg.add(var.set_inverted(config[CONF_INVERTED])) | ||||||
|  |     cg.add(var.set_flags(pins.gpio_flags_expr(config[CONF_MODE]))) | ||||||
|  |     return var | ||||||
							
								
								
									
										62
									
								
								esphome/components/wk2212_spi/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								esphome/components/wk2212_spi/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,62 @@ | |||||||
|  | import esphome.codegen as cg | ||||||
|  | import esphome.config_validation as cv | ||||||
|  | from esphome import pins | ||||||
|  | from esphome.components import spi, weikai | ||||||
|  | from esphome.const import ( | ||||||
|  |     CONF_ID, | ||||||
|  |     CONF_INVERTED, | ||||||
|  |     CONF_MODE, | ||||||
|  |     CONF_NUMBER, | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | CODEOWNERS = ["@DrCoolZic"] | ||||||
|  | DEPENDENCIES = ["spi"] | ||||||
|  | AUTO_LOAD = ["weikai", "weikai_spi"] | ||||||
|  | MULTI_CONF = True | ||||||
|  | CONF_WK2212_SPI = "wk2212_spi" | ||||||
|  |  | ||||||
|  | weikai_ns = cg.esphome_ns.namespace("weikai") | ||||||
|  | weikai_spi_ns = cg.esphome_ns.namespace("weikai_spi") | ||||||
|  | WeikaiComponentSPI = weikai_spi_ns.class_( | ||||||
|  |     "WeikaiComponentSPI", weikai.WeikaiComponent, spi.SPIDevice | ||||||
|  | ) | ||||||
|  | WeikaiGPIOPin = weikai_ns.class_( | ||||||
|  |     "WeikaiGPIOPin", cg.GPIOPin, cg.Parented.template(WeikaiComponentSPI) | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | CONFIG_SCHEMA = cv.All( | ||||||
|  |     weikai.WKBASE_SCHEMA.extend( | ||||||
|  |         {cv.GenerateID(): cv.declare_id(WeikaiComponentSPI)} | ||||||
|  |     ).extend(spi.spi_device_schema()), | ||||||
|  |     weikai.check_channel_max_2, | ||||||
|  | ) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | async def to_code(config): | ||||||
|  |     var = cg.new_Pvariable(config[CONF_ID]) | ||||||
|  |     cg.add(var.set_name(str(config[CONF_ID]))) | ||||||
|  |     await weikai.register_weikai(var, config) | ||||||
|  |     await spi.register_spi_device(var, config) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | WK2212_PIN_SCHEMA = cv.All( | ||||||
|  |     weikai.WEIKAI_PIN_SCHEMA.extend( | ||||||
|  |         { | ||||||
|  |             cv.GenerateID(): cv.declare_id(WeikaiGPIOPin), | ||||||
|  |             cv.Required(CONF_WK2212_SPI): cv.use_id(WeikaiComponentSPI), | ||||||
|  |         }, | ||||||
|  |     ), | ||||||
|  |     weikai.validate_pin_mode, | ||||||
|  | ) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @pins.PIN_SCHEMA_REGISTRY.register(CONF_WK2212_SPI, WK2212_PIN_SCHEMA) | ||||||
|  | async def sc16is75x_pin_to_code(config): | ||||||
|  |     var = cg.new_Pvariable(config[CONF_ID]) | ||||||
|  |     parent = await cg.get_variable(config[CONF_WK2212_SPI]) | ||||||
|  |     cg.add(var.set_parent(parent)) | ||||||
|  |     num = config[CONF_NUMBER] | ||||||
|  |     cg.add(var.set_pin(num)) | ||||||
|  |     cg.add(var.set_inverted(config[CONF_INVERTED])) | ||||||
|  |     cg.add(var.set_flags(pins.gpio_flags_expr(config[CONF_MODE]))) | ||||||
|  |     return var | ||||||
							
								
								
									
										20
									
								
								tests/components/wk2132_i2c/common.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								tests/components/wk2132_i2c/common.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | |||||||
|  | i2c: | ||||||
|  |   id: i2c_bus | ||||||
|  |   scl: ${scl_pin} | ||||||
|  |   sda: ${sda_pin} | ||||||
|  |   scan: true | ||||||
|  |   frequency: 600kHz | ||||||
|  |  | ||||||
|  | wk2132_i2c: | ||||||
|  |   - id: wk2132_i2c_id | ||||||
|  |     address: 0x70 | ||||||
|  |     i2c_id: i2c_bus | ||||||
|  |     uart: | ||||||
|  |       - id: wk2132_id_0 | ||||||
|  |         channel: 0 | ||||||
|  |         baud_rate: 115200 | ||||||
|  |         stop_bits: 1 | ||||||
|  |         parity: none | ||||||
|  |       - id: wk2132_id_1 | ||||||
|  |         channel: 1 | ||||||
|  |         baud_rate: 19200 | ||||||
							
								
								
									
										5
									
								
								tests/components/wk2132_i2c/test.esp32-idf.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								tests/components/wk2132_i2c/test.esp32-idf.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | |||||||
|  | substitutions: | ||||||
|  |   scl_pin: GPIO22 | ||||||
|  |   sda_pin: GPIO21 | ||||||
|  |  | ||||||
|  | <<: !include common.yaml | ||||||
							
								
								
									
										5
									
								
								tests/components/wk2132_i2c/test.esp32-s3-idf.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								tests/components/wk2132_i2c/test.esp32-s3-idf.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | |||||||
|  | substitutions: | ||||||
|  |   scl_pin: GPIO40 | ||||||
|  |   sda_pin: GPIO41 | ||||||
|  |  | ||||||
|  | <<: !include common.yaml | ||||||
							
								
								
									
										5
									
								
								tests/components/wk2132_i2c/test.esp32-s3.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								tests/components/wk2132_i2c/test.esp32-s3.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | |||||||
|  | substitutions: | ||||||
|  |   scl_pin: GPIO40 | ||||||
|  |   sda_pin: GPIO41 | ||||||
|  |  | ||||||
|  | <<: !include common.yaml | ||||||
							
								
								
									
										5
									
								
								tests/components/wk2132_i2c/test.esp32.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								tests/components/wk2132_i2c/test.esp32.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | |||||||
|  | substitutions: | ||||||
|  |   scl_pin: GPIO22 | ||||||
|  |   sda_pin: GPIO21 | ||||||
|  |  | ||||||
|  | <<: !include common.yaml | ||||||
							
								
								
									
										21
									
								
								tests/components/wk2132_spi/common.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								tests/components/wk2132_spi/common.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | |||||||
|  | spi: | ||||||
|  |   id: spi_bus | ||||||
|  |   clk_pin: ${clk_pin} | ||||||
|  |   mosi_pin: ${mosi_pin} | ||||||
|  |   miso_pin: ${miso_pin} | ||||||
|  |  | ||||||
|  | wk2132_spi: | ||||||
|  |   - id: wk2132_spi_id | ||||||
|  |     cs_pin: ${cs_pin} | ||||||
|  |     spi_id: spi_bus | ||||||
|  |     crystal: 11059200 | ||||||
|  |     data_rate: 1MHz | ||||||
|  |     uart: | ||||||
|  |       - id: wk2132_spi_id0 | ||||||
|  |         channel: 0 | ||||||
|  |         baud_rate: 115200 | ||||||
|  |         stop_bits: 1 | ||||||
|  |         parity: none | ||||||
|  |       - id: wk2132_spi_id1 | ||||||
|  |         channel: 1 | ||||||
|  |         baud_rate: 921600 | ||||||
							
								
								
									
										7
									
								
								tests/components/wk2132_spi/test.esp32-idf.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								tests/components/wk2132_spi/test.esp32-idf.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | |||||||
|  | substitutions: | ||||||
|  |   clk_pin: GPIO18 | ||||||
|  |   miso_pin: GPIO19 | ||||||
|  |   mosi_pin: GPIO23 | ||||||
|  |   cs_pin: GPIO5 | ||||||
|  |  | ||||||
|  | <<: !include common.yaml | ||||||
							
								
								
									
										7
									
								
								tests/components/wk2132_spi/test.esp32-s3-idf.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								tests/components/wk2132_spi/test.esp32-s3-idf.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | |||||||
|  | substitutions: | ||||||
|  |   clk_pin: GPIO40 | ||||||
|  |   miso_pin: GPIO41 | ||||||
|  |   mosi_pin: GPIO6 | ||||||
|  |   cs_pin: GPIO19 | ||||||
|  |  | ||||||
|  | <<: !include common.yaml | ||||||
							
								
								
									
										7
									
								
								tests/components/wk2132_spi/test.esp32-s3.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								tests/components/wk2132_spi/test.esp32-s3.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | |||||||
|  | substitutions: | ||||||
|  |   clk_pin: GPIO40 | ||||||
|  |   miso_pin: GPIO41 | ||||||
|  |   mosi_pin: GPIO6 | ||||||
|  |   cs_pin: GPIO19 | ||||||
|  |  | ||||||
|  | <<: !include common.yaml | ||||||
							
								
								
									
										7
									
								
								tests/components/wk2132_spi/test.esp32.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								tests/components/wk2132_spi/test.esp32.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | |||||||
|  | substitutions: | ||||||
|  |   clk_pin: GPIO18 | ||||||
|  |   miso_pin: GPIO19 | ||||||
|  |   mosi_pin: GPIO23 | ||||||
|  |   cs_pin: GPIO5 | ||||||
|  |  | ||||||
|  | <<: !include common.yaml | ||||||
							
								
								
									
										63
									
								
								tests/components/wk2168_i2c/common.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								tests/components/wk2168_i2c/common.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,63 @@ | |||||||
|  | i2c: | ||||||
|  |   id: i2c_bus | ||||||
|  |   scl: ${scl_pin} | ||||||
|  |   sda: ${sda_pin} | ||||||
|  |   scan: true | ||||||
|  |   frequency: 600kHz | ||||||
|  |  | ||||||
|  | #  component declaration | ||||||
|  | wk2168_i2c: | ||||||
|  |   - id: bridge_i2c | ||||||
|  |     i2c_id: i2c_bus | ||||||
|  |     address: 0x70 | ||||||
|  |     uart: | ||||||
|  |       - id: id0 | ||||||
|  |         channel: 0 | ||||||
|  |         baud_rate: 115200 | ||||||
|  |         stop_bits: 1 | ||||||
|  |         parity: none | ||||||
|  |       - id: id1 | ||||||
|  |         channel: 1 | ||||||
|  |         baud_rate: 115200 | ||||||
|  |       - id: id2 | ||||||
|  |         channel: 2 | ||||||
|  |         baud_rate: 115200 | ||||||
|  |       - id: id3 | ||||||
|  |         channel: 3 | ||||||
|  |         baud_rate: 115200 | ||||||
|  |  | ||||||
|  | # individual binary_sensor inputs | ||||||
|  | binary_sensor: | ||||||
|  |   - platform: gpio | ||||||
|  |     name: "pin_0" | ||||||
|  |     pin: | ||||||
|  |       wk2168_i2c: bridge_i2c | ||||||
|  |       number: 0 | ||||||
|  |       mode: | ||||||
|  |         input: true | ||||||
|  |   - platform: gpio | ||||||
|  |     name: "pin_1" | ||||||
|  |     pin: | ||||||
|  |       wk2168_i2c: bridge_i2c | ||||||
|  |       number: 1 | ||||||
|  |       mode: | ||||||
|  |         input: true | ||||||
|  |       inverted: true | ||||||
|  |  | ||||||
|  | # Individual binary outputs | ||||||
|  | switch: | ||||||
|  |   - platform: gpio | ||||||
|  |     name: "pin_2" | ||||||
|  |     pin: | ||||||
|  |       wk2168_i2c: bridge_i2c | ||||||
|  |       number: 2 | ||||||
|  |       mode: | ||||||
|  |         output: true | ||||||
|  |   - platform: gpio | ||||||
|  |     name: "pin_3" | ||||||
|  |     pin: | ||||||
|  |       wk2168_i2c: bridge_i2c | ||||||
|  |       number: 3 | ||||||
|  |       mode: | ||||||
|  |         output: true | ||||||
|  |       inverted: true | ||||||
							
								
								
									
										5
									
								
								tests/components/wk2168_i2c/test.esp32-idf.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								tests/components/wk2168_i2c/test.esp32-idf.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | |||||||
|  | substitutions: | ||||||
|  |   scl_pin: GPIO22 | ||||||
|  |   sda_pin: GPIO21 | ||||||
|  |  | ||||||
|  | <<: !include common.yaml | ||||||
							
								
								
									
										5
									
								
								tests/components/wk2168_i2c/test.esp32-s3-idf.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								tests/components/wk2168_i2c/test.esp32-s3-idf.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | |||||||
|  | substitutions: | ||||||
|  |   scl_pin: GPIO40 | ||||||
|  |   sda_pin: GPIO41 | ||||||
|  |  | ||||||
|  | <<: !include common.yaml | ||||||
							
								
								
									
										5
									
								
								tests/components/wk2168_i2c/test.esp32-s3.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								tests/components/wk2168_i2c/test.esp32-s3.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | |||||||
|  | substitutions: | ||||||
|  |   scl_pin: GPIO40 | ||||||
|  |   sda_pin: GPIO41 | ||||||
|  |  | ||||||
|  | <<: !include common.yaml | ||||||
							
								
								
									
										5
									
								
								tests/components/wk2168_i2c/test.esp32.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								tests/components/wk2168_i2c/test.esp32.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | |||||||
|  | substitutions: | ||||||
|  |   scl_pin: GPIO22 | ||||||
|  |   sda_pin: GPIO21 | ||||||
|  |  | ||||||
|  | <<: !include common.yaml | ||||||
							
								
								
									
										63
									
								
								tests/components/wk2168_spi/common.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								tests/components/wk2168_spi/common.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,63 @@ | |||||||
|  | spi: | ||||||
|  |   id: spi_bus | ||||||
|  |   clk_pin: ${clk_pin} | ||||||
|  |   mosi_pin: ${mosi_pin} | ||||||
|  |   miso_pin: ${miso_pin} | ||||||
|  |  | ||||||
|  | wk2168_spi: | ||||||
|  |   - id: bridge_spi | ||||||
|  |     cs_pin: ${cs_pin} | ||||||
|  |     spi_id: spi_bus | ||||||
|  |     crystal: 11059200 | ||||||
|  |     data_rate: 1MHz | ||||||
|  |     uart: | ||||||
|  |       - id: id0 | ||||||
|  |         channel: 0 | ||||||
|  |         baud_rate: 115200 | ||||||
|  |         stop_bits: 1 | ||||||
|  |         parity: none | ||||||
|  |       - id: id1 | ||||||
|  |         channel: 1 | ||||||
|  |         baud_rate: 115200 | ||||||
|  |       - id: id2 | ||||||
|  |         channel: 2 | ||||||
|  |         baud_rate: 115200 | ||||||
|  |       - id: id3 | ||||||
|  |         channel: 3 | ||||||
|  |         baud_rate: 115200 | ||||||
|  |  | ||||||
|  | # individual binary_sensor inputs | ||||||
|  | binary_sensor: | ||||||
|  |   - platform: gpio | ||||||
|  |     name: "pin_0" | ||||||
|  |     pin: | ||||||
|  |       wk2168_spi: bridge_spi | ||||||
|  |       number: 0 | ||||||
|  |       mode: | ||||||
|  |         input: true | ||||||
|  |   - platform: gpio | ||||||
|  |     name: "pin_1" | ||||||
|  |     pin: | ||||||
|  |       wk2168_spi: bridge_spi | ||||||
|  |       number: 1 | ||||||
|  |       mode: | ||||||
|  |         input: true | ||||||
|  |       inverted: true | ||||||
|  |  | ||||||
|  | # Individual binary outputs | ||||||
|  | switch: | ||||||
|  |   - platform: gpio | ||||||
|  |     name: "pin_2" | ||||||
|  |     pin: | ||||||
|  |       wk2168_spi: bridge_spi | ||||||
|  |       number: 2 | ||||||
|  |       mode: | ||||||
|  |         output: true | ||||||
|  |   - platform: gpio | ||||||
|  |     name: "pin_3" | ||||||
|  |     pin: | ||||||
|  |       wk2168_spi: bridge_spi | ||||||
|  |       number: 3 | ||||||
|  |       mode: | ||||||
|  |         output: true | ||||||
|  |       inverted: true | ||||||
							
								
								
									
										7
									
								
								tests/components/wk2168_spi/test.esp32-idf.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								tests/components/wk2168_spi/test.esp32-idf.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | |||||||
|  | substitutions: | ||||||
|  |   clk_pin: GPIO18 | ||||||
|  |   miso_pin: GPIO19 | ||||||
|  |   mosi_pin: GPIO23 | ||||||
|  |   cs_pin: GPIO5 | ||||||
|  |  | ||||||
|  | <<: !include common.yaml | ||||||
							
								
								
									
										7
									
								
								tests/components/wk2168_spi/test.esp32-s3-idf.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								tests/components/wk2168_spi/test.esp32-s3-idf.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | |||||||
|  | substitutions: | ||||||
|  |   clk_pin: GPIO40 | ||||||
|  |   miso_pin: GPIO41 | ||||||
|  |   mosi_pin: GPIO6 | ||||||
|  |   cs_pin: GPIO19 | ||||||
|  |  | ||||||
|  | <<: !include common.yaml | ||||||
							
								
								
									
										7
									
								
								tests/components/wk2168_spi/test.esp32-s3.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								tests/components/wk2168_spi/test.esp32-s3.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | |||||||
|  | substitutions: | ||||||
|  |   clk_pin: GPIO40 | ||||||
|  |   miso_pin: GPIO41 | ||||||
|  |   mosi_pin: GPIO6 | ||||||
|  |   cs_pin: GPIO19 | ||||||
|  |  | ||||||
|  | <<: !include common.yaml | ||||||
							
								
								
									
										7
									
								
								tests/components/wk2168_spi/test.esp32.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								tests/components/wk2168_spi/test.esp32.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | |||||||
|  | substitutions: | ||||||
|  |   clk_pin: GPIO18 | ||||||
|  |   miso_pin: GPIO19 | ||||||
|  |   mosi_pin: GPIO23 | ||||||
|  |   cs_pin: GPIO5 | ||||||
|  |  | ||||||
|  | <<: !include common.yaml | ||||||
							
								
								
									
										28
									
								
								tests/components/wk2204_i2c/common.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								tests/components/wk2204_i2c/common.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,28 @@ | |||||||
|  | i2c: | ||||||
|  |   id: i2c_bus | ||||||
|  |   scl: ${scl_pin} | ||||||
|  |   sda: ${sda_pin} | ||||||
|  |   scan: true | ||||||
|  |   frequency: 600kHz | ||||||
|  |  | ||||||
|  | wk2204_i2c: | ||||||
|  |   - id: wk2204_i2c_id | ||||||
|  |     i2c_id: i2c_bus | ||||||
|  |     address: 0x70 | ||||||
|  |     uart: | ||||||
|  |       - id: wk2204_id_0 | ||||||
|  |         channel: 0 | ||||||
|  |         baud_rate: 115200 | ||||||
|  |         stop_bits: 1 | ||||||
|  |         parity: none | ||||||
|  |       - id: wk2204_id_1 | ||||||
|  |         channel: 1 | ||||||
|  |         baud_rate: 19200 | ||||||
|  |       - id: wk2204_id_2 | ||||||
|  |         channel: 2 | ||||||
|  |         baud_rate: 115200 | ||||||
|  |         stop_bits: 1 | ||||||
|  |         parity: none | ||||||
|  |       - id: wk2204_id_3 | ||||||
|  |         channel: 3 | ||||||
|  |         baud_rate: 19200 | ||||||
							
								
								
									
										5
									
								
								tests/components/wk2204_i2c/test.esp32-idf.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								tests/components/wk2204_i2c/test.esp32-idf.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | |||||||
|  | substitutions: | ||||||
|  |   scl_pin: GPIO22 | ||||||
|  |   sda_pin: GPIO21 | ||||||
|  |  | ||||||
|  | <<: !include common.yaml | ||||||
							
								
								
									
										5
									
								
								tests/components/wk2204_i2c/test.esp32-s3-idf.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								tests/components/wk2204_i2c/test.esp32-s3-idf.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | |||||||
|  | substitutions: | ||||||
|  |   scl_pin: GPIO40 | ||||||
|  |   sda_pin: GPIO41 | ||||||
|  |  | ||||||
|  | <<: !include common.yaml | ||||||
							
								
								
									
										5
									
								
								tests/components/wk2204_i2c/test.esp32-s3.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								tests/components/wk2204_i2c/test.esp32-s3.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | |||||||
|  | substitutions: | ||||||
|  |   scl_pin: GPIO40 | ||||||
|  |   sda_pin: GPIO41 | ||||||
|  |  | ||||||
|  | <<: !include common.yaml | ||||||
							
								
								
									
										5
									
								
								tests/components/wk2204_i2c/test.esp32.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								tests/components/wk2204_i2c/test.esp32.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | |||||||
|  | substitutions: | ||||||
|  |   scl_pin: GPIO22 | ||||||
|  |   sda_pin: GPIO21 | ||||||
|  |  | ||||||
|  | <<: !include common.yaml | ||||||
							
								
								
									
										29
									
								
								tests/components/wk2204_spi/common.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								tests/components/wk2204_spi/common.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | |||||||
|  | spi: | ||||||
|  |   id: spi_bus | ||||||
|  |   clk_pin: ${clk_pin} | ||||||
|  |   mosi_pin: ${mosi_pin} | ||||||
|  |   miso_pin: ${miso_pin} | ||||||
|  |  | ||||||
|  | wk2204_spi: | ||||||
|  |   - id: wk2204_spi_id | ||||||
|  |     cs_pin: ${cs_pin} | ||||||
|  |     spi_id: spi_bus | ||||||
|  |     crystal: 11059200 | ||||||
|  |     data_rate: 1MHz | ||||||
|  |     uart: | ||||||
|  |       - id: wk2204_spi_id0 | ||||||
|  |         channel: 0 | ||||||
|  |         baud_rate: 115200 | ||||||
|  |         stop_bits: 1 | ||||||
|  |         parity: none | ||||||
|  |       - id: wk2204_spi_id1 | ||||||
|  |         channel: 1 | ||||||
|  |         baud_rate: 921600 | ||||||
|  |       - id: wk2204_spi_id2 | ||||||
|  |         channel: 2 | ||||||
|  |         baud_rate: 115200 | ||||||
|  |         stop_bits: 1 | ||||||
|  |         parity: none | ||||||
|  |       - id: wk2204_spi_id3 | ||||||
|  |         channel: 3 | ||||||
|  |         baud_rate: 921600 | ||||||
							
								
								
									
										7
									
								
								tests/components/wk2204_spi/test.esp32-idf.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								tests/components/wk2204_spi/test.esp32-idf.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | |||||||
|  | substitutions: | ||||||
|  |   clk_pin: GPIO18 | ||||||
|  |   miso_pin: GPIO19 | ||||||
|  |   mosi_pin: GPIO23 | ||||||
|  |   cs_pin: GPIO5 | ||||||
|  |  | ||||||
|  | <<: !include common.yaml | ||||||
							
								
								
									
										7
									
								
								tests/components/wk2204_spi/test.esp32-s3-idf.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								tests/components/wk2204_spi/test.esp32-s3-idf.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | |||||||
|  | substitutions: | ||||||
|  |   clk_pin: GPIO40 | ||||||
|  |   miso_pin: GPIO41 | ||||||
|  |   mosi_pin: GPIO6 | ||||||
|  |   cs_pin: GPIO19 | ||||||
|  |  | ||||||
|  | <<: !include common.yaml | ||||||
							
								
								
									
										7
									
								
								tests/components/wk2204_spi/test.esp32-s3.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								tests/components/wk2204_spi/test.esp32-s3.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | |||||||
|  | substitutions: | ||||||
|  |   clk_pin: GPIO40 | ||||||
|  |   miso_pin: GPIO41 | ||||||
|  |   mosi_pin: GPIO6 | ||||||
|  |   cs_pin: GPIO19 | ||||||
|  |  | ||||||
|  | <<: !include common.yaml | ||||||
							
								
								
									
										7
									
								
								tests/components/wk2204_spi/test.esp32.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								tests/components/wk2204_spi/test.esp32.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | |||||||
|  | substitutions: | ||||||
|  |   clk_pin: GPIO18 | ||||||
|  |   miso_pin: GPIO19 | ||||||
|  |   mosi_pin: GPIO23 | ||||||
|  |   cs_pin: GPIO5 | ||||||
|  |  | ||||||
|  | <<: !include common.yaml | ||||||
							
								
								
									
										59
									
								
								tests/components/wk2212_i2c/common.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								tests/components/wk2212_i2c/common.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,59 @@ | |||||||
|  | i2c: | ||||||
|  |   id: i2c_bus | ||||||
|  |   scl: ${scl_pin} | ||||||
|  |   sda: ${sda_pin} | ||||||
|  |   scan: true | ||||||
|  |   frequency: 600kHz | ||||||
|  |  | ||||||
|  | #  component declaration | ||||||
|  | wk2212_i2c: | ||||||
|  |   - id: bridge_i2c | ||||||
|  |     i2c_id: i2c_bus | ||||||
|  |     address: 0x70 | ||||||
|  |     uart: | ||||||
|  |       - id: uart_i2c_id0 | ||||||
|  |         channel: 0 | ||||||
|  |         baud_rate: 115200 | ||||||
|  |         stop_bits: 1 | ||||||
|  |         parity: none | ||||||
|  |       - id: uart_i2c_id1 | ||||||
|  |         channel: 1 | ||||||
|  |         baud_rate: 115200 | ||||||
|  |         stop_bits: 1 | ||||||
|  |         parity: none | ||||||
|  |  | ||||||
|  | # individual binary_sensor inputs | ||||||
|  | binary_sensor: | ||||||
|  |   - platform: gpio | ||||||
|  |     name: "pin_0" | ||||||
|  |     pin: | ||||||
|  |       wk2212_i2c: bridge_i2c | ||||||
|  |       number: 0 | ||||||
|  |       mode: | ||||||
|  |         input: true | ||||||
|  |   - platform: gpio | ||||||
|  |     name: "pin_1" | ||||||
|  |     pin: | ||||||
|  |       wk2212_i2c: bridge_i2c | ||||||
|  |       number: 1 | ||||||
|  |       mode: | ||||||
|  |         input: true | ||||||
|  |       inverted: true | ||||||
|  |  | ||||||
|  | # Individual binary outputs | ||||||
|  | switch: | ||||||
|  |   - platform: gpio | ||||||
|  |     name: "pin_2" | ||||||
|  |     pin: | ||||||
|  |       wk2212_i2c: bridge_i2c | ||||||
|  |       number: 2 | ||||||
|  |       mode: | ||||||
|  |         output: true | ||||||
|  |   - platform: gpio | ||||||
|  |     name: "pin_3" | ||||||
|  |     pin: | ||||||
|  |       wk2212_i2c: bridge_i2c | ||||||
|  |       number: 3 | ||||||
|  |       mode: | ||||||
|  |         output: true | ||||||
|  |       inverted: true | ||||||
							
								
								
									
										5
									
								
								tests/components/wk2212_i2c/test.esp32-idf.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								tests/components/wk2212_i2c/test.esp32-idf.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | |||||||
|  | substitutions: | ||||||
|  |   scl_pin: GPIO22 | ||||||
|  |   sda_pin: GPIO21 | ||||||
|  |  | ||||||
|  | <<: !include common.yaml | ||||||
							
								
								
									
										5
									
								
								tests/components/wk2212_i2c/test.esp32-s3-idf.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								tests/components/wk2212_i2c/test.esp32-s3-idf.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | |||||||
|  | substitutions: | ||||||
|  |   scl_pin: GPIO40 | ||||||
|  |   sda_pin: GPIO41 | ||||||
|  |  | ||||||
|  | <<: !include common.yaml | ||||||
							
								
								
									
										5
									
								
								tests/components/wk2212_i2c/test.esp32-s3.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								tests/components/wk2212_i2c/test.esp32-s3.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | |||||||
|  | substitutions: | ||||||
|  |   scl_pin: GPIO40 | ||||||
|  |   sda_pin: GPIO41 | ||||||
|  |  | ||||||
|  | <<: !include common.yaml | ||||||
							
								
								
									
										5
									
								
								tests/components/wk2212_i2c/test.esp32.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								tests/components/wk2212_i2c/test.esp32.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | |||||||
|  | substitutions: | ||||||
|  |   scl_pin: GPIO22 | ||||||
|  |   sda_pin: GPIO21 | ||||||
|  |  | ||||||
|  | <<: !include common.yaml | ||||||
							
								
								
									
										58
									
								
								tests/components/wk2212_spi/common.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								tests/components/wk2212_spi/common.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,58 @@ | |||||||
|  | spi: | ||||||
|  |   id: spi_bus | ||||||
|  |   clk_pin: ${clk_pin} | ||||||
|  |   mosi_pin: ${mosi_pin} | ||||||
|  |   miso_pin: ${miso_pin} | ||||||
|  |  | ||||||
|  | wk2212_spi: | ||||||
|  |   - id: bridge_spi | ||||||
|  |     cs_pin: ${cs_pin} | ||||||
|  |     spi_id: spi_bus | ||||||
|  |     crystal: 11059200 | ||||||
|  |     data_rate: 1MHz | ||||||
|  |     uart: | ||||||
|  |       - id: id0 | ||||||
|  |         channel: 0 | ||||||
|  |         baud_rate: 115200 | ||||||
|  |         stop_bits: 1 | ||||||
|  |         parity: none | ||||||
|  |       - id: id1 | ||||||
|  |         channel: 1 | ||||||
|  |         baud_rate: 115200 | ||||||
|  |  | ||||||
|  | # individual binary_sensor inputs | ||||||
|  | binary_sensor: | ||||||
|  |   - platform: gpio | ||||||
|  |     name: "pin_0" | ||||||
|  |     pin: | ||||||
|  |       wk2212_spi: bridge_spi | ||||||
|  |       number: 0 | ||||||
|  |       mode: | ||||||
|  |         input: true | ||||||
|  |   - platform: gpio | ||||||
|  |     name: "pin_1" | ||||||
|  |     pin: | ||||||
|  |       wk2212_spi: bridge_spi | ||||||
|  |       number: 1 | ||||||
|  |       mode: | ||||||
|  |         input: true | ||||||
|  |       inverted: true | ||||||
|  |  | ||||||
|  | # Individual binary outputs | ||||||
|  | switch: | ||||||
|  |   - platform: gpio | ||||||
|  |     name: "pin_2" | ||||||
|  |     pin: | ||||||
|  |       wk2212_spi: bridge_spi | ||||||
|  |       number: 2 | ||||||
|  |       mode: | ||||||
|  |         output: true | ||||||
|  |   - platform: gpio | ||||||
|  |     name: "pin_3" | ||||||
|  |     pin: | ||||||
|  |       wk2212_spi: bridge_spi | ||||||
|  |       number: 3 | ||||||
|  |       mode: | ||||||
|  |         output: true | ||||||
|  |       inverted: true | ||||||
|  |  | ||||||
							
								
								
									
										7
									
								
								tests/components/wk2212_spi/test.esp32-idf.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								tests/components/wk2212_spi/test.esp32-idf.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | |||||||
|  | substitutions: | ||||||
|  |   clk_pin: GPIO18 | ||||||
|  |   miso_pin: GPIO19 | ||||||
|  |   mosi_pin: GPIO23 | ||||||
|  |   cs_pin: GPIO5 | ||||||
|  |  | ||||||
|  | <<: !include common.yaml | ||||||
							
								
								
									
										7
									
								
								tests/components/wk2212_spi/test.esp32-s3-idf.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								tests/components/wk2212_spi/test.esp32-s3-idf.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | |||||||
|  | substitutions: | ||||||
|  |   clk_pin: GPIO40 | ||||||
|  |   miso_pin: GPIO41 | ||||||
|  |   mosi_pin: GPIO6 | ||||||
|  |   cs_pin: GPIO19 | ||||||
|  |  | ||||||
|  | <<: !include common.yaml | ||||||
							
								
								
									
										7
									
								
								tests/components/wk2212_spi/test.esp32-s3.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								tests/components/wk2212_spi/test.esp32-s3.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | |||||||
|  | substitutions: | ||||||
|  |   clk_pin: GPIO40 | ||||||
|  |   miso_pin: GPIO41 | ||||||
|  |   mosi_pin: GPIO6 | ||||||
|  |   cs_pin: GPIO19 | ||||||
|  |  | ||||||
|  | <<: !include common.yaml | ||||||
							
								
								
									
										7
									
								
								tests/components/wk2212_spi/test.esp32.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								tests/components/wk2212_spi/test.esp32.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | |||||||
|  | substitutions: | ||||||
|  |   clk_pin: GPIO18 | ||||||
|  |   miso_pin: GPIO19 | ||||||
|  |   mosi_pin: GPIO23 | ||||||
|  |   cs_pin: GPIO5 | ||||||
|  |  | ||||||
|  | <<: !include common.yaml | ||||||
		Reference in New Issue
	
	Block a user