Firmware SDK
twr_pyq1648.c
1 #include <twr_pyq1648.h>
2 #include <twr_irq.h>
3 #include <twr_gpio.h>
4 #include <twr_system.h>
5 #include <twr_timer.h>
6 #include <stm32l0xx.h>
7 
8 #define TWR_PYQ1648_BPF 0x00
9 #define TWR_PYQ1648_LPF 0x01
10 #define TWR_PYQ1648_WAKE_UP_MODE 0x02
11 
12 #define TWR_PYQ1648_DELAY_RUN 50
13 #define TWR_PYQ1648_DELAY_INITIALIZATION 10
14 #define TWR_PYQ1648_UPDATE_INTERVAL 100
15 
16 static inline void _twr_pyq1648_msp_init(twr_gpio_channel_t gpio_channel_serin, twr_gpio_channel_t gpio_channel_dl);
17 static inline void _twr_pyq1648_dev_init(twr_pyq1648_t *self);
18 static inline void _twr_pyq1648_compose_event_unit_config(twr_pyq1648_t *self);
19 static void _twr_pyq1648_task(void *param);
20 
21 static const uint8_t _twr_pyq1648_sensitivity_table[4] =
22 {
27 };
28 
29 extern GPIO_TypeDef * twr_gpio_port[];
30 extern uint16_t twr_gpio_16_bit_mask[];
31 extern uint32_t twr_gpio_32_bit_upper_mask[];
32 
33 static GPIO_TypeDef **_pyq1648_gpiox_table = twr_gpio_port;
34 static uint16_t *_pyq1648_set_mask = twr_gpio_16_bit_mask;
35 static uint32_t *_pyq1648_reset_mask = twr_gpio_32_bit_upper_mask;
36 
37 void twr_pyq1648_init(twr_pyq1648_t *self, twr_gpio_channel_t gpio_channel_serin, twr_gpio_channel_t gpio_channel_dl)
38 {
39  // Initialize structure
40  memset(self, 0, sizeof(*self));
41 
42  // Initialize default values
43  self->_sensitivity = _twr_pyq1648_sensitivity_table[TWR_PYQ1648_SENSITIVITY_HIGH];
44  self->_blank_period = 1000;
45 
46  // Initialize actually used pins
47  self->_gpio_channel_serin = gpio_channel_serin;
48  self->_gpio_channel_dl = gpio_channel_dl;
49 
50  // Initialize event_unit_configuration register value
51  // _twr_pyq1648_compose_event_unit_config(self);
52 
53  // Register task
54  self->_task_id = twr_scheduler_register(_twr_pyq1648_task, self, TWR_PYQ1648_DELAY_RUN);
55 
57 }
58 
59 void twr_pyq1648_set_event_handler(twr_pyq1648_t *self, void (*event_handler)(twr_pyq1648_t *, twr_pyq1648_event_t, void *), void *event_param)
60 {
61  // Set event handler
62  self->_event_handler = event_handler;
63 
64  // Set event param
65  self->_event_param = event_param;
66 }
67 
69 {
70  // Set sensitivity to desired value
71  self->_sensitivity = _twr_pyq1648_sensitivity_table[sensitivity];
72 
73  self->_state = TWR_PYQ1648_STATE_INITIALIZE;
74 
75  twr_scheduler_plan_now(self->_task_id);
76 }
77 
79 {
80  // Set blank period
81  self->_blank_period = blank_period;
82 }
83 
84 void _twr_pyq1648_compose_event_unit_config(twr_pyq1648_t *self)
85 {
86  // --------------------------------------------------------------------------------------------------------------------------------------
87  // | Event unit configuration |
88  // --------------------------------------------------------------------------------------------------------------------------------------
89  // | 7bit sensitivity | 4bit blind time | 2bit pulse counter | 2bit window time | 2bit operatin mode | 2bit filter source | 5bit reserved |
90  // --------------------------------------------------------------------------------------------------------------------------------------
91  // | from self | handled by SW | 0x00 | 0x00 | wake up mode | Band pass filter | has to be 16 |
92  // --------------------------------------------------------------------------------------------------------------------------------------
93 
94  self->_config = 0x00000000;
95  self->_config |= (self->_sensitivity << 17) | (TWR_PYQ1648_WAKE_UP_MODE << 7) | (TWR_PYQ1648_BPF << 5) |0x10;
96 }
97 
98 static inline void _twr_pyq1648_msp_init(twr_gpio_channel_t gpio_channel_serin, twr_gpio_channel_t gpio_channel_dl)
99 {
100  // Initialize SerialIn (SERIN) GPIO pin
101  twr_gpio_init(gpio_channel_serin);
102  twr_gpio_set_mode(gpio_channel_serin, TWR_GPIO_MODE_OUTPUT);
103 
104  // Initialize DirectLink (DL) GPIO pin
105  twr_gpio_init(gpio_channel_dl);
106  twr_gpio_set_mode(gpio_channel_dl, TWR_GPIO_MODE_INPUT);
107  twr_gpio_set_pull(gpio_channel_dl, TWR_GPIO_PULL_DOWN);
108 }
109 
110 static void _twr_pyq1648_clear_event(twr_pyq1648_t *self)
111 {
112  // Clear event by pull down DL
113  twr_gpio_set_mode(self->_gpio_channel_dl, TWR_GPIO_MODE_OUTPUT);
114  twr_gpio_set_output(self->_gpio_channel_dl, 0);
115  twr_gpio_set_mode(self->_gpio_channel_dl, TWR_GPIO_MODE_INPUT);
116 }
117 
118 // TODO Consider using "OneWire"
119 static inline void _twr_pyq1648_dev_init(twr_pyq1648_t *self)
120 {
121  // Disable interrupts
122  twr_irq_disable();
123 
124  // Enable PLL
125  twr_system_pll_enable();
126 
127  // Load desired event unit configuration
128  uint32_t regval = self->_config;
129  uint32_t regmask = 0x1000000;
130  bool next_bit;
131 
132  // Prepare fast GPIO access
133  uint32_t bsrr_mask[2] =
134  {
135  [0] = _pyq1648_reset_mask[self->_gpio_channel_serin],
136  [1] = _pyq1648_set_mask[self->_gpio_channel_serin]
137  };
138  GPIO_TypeDef *GPIOx = _pyq1648_gpiox_table[self->_gpio_channel_serin];
139  volatile uint32_t *GPIOx_BSRR = &GPIOx->BSRR;
140 
141  // Low level pin initialization
142  _twr_pyq1648_msp_init(self->_gpio_channel_serin, self->_gpio_channel_dl);
143 
144  // Transmit event unit configuration
145  for (int i = 0; i < 25; i++)
146  {
147  next_bit = (regval & regmask) != 0 ? true : false;
148  regmask >>= 1;
149 
150  twr_timer_start();
151 
152  *GPIOx_BSRR = bsrr_mask[0];
153 
154  while (twr_timer_get_microseconds() < 1)
155  {
156  continue;
157  }
158 
159  *GPIOx_BSRR = bsrr_mask[1];
160 
161  while (twr_timer_get_microseconds() < 2)
162  {
163  continue;
164  }
165 
166  *GPIOx_BSRR = bsrr_mask[next_bit];
167 
168  while (twr_timer_get_microseconds() < 83)
169  {
170  continue;
171  }
172 
173  twr_timer_stop();
174  }
175 
176  twr_gpio_set_output(self->_gpio_channel_serin, 0);
177 
178  // Disable PLL
179  twr_system_pll_disable();
180 
181  // Enable interrupts
182  twr_irq_enable();
183 }
184 
185 static void _twr_pyq1648_task(void *param)
186 {
187  twr_pyq1648_t *self = param;
188 
189 start:
190 
191  switch (self->_state)
192  {
193  case TWR_PYQ1648_STATE_ERROR:
194  {
195  if (self->_event_handler != NULL)
196  {
197  self->_event_handler(self, TWR_PYQ1648_EVENT_ERROR, self->_event_param);
198  }
199 
200  self->_state = TWR_PYQ1648_STATE_INITIALIZE;
201 
202  twr_scheduler_plan_current_relative(TWR_PYQ1648_UPDATE_INTERVAL);
203 
204  return;
205  }
206  case TWR_PYQ1648_STATE_INITIALIZE:
207  {
208  self->_state = TWR_PYQ1648_STATE_ERROR;
209 
210  _twr_pyq1648_compose_event_unit_config(self);
211 
212  _twr_pyq1648_dev_init(self);
213 
214  self->_state = TWR_PYQ1648_STATE_IGNORE;
215 
216  twr_scheduler_plan_current_relative(TWR_PYQ1648_DELAY_INITIALIZATION);
217 
218  return;
219  }
220  case TWR_PYQ1648_STATE_IGNORE:
221  {
222  self->_state = TWR_PYQ1648_STATE_ERROR;
223 
224  if (self->_ignore_untill == 0)
225  {
226  // TODO ... acquire !!!
227  self->_ignore_untill = twr_tick_get() + (75000 / 15);
228  }
229 
230  if (twr_gpio_get_input(self->_gpio_channel_dl) != 0)
231  {
232  _twr_pyq1648_clear_event(self);
233  }
234 
235  if (twr_tick_get() >= self->_ignore_untill)
236  {
237  self->_state = TWR_PYQ1648_STATE_CHECK;
238  }
239  else
240  {
241  self->_state = TWR_PYQ1648_STATE_IGNORE;
242  }
243 
244  twr_scheduler_plan_current_relative(TWR_PYQ1648_UPDATE_INTERVAL);
245 
246  return;
247  }
248  case TWR_PYQ1648_STATE_CHECK:
249  {
250  twr_tick_t tick_now = twr_tick_get();
251 
252  self->_state = TWR_PYQ1648_STATE_ERROR;
253 
254  if (twr_gpio_get_input(self->_gpio_channel_dl) != 0)
255  {
256  if (tick_now >= self->_aware_time)
257  {
258  if (self->_event_handler != NULL)
259  {
260  self->_event_handler(self, TWR_PYQ1648_EVENT_MOTION, self->_event_param);
261  }
262 
263  self->_aware_time = tick_now + self->_blank_period;
264  }
265  _twr_pyq1648_clear_event(self);
266  }
267 
268  self->_state = TWR_PYQ1648_STATE_CHECK;
269 
270  twr_scheduler_plan_current_relative(TWR_PYQ1648_UPDATE_INTERVAL);
271 
272  return;
273  }
274  default:
275  {
276  self->_state = TWR_PYQ1648_STATE_ERROR;
277 
278  goto start;
279  }
280  }
281 }
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_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_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:13
int twr_gpio_get_input(twr_gpio_channel_t channel)
Get input state for GPIO channel.
Definition: twr_gpio.c:465
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_GPIO_MODE_INPUT
GPIO channel operates as input.
Definition: twr_gpio.h:105
@ TWR_GPIO_MODE_OUTPUT
GPIO channel operates as output.
Definition: twr_gpio.h:108
@ TWR_GPIO_PULL_DOWN
GPIO channel has pull-down.
Definition: twr_gpio.h:96
void twr_irq_disable(void)
Disable interrupt requests globally (call can be nested)
Definition: twr_irq.c:7
void twr_irq_enable(void)
Enable interrupt requests globally (call can be nested)
Definition: twr_irq.c:21
struct twr_pyq1648_t twr_pyq1648_t
PYQ1648 instance.
Definition: twr_pyq1648.h:44
void twr_pyq1648_set_sensitivity(twr_pyq1648_t *self, twr_pyq1648_sensitivity_t sensitivity)
Set PYQ1648 sensitivity.
Definition: twr_pyq1648.c:68
void twr_pyq1648_set_blank_period(twr_pyq1648_t *self, twr_tick_t blank_period)
Set blank period (for how long alarm events will be ignored)
Definition: twr_pyq1648.c:78
void twr_pyq1648_init(twr_pyq1648_t *self, twr_gpio_channel_t gpio_channel_serin, twr_gpio_channel_t gpio_channel_dl)
Initialize PYQ1648 driver.
Definition: twr_pyq1648.c:37
twr_pyq1648_sensitivity_t
Possible sensitivities.
Definition: twr_pyq1648.h:27
void twr_pyq1648_set_event_handler(twr_pyq1648_t *self, void(*event_handler)(twr_pyq1648_t *, twr_pyq1648_event_t, void *), void *event_param)
Set callback function.
Definition: twr_pyq1648.c:59
twr_pyq1648_event_t
Callback events.
Definition: twr_pyq1648.h:15
@ TWR_PYQ1648_SENSITIVITY_HIGH
High sensitivity.
Definition: twr_pyq1648.h:35
@ TWR_PYQ1648_SENSITIVITY_VERY_HIGH
Very high sensitivity.
Definition: twr_pyq1648.h:38
@ TWR_PYQ1648_SENSITIVITY_LOW
Low sensitivity.
Definition: twr_pyq1648.h:29
@ TWR_PYQ1648_SENSITIVITY_MEDIUM
Medium sensitivity.
Definition: twr_pyq1648.h:32
@ TWR_PYQ1648_EVENT_ERROR
Error event.
Definition: twr_pyq1648.h:17
@ TWR_PYQ1648_EVENT_MOTION
Update event.
Definition: twr_pyq1648.h:20
void twr_scheduler_plan_current_relative(twr_tick_t tick)
Schedule current task to tick relative from current spin.
void twr_scheduler_plan_now(twr_scheduler_task_id_t task_id)
Schedule specified task for immediate execution.
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
twr_tick_t twr_tick_get(void)
Get absolute timestamp since start of program.
Definition: twr_tick.c:7
uint64_t twr_tick_t
Timestamp data type.
Definition: twr_tick.h:16
void twr_timer_init(void)
Initialize timer.
Definition: twr_timer.c:23
void twr_timer_stop(void)
Stop timer.
Definition: twr_timer.c:42
void twr_timer_start(void)
Start timer.
Definition: twr_timer.c:28
uint16_t twr_timer_get_microseconds(void)
Get actual tick of timer.
Definition: twr_timer.c:54