Firmware SDK
 All Data Structures Functions Variables Typedefs Enumerations Enumerator Groups Pages
bc_ir_rx.c
1 
2 #include <stm32l0xx.h>
3 #include <bc_common.h>
4 #include <bc_gpio.h>
5 #include <bc_exti.h>
6 #include <bc_scheduler.h>
7 #include <bc_system.h>
8 #include "bc_ir_rx.h"
9 #include <bc_timer.h>
10 
11 //#define _BC_IR_RX_DEBUG
12 
13 // IR receiver has to be connected on
14 // BC_GPIO_P10
15 // No external pull-up required, internal pull-up is activated
16 
17 static struct
18 {
19  TIM_HandleTypeDef ir_timer;
20  uint8_t counter;
21  uint32_t ir_rx_temp;
22  uint32_t ir_rx_value;
23 
24  bc_scheduler_task_id_t task_id_notify;
25 
26  void (*event_handler)(bc_ir_rx_event_t, void *);
27  void *event_param;
28 
29  #ifdef _BC_IR_RX_DEBUG
30  uint16_t lengths[40];
31  #endif
32 } _bc_ir_rx;
33 
34 static void TIM6_handler(void *param);
35 
36 void bc_ir_rx_get_code(uint32_t *nec_code)
37 {
38  *nec_code = _bc_ir_rx.ir_rx_value;
39 }
40 
41 
42 static void _bc_ir_rx_task_notify(void *param)
43 {
44  (void) param;
45 
46  if (_bc_ir_rx.event_handler != NULL)
47  {
48  _bc_ir_rx.event_handler(BC_IR_RX_NEC_FORMAT, _bc_ir_rx.event_param);
49  }
50 }
51 
52 static void _bc_ir_rx_exti_int(bc_exti_line_t line, void *param)
53 {
54  (void) param;
55  (void) line;
56 
57  #ifdef _BC_IR_RX_DEBUG
59  #endif
60 
61  if(_bc_ir_rx.counter == 0)
62  {
63  // Start pulse, start timer
64  __HAL_TIM_DISABLE(&_bc_ir_rx.ir_timer);
65  __HAL_TIM_DISABLE_IT(&_bc_ir_rx.ir_timer, TIM_IT_UPDATE);
66  __HAL_TIM_CLEAR_IT(&_bc_ir_rx.ir_timer, TIM_IT_UPDATE);
67 
68  HAL_TIM_Base_Start_IT(&_bc_ir_rx.ir_timer);
69  _bc_ir_rx.counter++;
70  return;
71  }
72 
73  // Get value and clear the timer
74  uint16_t act_len = __HAL_TIM_GET_COUNTER(&_bc_ir_rx.ir_timer);
75  __HAL_TIM_SET_COUNTER(&_bc_ir_rx.ir_timer, 0);
76 
77  // Array for debugging
78  #ifdef _BC_IR_RX_DEBUG
79  _bc_ir_rx.lengths[_bc_ir_rx.counter] = act_len;
80  #endif
81 
82  // Check start pulse length
83  if(_bc_ir_rx.counter == 1)
84  {
85  if(act_len < 8000 || act_len > 14000)
86  {
87  // Ignore this packet
88  volatile int a = 5;
89  a++;
90  return;
91  }
92  }
93 
94  if(_bc_ir_rx.counter == 2)
95  {
96  _bc_ir_rx.ir_rx_temp = 0;
97  }
98 
99  // ignore first two items (first zero value and start pulse)
100  if(act_len > 1500 && _bc_ir_rx.counter >= 2)
101  {
102  _bc_ir_rx.ir_rx_temp |= (1 << (_bc_ir_rx.counter-2));
103  }
104 
105  // Received packet
106  if(_bc_ir_rx.counter == 33)
107  {
108  #ifdef _BC_IR_RX_DEBUG
109  // Debug toggle
113  #endif
114 
115  _bc_ir_rx.counter = 0;
116  _bc_ir_rx.ir_rx_value = _bc_ir_rx.ir_rx_temp;
117 
118  // The ir_rx_value should have inverted one addr and one command byte, but
119  // the test of my IR remotes shows, that only the second CMD byte is inversion of the fist one
120 
121  __HAL_TIM_DISABLE(&_bc_ir_rx.ir_timer);
122  __HAL_TIM_DISABLE_IT(&_bc_ir_rx.ir_timer, TIM_IT_UPDATE);
123  __HAL_TIM_CLEAR_IT(&_bc_ir_rx.ir_timer, TIM_IT_UPDATE);
124 
125  bc_scheduler_plan_now(_bc_ir_rx.task_id_notify);
126 
127  return;
128  }
129 
130  _bc_ir_rx.counter++;
131 }
132 
133 void bc_ir_rx_set_event_handler(void (*event_handler)(bc_ir_rx_event_t, void *), void *event_param)
134 {
135  _bc_ir_rx.event_handler = event_handler;
136  _bc_ir_rx.event_param = event_param;
137 }
138 
139 void bc_ir_rx_init()
140 {
141  // TODO: Needs fix to allow low power
142  bc_system_pll_enable();
143 
144  // IR input
148  // External interrupt
149  bc_exti_register(BC_EXTI_LINE_P10, BC_EXTI_EDGE_FALLING, _bc_ir_rx_exti_int, NULL);
150 
151  #ifdef _BC_IR_RX_DEBUG
152  // Debug output
155  #endif
156 
157  // Used TIM6 so we don't have collision of IRQ handlers functions
158  __TIM6_CLK_ENABLE();
159  _bc_ir_rx.ir_timer.Instance = TIM6;
160  // Running @ 32MHz, set timer to 1us resolution
161  _bc_ir_rx.ir_timer.Init.Prescaler = SystemCoreClock / 1000000;
162  _bc_ir_rx.ir_timer.Init.CounterMode = TIM_COUNTERMODE_UP;
163  // Period is also the timeout in case the IR code is not complete
164  _bc_ir_rx.ir_timer.Init.Period = 16000;
165  _bc_ir_rx.ir_timer.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
166  HAL_TIM_Base_Init(&_bc_ir_rx.ir_timer);
167  HAL_NVIC_EnableIRQ(TIM6_IRQn);
168 
169  bc_timer_set_irq_handler(TIM6, TIM6_handler, NULL);
170 
171 
172  _bc_ir_rx.task_id_notify = bc_scheduler_register(_bc_ir_rx_task_notify, NULL, BC_TICK_INFINITY);
173 
174 }
175 
176 static void TIM6_handler(void *param)
177 {
178  (void) param;
179 
180  #ifdef _BC_IR_RX_DEBUG
185  #endif
186 
187  if(__HAL_TIM_GET_FLAG(&_bc_ir_rx.ir_timer, TIM_FLAG_UPDATE) != RESET)
188  {
189  if(__HAL_TIM_GET_IT_SOURCE(&_bc_ir_rx.ir_timer, TIM_IT_UPDATE) !=RESET)
190  {
191  // Stop timer
192  __HAL_TIM_CLEAR_IT(&_bc_ir_rx.ir_timer, TIM_IT_UPDATE);
193  __HAL_TIM_DISABLE(&_bc_ir_rx.ir_timer);
194  __HAL_TIM_DISABLE_IT(&_bc_ir_rx.ir_timer, TIM_IT_UPDATE);
195 
196  _bc_ir_rx.counter = 0;
197  }
198  }
199 }
GPIO channel has pull-up.
Definition: bc_gpio.h:87
EXTI line P10.
Definition: bc_exti.h:165
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
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_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
GPIO channel P10.
Definition: bc_gpio.h:45
size_t bc_scheduler_task_id_t
Task ID assigned by scheduler.
Definition: bc_scheduler.h:18
GPIO channel operates as input.
Definition: bc_gpio.h:99
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
GPIO channel P11.
Definition: bc_gpio.h:48
bool bc_timer_set_irq_handler(TIM_TypeDef *tim, void(*irq_handler)(void *), void *irq_param)
Register timer IRQ handler.
Definition: bc_timer.c:74
bc_exti_line_t
EXTI lines.
Definition: bc_exti.h:21
void bc_gpio_toggle_output(bc_gpio_channel_t channel)
Toggle output state for GPIO channel.
Definition: bc_gpio.c:454
#define BC_TICK_INFINITY
Maximum timestamp value.
Definition: bc_tick.h:12
void bc_gpio_init(bc_gpio_channel_t channel)
Initialize GPIO channel.
Definition: bc_gpio.c:301
GPIO channel operates as output.
Definition: bc_gpio.h:102
EXTI line is configured to falling edge sensitivity.
Definition: bc_exti.h:201