switch_driver.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. /*
  2. * Copyright (c) 2021 Espressif Systems (Shanghai) CO LTD
  3. * All rights reserved.
  4. *
  5. *
  6. * Redistribution and use in source and binary forms, with or without modification,
  7. * are permitted provided that the following conditions are met:
  8. *
  9. * 1. Redistributions of source code must retain the above copyright notice,
  10. * this list of conditions and the following disclaimer.
  11. *
  12. * 2. Redistributions in binary form, except as embedded into a Espressif Systems
  13. * integrated circuit in a product or a software update for such product,
  14. * must reproduce the above copyright notice, this list of conditions and
  15. * the following disclaimer in the documentation and/or other materials
  16. * provided with the distribution.
  17. *
  18. * 3. Neither the name of the copyright holder nor the names of its contributors
  19. * may be used to endorse or promote products derived from this software without
  20. * specific prior written permission.
  21. *
  22. * 4. Any software provided in binary form under this license must not be reverse
  23. * engineered, decompiled, modified and/or disassembled.
  24. *
  25. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  26. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  27. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  28. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
  29. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  30. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  31. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  32. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  33. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  34. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  35. * POSSIBILITY OF SUCH DAMAGE.
  36. */
  37. #include "esp_log.h"
  38. #include "freertos/FreeRTOS.h"
  39. #include "freertos/task.h"
  40. #include "freertos/queue.h"
  41. #include "switch_driver.h"
  42. /**
  43. * @brief:
  44. * This example code shows how to configure light switch with attribute as well as button switch handler.
  45. *
  46. * @note:
  47. Currently only support toggle switch functionality available
  48. *
  49. * @note:
  50. * For other possible switch functions (on/off,level up/down,step up/down). User need to implement and create them by themselves
  51. */
  52. static QueueHandle_t gpio_evt_queue = NULL;
  53. /* button function pair, should be defined in switch example source file */
  54. static switch_func_pair_t *switch_func_pair;
  55. /* call back function pointer */
  56. static esp_switch_callback_t func_ptr;
  57. /* which button is pressed */
  58. static uint8_t switch_num;
  59. static const char *TAG = "ESP_ZB_SWITCH";
  60. static void IRAM_ATTR gpio_isr_handler(void *arg)
  61. {
  62. xQueueSendFromISR(gpio_evt_queue, (switch_func_pair_t *)arg, NULL);
  63. }
  64. /**
  65. * @brief Enable GPIO (switchs refer to) isr
  66. *
  67. * @param enabled enable isr if true.
  68. */
  69. static void switch_driver_gpios_intr_enabled(bool enabled)
  70. {
  71. for (int i = 0; i < switch_num; ++i) {
  72. if (enabled) {
  73. gpio_intr_enable((switch_func_pair + i)->pin);
  74. } else {
  75. gpio_intr_disable((switch_func_pair + i)->pin);
  76. }
  77. }
  78. }
  79. /**
  80. * @brief Tasks for checking the button event and debounce the switch state
  81. *
  82. * @param arg Unused value.
  83. */
  84. static void switch_driver_button_detected(void *arg)
  85. {
  86. gpio_num_t io_num = GPIO_NUM_NC;
  87. switch_func_pair_t button_func_pair;
  88. static switch_state_t switch_state = SWITCH_IDLE;
  89. bool evt_flag = false;
  90. for (;;) {
  91. /* check if there is any queue received, if yes read out the button_func_pair */
  92. if (xQueueReceive(gpio_evt_queue, &button_func_pair, portMAX_DELAY)) {
  93. io_num = button_func_pair.pin;
  94. switch_driver_gpios_intr_enabled(false);
  95. evt_flag = true;
  96. }
  97. while (evt_flag) {
  98. bool value = gpio_get_level(io_num);
  99. switch (switch_state) {
  100. case SWITCH_IDLE:
  101. switch_state = (value == GPIO_INPUT_LEVEL_ON) ? SWITCH_PRESS_DETECTED : SWITCH_IDLE;
  102. break;
  103. case SWITCH_PRESS_DETECTED:
  104. switch_state = (value == GPIO_INPUT_LEVEL_ON) ? SWITCH_PRESS_DETECTED : SWITCH_RELEASE_DETECTED;
  105. break;
  106. case SWITCH_RELEASE_DETECTED:
  107. switch_state = SWITCH_IDLE;
  108. /* callback to button_handler */
  109. (*func_ptr)(button_func_pair);
  110. break;
  111. default:
  112. break;
  113. }
  114. if (switch_state == SWITCH_IDLE) {
  115. switch_driver_gpios_intr_enabled(true);
  116. evt_flag = false;
  117. break;
  118. }
  119. vTaskDelay(10 / portTICK_PERIOD_MS);
  120. }
  121. }
  122. }
  123. /**
  124. * @brief init GPIO configuration as well as isr
  125. *
  126. * @param button_func_pair pointer of the button pair.
  127. * @param button_num number of button pair.
  128. */
  129. static bool switch_driver_gpio_init(switch_func_pair_t *button_func_pair, uint8_t button_num)
  130. {
  131. gpio_config_t io_conf = {};
  132. switch_func_pair = button_func_pair;
  133. switch_num = button_num;
  134. uint64_t pin_bit_mask = 0;
  135. /* set up button func pair pin mask */
  136. for (int i = 0; i < button_num; ++i) {
  137. pin_bit_mask |= (1ULL << (button_func_pair + i)->pin);
  138. }
  139. /* interrupt of falling edge */
  140. io_conf.intr_type = GPIO_INTR_NEGEDGE;
  141. io_conf.pin_bit_mask = pin_bit_mask;
  142. io_conf.mode = GPIO_MODE_INPUT;
  143. io_conf.pull_up_en = 1;
  144. /* configure GPIO with the given settings */
  145. gpio_config(&io_conf);
  146. /* create a queue to handle gpio event from isr */
  147. gpio_evt_queue = xQueueCreate(10, sizeof(switch_func_pair_t));
  148. if ( gpio_evt_queue == 0) {
  149. ESP_LOGE(TAG, "Queue was not created and must not be used");
  150. return false;
  151. }
  152. /* start gpio task */
  153. xTaskCreate(switch_driver_button_detected, "button_detected", 2048, NULL, 10, NULL);
  154. /* install gpio isr service */
  155. gpio_install_isr_service(ESP_INTR_FLAG_DEFAULT);
  156. for (int i = 0; i < button_num; ++i) {
  157. gpio_isr_handler_add((button_func_pair + i)->pin, gpio_isr_handler, (void *) (button_func_pair + i));
  158. }
  159. return true;
  160. }
  161. bool switch_driver_init(switch_func_pair_t *button_func_pair, uint8_t button_num, esp_switch_callback_t cb)
  162. {
  163. if (!switch_driver_gpio_init(button_func_pair, button_num)) {
  164. return false;
  165. }
  166. func_ptr = cb;
  167. return true;
  168. }