1 | // espy Copyright (c) 2023 Josh Stockin <josh@joshstock.in> |
2 | // [https://joshstock.in] [https://github.com/joshuas3] |
3 | // |
4 | // This software is licensed and distributed under the terms of the MIT License. |
5 | // See the MIT License in the LICENSE file of this project's root folder. |
6 | // |
7 | // This comment block and its contents, including this disclaimer, MUST be |
8 | // preserved in all copies or distributions of this software's source. |
9 |
|
10 |
|
11 | // Filename: input.c |
12 | // Description: Handlers for radio receiver, rotary encoder |
13 |
|
14 |
|
15 | #include "esp_attr.h" |
16 | #include "esp_err.h" |
17 | #include "esp_check.h" |
18 | #include "esp_log.h" |
19 | #include "freertos/FreeRTOS.h" |
20 | #include "freertos/queue.h" |
21 | #include "driver/gpio.h" |
22 | #include "driver/gptimer.h" |
23 |
|
24 | #include "input.h" |
25 | #include "pins.h" |
26 |
|
27 |
|
28 | static const char* TAG = "input.c"; |
29 |
|
30 | static uint8_t current_radio_channel = 0; |
31 | static uint16_t radio_channels[NUM_RADIO_CHANNELS + 1] = {0}; |
32 | static bool updated = false; |
33 |
|
34 | QueueHandle_t xInputQueue; |
35 | gptimer_handle_t pulse_timer = NULL; |
36 |
|
37 | esp_err_t setup_radio_and_rotenc_input( void ) { |
38 |
|
39 | ESP_LOGI( TAG, "creating input queue" ); |
40 |
|
41 | xInputQueue = xQueueCreate( 400, sizeof( xInputEvent ) ); // xInputEvent from input.h |
42 | ESP_RETURN_ON_FALSE( xInputQueue != 0, ESP_FAIL, TAG, "xQueueCreate failed" ); |
43 |
|
44 | ESP_LOGI( TAG, "configuring RADIO_PPM pin for input, pull_down_en" ); |
45 |
|
46 | gpio_config_t radio_pin_conf = { |
47 | .pin_bit_mask = (1ULL << RADIO_PPM), |
48 | .mode = GPIO_MODE_INPUT, |
49 | .pull_down_en = 1, |
50 | .pull_up_en = 0, |
51 | }; |
52 | ESP_RETURN_ON_ERROR( gpio_config( &radio_pin_conf ), TAG, "gpio_config failed" ); |
53 |
|
54 | ESP_LOGI( TAG, "configuring and starting hardware gptimer (1MHz)" ); |
55 |
|
56 | gptimer_config_t timer_config = { |
57 | .clk_src = GPTIMER_CLK_SRC_DEFAULT, |
58 | .direction = GPTIMER_COUNT_UP, |
59 | .resolution_hz = 1000000, // 1MHz, microsecond precision |
60 | }; |
61 | ESP_RETURN_ON_ERROR( gptimer_new_timer( &timer_config, &pulse_timer ), TAG, "gptimer_new_timer failed" ); |
62 | ESP_RETURN_ON_ERROR( gptimer_enable( pulse_timer ), TAG, "gptimer_enable failed" ); |
63 | ESP_RETURN_ON_ERROR( gptimer_start( pulse_timer ), TAG, "gptimer_start failed" ); |
64 |
|
65 | ESP_LOGI( TAG, "creating positive edge RADIO_PPM interrupt for radio_pulse callback" ); |
66 |
|
67 | ESP_RETURN_ON_ERROR( gpio_set_intr_type( RADIO_PPM, GPIO_INTR_POSEDGE ), TAG, "gpio_set_intr_type failed" ); |
68 | ESP_RETURN_ON_ERROR( gpio_isr_handler_add( RADIO_PPM, radio_pulse, NULL ), TAG, "gpio_isr_handler_add failed" ); |
69 | ESP_RETURN_ON_ERROR( gpio_intr_enable( RADIO_PPM ), TAG, "gpio_intr_enable failed" ); |
70 |
|
71 | // wakeup_enable not allowed for rising edge interrupts |
72 | // TODO: move to sleep handler |
73 | // ESP_RETURN_ON_ERROR( gpio_wakeup_enable( RADIO_PPM, GPIO_INTR_POSEDGE ), TAG, "gpio_wakeup_enable failed" ); |
74 |
|
75 | ESP_LOGI( TAG, "creating input handler task" ); |
76 |
|
77 | TaskHandle_t input_task = NULL; |
78 | xTaskCreate( input_handler_task, "input_handler_task", 2048, NULL, 20, &input_task ); // stack size 400 bytes, priority 2 |
79 |
|
80 | ESP_LOGI( TAG, "input setup done" ); |
81 |
|
82 | return ESP_OK; |
83 |
|
84 | } |
85 |
|
86 | void IRAM_ATTR radio_pulse( void* arg ) { |
87 |
|
88 | // get pulse timer value |
89 | uint64_t offset = 0; |
90 | gptimer_get_raw_count( pulse_timer, &offset ); |
91 |
|
92 | if (offset >= RADIO_PULSE_STOPGAP_US || current_radio_channel == NUM_RADIO_CHANNELS) { |
93 | radio_channels[NUM_RADIO_CHANNELS] = offset; |
94 | current_radio_channel = 0; |
95 | } else { |
96 | radio_channels[current_radio_channel++] = offset; |
97 | } |
98 | updated = true; |
99 |
|
100 | // reset timer |
101 | gptimer_set_raw_count( pulse_timer, 0 ); |
102 |
|
103 | } |
104 |
|
105 | void input_handler_task( void* arg ) { |
106 | // clears input event queue |
107 |
|
108 | //xInputEvent event; |
109 | for ( ;; ) { |
110 | /* |
111 | while ( xQueueReceive( xInputQueue, &event, 2 ) ) { |
112 | |
113 | if ( event.type == INPUT_EVENT_RADIOPULSE ) { |
114 | // ppm radio receiver handling |
115 | |
116 | } else if ( event.type == INPUT_EVENT_ROTENCSW ) { |
117 | |
118 | // TODO |
119 | |
120 | } else if ( event.type == INPUT_EVENT_ROTENCTURN ) { |
121 | |
122 | // TODO |
123 | |
124 | } |
125 | |
126 | }*/ |
127 | if (updated) { |
128 | ESP_LOGD( TAG, "\nCHANNELS\nch1: %u\nch2: %u\nch3: %u\nch4: %u\nch5: %u\nch6: %u\nch7: %u\nch8: %u\nch9: %u\nch10: %u\ngap dist: %u\n", radio_channels[0], radio_channels[1], radio_channels[2], radio_channels[3], radio_channels[4], radio_channels[5], radio_channels[6], radio_channels[7], radio_channels[8], radio_channels[9], radio_channels[10] ); |
129 | updated = false; |
130 | } |
131 |
|
132 | vTaskDelay(10); |
133 | taskYIELD(); // queue is empty, don't waste anymore processor time |
134 | } |
135 |
|
136 | } |
137 |
|