mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-22 11:43:51 +01:00 
			
		
		
		
	Fix SN74HC595 doesn't use ESPHome HAL and add lint checks for it (#1188)
This commit is contained in:
		| @@ -58,7 +58,7 @@ void ADCSensor::update() { | |||||||
| } | } | ||||||
| float ADCSensor::sample() { | float ADCSensor::sample() { | ||||||
| #ifdef ARDUINO_ARCH_ESP32 | #ifdef ARDUINO_ARCH_ESP32 | ||||||
|   float value_v = analogRead(this->pin_) / 4095.0f; |   float value_v = analogRead(this->pin_) / 4095.0f;  // NOLINT | ||||||
|   switch (this->attenuation_) { |   switch (this->attenuation_) { | ||||||
|     case ADC_0db: |     case ADC_0db: | ||||||
|       value_v *= 1.1; |       value_v *= 1.1; | ||||||
| @@ -80,7 +80,7 @@ float ADCSensor::sample() { | |||||||
| #ifdef USE_ADC_SENSOR_VCC | #ifdef USE_ADC_SENSOR_VCC | ||||||
|   return ESP.getVcc() / 1024.0f; |   return ESP.getVcc() / 1024.0f; | ||||||
| #else | #else | ||||||
|   return analogRead(this->pin_) / 1024.0f; |   return analogRead(this->pin_) / 1024.0f;  // NOLINT | ||||||
| #endif | #endif | ||||||
| #endif | #endif | ||||||
| } | } | ||||||
|   | |||||||
| @@ -101,7 +101,7 @@ void MAX7219Component::loop() { | |||||||
| } | } | ||||||
|  |  | ||||||
| void MAX7219Component::display() { | void MAX7219Component::display() { | ||||||
|   byte pixels[8]; |   uint8_t pixels[8]; | ||||||
|   // Run this loop for every MAX CHIP (GRID OF 64 leds) |   // Run this loop for every MAX CHIP (GRID OF 64 leds) | ||||||
|   // Run this routine for the rows of every chip 8x row 0 top to 7 bottom |   // Run this routine for the rows of every chip 8x row 0 top to 7 bottom | ||||||
|   // Fill the pixel parameter with diplay data |   // Fill the pixel parameter with diplay data | ||||||
| @@ -205,29 +205,32 @@ void MAX7219Component::scroll_left() { | |||||||
|   this->stepsleft_++; |   this->stepsleft_++; | ||||||
| } | } | ||||||
|  |  | ||||||
| void MAX7219Component::send_char(byte chip, byte data) { | void MAX7219Component::send_char(uint8_t chip, uint8_t data) { | ||||||
|   // get this character from PROGMEM |   // get this character from PROGMEM | ||||||
|   for (byte i = 0; i < 8; i++) |   for (uint8_t i = 0; i < 8; i++) | ||||||
|     this->max_displaybuffer_[chip * 8 + i] = pgm_read_byte(&MAX7219_DOT_MATRIX_FONT[data][i]); |     this->max_displaybuffer_[chip * 8 + i] = pgm_read_byte(&MAX7219_DOT_MATRIX_FONT[data][i]); | ||||||
| }  // end of send_char | }  // end of send_char | ||||||
|  |  | ||||||
| // send one character (data) to position (chip) | // send one character (data) to position (chip) | ||||||
|  |  | ||||||
| void MAX7219Component::send64pixels(byte chip, const byte pixels[8]) { | void MAX7219Component::send64pixels(uint8_t chip, const uint8_t pixels[8]) { | ||||||
|   for (byte col = 0; col < 8; col++) {  // RUN THIS LOOP 8 times until column is 7 |   for (uint8_t col = 0; col < 8; col++) {  // RUN THIS LOOP 8 times until column is 7 | ||||||
|     this->enable();                        // start sending by enabling SPI |     this->enable();                        // start sending by enabling SPI | ||||||
|     for (byte i = 0; i < chip; i++)     // send extra NOPs to push the pixels out to extra displays |     for (uint8_t i = 0; i < chip; i++)     // send extra NOPs to push the pixels out to extra displays | ||||||
|       this->send_byte_(MAX7219_REGISTER_NOOP, |       this->send_byte_(MAX7219_REGISTER_NOOP, | ||||||
|                        MAX7219_REGISTER_NOOP);  // run this loop unit the matching chip is reached |                        MAX7219_REGISTER_NOOP);  // run this loop unit the matching chip is reached | ||||||
|     byte b = 0;                                 // rotate pixels 90 degrees -- set byte to 0 |     uint8_t b = 0;                              // rotate pixels 90 degrees -- set byte to 0 | ||||||
|     if (this->orientation_ == 0) { |     if (this->orientation_ == 0) { | ||||||
|       for (byte i = 0; i < 8; i++)                // run this loop 8 times for all the pixels[8] received |       for (uint8_t i = 0; i < 8; i++) { | ||||||
|         b |= bitRead(pixels[i], col) << (7 - i);  // change the column bits into row bits |         // run this loop 8 times for all the pixels[8] received | ||||||
|  |         b |= ((pixels[i] >> col) & 1) << (7 - i);  // change the column bits into row bits | ||||||
|  |       } | ||||||
|     } else if (this->orientation_ == 1) { |     } else if (this->orientation_ == 1) { | ||||||
|       b = pixels[col]; |       b = pixels[col]; | ||||||
|     } else if (this->orientation_ == 2) { |     } else if (this->orientation_ == 2) { | ||||||
|       for (byte i = 0; i < 8; i++) |       for (uint8_t i = 0; i < 8; i++) { | ||||||
|         b |= bitRead(pixels[i], 7 - col) << (7 - i); |         b |= ((pixels[i] >> (7 - col)) << (7 - i)); | ||||||
|  |       } | ||||||
|     } else { |     } else { | ||||||
|       b = pixels[7 - col]; |       b = pixels[7 - col]; | ||||||
|     } |     } | ||||||
| @@ -246,8 +249,8 @@ void MAX7219Component::send64pixels(byte chip, const byte pixels[8]) { | |||||||
| uint8_t MAX7219Component::printdigit(const char *str) { return this->printdigit(0, str); } | uint8_t MAX7219Component::printdigit(const char *str) { return this->printdigit(0, str); } | ||||||
|  |  | ||||||
| uint8_t MAX7219Component::printdigit(uint8_t start_pos, const char *s) { | uint8_t MAX7219Component::printdigit(uint8_t start_pos, const char *s) { | ||||||
|   byte chip; |   uint8_t chip = start_pos; | ||||||
|   for (chip = start_pos; chip < this->num_chips_ && *s; chip++) |   for (; chip < this->num_chips_ && *s; chip++) | ||||||
|     send_char(chip, *s++); |     send_char(chip, *s++); | ||||||
|   // space out rest |   // space out rest | ||||||
|   while (chip < (this->num_chips_)) |   while (chip < (this->num_chips_)) | ||||||
|   | |||||||
| @@ -19,10 +19,10 @@ void MCP3008::dump_config() { | |||||||
| } | } | ||||||
|  |  | ||||||
| float MCP3008::read_data_(uint8_t pin) { | float MCP3008::read_data_(uint8_t pin) { | ||||||
|   byte data_msb = 0; |   uint8_t data_msb = 0; | ||||||
|   byte data_lsb = 0; |   uint8_t data_lsb = 0; | ||||||
|  |  | ||||||
|   byte command = ((0x01 << 7) |          // start bit |   uint8_t command = ((0x01 << 7) |          // start bit | ||||||
|                      ((pin & 0x07) << 4));  // channel number |                      ((pin & 0x07) << 4));  // channel number | ||||||
|  |  | ||||||
|   this->enable(); |   this->enable(); | ||||||
|   | |||||||
| @@ -10,17 +10,17 @@ void SN74HC595Component::setup() { | |||||||
|   ESP_LOGCONFIG(TAG, "Setting up SN74HC595..."); |   ESP_LOGCONFIG(TAG, "Setting up SN74HC595..."); | ||||||
|  |  | ||||||
|   if (this->have_oe_pin_) {  // disable output |   if (this->have_oe_pin_) {  // disable output | ||||||
|     pinMode(this->oe_pin_->get_pin(), OUTPUT); |     this->oe_pin_->pin_mode(OUTPUT); | ||||||
|     digitalWrite(this->oe_pin_->get_pin(), HIGH); |     this->oe_pin_->digital_write(true); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   // initialize output pins |   // initialize output pins | ||||||
|   pinMode(this->clock_pin_->get_pin(), OUTPUT); |   this->clock_pin_->pin_mode(OUTPUT); | ||||||
|   pinMode(this->data_pin_->get_pin(), OUTPUT); |   this->data_pin_->pin_mode(OUTPUT); | ||||||
|   pinMode(this->latch_pin_->get_pin(), OUTPUT); |   this->latch_pin_->pin_mode(OUTPUT); | ||||||
|   digitalWrite(this->clock_pin_->get_pin(), LOW); |   this->clock_pin_->digital_write(LOW); | ||||||
|   digitalWrite(this->data_pin_->get_pin(), LOW); |   this->data_pin_->digital_write(LOW); | ||||||
|   digitalWrite(this->latch_pin_->get_pin(), LOW); |   this->latch_pin_->digital_write(LOW); | ||||||
|  |  | ||||||
|   // send state to shift register |   // send state to shift register | ||||||
|   this->write_gpio_(); |   this->write_gpio_(); | ||||||
| @@ -28,26 +28,33 @@ void SN74HC595Component::setup() { | |||||||
|  |  | ||||||
| void SN74HC595Component::dump_config() { ESP_LOGCONFIG(TAG, "SN74HC595:"); } | void SN74HC595Component::dump_config() { ESP_LOGCONFIG(TAG, "SN74HC595:"); } | ||||||
|  |  | ||||||
| bool SN74HC595Component::digital_read_(uint8_t pin) { return bitRead(this->output_bits_, pin); } | bool SN74HC595Component::digital_read_(uint8_t pin) { return this->output_bits_ >> pin; } | ||||||
|  |  | ||||||
| void SN74HC595Component::digital_write_(uint8_t pin, bool value) { | void SN74HC595Component::digital_write_(uint8_t pin, bool value) { | ||||||
|   bitWrite(this->output_bits_, pin, value); |   uint32_t mask = 1UL << pin; | ||||||
|  |   this->output_bits_ &= ~mask; | ||||||
|  |   if (value) | ||||||
|  |     this->output_bits_ |= mask; | ||||||
|   this->write_gpio_(); |   this->write_gpio_(); | ||||||
| } | } | ||||||
|  |  | ||||||
| bool SN74HC595Component::write_gpio_() { | bool SN74HC595Component::write_gpio_() { | ||||||
|   for (int i = this->sr_count_ - 1; i >= 0; i--) { |   for (int i = this->sr_count_ - 1; i >= 0; i--) { | ||||||
|     uint8_t data = (uint8_t)(this->output_bits_ >> (8 * i) & 0xff); |     uint8_t data = (uint8_t)(this->output_bits_ >> (8 * i) & 0xff); | ||||||
|     shiftOut(this->data_pin_->get_pin(), this->clock_pin_->get_pin(), MSBFIRST, data); |     for (int j = 0; j < 8; j++) { | ||||||
|  |       this->data_pin_->digital_write(data & (1 << (7 - j))); | ||||||
|  |       this->clock_pin_->digital_write(true); | ||||||
|  |       this->clock_pin_->digital_write(false); | ||||||
|  |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   // pulse latch to activate new values |   // pulse latch to activate new values | ||||||
|   digitalWrite(this->latch_pin_->get_pin(), HIGH); |   this->latch_pin_->digital_write(true); | ||||||
|   digitalWrite(this->latch_pin_->get_pin(), LOW); |   this->latch_pin_->digital_write(false); | ||||||
|  |  | ||||||
|   // enable output if configured |   // enable output if configured | ||||||
|   if (this->have_oe_pin_) { |   if (this->have_oe_pin_) { | ||||||
|     digitalWrite(this->oe_pin_->get_pin(), LOW); |     this->oe_pin_->digital_write(false); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   return true; |   return true; | ||||||
|   | |||||||
| @@ -144,7 +144,7 @@ void SX1509Component::clock_(byte osc_source, byte osc_pin_function, byte osc_fr | |||||||
|   osc_source = (osc_source & 0b11) << 5;           // 2-bit value, bits 6:5 |   osc_source = (osc_source & 0b11) << 5;           // 2-bit value, bits 6:5 | ||||||
|   osc_pin_function = (osc_pin_function & 1) << 4;  // 1-bit value bit 4 |   osc_pin_function = (osc_pin_function & 1) << 4;  // 1-bit value bit 4 | ||||||
|   osc_freq_out = (osc_freq_out & 0b1111);          // 4-bit value, bits 3:0 |   osc_freq_out = (osc_freq_out & 0b1111);          // 4-bit value, bits 3:0 | ||||||
|   byte reg_clock = osc_source | osc_pin_function | osc_freq_out; |   uint8_t reg_clock = osc_source | osc_pin_function | osc_freq_out; | ||||||
|   this->write_byte(REG_CLOCK, reg_clock); |   this->write_byte(REG_CLOCK, reg_clock); | ||||||
|  |  | ||||||
|   osc_divider = constrain(osc_divider, 1, 7); |   osc_divider = constrain(osc_divider, 1, 7); | ||||||
|   | |||||||
| @@ -17,7 +17,8 @@ void UltrasonicSensorComponent::update() { | |||||||
|   delayMicroseconds(this->pulse_time_us_); |   delayMicroseconds(this->pulse_time_us_); | ||||||
|   this->trigger_pin_->digital_write(false); |   this->trigger_pin_->digital_write(false); | ||||||
|  |  | ||||||
|   uint32_t time = pulseIn(this->echo_pin_->get_pin(), uint8_t(!this->echo_pin_->is_inverted()), this->timeout_us_); |   uint32_t time = pulseIn(  // NOLINT | ||||||
|  |       this->echo_pin_->get_pin(), uint8_t(!this->echo_pin_->is_inverted()), this->timeout_us_); | ||||||
|  |  | ||||||
|   ESP_LOGV(TAG, "Echo took %uµs", time); |   ESP_LOGV(TAG, "Echo took %uµs", time); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -255,6 +255,63 @@ def lint_conf_from_const_py(fname, match): | |||||||
|             "const.py directly.".format(highlight(name))) |             "const.py directly.".format(highlight(name))) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | RAW_PIN_ACCESS_RE = r'^\s(pinMode|digitalWrite|digitalRead)\((.*)->get_pin\(\),\s*([^)]+).*\)' | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @lint_re_check(RAW_PIN_ACCESS_RE, include=cpp_include) | ||||||
|  | def lint_no_raw_pin_access(fname, match): | ||||||
|  |     func = match.group(1) | ||||||
|  |     pin = match.group(2) | ||||||
|  |     mode = match.group(3) | ||||||
|  |     new_func = { | ||||||
|  |         'pinMode': 'pin_mode', | ||||||
|  |         'digitalWrite': 'digital_write', | ||||||
|  |         'digitalRead': 'digital_read', | ||||||
|  |     }[func] | ||||||
|  |     new_code = highlight(f'{pin}->{new_func}({mode})') | ||||||
|  |     return (f"Don't use raw {func} calls. Instead, use the `->{new_func}` function: {new_code}") | ||||||
|  |  | ||||||
|  |  | ||||||
|  | # Functions from Arduino framework that are forbidden to use directly | ||||||
|  | ARDUINO_FORBIDDEN = [ | ||||||
|  |     'digitalWrite', 'digitalRead', 'pinMode', | ||||||
|  |     'shiftOut', 'shiftIn', | ||||||
|  |     'radians', 'degrees', | ||||||
|  |     'interrupts', 'noInterrupts', | ||||||
|  |     'lowByte', 'highByte', | ||||||
|  |     'bitRead', 'bitSet', 'bitClear', 'bitWrite', | ||||||
|  |     'bit', 'analogRead', 'analogWrite', | ||||||
|  |     'pulseIn', 'pulseInLong', | ||||||
|  |     'tone', | ||||||
|  | ] | ||||||
|  | ARDUINO_FORBIDDEN_RE = r'[^\w\d](' + r'|'.join(ARDUINO_FORBIDDEN) + r')\(.*' | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @lint_re_check(ARDUINO_FORBIDDEN_RE, include=cpp_include, exclude=[ | ||||||
|  |     'esphome/components/mqtt/custom_mqtt_device.h', | ||||||
|  |     'esphome/core/esphal.*', | ||||||
|  | ]) | ||||||
|  | def lint_no_arduino_framework_functions(fname, match): | ||||||
|  |     nolint = highlight("// NOLINT") | ||||||
|  |     return ( | ||||||
|  |         f"The function {highlight(match.group(1))} from the Arduino framework is forbidden to be " | ||||||
|  |         f"used directly in the ESPHome codebase. Please use ESPHome's abstractions and equivalent " | ||||||
|  |         f"C++ instead.\n" | ||||||
|  |         f"\n" | ||||||
|  |         f"(If the function is strictly necessary, please add `{nolint}` to the end of the line)" | ||||||
|  |     ) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @lint_re_check(r'[^\w\d]byte\s+[\w\d]+\s*=.*', include=cpp_include, exclude={ | ||||||
|  |     'esphome/components/tuya/tuya.h', | ||||||
|  | }) | ||||||
|  | def lint_no_byte_datatype(fname, match): | ||||||
|  |     return ( | ||||||
|  |         f"The datatype {highlight('byte')} is not allowed to be used in ESPHome. " | ||||||
|  |         f"Please use {highlight('uint8_t')} instead." | ||||||
|  |     ) | ||||||
|  |  | ||||||
|  |  | ||||||
| @lint_post_check | @lint_post_check | ||||||
| def lint_constants_usage(): | def lint_constants_usage(): | ||||||
|     errors = [] |     errors = [] | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user