kbd.c
Go to the documentation of this file.00001
00043 #include <hw_kbd.h>
00044
00045 #include <drv/timer.h>
00046 #include <drv/kbd.h>
00047
00048 #include <cfg/debug.h>
00049 #include <cfg/module.h>
00050 #include <appconfig.h>
00051
00052
00053 #if !defined(CONFIG_KBD_POLL) || (CONFIG_KBD_POLL != KBD_POLL_SOFTINT && CONFIG_KBD_POLL != CONFIG_POLL_FREERTOS)
00054 #error CONFIG_KBD_POLL must be defined to either KBD_POLL_SOFTINT or CONFIG_POLL_FREERTOS
00055 #endif
00056 #if !defined(CONFIG_KBD_BEEP) || (CONFIG_KBD_BEEP != 0 && CONFIG_KBD_BEEP != 1)
00057 #error CONFIG_KBD_BEEP must be defined to either 0 or 1
00058 #endif
00059 #if !defined(CONFIG_KBD_OBSERVER) || (CONFIG_KBD_OBSERVER != 0 && CONFIG_KBD_OBSERVER != 1)
00060 #error CONFIG_KBD_OBSERVER must be defined to either 0 or 1
00061 #endif
00062 #if !defined(CONFIG_KBD_LONGPRESS) || (CONFIG_KBD_LONGPRESS != 0 && CONFIG_KBD_LONGPRESS != 1)
00063 #error CONFIG_KBD_LONGPRESS must be defined to either 0 or 1
00064 #endif
00065
00066 #if CONFIG_KBD_BEEP
00067 #include <drv/buzzer.h>
00068 #endif
00069
00070 #define KBD_CHECK_INTERVAL 10
00071 #define KBD_DEBOUNCE_TIME 30
00072 #define KBD_BEEP_TIME 5
00074 #define KBD_REPEAT_DELAY 400
00075 #define KBD_REPEAT_RATE 100
00076 #define KBD_REPEAT_MAXRATE 20
00077 #define KBD_REPEAT_ACCEL 5
00079 #define KBD_LNG_DELAY 1000
00083 static enum { KS_IDLE, KS_REPDELAY, KS_REPEAT } kbd_rptStatus;
00084
00085
00086 static volatile keymask_t kbd_buf;
00087 static volatile keymask_t kbd_cnt;
00088 static keymask_t kbd_rpt_mask;
00090 #if CONFIG_KBD_POLL == KBD_POLL_SOFTINT
00091 static Timer kbd_timer;
00092 #endif
00093
00094 static List kbd_rawHandlers;
00095 static List kbd_handlers;
00097 static KbdHandler kbd_defHandler;
00098 static KbdHandler kbd_debHandler;
00099 static KbdHandler kbd_rptHandler;
00101 #if CONFIG_KBD_LONGPRESS
00102 static KbdHandler kbd_lngHandler;
00103 #endif
00104
00105 #if CONFIG_KBD_OBSERVER
00106 #include <mware/observer.h>
00107 Subject kbd_subject;
00108 #endif
00109
00110
00120 static void kbd_poll(void)
00121 {
00123 static keymask_t current_key;
00124
00125 struct KbdHandler *handler;
00126 keymask_t key = kbd_readkeys();
00127
00128
00129 FOREACH_NODE(handler, &kbd_rawHandlers)
00130 key = handler->hook(key);
00131
00132
00133 if (key != current_key)
00134 {
00135
00136 current_key = key;
00137
00138
00139 FOREACH_NODE(handler, &kbd_handlers)
00140 key = handler->hook(key);
00141 }
00142 }
00143
00144 #if CONFIG_KBD_POLL == KBD_POLL_SOFTINT
00145
00149 static void kbd_softint(UNUSED_ARG(iptr_t, arg))
00150 {
00151 kbd_poll();
00152 timer_add(&kbd_timer);
00153 }
00154
00155 #elif CONFIG_KBD_POLL == CONFIG_POLL_FREERTOS
00156
00157 #include "FreeRTOS.h"
00158 #include "task.h"
00159
00160 static portTASK_FUNCTION(kbd_task, arg)
00161 {
00162 for (;;)
00163 {
00164 kbd_poll();
00165 timer_delay(KBD_CHECK_INTERVAL);
00166 }
00167 }
00168
00169 #endif
00170
00185 keymask_t kbd_peek(void)
00186 {
00187 keymask_t key = 0;
00188
00189
00190
00191 extern void schedule(void);
00192 schedule();
00193
00194
00195 IRQ_DISABLE;
00196 if (kbd_cnt)
00197 {
00198 --kbd_cnt;
00199 key = kbd_buf;
00200 }
00201 IRQ_ENABLE;
00202
00203 return key;
00204 }
00205
00211 keymask_t kbd_get(void)
00212 {
00213 keymask_t key;
00214
00215 while (!(key = kbd_peek())) {}
00216
00217 return key;
00218 }
00219
00220
00226 keymask_t kbd_get_timeout(mtime_t timeout)
00227 {
00228 keymask_t key;
00229
00230 ticks_t start = timer_clock();
00231 ticks_t stop = ms_to_ticks(timeout);
00232 do
00233 {
00234 if ((key = kbd_peek()))
00235 return key;
00236 }
00237 while (timer_clock() - start < stop);
00238
00239 return K_TIMEOUT;
00240 }
00241
00242
00243 void kbd_addHandler(struct KbdHandler *handler)
00244 {
00245 KbdHandler *node;
00246 List *list;
00247
00248 cpuflags_t flags;
00249 IRQ_SAVE_DISABLE(flags);
00250
00251
00252 list = (handler->flags & KHF_RAWKEYS) ?
00253 &kbd_rawHandlers : &kbd_handlers;
00254
00255
00256
00257
00258
00259 FOREACH_NODE(node,list)
00260 if (node->pri < handler->pri)
00261 break;
00262
00263
00264 INSERT_BEFORE(&handler->link, &node->link);
00265
00266 IRQ_RESTORE(flags);
00267 }
00268
00269
00270 void kbd_remHandler(struct KbdHandler *handler)
00271 {
00272
00273 ATOMIC(REMOVE(&handler->link));
00274 }
00275
00276
00283 static keymask_t kbd_defHandlerFunc(keymask_t key)
00284 {
00285 if (key)
00286 {
00287
00288 kbd_buf = key;
00289 kbd_cnt = 1;
00290
00291 #if CONFIG_KBD_OBSERVER
00292 observer_notify(&kbd_subject, KBD_EVENT_KEY, &key);
00293 #endif
00294
00295 #if CONFIG_KBD_BEEP
00296 if (!(key & K_REPEAT))
00297 buz_beep(KBD_BEEP_TIME);
00298 #endif
00299 }
00300
00301
00302 return 0;
00303 }
00304
00308 static keymask_t kbd_debHandlerFunc(keymask_t key)
00309 {
00311 static keymask_t debounce_key;
00312
00314 static ticks_t debounce_time;
00315
00317 static keymask_t new_key;
00318
00319
00320 ticks_t now = timer_clock();
00321
00322 if (key != debounce_key)
00323 {
00324
00325 debounce_key = key;
00326 debounce_time = now;
00327 }
00328 else if ((new_key != debounce_key)
00329 && (now - debounce_time > ms_to_ticks(KBD_DEBOUNCE_TIME)))
00330 {
00331 new_key = debounce_key;
00332 debounce_time = now;
00333 }
00334
00335 return new_key;
00336 }
00337
00338 #if CONFIG_KBD_LONGPRESS
00339
00342 static keymask_t kbd_lngHandlerFunc(keymask_t key)
00343 {
00344 static ticks_t start;
00345 ticks_t now = timer_clock();
00346
00347 if (key & K_LNG_MASK)
00348 {
00349 if (now - start > ms_to_ticks(KBD_LNG_DELAY))
00350 key |= K_LONG;
00351 }
00352 else
00353 start = now;
00354 return key;
00355 }
00356 #endif
00357
00361 keymask_t kbd_setRepeatMask(keymask_t mask)
00362 {
00363 keymask_t oldmask = kbd_rpt_mask;
00364 ATOMIC(kbd_rpt_mask = mask);
00365 return oldmask;
00366 }
00367
00371 static keymask_t kbd_rptHandlerFunc(keymask_t key)
00372 {
00373
00374 static ticks_t repeat_time;
00375
00376
00377 static ticks_t repeat_rate;
00379 ticks_t now = timer_clock();
00380
00381 switch (kbd_rptStatus)
00382 {
00383 case KS_IDLE:
00384 if (key & kbd_rpt_mask)
00385 {
00386 repeat_time = now;
00387 kbd_rptStatus = KS_REPDELAY;
00388 }
00389 break;
00390
00391 case KS_REPDELAY:
00392 if (key & kbd_rpt_mask)
00393 {
00394 if (now - repeat_time > ms_to_ticks(KBD_REPEAT_DELAY))
00395 {
00396 key = (key & kbd_rpt_mask) | K_REPEAT;
00397 repeat_time = now;
00398 repeat_rate = ms_to_ticks(KBD_REPEAT_RATE);
00399 kbd_rptStatus = KS_REPEAT;
00400 }
00401 else
00402 key = 0;
00403 }
00404 else
00405 kbd_rptStatus = KS_IDLE;
00406 break;
00407
00408 case KS_REPEAT:
00409 if (key & kbd_rpt_mask)
00410 {
00411 if (now - repeat_time > repeat_rate)
00412 {
00413
00414 key = (key & kbd_rpt_mask) | K_REPEAT;
00415 repeat_time = now;
00416
00417
00418 if (repeat_rate > ms_to_ticks(KBD_REPEAT_MAXRATE))
00419 repeat_rate -= ms_to_ticks(KBD_REPEAT_ACCEL);
00420 }
00421 else
00422 key = 0;
00423 }
00424 else
00425 kbd_rptStatus = KS_IDLE;
00426
00427 break;
00428 }
00429
00430 return key;
00431 }
00432
00433
00434 MOD_DEFINE(kbd)
00435
00436
00439 void kbd_init(void)
00440 {
00441 #if CONFIG_KBD_BEEP
00442 MOD_CHECK(buzzer);
00443 #endif
00444
00445 KBD_HW_INIT;
00446
00447
00448 LIST_INIT(&kbd_handlers);
00449 LIST_INIT(&kbd_rawHandlers);
00450
00451
00452 kbd_debHandler.hook = kbd_debHandlerFunc;
00453 kbd_debHandler.pri = 100;
00454 kbd_debHandler.flags = KHF_RAWKEYS;
00455 kbd_addHandler(&kbd_debHandler);
00456
00457 #if CONFIG_KBD_LONGPRESS
00458
00459 kbd_lngHandler.hook = kbd_lngHandlerFunc;
00460 kbd_lngHandler.pri = 90;
00461 kbd_lngHandler.flags = KHF_RAWKEYS;
00462 kbd_addHandler(&kbd_lngHandler);
00463 #endif
00464
00465
00466 kbd_rptHandler.hook = kbd_rptHandlerFunc;
00467 kbd_rptHandler.pri = 80;
00468 kbd_rptHandler.flags = KHF_RAWKEYS;
00469 kbd_addHandler(&kbd_rptHandler);
00470
00471
00472 kbd_defHandler.hook = kbd_defHandlerFunc;
00473 kbd_defHandler.pri = -128;
00474 kbd_addHandler(&kbd_defHandler);
00475
00476 #if CONFIG_KBD_OBSERVER
00477 observer_InitSubject(&kbd_subject);
00478 #endif
00479
00480 #if CONFIG_KBD_POLL == KBD_POLL_SOFTINT
00481
00482 MOD_CHECK(timer);
00483
00484
00485 event_initSoftInt(&kbd_timer.expire, kbd_softint, NULL);
00486 timer_setDelay(&kbd_timer, ms_to_ticks(KBD_CHECK_INTERVAL));
00487 timer_add(&kbd_timer);
00488
00489 #elif CONFIG_KBD_POLL == CONFIG_POLL_FREERTOS
00490
00491
00492 xTaskCreate(kbd_task, "kbd", CONFIG_STACK_KBD,
00493 NULL, CONFIG_PRI_KBD, NULL);
00494
00495 #else
00496 #error "Define keyboard poll method"
00497 #endif
00498
00499 MOD_INIT(kbd);
00500 }