Sistema l'errore da me commesso in fase di conversione...
[bertos.git] / drv / kbd.c
1 /**
2  * \file
3  * <!--
4  * Copyright 2003, 2004, 2005 Develer S.r.l. (http://www.develer.com/)
5  * Copyright 1999, 2003 Bernardo Innocenti
6  * This file is part of DevLib - See README.devlib for information.
7  * -->
8  *
9  * \version $Id$
10  *
11  * \author Bernardo Innocenti <bernie@develer.com>
12  * \author Stefano Fedrigo <aleph@develer.com>
13  * \author Francesco Sacchi <batt@develer.com>
14  *
15  * \brief Keyboard driver (implementation)
16  */
17
18 /*#*
19  *#* $Log$
20  *#* Revision 1.9  2006/09/13 18:25:45  bernie
21  *#* Merge CONFIG_KBD_LONGPRESS.
22  *#*
23  *#* Revision 1.8  2006/07/19 12:56:25  bernie
24  *#* Convert to new Doxygen style.
25  *#*
26  *#* Revision 1.7  2006/06/03 13:57:36  bernie
27  *#* Make keyboard repeat mask run-time configurable.
28  *#*
29  *#* Revision 1.6  2006/03/20 17:50:17  bernie
30  *#* Add FreeRTOS and Observers support.
31  *#*
32  *#* Revision 1.5  2006/02/27 22:39:45  bernie
33  *#* Misc build and doc fixes from project_grl.
34  *#*
35  *#* Revision 1.4  2006/02/24 00:27:14  bernie
36  *#* Use new naming convention for list macros.
37  *#*
38  *#* Revision 1.3  2006/02/17 21:15:42  bernie
39  *#* Add MOD_CHECK() checks.
40  *#*
41  *#* Revision 1.2  2006/02/10 12:36:20  bernie
42  *#* Add preliminary FreeRTOS support; Enforce CONFIG_* definitions.
43  *#*
44  *#* Revision 1.1  2005/06/27 21:28:45  bernie
45  *#* Import generic keyboard driver.
46  *#*
47  *#*/
48
49 #include <hw_kbd.h>
50
51 #include <drv/timer.h>
52 #include <drv/kbd.h>
53
54 #include <cfg/debug.h>
55 #include <cfg/module.h>
56 #include <appconfig.h>
57
58 /* Configuration sanity checks */
59 #if !defined(CONFIG_KBD_POLL) || (CONFIG_KBD_POLL != KBD_POLL_SOFTINT && CONFIG_KBD_POLL != CONFIG_POLL_FREERTOS)
60         #error CONFIG_KBD_POLL must be defined to either KBD_POLL_SOFTINT or CONFIG_POLL_FREERTOS
61 #endif
62 #if !defined(CONFIG_KBD_BEEP) || (CONFIG_KBD_BEEP != 0 && CONFIG_KBD_BEEP != 1)
63         #error CONFIG_KBD_BEEP must be defined to either 0 or 1
64 #endif
65 #if !defined(CONFIG_KBD_OBSERVER) || (CONFIG_KBD_OBSERVER != 0 && CONFIG_KBD_OBSERVER != 1)
66         #error CONFIG_KBD_OBSERVER must be defined to either 0 or 1
67 #endif
68 #if !defined(CONFIG_KBD_LONGPRESS) || (CONFIG_KBD_LONGPRESS != 0 && CONFIG_KBD_LONGPRESS != 1)
69         #error CONFIG_KBD_LONGPRESS must be defined to either 0 or 1
70 #endif
71
72 #if CONFIG_KBD_BEEP
73         #include <drv/buzzer.h>
74 #endif
75
76 #define KBD_CHECK_INTERVAL  10  /**< (ms) Timing for kbd softint */
77 #define KBD_DEBOUNCE_TIME   30  /**< (ms) Debounce time */
78 #define KBD_BEEP_TIME        5  /**< (ms) Duration of keybeep */
79
80 #define KBD_REPEAT_DELAY   400  /**< (ms) Keyboard repeat delay for first character */
81 #define KBD_REPEAT_RATE    100  /**< (ms) Initial interchar delay for keyboard repeat */
82 #define KBD_REPEAT_MAXRATE  20  /**< (ms) Minimum delay for keyboard repeat */
83 #define KBD_REPEAT_ACCEL     5  /**< (ms) Keyboard repeat speed increase */
84
85 #define KBD_LNG_DELAY     1000  /**< (ms) Keyboard long pression keys delay */
86
87
88 /** Status for keyboard repeat state machine */
89 static enum { KS_IDLE, KS_REPDELAY, KS_REPEAT } kbd_rptStatus;
90
91
92 static volatile keymask_t kbd_buf; /**< Single entry keyboard buffer */
93 static volatile keymask_t kbd_cnt; /**< Number of keypress events in \c kbd_buf */
94 static keymask_t kbd_rpt_mask;     /**< Mask of repeatable keys. */
95
96 #if CONFIG_KBD_POLL == KBD_POLL_SOFTINT
97 static Timer kbd_timer;            /**< Keyboard softtimer */
98 #endif
99
100 static List kbd_rawHandlers;       /**< Raw keyboard handlers */
101 static List kbd_handlers;          /**< Cooked keyboard handlers */
102
103 static KbdHandler kbd_defHandler;  /**< The default keyboard handler */
104 static KbdHandler kbd_debHandler;  /**< The debounce keyboard handler */
105 static KbdHandler kbd_rptHandler;  /**< Auto-repeat keyboard handler */
106
107 #if CONFIG_KBD_LONGPRESS
108 static KbdHandler kbd_lngHandler;  /**< Long pression keys handler */
109 #endif
110
111 #if CONFIG_KBD_OBSERVER
112         #include <mware/observer.h>
113         Subject kbd_subject;
114 #endif
115
116
117 /**
118  * Poll keyboard and dispatch keys to handlers.
119  *
120  * Read the key states and invoke all keyboard
121  * handlers to process the new state.
122  *
123  * Call this function periodically using a software
124  * timer, an interrupt or a process.
125  */
126 static void kbd_poll(void)
127 {
128         /** Currently depressed key */
129         static keymask_t current_key;
130
131         struct KbdHandler *handler;
132         keymask_t key = kbd_readkeys();
133
134         /* Call raw input handlers */
135         FOREACH_NODE(handler, &kbd_rawHandlers)
136                 key = handler->hook(key);
137
138         /* If this key was not previously pressed */
139         if (key != current_key)
140         {
141                 /* Remember last key */
142                 current_key = key;
143
144                 /* Call cooked input handlers */
145                 FOREACH_NODE(handler, &kbd_handlers)
146                         key = handler->hook(key);
147         }
148 }
149
150 #if CONFIG_KBD_POLL == KBD_POLL_SOFTINT
151
152 /**
153  * Keyboard soft-irq handler.
154  */
155 static void kbd_softint(UNUSED_ARG(iptr_t, arg))
156 {
157         kbd_poll();
158         timer_add(&kbd_timer);
159 }
160
161 #elif CONFIG_KBD_POLL == CONFIG_POLL_FREERTOS
162
163 #include "FreeRTOS.h"
164 #include "task.h"
165
166 static portTASK_FUNCTION(kbd_task, arg)
167 {
168         for (;;)
169         {
170                 kbd_poll();
171                 timer_delay(KBD_CHECK_INTERVAL);
172         }
173 }
174
175 #endif /* CONFIG_KBD_POLL */
176
177 /**
178  * \brief Read a key from the keyboard buffer.
179  *
180  * When a key is kept depressed between calls of this function a value
181  * is returned only after the time specified with KBD_REPAT_DELAY to
182  * avoid too fast keyboard repeat.
183  *
184  * \note Calls \c schedule() internally.
185  *
186  * \note This function is \b not interrupt safe!
187  *
188  * \return The mask of depressed keys or 0 if no keys are depressed.
189  *
190  */
191 keymask_t kbd_peek(void)
192 {
193         keymask_t key = 0;
194
195 // FIXME: make it optional
196         /* Let other tasks run for a while */
197         extern void schedule(void);
198         schedule();
199
200         /* Extract an event from the keyboard buffer */
201         IRQ_DISABLE;
202         if (kbd_cnt)
203         {
204                 --kbd_cnt;
205                 key = kbd_buf;
206         }
207         IRQ_ENABLE;
208
209         return key;
210 }
211
212 /**
213  * Wait for a keypress and return the mask of depressed keys.
214  *
215  * \note This function is \b not interrupt safe!
216  */
217 keymask_t kbd_get(void)
218 {
219         keymask_t key;
220
221         while (!(key = kbd_peek())) {}
222
223         return key;
224 }
225
226
227 /**
228  * Wait up to \c timeout ms for a keypress
229  * and return the mask of depressed keys, or K_TIMEOUT
230  * if the timeout was reacked.
231  */
232 keymask_t kbd_get_timeout(mtime_t timeout)
233 {
234         keymask_t key;
235
236         ticks_t start = timer_clock();
237         ticks_t stop  = ms_to_ticks(timeout);
238         do
239         {
240                 if ((key = kbd_peek()))
241                         return key;
242         }
243         while (timer_clock() - start < stop);
244
245         return K_TIMEOUT;
246 }
247
248
249 void kbd_addHandler(struct KbdHandler *handler)
250 {
251         KbdHandler *node;
252         List *list;
253
254         cpuflags_t flags;
255         IRQ_SAVE_DISABLE(flags);
256
257         /* Choose between raw and coocked handlers list */
258         list = (handler->flags & KHF_RAWKEYS) ?
259                 &kbd_rawHandlers : &kbd_handlers;
260
261         /*
262          * Search for the first node whose priority
263          * is lower than the timer we want to add.
264          */
265         FOREACH_NODE(node,list)
266                 if (node->pri < handler->pri)
267                         break;
268
269         /* Enqueue handler in the handlers chain */
270         INSERT_BEFORE(&handler->link, &node->link);
271
272         IRQ_RESTORE(flags);
273 }
274
275
276 void kbd_remHandler(struct KbdHandler *handler)
277 {
278         /* Remove the handler */
279         ATOMIC(REMOVE(&handler->link));
280 }
281
282
283 /**
284  * This is the default key handler, called after
285  * all other handlers have had their chance to
286  * do their special processing. This handler
287  * pushes all input in the keyboard FIFO buffer.
288  */
289 static keymask_t kbd_defHandlerFunc(keymask_t key)
290 {
291         if (key)
292         {
293                 /* Force a single event in kbd buffer */
294                 kbd_buf = key;
295                 kbd_cnt = 1;
296
297                 #if CONFIG_KBD_OBSERVER
298                         observer_notify(&kbd_subject, KBD_EVENT_KEY, &key);
299                 #endif
300
301                 #if CONFIG_KBD_BEEP
302                         if (!(key & K_REPEAT))
303                                 buz_beep(KBD_BEEP_TIME);
304                 #endif
305         }
306
307         /* Eat all input */
308         return 0;
309 }
310
311 /**
312  * Handle keyboard debounce
313  */
314 static keymask_t kbd_debHandlerFunc(keymask_t key)
315 {
316         /** Buffer for debounce */
317         static keymask_t debounce_key;
318
319         /** Timer for keyboard debounce */
320         static ticks_t debounce_time;
321
322         /** Key aquired after debounce */
323         static keymask_t new_key;
324
325
326         ticks_t now = timer_clock();
327
328         if (key != debounce_key)
329         {
330                 /* Reset debounce timer */
331                 debounce_key = key;
332                 debounce_time = now;
333         }
334         else if ((new_key != debounce_key)
335                 && (now - debounce_time > ms_to_ticks(KBD_DEBOUNCE_TIME)))
336         {
337                 new_key = debounce_key;
338                 debounce_time = now;
339         }
340
341         return new_key;
342 }
343
344 #if CONFIG_KBD_LONGPRESS
345 /**
346  * Handle long pression keys.
347  */
348 static keymask_t kbd_lngHandlerFunc(keymask_t key)
349 {
350         static ticks_t start;
351         ticks_t now = timer_clock();
352
353         if (key & K_LNG_MASK)
354         {
355                 if (now - start > ms_to_ticks(KBD_LNG_DELAY))
356                         key |= K_LONG;
357         }
358         else
359                 start = now;
360         return key;
361 }
362 #endif
363
364 /**
365  * Set current mask of repeatable keys.
366  */
367 keymask_t kbd_setRepeatMask(keymask_t mask)
368 {
369         keymask_t oldmask = kbd_rpt_mask;
370         ATOMIC(kbd_rpt_mask = mask);
371         return oldmask;
372 }
373
374 /**
375  * Handle keyboard repeat
376  */
377 static keymask_t kbd_rptHandlerFunc(keymask_t key)
378 {
379         /* Timer for keyboard repeat events. */
380         static ticks_t repeat_time;
381
382         /* Current repeat rate (for acceleration). */
383         static ticks_t repeat_rate; /** Current repeat rate (for acceleration) */
384
385         ticks_t now = timer_clock();
386
387         switch (kbd_rptStatus)
388         {
389                 case KS_IDLE:
390                         if (key & kbd_rpt_mask)
391                         {
392                                 repeat_time = now;
393                                 kbd_rptStatus = KS_REPDELAY;
394                         }
395                         break;
396
397                 case KS_REPDELAY:
398                         if (key & kbd_rpt_mask)
399                         {
400                                 if (now - repeat_time > ms_to_ticks(KBD_REPEAT_DELAY))
401                                 {
402                                         key = (key & kbd_rpt_mask) | K_REPEAT;
403                                         repeat_time = now;
404                                         repeat_rate = ms_to_ticks(KBD_REPEAT_RATE);
405                                         kbd_rptStatus = KS_REPEAT;
406                                 }
407                                 else
408                                         key = 0;
409                         }
410                         else
411                                 kbd_rptStatus = KS_IDLE;
412                         break;
413
414                 case KS_REPEAT:
415                         if (key & kbd_rpt_mask)
416                         {
417                                 if (now - repeat_time > repeat_rate)
418                                 {
419                                         /* Enqueue a new event in the buffer */
420                                         key = (key & kbd_rpt_mask) | K_REPEAT;
421                                         repeat_time = now;
422
423                                         /* Repeat rate acceleration */
424                                         if (repeat_rate > ms_to_ticks(KBD_REPEAT_MAXRATE))
425                                                 repeat_rate -= ms_to_ticks(KBD_REPEAT_ACCEL);
426                                 }
427                                 else
428                                         key = 0;
429                         }
430                         else
431                                 kbd_rptStatus = KS_IDLE;
432
433                         break;
434         }
435
436         return key;
437 }
438
439
440 MOD_DEFINE(kbd)
441
442 /**
443  * Initialize keyboard ports and softtimer
444  */
445 void kbd_init(void)
446 {
447 #if CONFIG_KBD_BEEP
448         MOD_CHECK(buzzer);
449 #endif
450
451         KBD_HW_INIT;
452
453         /* Init handlers lists */
454         LIST_INIT(&kbd_handlers);
455         LIST_INIT(&kbd_rawHandlers);
456
457         /* Add debounce keyboard handler */
458         kbd_debHandler.hook = kbd_debHandlerFunc;
459         kbd_debHandler.pri = 100; /* high priority */
460         kbd_debHandler.flags = KHF_RAWKEYS;
461         kbd_addHandler(&kbd_debHandler);
462
463         #if CONFIG_KBD_LONGPRESS
464         /* Add long pression keyboard handler */
465         kbd_lngHandler.hook = kbd_lngHandlerFunc;
466         kbd_lngHandler.pri = 90; /* high priority */
467         kbd_lngHandler.flags = KHF_RAWKEYS;
468         kbd_addHandler(&kbd_lngHandler);
469         #endif
470
471         /* Add repeat keyboard handler */
472         kbd_rptHandler.hook = kbd_rptHandlerFunc;
473         kbd_rptHandler.pri = 80; /* high priority */
474         kbd_rptHandler.flags = KHF_RAWKEYS;
475         kbd_addHandler(&kbd_rptHandler);
476
477         /* Add default keyboard handler */
478         kbd_defHandler.hook = kbd_defHandlerFunc;
479         kbd_defHandler.pri = -128; /* lowest priority */
480         kbd_addHandler(&kbd_defHandler);
481
482 #if CONFIG_KBD_OBSERVER
483         observer_InitSubject(&kbd_subject);
484 #endif
485
486 #if CONFIG_KBD_POLL == KBD_POLL_SOFTINT
487
488         MOD_CHECK(timer);
489
490         /* Add kbd handler to soft timers list */
491         event_initSoftInt(&kbd_timer.expire, kbd_softint, NULL);
492         timer_setDelay(&kbd_timer, ms_to_ticks(KBD_CHECK_INTERVAL));
493         timer_add(&kbd_timer);
494
495 #elif CONFIG_KBD_POLL == CONFIG_POLL_FREERTOS
496
497         /* Create a timer specific thread */
498         xTaskCreate(kbd_task, "kbd", CONFIG_STACK_KBD,
499                         NULL, CONFIG_PRI_KBD, NULL);
500
501 #else
502         #error "Define keyboard poll method"
503 #endif
504
505         MOD_INIT(kbd);
506 }