313 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			313 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| #include "zh_ac_dimmer.h"
 | |
| 
 | |
| static const char *TAG = "zh_ac_dimmer";
 | |
| 
 | |
| #define ZH_LOGI(msg, ...) ESP_LOGI(TAG, msg, ##__VA_ARGS__)
 | |
| #define ZH_LOGW(msg, ...) ESP_LOGW(TAG, msg, ##__VA_ARGS__)
 | |
| #define ZH_LOGE(msg, ...) ESP_LOGE(TAG, msg, ##__VA_ARGS__)
 | |
| #define ZH_LOGE_ERR(msg, err, ...) ESP_LOGE(TAG, "[%s:%d:%s] " msg, __FILE__, __LINE__, esp_err_to_name(err), ##__VA_ARGS__)
 | |
| 
 | |
| #define ZH_ERROR_CHECK(cond, err, msg, ...) \
 | |
|     if (!(cond))                            \
 | |
|     {                                       \
 | |
|         ZH_LOGE_ERR(msg, err);              \
 | |
|         return err;                         \
 | |
|     }
 | |
| 
 | |
| #define ZH_ERROR_CHECK_GOTO(cond, err, tag, msg, ...) \
 | |
|     if (!(cond))                                      \
 | |
|     {                                                 \
 | |
|         ZH_LOGE_ERR(msg, err);                        \
 | |
|         goto tag;                                     \
 | |
|     }
 | |
| 
 | |
| static zh_ac_dimmer_init_config_t _init_config = {0};
 | |
| volatile static bool _is_dimmer_work = false;
 | |
| volatile static uint8_t _dimmer_value = 0;
 | |
| volatile static uint8_t _dimmer_count = 0;
 | |
| static bool _is_initialized = false;
 | |
| volatile static bool _is_zero_crossing = false;
 | |
| 
 | |
| static esp_err_t _zh_ac_dimmer_validate_config(const zh_ac_dimmer_init_config_t *config);
 | |
| static esp_err_t _zh_ac_dimmer_gpio_init(const zh_ac_dimmer_init_config_t *config);
 | |
| static esp_err_t _zh_ac_dimmer_interrupt_init(const zh_ac_dimmer_init_config_t *config);
 | |
| static esp_err_t _zh_ac_dimmer_resources_init(const zh_ac_dimmer_init_config_t *config);
 | |
| // static esp_err_t _zh_espnow_register_callbacks(bool battery_mode);
 | |
| static esp_err_t _zh_ac_dimmer_task_create(const zh_ac_dimmer_init_config_t *config);
 | |
| 
 | |
| static void _zh_ac_dimmer_isr_handler(void *arg);
 | |
| // static void _zh_ac_dimmer_isr_processing_task(void *pvParameter);
 | |
| 
 | |
| // static esp_err_t _zh_avr_ac_dimmer_timer_init(void);
 | |
| 
 | |
| // static esp_err_t _zh_pcf8574_validate_config(const zh_pcf8574_init_config_t *config);
 | |
| // static esp_err_t _zh_pcf8574_configure_i2c_device(const zh_pcf8574_init_config_t *config, zh_pcf8574_handle_t *handle);
 | |
| // static esp_err_t _zh_pcf8574_configure_interrupts(const zh_pcf8574_init_config_t *config, zh_pcf8574_handle_t handle);
 | |
| // static void _zh_pcf8574_isr_handler(void *arg);
 | |
| // static void _zh_pcf8574_isr_processing_task(void *pvParameter);
 | |
| 
 | |
| esp_err_t zh_ac_dimmer_init(const zh_ac_dimmer_init_config_t *config)
 | |
| {
 | |
|     ZH_LOGI("AC dimmer initialization started.");
 | |
|     ZH_ERROR_CHECK(_is_initialized == false, ESP_ERR_INVALID_STATE, "AC dimmer initialization failed. AC dimmer is already initialized.");
 | |
|     esp_err_t err = _zh_ac_dimmer_validate_config(config);
 | |
|     ZH_ERROR_CHECK(err == ESP_OK, err, "AC dimmer initialization failed. Initial configuration check failed.");
 | |
|     err = _zh_ac_dimmer_gpio_init(config);
 | |
|     ZH_ERROR_CHECK(err == ESP_OK, err, "AC dimmer initialization failed. GPIO initialization failed.");
 | |
|     err = _zh_ac_dimmer_interrupt_init(config);
 | |
|     ZH_ERROR_CHECK(err == ESP_OK, err, "AC dimmer initialization failed. Interrupt initialization failed.");
 | |
|     err = _zh_ac_dimmer_resources_init(config);
 | |
|     ZH_ERROR_CHECK(err == ESP_OK, err, "AC dimmer initialization failed. Resources initialization failed.");
 | |
|     err = _zh_ac_dimmer_task_create(config);
 | |
|     ZH_ERROR_CHECK(err == ESP_OK, err, "AC dimmer initialization failed. Task initialization failed.");
 | |
|     _init_config = *config;
 | |
|     _is_initialized = true;
 | |
|     ZH_LOGI("AC dimmer initialization completed successfully.");
 | |
|     return ESP_OK;
 | |
| }
 | |
| 
 | |
| // esp_err_t zh_avr_ac_dimmer_start(void)
 | |
| // {
 | |
| //     ZH_ERROR_CHECK(_is_initialized == true, AVR_ERR_NOT_FOUND);
 | |
| //     _is_dimmer_work = true;
 | |
| //     return AVR_OK;
 | |
| // }
 | |
| 
 | |
| // esp_err_t zh_avr_ac_dimmer_stop(void)
 | |
| // {
 | |
| //     ZH_ERROR_CHECK(_is_initialized == true, AVR_ERR_NOT_FOUND);
 | |
| //     _is_dimmer_work = false;
 | |
| //     return AVR_OK;
 | |
| // }
 | |
| 
 | |
| // esp_err_t zh_avr_ac_dimmer_set(uint8_t value)
 | |
| // {
 | |
| //     ZH_ERROR_CHECK(value <= 100, AVR_ERR_INVALID_ARG);
 | |
| //     _dimmer_value = value;
 | |
| //     return AVR_OK;
 | |
| // }
 | |
| 
 | |
| // void zh_avr_ac_dimmer_isr_handler(void)
 | |
| // {
 | |
| //     bool flag = false;
 | |
| //     switch (_init_config.zero_cross_port)
 | |
| //     {
 | |
| //     case AVR_PORTB:
 | |
| //         if ((PINB & (1 << _init_config.zero_cross_gpio)) == (1 << _init_config.zero_cross_gpio))
 | |
| //         {
 | |
| //             ZH_ZERO_CROSSING_ON;
 | |
| //         }
 | |
| //         if ((PINB & (1 << _init_config.zero_cross_gpio)) == 0)
 | |
| //         {
 | |
| //             ZH_ZERO_CROSSING_OFF;
 | |
| //         }
 | |
| //         break;
 | |
| //     case AVR_PORTC:
 | |
| //         if ((PINC & (1 << _init_config.zero_cross_gpio)) == (1 << _init_config.zero_cross_gpio))
 | |
| //         {
 | |
| //             ZH_ZERO_CROSSING_ON;
 | |
| //         }
 | |
| //         if ((PINC & (1 << _init_config.zero_cross_gpio)) == 0)
 | |
| //         {
 | |
| //             ZH_ZERO_CROSSING_OFF;
 | |
| //         }
 | |
| //         break;
 | |
| //     case AVR_PORTD:
 | |
| //         if ((PIND & (1 << _init_config.zero_cross_gpio)) == (1 << _init_config.zero_cross_gpio))
 | |
| //         {
 | |
| //             ZH_ZERO_CROSSING_ON;
 | |
| //         }
 | |
| //         if ((PIND & (1 << _init_config.zero_cross_gpio)) == 0)
 | |
| //         {
 | |
| //             ZH_ZERO_CROSSING_OFF;
 | |
| //         }
 | |
| //         break;
 | |
| //     default:
 | |
| //         break;
 | |
| //     }
 | |
| //     if (_is_dimmer_work == true && flag == true)
 | |
| //     {
 | |
| //         if (_dimmer_value != 0)
 | |
| //         {
 | |
| //             if (_dimmer_value == 100)
 | |
| //             {
 | |
| //                 TIMSK0 &= ~(1 << OCIE0A);
 | |
| //                 switch (_init_config.triac_port)
 | |
| //                 {
 | |
| //                 case AVR_PORTB:
 | |
| //                     PORTB |= (1 << _init_config.triac_gpio);
 | |
| //                     break;
 | |
| //                 case AVR_PORTC:
 | |
| //                     PORTC |= (1 << _init_config.triac_gpio);
 | |
| //                     break;
 | |
| //                 case AVR_PORTD:
 | |
| //                     PORTD |= (1 << _init_config.triac_gpio);
 | |
| //                     break;
 | |
| //                 default:
 | |
| //                     break;
 | |
| //                 }
 | |
| //             }
 | |
| //             else
 | |
| //             {
 | |
| //                 TCNT0 = 0;
 | |
| //                 TIFR0 = (1 << OCF0A);
 | |
| //                 TIMSK0 |= (1 << OCIE0A);
 | |
| //             }
 | |
| //         }
 | |
| //     }
 | |
| // }
 | |
| 
 | |
| // static esp_err_t _zh_avr_ac_dimmer_validate_config(const zh_avr_ac_dimmer_init_config_t *config)
 | |
| // {
 | |
| //     ZH_ERROR_CHECK(config != NULL, AVR_ERR_INVALID_ARG);
 | |
| //     ZH_ERROR_CHECK((config->zero_cross_gpio >= 0 && config->zero_cross_gpio <= 7), AVR_ERR_INVALID_ARG);
 | |
| //     ZH_ERROR_CHECK((config->triac_gpio >= 0 && config->triac_gpio <= 7), AVR_ERR_INVALID_ARG);
 | |
| //     ZH_ERROR_CHECK(config->zero_cross_port >= AVR_PORTB && config->zero_cross_port <= AVR_PORTD, AVR_ERR_INVALID_ARG);
 | |
| //     ZH_ERROR_CHECK(config->triac_port >= AVR_PORTB && config->triac_port <= AVR_PORTD, AVR_ERR_INVALID_ARG);
 | |
| //     ZH_ERROR_CHECK(config->ac_dimmer_frequency >= ZH_50HZ && config->ac_dimmer_frequency <= ZH_400HZ, AVR_ERR_INVALID_ARG);
 | |
| //     return AVR_OK;
 | |
| // }
 | |
| 
 | |
| // static void _zh_avr_ac_dimmer_gpio_init(void)
 | |
| // {
 | |
| //     switch (_init_config.zero_cross_port)
 | |
| //     {
 | |
| //     case AVR_PORTB:
 | |
| //         DDRB &= ~(1 << _init_config.zero_cross_gpio);
 | |
| //         PORTB |= (1 << _init_config.zero_cross_gpio);
 | |
| //         PCICR |= (1 << PCIE0);
 | |
| //         PCMSK0 |= (1 << _init_config.zero_cross_gpio);
 | |
| //         break;
 | |
| //     case AVR_PORTC:
 | |
| //         DDRC &= ~(1 << _init_config.zero_cross_gpio);
 | |
| //         PORTC |= (1 << _init_config.zero_cross_gpio);
 | |
| //         PCICR |= (1 << PCIE1);
 | |
| //         PCMSK1 |= (1 << _init_config.zero_cross_gpio);
 | |
| //         break;
 | |
| //     case AVR_PORTD:
 | |
| //         DDRD &= ~(1 << _init_config.zero_cross_gpio);
 | |
| //         PORTD |= (1 << _init_config.zero_cross_gpio);
 | |
| //         PCICR |= (1 << PCIE2);
 | |
| //         PCMSK2 |= (1 << _init_config.zero_cross_gpio);
 | |
| //         break;
 | |
| //     default:
 | |
| //         break;
 | |
| //     }
 | |
| //     switch (_init_config.triac_port)
 | |
| //     {
 | |
| //     case AVR_PORTB:
 | |
| //         DDRB |= (1 << _init_config.triac_gpio);
 | |
| //         PORTB &= ~(1 << _init_config.triac_gpio);
 | |
| //         break;
 | |
| //     case AVR_PORTC:
 | |
| //         DDRC |= (1 << _init_config.triac_gpio);
 | |
| //         PORTC &= ~(1 << _init_config.triac_gpio);
 | |
| //         break;
 | |
| //     case AVR_PORTD:
 | |
| //         DDRD |= (1 << _init_config.triac_gpio);
 | |
| //         PORTD &= ~(1 << _init_config.triac_gpio);
 | |
| //         break;
 | |
| //     default:
 | |
| //         break;
 | |
| //     }
 | |
| // }
 | |
| 
 | |
| // static esp_err_t _zh_avr_ac_dimmer_timer_init(void)
 | |
| // {
 | |
| //     // Frequency calculator http://rcl-radio.ru/?p=111487.
 | |
| //     TCCR0A |= (1 << WGM01);
 | |
| //     switch (F_CPU)
 | |
| //     {
 | |
| //     case 8000000: // When operating from an internal RC generator, frequency deviation of up to 5% is possible.
 | |
| //         switch (_init_config.ac_dimmer_frequency)
 | |
| //         {
 | |
| //         case ZH_50HZ:
 | |
| //             OCR0A = 94; // Timer tick every 0,00009524 sec.
 | |
| //             TCCR0B |= (1 << CS01);
 | |
| //             break;
 | |
| //         case ZH_60HZ: // Timer tick every 0,00007937 sec.
 | |
| //             OCR0A = 78;
 | |
| //             TCCR0B |= (1 << CS01);
 | |
| //             break;
 | |
| //         case ZH_400HZ: // Timer tick every 0,0000119 sec.
 | |
| //             OCR0A = 94;
 | |
| //             TCCR0B |= (1 << CS00);
 | |
| //             break;
 | |
| //         default:
 | |
| //             break;
 | |
| //         }
 | |
| //         break;
 | |
| //     case 16000000:
 | |
| //         switch (_init_config.ac_dimmer_frequency)
 | |
| //         {
 | |
| //         case ZH_50HZ: // Timer tick every 0,0001 sec.
 | |
| //             OCR0A = 24;
 | |
| //             TCCR0B |= (1 << CS01) | (1 << CS00);
 | |
| //             break;
 | |
| //         case ZH_60HZ: // Timer tick every 0,00008333 sec.
 | |
| //             OCR0A = 165;
 | |
| //             TCCR0B |= (1 << CS01);
 | |
| //             break;
 | |
| //         case ZH_400HZ: // Timer tick every 0,0000125 sec.
 | |
| //             OCR0A = 24;
 | |
| //             TCCR0B |= (1 << CS01);
 | |
| //             break;
 | |
| //         default:
 | |
| //             break;
 | |
| //         }
 | |
| //         break;
 | |
| //     case 20000000:
 | |
| //         switch (_init_config.ac_dimmer_frequency)
 | |
| //         {
 | |
| //         case ZH_50HZ: // Timer tick every 0,0001 sec.
 | |
| //             OCR0A = 249;
 | |
| //             TCCR0B |= (1 << CS01);
 | |
| //             break;
 | |
| //         case ZH_60HZ: // Timer tick every 0,00008333 sec.
 | |
| //             OCR0A = 207;
 | |
| //             TCCR0B |= (1 << CS01);
 | |
| //             break;
 | |
| //         case ZH_400HZ: // Timer tick every 0,0000125 sec.
 | |
| //             OCR0A = 249;
 | |
| //             TCCR0B |= (1 << CS00);
 | |
| //             break;
 | |
| //         default:
 | |
| //             break;
 | |
| //         }
 | |
| //         break;
 | |
| //     default:
 | |
| //         return AVR_ERR_INVALID_ARG;
 | |
| //         break;
 | |
| //     }
 | |
| //     return AVR_OK;
 | |
| // }
 | |
| 
 | |
| // ISR(TIMER0_COMPA_vect)
 | |
| // {
 | |
| //     ++_dimmer_count;
 | |
| //     if (_dimmer_count == (100 - _dimmer_value))
 | |
| //     {
 | |
| //         _dimmer_count = 0;
 | |
| //         TIMSK0 &= ~(1 << OCIE0A);
 | |
| //         switch (_init_config.triac_port)
 | |
| //         {
 | |
| //         case AVR_PORTB:
 | |
| //             PORTB |= (1 << _init_config.triac_gpio);
 | |
| //             _delay_us(ZH_TRIAC_TIME);
 | |
| //             PORTB &= ~(1 << _init_config.triac_gpio);
 | |
| //             break;
 | |
| //         case AVR_PORTC:
 | |
| //             PORTC |= (1 << _init_config.triac_gpio);
 | |
| //             _delay_us(ZH_TRIAC_TIME);
 | |
| //             PORTC &= ~(1 << _init_config.triac_gpio);
 | |
| //         case AVR_PORTD:
 | |
| //             PORTD |= (1 << _init_config.triac_gpio);
 | |
| //             _delay_us(ZH_TRIAC_TIME);
 | |
| //             PORTD &= ~(1 << _init_config.triac_gpio);
 | |
| //             break;
 | |
| //         default:
 | |
| //             break;
 | |
| //         }
 | |
| //     }
 | |
| //     TIFR0 = (1 << OCF0A);
 | |
| // }
 |