Firmware SDK
twr_module_encoder.c
1 #include <twr_module_encoder.h>
2 #include <twr_scheduler.h>
3 #include <twr_exti.h>
4 #include <twr_irq.h>
5 #include <twr_system.h>
6 #include <twr_timer.h>
7 
8 static struct
9 {
10  bool initialized;
12  void (*event_handler)(twr_module_encoder_event_t, void *);
13  void *event_param;
14  twr_button_t button;
15  int increment;
16  int increment_shadow;
17  int samples;
18 
19 } _twr_module_encoder;
20 
21 static void _twr_module_encoder_task(void *param);
22 
23 static void _twr_module_encoder_exti_handler(twr_exti_line_t line, void *param);
24 
25 static void _twr_module_encoder_button_event_handler(twr_button_t *self, twr_button_event_t event, void *event_param);
26 
27 static bool _twr_module_encoder_present_test(void);
28 
30 {
31  memset(&_twr_module_encoder, 0, sizeof(_twr_module_encoder));
32 
33  // Initialize encoder button
34  twr_button_init(&_twr_module_encoder.button, TWR_GPIO_BUTTON, TWR_GPIO_PULL_DOWN, false);
35  twr_button_set_event_handler(&_twr_module_encoder.button, _twr_module_encoder_button_event_handler, NULL);
36 
37  // Init encoder GPIO pins
39 
41 
42  // Register task
43  _twr_module_encoder.task_id = twr_scheduler_register(_twr_module_encoder_task, NULL, 0);
44 }
45 
47 {
48  // Unregister task
49  twr_scheduler_unregister(_twr_module_encoder.task_id);
50 
52 
54 
55  if (_twr_module_encoder.initialized)
56  {
58 
60  }
61 }
62 
63 void twr_module_encoder_set_event_handler(void (*event_handler)(twr_module_encoder_event_t, void *), void *event_param)
64 {
65  _twr_module_encoder.event_handler = event_handler;
66 
67  _twr_module_encoder.event_param = event_param;
68 }
69 
71 {
72  return &_twr_module_encoder.button;
73 }
74 
76 {
77  return _twr_module_encoder.increment_shadow;
78 }
79 
81 {
82  if (_twr_module_encoder.initialized)
83  {
84  return true;
85  }
86 
87  return _twr_module_encoder_present_test();
88 }
89 
90 static void _twr_module_encoder_task(void *param)
91 {
92  (void) param;
93 
94  if (_twr_module_encoder.initialized)
95  {
96  // Disable interrupts
98 
99  _twr_module_encoder.increment_shadow = _twr_module_encoder.increment;
100  _twr_module_encoder.increment = 0;
101 
102  // Enable interrupts
103  twr_irq_enable();
104 
105  if (_twr_module_encoder.increment_shadow != 0)
106  {
107  if (_twr_module_encoder.event_handler != NULL)
108  {
109  _twr_module_encoder.event_handler(TWR_MODULE_ENCODER_EVENT_ROTATION, _twr_module_encoder.event_param);
110  }
111  }
112  }
113  else
114  {
115  if (_twr_module_encoder_present_test())
116  {
117  // Set encoder GPIO pins as inputs
120 
121  // Remember initial GPIO states
122  _twr_module_encoder.samples |= twr_gpio_get_input(TWR_GPIO_P4) ? 0x1 : 0;
123  _twr_module_encoder.samples |= twr_gpio_get_input(TWR_GPIO_P5) ? 0x2 : 0;
124 
125  // Register interrupts on both GPIO pins
126  twr_exti_register(TWR_EXTI_LINE_P4, TWR_EXTI_EDGE_RISING_AND_FALLING, _twr_module_encoder_exti_handler, NULL);
127  twr_exti_register(TWR_EXTI_LINE_P5, TWR_EXTI_EDGE_RISING_AND_FALLING, _twr_module_encoder_exti_handler, NULL);
128 
129  _twr_module_encoder.initialized = true;
130  }
131  else
132  {
133  if (_twr_module_encoder.event_handler != NULL)
134  {
135  _twr_module_encoder.event_handler(TWR_MODULE_ENCODER_EVENT_ERROR, _twr_module_encoder.event_param);
136  }
137  }
138  }
139 }
140 
141 static void _twr_module_encoder_exti_handler(twr_exti_line_t line, void *param)
142 {
143  (void) line;
144  (void) param;
145 
146  // Read current GPIO state
147  _twr_module_encoder.samples <<= 2;
148  _twr_module_encoder.samples |= twr_gpio_get_input(TWR_GPIO_P4) ? 0x1 : 0;
149  _twr_module_encoder.samples |= twr_gpio_get_input(TWR_GPIO_P5) ? 0x2 : 0;
150  _twr_module_encoder.samples &= 0xf;
151 
152  if (_twr_module_encoder.samples == 0x7)
153  {
154  _twr_module_encoder.increment--;
155 
156  twr_scheduler_plan_now(_twr_module_encoder.task_id);
157  }
158  else if (_twr_module_encoder.samples == 0xd)
159  {
160  _twr_module_encoder.increment++;
161 
162  twr_scheduler_plan_now(_twr_module_encoder.task_id);
163  }
164 }
165 
166 static void _twr_module_encoder_button_event_handler(twr_button_t *self, twr_button_event_t event, void *event_param)
167 {
168  (void) self;
169  (void) event_param;
170 
171  if (_twr_module_encoder.event_handler == NULL)
172  {
173  return;
174  }
175 
176  if (event == TWR_BUTTON_EVENT_PRESS)
177  {
178  _twr_module_encoder.event_handler(TWR_MODULE_ENCODER_EVENT_PRESS, _twr_module_encoder.event_param);
179  }
180  else if (event == TWR_BUTTON_EVENT_RELEASE)
181  {
182  _twr_module_encoder.event_handler(TWR_MODULE_ENCODER_EVENT_RELEASE, _twr_module_encoder.event_param);
183  }
184  else if (event == TWR_BUTTON_EVENT_CLICK)
185  {
186  _twr_module_encoder.event_handler(TWR_MODULE_ENCODER_EVENT_CLICK, _twr_module_encoder.event_param);
187  }
188  else if (event == TWR_BUTTON_EVENT_HOLD)
189  {
190  _twr_module_encoder.event_handler(TWR_MODULE_ENCODER_EVENT_HOLD, _twr_module_encoder.event_param);
191  }
192 }
193 
194 static bool _twr_module_encoder_test_pin(twr_gpio_channel_t channel)
195 {
197 
198  twr_gpio_set_output(channel, 1);
199 
201 
203 
204  twr_timer_start();
205 
206  twr_timer_delay(20);
207 
208  twr_timer_stop();
209 
210  int value = twr_gpio_get_input(channel);
211 
213 
215 
216  return value != 0;
217 }
218 
219 static bool _twr_module_encoder_present_test(void)
220 {
221  twr_system_pll_enable();
222 
223  twr_timer_init();
224 
226 
228 
229  bool is_present = _twr_module_encoder_test_pin(TWR_GPIO_P4) && _twr_module_encoder_test_pin(TWR_GPIO_P5);
230 
231  twr_system_pll_disable();
232 
233  return is_present;
234 }
int twr_module_encoder_get_increment(void)
Read encoder delta increment (can be positive or negative number)
void twr_gpio_set_mode(twr_gpio_channel_t channel, twr_gpio_mode_t mode)
Set mode of operation for GPIO channel.
Definition: twr_gpio.c:367
twr_button_event_t
Callback events.
Definition: twr_button.h:14
Event button hold (pressed for longer time)
Definition: twr_button.h:26
Event button clicked (pressed and released within certain time)
void twr_irq_enable(void)
Enable interrupt requests globally (call can be nested)
Definition: twr_irq.c:21
Event button pressed.
Definition: twr_button.h:17
int twr_gpio_get_input(twr_gpio_channel_t channel)
Get input state for GPIO channel.
Definition: twr_gpio.c:465
GPIO channel operates as output.
Definition: twr_gpio.h:108
GPIO channel BUTTON.
Definition: twr_gpio.h:72
twr_scheduler_task_id_t twr_scheduler_register(void(*task)(void *), void *param, twr_tick_t tick)
Register task in scheduler.
Definition: twr_scheduler.c:53
Event button clicked (pressed and released within certain time)
Definition: twr_button.h:23
void twr_gpio_set_pull(twr_gpio_channel_t channel, twr_gpio_pull_t pull)
Set pull-up/pull-down configuration for GPIO channel.
Definition: twr_gpio.c:340
void twr_button_set_event_handler(twr_button_t *self, void(*event_handler)(twr_button_t *, twr_button_event_t, void *), void *event_param)
Set callback function.
Definition: twr_button.c:66
GPIO channel operates in analog mode.
Definition: twr_gpio.h:114
Event button hold (pressed for longer time)
GPIO channel has no pull-up/pull-down.
Definition: twr_gpio.h:90
void twr_timer_stop(void)
Stop timer.
Definition: twr_timer.c:42
twr_exti_line_t
EXTI lines.
Definition: twr_exti.h:21
EXTI line P5.
Definition: twr_exti.h:150
void twr_gpio_init(twr_gpio_channel_t channel)
Initialize GPIO channel.
Definition: twr_gpio.c:325
twr_gpio_channel_t
GPIO channels.
Definition: twr_gpio.h:12
EXTI line is configured to both rising and falling edge sensitivity.
Definition: twr_exti.h:204
size_t twr_scheduler_task_id_t
Task ID assigned by scheduler.
Definition: twr_scheduler.h:22
void twr_button_init(twr_button_t *self, twr_gpio_channel_t gpio_channel, twr_gpio_pull_t gpio_pull, int idle_state)
Initialize button.
Definition: twr_button.c:20
twr_button_t * twr_module_encoder_get_button_instance(void)
Get encoder button instance.
void twr_timer_init(void)
Initialize timer.
Definition: twr_timer.c:23
void twr_module_encoder_init(void)
Initialize Encoder Module.
GPIO channel P4, A4, DAC0.
Definition: twr_gpio.h:27
EXTI line P4.
Definition: twr_exti.h:147
void twr_gpio_set_output(twr_gpio_channel_t channel, int state)
Set output state for GPIO channel.
Definition: twr_gpio.c:471
void twr_scheduler_unregister(twr_scheduler_task_id_t task_id)
Unregister specified task.
Definition: twr_scheduler.c:77
GPIO channel operates as input.
Definition: twr_gpio.h:105
void twr_module_encoder_set_event_handler(void(*event_handler)(twr_module_encoder_event_t, void *), void *event_param)
Set callback function.
Event error (module is not present)
void twr_exti_unregister(twr_exti_line_t line)
Disable EXTI line interrupt.
Definition: twr_exti.c:90
GPIO channel has pull-down.
Definition: twr_gpio.h:96
void twr_exti_register(twr_exti_line_t line, twr_exti_edge_t edge, void(*callback)(twr_exti_line_t, void *), void *param)
Enable EXTI line interrupt and register callback function.
Definition: twr_exti.c:17
void twr_irq_disable(void)
Disable interrupt requests globally (call can be nested)
Definition: twr_irq.c:7
GPIO channel P5, A5, DAC1.
Definition: twr_gpio.h:30
twr_module_encoder_event_t
Callback events.
bool twr_module_encoder_is_present(void)
Get Encoder Module is pressent, can use without twr_module_encoder_init.
void twr_module_encoder_deinit(void)
Deinitialize Encoder Module.
void twr_timer_delay(uint16_t microseconds)
Relative delay.
Definition: twr_timer.c:59
struct twr_button_t twr_button_t
Button instance.
Definition: twr_button.h:32
void twr_scheduler_plan_now(twr_scheduler_task_id_t task_id)
Schedule specified task for immediate execution.
void twr_timer_start(void)
Start timer.
Definition: twr_timer.c:28
Event button released.
Definition: twr_button.h:20