#include "zh_onewire_slave.h" #define RESET_PULSE_DURATION 480 // Minimum value according to datasheet. #define WAITING_TIME_AFTER_RESET_PULSE 35 // Average value between possible datasheet values (15-60). #define PRESENCE_PULSE_DURATION 180 // Average value between possible datasheet values (60-240). #define TIME_SLOT_DURATION 90 // Average value between possible datasheet values (60-120). static bool _rx_done_callback(rmt_channel_handle_t channel, const rmt_rx_done_event_data_t *edata, void *user_data); static size_t _tx_encoder_callback(const void *data, size_t data_size, size_t symbols_written, size_t symbols_free, rmt_symbol_word_t *symbols, bool *done, void *arg); static void _rx_processing(void *pvParameter); static void _gpio_interrupt_callback(void *arg); static void _gpio_interrupt_processing(void *pvParameter); static const char *TAG = "zh_onewire_slave"; static rmt_channel_handle_t _tx_channel_handle = NULL; static rmt_channel_handle_t _rx_channel_handle = NULL; static rmt_encoder_handle_t _tx_encoder_handle = NULL; static rmt_symbol_word_t _rx_raw_buffer[64]; static QueueHandle_t _receive_queue = {0}; static QueueHandle_t _gpio_interrupt_queue = {0}; static zh_onewire_slave_init_config_t _init_config = {0}; static bool _is_initialized = false; static uint64_t last_low_level_time = 0xFFFFFFFF; typedef struct { uint8_t level; uint64_t time; } _gpio_interrupt_data_t; static rmt_receive_config_t _receive_config = { .signal_range_min_ns = 1000, .signal_range_max_ns = TIME_SLOT_DURATION * 1000, }; static rmt_transmit_config_t _transmit_config = { .loop_count = 0, }; static const rmt_symbol_word_t _presence_symbol_word = { .level0 = 1, .duration0 = PRESENCE_PULSE_DURATION, .level1 = 0, .duration1 = 0}; esp_err_t zh_onewire_slave_init(const zh_onewire_slave_init_config_t *config) { ESP_LOGI(TAG, "Onewire slave initialization begin."); if (config == NULL) { ESP_LOGE(TAG, "Onewire slave initialization fail. Invalid argument."); return ESP_ERR_INVALID_ARG; } _init_config = *config; rmt_tx_channel_config_t tx_channel_config = { .clk_src = RMT_CLK_SRC_DEFAULT, .gpio_num = _init_config.bus_pin, .mem_block_symbols = 64, .resolution_hz = 1000000, .trans_queue_depth = 4, .flags.invert_out = true, .flags.with_dma = false, .flags.io_loop_back = true, .flags.io_od_mode = true, }; rmt_rx_channel_config_t rx_channel_config = { .clk_src = RMT_CLK_SRC_DEFAULT, .resolution_hz = 1000000, .mem_block_symbols = 64, .gpio_num = _init_config.bus_pin, .flags.invert_in = false, .flags.with_dma = false, }; if (rmt_new_rx_channel(&rx_channel_config, &_rx_channel_handle) != ESP_OK) { ESP_LOGE(TAG, "Onewire slave initialization fail. RMT driver error at line %d.", __LINE__); return ESP_FAIL; } if (rmt_new_tx_channel(&tx_channel_config, &_tx_channel_handle) != ESP_OK) { ESP_LOGE(TAG, "Onewire slave initialization fail. RMT driver error at line %d.", __LINE__); return ESP_FAIL; } rmt_rx_event_callbacks_t rx_event_callbacks = { .on_recv_done = _rx_done_callback, }; if (rmt_rx_register_event_callbacks(_rx_channel_handle, &rx_event_callbacks, NULL) != ESP_OK) { ESP_LOGE(TAG, "Onewire slave initialization fail. RMT driver error at line %d.", __LINE__); return ESP_FAIL; } const rmt_simple_encoder_config_t simple_encoder_config = { .callback = _tx_encoder_callback}; if (rmt_new_simple_encoder(&simple_encoder_config, &_tx_encoder_handle) != ESP_OK) { ESP_LOGE(TAG, "Onewire slave initialization fail. RMT driver error at line %d.", __LINE__); return ESP_FAIL; } if (rmt_enable(_rx_channel_handle) != ESP_OK) { ESP_LOGE(TAG, "Onewire slave initialization fail. RMT driver error at line %d.", __LINE__); return ESP_FAIL; } if (rmt_enable(_tx_channel_handle) != ESP_OK) { ESP_LOGE(TAG, "Onewire slave initialization fail. RMT driver error at line %d.", __LINE__); return ESP_FAIL; } _receive_queue = xQueueCreate(1, sizeof(rmt_rx_done_event_data_t)); if (xTaskCreatePinnedToCore(&_rx_processing, "NULL", _init_config.stack_size, NULL, _init_config.task_priority, NULL, tskNO_AFFINITY) != pdPASS) { ESP_LOGE(TAG, "Onewire slave initialization fail. Internal error at line %d.", __LINE__); return ESP_FAIL; } // rmt_receive(_rx_channel_handle, _rx_raw_buffer, sizeof(_rx_raw_buffer), &_receive_config); gpio_config_t pin_config = {0}; pin_config.intr_type = GPIO_INTR_ANYEDGE; pin_config.mode = GPIO_MODE_INPUT; pin_config.pin_bit_mask = (1ULL << (_init_config.bus_pin + 1)); if (gpio_config(&pin_config) != pdPASS) { ESP_LOGE(TAG, "Onewire slave initialization fail. Internal error at line %d.", __LINE__); return ESP_FAIL; } _gpio_interrupt_queue = xQueueCreate(10, sizeof(_gpio_interrupt_data_t)); // Check queue size!!! if (xTaskCreatePinnedToCore(&_gpio_interrupt_processing, "NULL", _init_config.stack_size, NULL, (_init_config.task_priority), NULL, 1) != pdPASS) { ESP_LOGE(TAG, "Onewire slave initialization fail. Internal error at line %d.", __LINE__); return ESP_FAIL; } gpio_install_isr_service(0); gpio_isr_handler_add((_init_config.bus_pin + 1), _gpio_interrupt_callback, NULL); _is_initialized = true; ESP_LOGI(TAG, "Onewire slave initialization success."); return ESP_OK; } static bool _rx_done_callback(rmt_channel_handle_t channel, const rmt_rx_done_event_data_t *edata, void *user_data) { BaseType_t high_task_wakeup = pdFALSE; xQueueSendFromISR(_receive_queue, edata, &high_task_wakeup); return high_task_wakeup == pdTRUE; } static size_t _tx_encoder_callback(const void *data, size_t data_size, size_t symbols_written, size_t symbols_free, rmt_symbol_word_t *symbols, bool *done, void *arg) { symbols[0] = _presence_symbol_word; *done = true; return 1; } static void _rx_processing(void *pvParameter) { rmt_rx_done_event_data_t rx_data = {0}; while (xQueueReceive(_receive_queue, &rx_data, portMAX_DELAY) == pdTRUE) { rmt_receive(_rx_channel_handle, _rx_raw_buffer, sizeof(_rx_raw_buffer), &_receive_config); } } void _gpio_interrupt_callback(void *arg) { // uint8_t level = gpio_get_level((_init_config.bus_pin + 1)); // uint64_t time = esp_timer_get_time(); if (gpio_get_level((_init_config.bus_pin + 1)) == 0) { last_low_level_time = esp_timer_get_time(); } else { if ((esp_timer_get_time() - last_low_level_time) > (RESET_PULSE_DURATION * 0.9) && (esp_timer_get_time() - last_low_level_time) < (RESET_PULSE_DURATION * 2)) { // Reset is detected. } } // _gpio_interrupt_data_t data = {0}; // data.level = gpio_get_level((_init_config.bus_pin + 1)); // data.time = esp_timer_get_time(); // xQueueSendFromISR(_gpio_interrupt_queue, &data, NULL); } void _gpio_interrupt_processing(void *pvParameter) { _gpio_interrupt_data_t data = {0}; uint64_t last_time = esp_timer_get_time(); while (xQueueReceive(_gpio_interrupt_queue, &data, portMAX_DELAY) == pdTRUE) { if (data.level == 0) { last_time = data.time; } else { if ((data.time - last_time) > (RESET_PULSE_DURATION * 0.9) && (data.time - last_time) < (RESET_PULSE_DURATION * 2)) { uint8_t pulse[1] = {1}; // Reset all transmittions. rmt_transmit(_tx_channel_handle, _tx_encoder_handle, pulse, sizeof(pulse), &_transmit_config); rmt_tx_wait_all_done(_tx_channel_handle, portMAX_DELAY); } } } vTaskDelete(NULL); }