Firmware SDK
 All Data Structures Functions Variables Typedefs Enumerations Enumerator Groups Pages
bc_module_encoder.c
1 #include <bc_module_encoder.h>
2 #include <bc_scheduler.h>
3 #include <bc_exti.h>
4 #include <bc_irq.h>
5 #include <bc_system.h>
6 #include <bc_timer.h>
7 
8 static struct
9 {
10  bool initialized;
11  bc_scheduler_task_id_t task_id;
12  void (*event_handler)(bc_module_encoder_event_t, void *);
13  void *event_param;
14  bc_button_t button;
15  int increment;
16  int increment_shadow;
17  int samples;
18 
19 } _bc_module_encoder;
20 
21 static void _bc_module_encoder_task(void *param);
22 
23 static void _bc_module_encoder_exti_handler(bc_exti_line_t line, void *param);
24 
25 static void _bc_module_encoder_button_event_handler(bc_button_t *self, bc_button_event_t event, void *event_param);
26 
27 static bool _bc_module_encoder_present_test(void);
28 
30 {
31  memset(&_bc_module_encoder, 0, sizeof(_bc_module_encoder));
32 
33  // Initialize encoder button
34  bc_button_init(&_bc_module_encoder.button, BC_GPIO_BUTTON, BC_GPIO_PULL_DOWN, false);
35  bc_button_set_event_handler(&_bc_module_encoder.button, _bc_module_encoder_button_event_handler, NULL);
36 
37  // Init encoder GPIO pins
39 
41 
42  // Register task
43  _bc_module_encoder.task_id = bc_scheduler_register(_bc_module_encoder_task, NULL, 0);
44 }
45 
47 {
48  // Unregister task
49  bc_scheduler_unregister(_bc_module_encoder.task_id);
50 
52 
54 
55  if (_bc_module_encoder.initialized)
56  {
58 
60  }
61 }
62 
63 void bc_module_encoder_set_event_handler(void (*event_handler)(bc_module_encoder_event_t, void *), void *event_param)
64 {
65  _bc_module_encoder.event_handler = event_handler;
66 
67  _bc_module_encoder.event_param = event_param;
68 }
69 
71 {
72  return &_bc_module_encoder.button;
73 }
74 
76 {
77  return _bc_module_encoder.increment_shadow;
78 }
79 
81 {
82  if (_bc_module_encoder.initialized)
83  {
84  return true;
85  }
86 
87  return _bc_module_encoder_present_test();
88 }
89 
90 static void _bc_module_encoder_task(void *param)
91 {
92  (void) param;
93 
94  if (_bc_module_encoder.initialized)
95  {
96  // Disable interrupts
98 
99  _bc_module_encoder.increment_shadow = _bc_module_encoder.increment;
100  _bc_module_encoder.increment = 0;
101 
102  // Enable interrupts
103  bc_irq_enable();
104 
105  if (_bc_module_encoder.increment_shadow != 0)
106  {
107  if (_bc_module_encoder.event_handler != NULL)
108  {
109  _bc_module_encoder.event_handler(BC_MODULE_ENCODER_EVENT_ROTATION, _bc_module_encoder.event_param);
110  }
111  }
112  }
113  else
114  {
115  if (_bc_module_encoder_present_test())
116  {
117  // Set encoder GPIO pins as inputs
120 
121  // Remember initial GPIO states
122  _bc_module_encoder.samples |= bc_gpio_get_input(BC_GPIO_P4) ? 0x1 : 0;
123  _bc_module_encoder.samples |= bc_gpio_get_input(BC_GPIO_P5) ? 0x2 : 0;
124 
125  // Register interrupts on both GPIO pins
126  bc_exti_register(BC_EXTI_LINE_P4, BC_EXTI_EDGE_RISING_AND_FALLING, _bc_module_encoder_exti_handler, NULL);
127  bc_exti_register(BC_EXTI_LINE_P5, BC_EXTI_EDGE_RISING_AND_FALLING, _bc_module_encoder_exti_handler, NULL);
128 
129  _bc_module_encoder.initialized = true;
130  }
131  else
132  {
133  if (_bc_module_encoder.event_handler != NULL)
134  {
135  _bc_module_encoder.event_handler(BC_MODULE_ENCODER_EVENT_ERROR, _bc_module_encoder.event_param);
136  }
137  }
138  }
139 }
140 
141 static void _bc_module_encoder_exti_handler(bc_exti_line_t line, void *param)
142 {
143  (void) line;
144  (void) param;
145 
146  // Read current GPIO state
147  _bc_module_encoder.samples <<= 2;
148  _bc_module_encoder.samples |= bc_gpio_get_input(BC_GPIO_P4) ? 0x1 : 0;
149  _bc_module_encoder.samples |= bc_gpio_get_input(BC_GPIO_P5) ? 0x2 : 0;
150  _bc_module_encoder.samples &= 0xf;
151 
152  if (_bc_module_encoder.samples == 0x7)
153  {
154  _bc_module_encoder.increment--;
155 
156  bc_scheduler_plan_now(_bc_module_encoder.task_id);
157  }
158  else if (_bc_module_encoder.samples == 0xd)
159  {
160  _bc_module_encoder.increment++;
161 
162  bc_scheduler_plan_now(_bc_module_encoder.task_id);
163  }
164 }
165 
166 static void _bc_module_encoder_button_event_handler(bc_button_t *self, bc_button_event_t event, void *event_param)
167 {
168  (void) self;
169  (void) event_param;
170 
171  if (_bc_module_encoder.event_handler == NULL)
172  {
173  return;
174  }
175 
176  if (event == BC_BUTTON_EVENT_PRESS)
177  {
178  _bc_module_encoder.event_handler(BC_MODULE_ENCODER_EVENT_PRESS, _bc_module_encoder.event_param);
179  }
180  else if (event == BC_BUTTON_EVENT_RELEASE)
181  {
182  _bc_module_encoder.event_handler(BC_MODULE_ENCODER_EVENT_RELEASE, _bc_module_encoder.event_param);
183  }
184  else if (event == BC_BUTTON_EVENT_CLICK)
185  {
186  _bc_module_encoder.event_handler(BC_MODULE_ENCODER_EVENT_CLICK, _bc_module_encoder.event_param);
187  }
188  else if (event == BC_BUTTON_EVENT_HOLD)
189  {
190  _bc_module_encoder.event_handler(BC_MODULE_ENCODER_EVENT_HOLD, _bc_module_encoder.event_param);
191  }
192 }
193 
194 static bool _bc_module_encoder_test_pin(bc_gpio_channel_t channel)
195 {
197 
198  bc_gpio_set_output(channel, 1);
199 
201 
203 
204  bc_timer_start();
205 
206  bc_timer_delay(20);
207 
208  bc_timer_stop();
209 
210  int value = bc_gpio_get_input(channel);
211 
213 
215 
216  return value != 0;
217 }
218 
219 static bool _bc_module_encoder_present_test(void)
220 {
221  bc_system_pll_enable();
222 
223  bc_timer_init();
224 
226 
228 
229  bool is_present = _bc_module_encoder_test_pin(BC_GPIO_P4) && _bc_module_encoder_test_pin(BC_GPIO_P5);
230 
231  bc_system_pll_disable();
232 
233  return is_present;
234 }
GPIO channel P5.
Definition: bc_gpio.h:30
void bc_irq_enable(void)
Enable interrupt requests globally (call can be nested)
Definition: bc_irq.c:21
bc_button_t * bc_module_encoder_get_button_instance(void)
Get encoder button instance.
EXTI line P5.
Definition: bc_exti.h:150
GPIO channel has no pull-up/pull-down.
Definition: bc_gpio.h:84
Event button released.
Definition: bc_button.h:20
bc_module_encoder_event_t
Callback events.
void bc_timer_start(void)
Start timer.
Definition: bc_timer.c:24
Event button pressed.
Definition: bc_button.h:17
bc_scheduler_task_id_t bc_scheduler_register(void(*task)(void *), void *param, bc_tick_t tick)
Register task in scheduler.
Definition: bc_scheduler.c:56
EXTI line P4.
Definition: bc_exti.h:147
int bc_module_encoder_get_increment(void)
Read encoder delta increment (can be positive or negative number)
void bc_scheduler_plan_now(bc_scheduler_task_id_t task_id)
Schedule specified task for immediate execution.
Definition: bc_scheduler.c:119
void bc_timer_delay(uint16_t microseconds)
Relative delay.
Definition: bc_timer.c:40
void bc_gpio_set_output(bc_gpio_channel_t channel, int state)
Set output state for GPIO channel.
Definition: bc_gpio.c:442
EXTI line is configured to both rising and falling edge sensitivity.
Definition: bc_exti.h:204
void bc_gpio_set_mode(bc_gpio_channel_t channel, bc_gpio_mode_t mode)
Set mode of operation for GPIO channel.
Definition: bc_gpio.c:340
void bc_gpio_set_pull(bc_gpio_channel_t channel, bc_gpio_pull_t pull)
Set pull-up/pull-down configuration for GPIO channel.
Definition: bc_gpio.c:313
void bc_timer_stop(void)
Stop timer.
Definition: bc_timer.c:55
bool bc_module_encoder_is_present(void)
Get Encoder Module is pressent, can use without bc_module_encoder_init.
size_t bc_scheduler_task_id_t
Task ID assigned by scheduler.
Definition: bc_scheduler.h:18
int bc_gpio_get_input(bc_gpio_channel_t channel)
Get input state for GPIO channel.
Definition: bc_gpio.c:436
GPIO channel operates as input.
Definition: bc_gpio.h:99
bc_button_event_t
Callback events.
Definition: bc_button.h:14
GPIO channel BUTTON.
Definition: bc_gpio.h:72
void bc_exti_register(bc_exti_line_t line, bc_exti_edge_t edge, void(*callback)(bc_exti_line_t, void *), void *param)
Enable EXTI line interrupt and register callback function.
Definition: bc_exti.c:17
Event button hold (pressed for longer time)
Definition: bc_button.h:26
void bc_exti_unregister(bc_exti_line_t line)
Disable EXTI line interrupt.
Definition: bc_exti.c:90
Event error (module is not present)
bc_exti_line_t
EXTI lines.
Definition: bc_exti.h:21
GPIO channel has pull-down.
Definition: bc_gpio.h:90
bc_gpio_channel_t
GPIO channels.
Definition: bc_gpio.h:12
void bc_module_encoder_init(void)
Initialize Encoder Module.
Event button clicked (pressed and released within certain time)
Definition: bc_button.h:23
void bc_button_set_event_handler(bc_button_t *self, void(*event_handler)(bc_button_t *, bc_button_event_t, void *), void *event_param)
Set callback function.
Definition: bc_button.c:66
void bc_irq_disable(void)
Disable interrupt requests globally (call can be nested)
Definition: bc_irq.c:7
Event button pressed.
Event button clicked (pressed and released within certain time)
void bc_timer_init(void)
Initialize timer.
Definition: bc_timer.c:18
GPIO channel operates in analog mode.
Definition: bc_gpio.h:108
struct bc_button_t bc_button_t
Button instance.
Definition: bc_button.h:32
GPIO channel P4.
Definition: bc_gpio.h:27
void bc_button_init(bc_button_t *self, bc_gpio_channel_t gpio_channel, bc_gpio_pull_t gpio_pull, int idle_state)
Initialize button.
Definition: bc_button.c:20
void bc_gpio_init(bc_gpio_channel_t channel)
Initialize GPIO channel.
Definition: bc_gpio.c:301
void bc_scheduler_unregister(bc_scheduler_task_id_t task_id)
Unregister specified task.
Definition: bc_scheduler.c:80
void bc_module_encoder_set_event_handler(void(*event_handler)(bc_module_encoder_event_t, void *), void *event_param)
Set callback function.
GPIO channel operates as output.
Definition: bc_gpio.h:102
Event button hold (pressed for longer time)
void bc_module_encoder_deinit(void)
Deinitialize Encoder Module.