BeRTOS
kbd.c
Go to the documentation of this file.
00001 
00043 #include "hw/hw_kbd.h"
00044 
00045 #include "cfg/cfg_kbd.h"
00046 #include <cfg/debug.h>
00047 #include <cfg/module.h>
00048 
00049 #include <drv/timer.h>
00050 #include <mware/event.h>
00051 #include <drv/kbd.h>
00052 
00053 
00054 /* Configuration sanity checks */
00055 #if !defined(CONFIG_KBD_POLL) || (CONFIG_KBD_POLL != KBD_POLL_SOFTINT)
00056     #error CONFIG_KBD_POLL must be defined to either KBD_POLL_SOFTINT
00057 #endif
00058 #if !defined(CONFIG_KBD_BEEP) || (CONFIG_KBD_BEEP != 0 && CONFIG_KBD_BEEP != 1)
00059     #error CONFIG_KBD_BEEP must be defined to either 0 or 1
00060 #endif
00061 #if !defined(CONFIG_KBD_OBSERVER) || (CONFIG_KBD_OBSERVER != 0 && CONFIG_KBD_OBSERVER != 1)
00062     #error CONFIG_KBD_OBSERVER must be defined to either 0 or 1
00063 #endif
00064 #if !defined(CONFIG_KBD_LONGPRESS) || (CONFIG_KBD_LONGPRESS != 0 && CONFIG_KBD_LONGPRESS != 1)
00065     #error CONFIG_KBD_LONGPRESS must be defined to either 0 or 1
00066 #endif
00067 
00068 #if CONFIG_KBD_BEEP
00069     #include <drv/buzzer.h>
00070 #endif
00071 
00072 #define KBD_CHECK_INTERVAL  10  
00073 #define KBD_DEBOUNCE_TIME   30  
00074 #define KBD_BEEP_TIME        5  
00076 #define KBD_REPEAT_DELAY   400  
00077 #define KBD_REPEAT_RATE    100  
00078 #define KBD_REPEAT_MAXRATE  20  
00079 #define KBD_REPEAT_ACCEL     5  
00081 #define KBD_LNG_DELAY     1000  
00085 static enum { KS_IDLE, KS_REPDELAY, KS_REPEAT } kbd_rptStatus;
00086 
00088 static Event key_pressed;
00089 
00090 static volatile keymask_t kbd_buf; 
00091 static volatile keymask_t kbd_cnt; 
00092 static keymask_t kbd_rpt_mask;     
00094 #if CONFIG_KBD_POLL == KBD_POLL_SOFTINT
00095 static Timer kbd_timer;            
00096 #endif
00097 
00098 static List kbd_rawHandlers;       
00099 static List kbd_handlers;          
00101 static KbdHandler kbd_defHandler;  
00102 static KbdHandler kbd_debHandler;  
00103 static KbdHandler kbd_rptHandler;  
00105 #if CONFIG_KBD_LONGPRESS
00106 static KbdHandler kbd_lngHandler;  
00107 #endif
00108 
00109 #if CONFIG_KBD_OBSERVER
00110     #include <mware/observer.h>
00111     Subject kbd_subject;
00112 #endif
00113 
00114 
00124 static void kbd_poll(void)
00125 {
00127     static keymask_t current_key;
00128 
00129     struct KbdHandler *handler;
00130     keymask_t key = kbd_readkeys();
00131 
00132     /* Call raw input handlers */
00133     FOREACH_NODE(handler, &kbd_rawHandlers)
00134         key = handler->hook(key);
00135 
00136     /* If this key was not previously pressed */
00137     if (key != current_key)
00138     {
00139         /* Remember last key */
00140         current_key = key;
00141 
00142         /* Call cooked input handlers */
00143         FOREACH_NODE(handler, &kbd_handlers)
00144             key = handler->hook(key);
00145     }
00146 }
00147 
00148 #if CONFIG_KBD_POLL == KBD_POLL_SOFTINT
00149 
00153 static void kbd_softint(UNUSED_ARG(iptr_t, arg))
00154 {
00155     kbd_poll();
00156     timer_add(&kbd_timer);
00157 }
00158 
00159 #else
00160     #error "Define keyboard poll method"
00161 
00162 #endif /* CONFIG_KBD_POLL */
00163 
00178 keymask_t kbd_peek(void)
00179 {
00180     keymask_t key = 0;
00181 
00182 #if CONFIG_KBD_SCHED
00183     /* Let other tasks run for a while */
00184     extern void schedule(void);
00185     schedule();
00186 #endif
00187 
00188     /* Extract an event from the keyboard buffer */
00189     IRQ_DISABLE;
00190     if (kbd_cnt)
00191     {
00192         --kbd_cnt;
00193         key = kbd_buf;
00194     }
00195     IRQ_ENABLE;
00196 
00197     return key;
00198 }
00199 
00205 keymask_t kbd_get(void)
00206 {
00207     keymask_t key;
00208 
00209     #if CONFIG_KBD_POLL == KBD_POLL_SOFTINT
00210         event_wait(&key_pressed);
00211         key = kbd_peek();
00212     #else
00213         while (!(key = kbd_peek()))
00214             cpu_relax();
00215     #endif
00216 
00217     return key;
00218 }
00219 
00220 
00226 keymask_t kbd_get_timeout(mtime_t timeout)
00227 {
00228     if (event_waitTimeout(&key_pressed, timeout))
00229         return kbd_peek();
00230     else
00231         return K_TIMEOUT;
00232 }
00233 
00234 
00235 void kbd_addHandler(struct KbdHandler *handler)
00236 {
00237     KbdHandler *node;
00238     List *list;
00239 
00240     cpu_flags_t flags;
00241     IRQ_SAVE_DISABLE(flags);
00242 
00243     /* Choose between raw and coocked handlers list */
00244     list = (handler->flags & KHF_RAWKEYS) ?
00245         &kbd_rawHandlers : &kbd_handlers;
00246 
00247     /*
00248      * Search for the first node whose priority
00249      * is lower than the timer we want to add.
00250      */
00251     FOREACH_NODE(node,list)
00252         if (node->pri < handler->pri)
00253             break;
00254 
00255     /* Enqueue handler in the handlers chain */
00256     INSERT_BEFORE(&handler->link, &node->link);
00257 
00258     IRQ_RESTORE(flags);
00259 }
00260 
00261 
00262 void kbd_remHandler(struct KbdHandler *handler)
00263 {
00264     /* Remove the handler */
00265     ATOMIC(REMOVE(&handler->link));
00266 }
00267 
00268 
00275 static keymask_t kbd_defHandlerFunc(keymask_t key)
00276 {
00277     if (key)
00278     {
00279         /* Force a single event in kbd buffer */
00280         kbd_buf = key;
00281         kbd_cnt = 1;
00282         #if CONFIG_KBD_POLL == KBD_POLL_SOFTINT
00283             event_do(&key_pressed);
00284         #endif
00285 
00286         #if CONFIG_KBD_OBSERVER
00287             observer_notify(&kbd_subject, KBD_EVENT_KEY, &key);
00288         #endif
00289 
00290         #if CONFIG_KBD_BEEP
00291             if (!(key & K_REPEAT))
00292                 buz_beep(KBD_BEEP_TIME);
00293         #endif
00294     }
00295 
00296     /* Eat all input */
00297     return 0;
00298 }
00299 
00303 static keymask_t kbd_debHandlerFunc(keymask_t key)
00304 {
00306     static keymask_t debounce_key;
00307 
00309     static ticks_t debounce_time;
00310 
00312     static keymask_t new_key;
00313 
00314 
00315     ticks_t now = timer_clock();
00316 
00317     if (key != debounce_key)
00318     {
00319         /* Reset debounce timer */
00320         debounce_key = key;
00321         debounce_time = now;
00322     }
00323     else if ((new_key != debounce_key)
00324         && (now - debounce_time > ms_to_ticks(KBD_DEBOUNCE_TIME)))
00325     {
00326         new_key = debounce_key;
00327         debounce_time = now;
00328     }
00329 
00330     return new_key;
00331 }
00332 
00333 #if CONFIG_KBD_LONGPRESS
00334 
00337 static keymask_t kbd_lngHandlerFunc(keymask_t key)
00338 {
00339     static ticks_t start;
00340     ticks_t now = timer_clock();
00341 
00342     if (key & K_LNG_MASK)
00343     {
00344         if (now - start > ms_to_ticks(KBD_LNG_DELAY))
00345             key |= K_LONG;
00346     }
00347     else
00348         start = now;
00349     return key;
00350 }
00351 #endif
00352 
00356 keymask_t kbd_setRepeatMask(keymask_t mask)
00357 {
00358     keymask_t oldmask = kbd_rpt_mask;
00359     ATOMIC(kbd_rpt_mask = mask);
00360     return oldmask;
00361 }
00362 
00366 static keymask_t kbd_rptHandlerFunc(keymask_t key)
00367 {
00368     /* Timer for keyboard repeat events. */
00369     static ticks_t repeat_time;
00370 
00371     /* Current repeat rate (for acceleration). */
00372     static ticks_t repeat_rate; 
00374     ticks_t now = timer_clock();
00375 
00376     switch (kbd_rptStatus)
00377     {
00378         case KS_IDLE:
00379             if (key & kbd_rpt_mask)
00380             {
00381                 repeat_time = now;
00382                 kbd_rptStatus = KS_REPDELAY;
00383             }
00384             break;
00385 
00386         case KS_REPDELAY:
00387             if (key & kbd_rpt_mask)
00388             {
00389                 if (now - repeat_time > ms_to_ticks(KBD_REPEAT_DELAY))
00390                 {
00391                     key = (key & kbd_rpt_mask) | K_REPEAT;
00392                     repeat_time = now;
00393                     repeat_rate = ms_to_ticks(KBD_REPEAT_RATE);
00394                     kbd_rptStatus = KS_REPEAT;
00395                 }
00396                 else
00397                     key = 0;
00398             }
00399             else
00400                 kbd_rptStatus = KS_IDLE;
00401             break;
00402 
00403         case KS_REPEAT:
00404             if (key & kbd_rpt_mask)
00405             {
00406                 if (now - repeat_time > repeat_rate)
00407                 {
00408                     /* Enqueue a new event in the buffer */
00409                     key = (key & kbd_rpt_mask) | K_REPEAT;
00410                     repeat_time = now;
00411 
00412                     /* Repeat rate acceleration */
00413                     if (repeat_rate > ms_to_ticks(KBD_REPEAT_MAXRATE))
00414                         repeat_rate -= ms_to_ticks(KBD_REPEAT_ACCEL);
00415                 }
00416                 else
00417                     key = 0;
00418             }
00419             else
00420                 kbd_rptStatus = KS_IDLE;
00421 
00422             break;
00423     }
00424 
00425     return key;
00426 }
00427 
00428 
00429 MOD_DEFINE(kbd)
00430 
00431 
00434 void kbd_init(void)
00435 {
00436 #if CONFIG_KBD_BEEP
00437     MOD_CHECK(buzzer);
00438 #endif
00439 
00440     KBD_HW_INIT;
00441 
00442     /* Init handlers lists */
00443     LIST_INIT(&kbd_handlers);
00444     LIST_INIT(&kbd_rawHandlers);
00445 
00446     /* Add debounce keyboard handler */
00447     kbd_debHandler.hook = kbd_debHandlerFunc;
00448     kbd_debHandler.pri = 100; /* high priority */
00449     kbd_debHandler.flags = KHF_RAWKEYS;
00450     kbd_addHandler(&kbd_debHandler);
00451 
00452     #if CONFIG_KBD_LONGPRESS
00453     /* Add long pression keyboard handler */
00454     kbd_lngHandler.hook = kbd_lngHandlerFunc;
00455     kbd_lngHandler.pri = 90; /* high priority */
00456     kbd_lngHandler.flags = KHF_RAWKEYS;
00457     kbd_addHandler(&kbd_lngHandler);
00458     #endif
00459 
00460     /* Add repeat keyboard handler */
00461     kbd_rptHandler.hook = kbd_rptHandlerFunc;
00462     kbd_rptHandler.pri = 80; /* high priority */
00463     kbd_rptHandler.flags = KHF_RAWKEYS;
00464     kbd_addHandler(&kbd_rptHandler);
00465 
00466     /* Add default keyboard handler */
00467     kbd_defHandler.hook = kbd_defHandlerFunc;
00468     kbd_defHandler.pri = -128; /* lowest priority */
00469     kbd_addHandler(&kbd_defHandler);
00470 
00471 #if CONFIG_KBD_OBSERVER
00472     observer_InitSubject(&kbd_subject);
00473 #endif
00474 
00475 #if CONFIG_KBD_POLL == KBD_POLL_SOFTINT
00476 
00477     MOD_CHECK(timer);
00478     #if CONFIG_KERN
00479         MOD_CHECK(proc);
00480     #endif
00481 
00482     /* Initialize the keyboard event (key pressed) */
00483     event_initGeneric(&key_pressed);
00484 
00485     /* Add kbd handler to soft timers list */
00486     event_initSoftint(&kbd_timer.expire, kbd_softint, NULL);
00487     timer_setDelay(&kbd_timer, ms_to_ticks(KBD_CHECK_INTERVAL));
00488     timer_add(&kbd_timer);
00489 
00490 #else
00491     #error "Define keyboard poll method"
00492 
00493 #endif
00494 
00495     MOD_INIT(kbd);
00496 }