infrared.c 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. /*
  2. * infrared receiver (using espressif's example)
  3. *
  4. * (c) Philippe G. 2020, philippe_44@outlook.com
  5. *
  6. * This software is released under the MIT License.
  7. * https://opensource.org/licenses/MIT
  8. *
  9. */
  10. #include <stdio.h>
  11. #include <string.h>
  12. #include "freertos/FreeRTOS.h"
  13. #include "freertos/task.h"
  14. #include "esp_err.h"
  15. #include "esp_log.h"
  16. #include "driver/rmt.h"
  17. #include "infrared.h"
  18. static const char* TAG = "IR";
  19. #define RMT_RX_ACTIVE_LEVEL 0 /*!< If we connect with a IR receiver, the data is active low */
  20. #define RMT_RX_CHANNEL 0 /*!< RMT channel for receiver */
  21. #define RMT_CLK_DIV 100 /*!< RMT counter clock divider */
  22. #define RMT_TICK_10_US (80000000/RMT_CLK_DIV/100000) /*!< RMT counter value for 10 us.(Source clock is APB clock) */
  23. #define NEC_HEADER_HIGH_US 9000 /*!< NEC protocol header: positive 9ms */
  24. #define NEC_HEADER_LOW_US 4500 /*!< NEC protocol header: negative 4.5ms*/
  25. #define NEC_BIT_ONE_HIGH_US 560 /*!< NEC protocol data bit 1: positive 0.56ms */
  26. #define NEC_BIT_ONE_LOW_US (2250-NEC_BIT_ONE_HIGH_US) /*!< NEC protocol data bit 1: negative 1.69ms */
  27. #define NEC_BIT_ZERO_HIGH_US 560 /*!< NEC protocol data bit 0: positive 0.56ms */
  28. #define NEC_BIT_ZERO_LOW_US (1120-NEC_BIT_ZERO_HIGH_US) /*!< NEC protocol data bit 0: negative 0.56ms */
  29. #define NEC_BIT_MARGIN 150 /*!< NEC parse margin time */
  30. #define NEC_ITEM_DURATION(d) ((d & 0x7fff)*10/RMT_TICK_10_US) /*!< Parse duration time from memory register value */
  31. #define NEC_DATA_ITEM_NUM 34 /*!< NEC code item number: header + 32bit data + end */
  32. #define rmt_item32_tIMEOUT_US 9500 /*!< RMT receiver timeout value(us) */
  33. /****************************************************************************************
  34. *
  35. */
  36. static bool nec_check_in_range(int duration_ticks, int target_us, int margin_us) {
  37. if(( NEC_ITEM_DURATION(duration_ticks) < (target_us + margin_us))
  38. && ( NEC_ITEM_DURATION(duration_ticks) > (target_us - margin_us))) {
  39. return true;
  40. } else {
  41. return false;
  42. }
  43. }
  44. /****************************************************************************************
  45. *
  46. */
  47. static bool nec_header_if(rmt_item32_t* item) {
  48. if((item->level0 == RMT_RX_ACTIVE_LEVEL && item->level1 != RMT_RX_ACTIVE_LEVEL)
  49. && nec_check_in_range(item->duration0, NEC_HEADER_HIGH_US, NEC_BIT_MARGIN)
  50. && nec_check_in_range(item->duration1, NEC_HEADER_LOW_US, NEC_BIT_MARGIN)) {
  51. return true;
  52. }
  53. return false;
  54. }
  55. /****************************************************************************************
  56. *
  57. */
  58. static bool nec_bit_one_if(rmt_item32_t* item) {
  59. if((item->level0 == RMT_RX_ACTIVE_LEVEL && item->level1 != RMT_RX_ACTIVE_LEVEL)
  60. && nec_check_in_range(item->duration0, NEC_BIT_ONE_HIGH_US, NEC_BIT_MARGIN)
  61. && nec_check_in_range(item->duration1, NEC_BIT_ONE_LOW_US, NEC_BIT_MARGIN)) {
  62. return true;
  63. }
  64. return false;
  65. }
  66. /****************************************************************************************
  67. *
  68. */
  69. static bool nec_bit_zero_if(rmt_item32_t* item) {
  70. if((item->level0 == RMT_RX_ACTIVE_LEVEL && item->level1 != RMT_RX_ACTIVE_LEVEL)
  71. && nec_check_in_range(item->duration0, NEC_BIT_ZERO_HIGH_US, NEC_BIT_MARGIN)
  72. && nec_check_in_range(item->duration1, NEC_BIT_ZERO_LOW_US, NEC_BIT_MARGIN)) {
  73. return true;
  74. }
  75. return false;
  76. }
  77. /****************************************************************************************
  78. *
  79. */
  80. static int nec_parse_items(rmt_item32_t* item, int item_num, uint16_t* addr, uint16_t* data) {
  81. int w_len = item_num;
  82. if(w_len < NEC_DATA_ITEM_NUM) {
  83. return -1;
  84. }
  85. int i = 0, j = 0;
  86. if(!nec_header_if(item++)) {
  87. return -1;
  88. }
  89. uint16_t addr_t = 0;
  90. for(j = 15; j >= 0; j--) {
  91. if(nec_bit_one_if(item)) {
  92. addr_t |= (1 << j);
  93. } else if(nec_bit_zero_if(item)) {
  94. addr_t |= (0 << j);
  95. } else {
  96. return -1;
  97. }
  98. item++;
  99. i++;
  100. }
  101. uint16_t data_t = 0;
  102. for(j = 15; j >= 0; j--) {
  103. if(nec_bit_one_if(item)) {
  104. data_t |= (1 << j);
  105. } else if(nec_bit_zero_if(item)) {
  106. data_t |= (0 << j);
  107. } else {
  108. return -1;
  109. }
  110. item++;
  111. i++;
  112. }
  113. *addr = addr_t;
  114. *data = data_t;
  115. return i;
  116. }
  117. /****************************************************************************************
  118. *
  119. */
  120. void infrared_receive(RingbufHandle_t rb, infrared_handler handler) {
  121. size_t rx_size = 0;
  122. rmt_item32_t* item = (rmt_item32_t*) xRingbufferReceive(rb, &rx_size, 10 / portTICK_RATE_MS);
  123. if (item) {
  124. uint16_t addr, cmd;
  125. int offset = 0;
  126. while (1) {
  127. // parse data value from ringbuffer.
  128. int res = nec_parse_items(item + offset, rx_size / 4 - offset, &addr, &cmd);
  129. if (res > 0) {
  130. offset += res + 1;
  131. handler(addr, cmd);
  132. ESP_LOGD(TAG, "RMT RCV --- addr: 0x%04x cmd: 0x%04x", addr, cmd);
  133. } else break;
  134. }
  135. // after parsing the data, return spaces to ringbuffer.
  136. vRingbufferReturnItem(rb, (void*) item);
  137. }
  138. }
  139. /****************************************************************************************
  140. *
  141. */
  142. void infrared_init(RingbufHandle_t *rb, int gpio) {
  143. rmt_config_t rmt_rx;
  144. ESP_LOGI(TAG, "Starting Infrared Receiver on gpio %d", gpio);
  145. // initialize RMT driver
  146. rmt_rx.channel = RMT_RX_CHANNEL;
  147. rmt_rx.gpio_num = gpio;
  148. rmt_rx.clk_div = RMT_CLK_DIV;
  149. rmt_rx.mem_block_num = 1;
  150. rmt_rx.rmt_mode = RMT_MODE_RX;
  151. rmt_rx.rx_config.filter_en = true;
  152. rmt_rx.rx_config.filter_ticks_thresh = 100;
  153. rmt_rx.rx_config.idle_threshold = rmt_item32_tIMEOUT_US / 10 * (RMT_TICK_10_US);
  154. rmt_config(&rmt_rx);
  155. rmt_driver_install(rmt_rx.channel, 1000, 0);
  156. // get RMT RX ringbuffer
  157. rmt_get_ringbuf_handle(RMT_RX_CHANNEL, rb);
  158. rmt_rx_start(RMT_RX_CHANNEL, 1);
  159. }