keys.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2001-2009 by egnite Software GmbH. All rights reserved.
00003  * Copyright (C) 2009 by Ulrich Prinz (uprinz2@netscape.net)
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  *
00009  * 1. Redistributions of source code must retain the above copyright
00010  *    notice, this list of conditions and the following disclaimer.
00011  * 2. Redistributions in binary form must reproduce the above copyright
00012  *    notice, this list of conditions and the following disclaimer in the
00013  *    documentation and/or other materials provided with the distribution.
00014  * 3. Neither the name of the copyright holders nor the names of
00015  *    contributors may be used to endorse or promote products derived
00016  *    from this software without specific prior written permission.
00017  *
00018  * THIS SOFTWARE IS PROVIDED BY EMBEDDED IT AND CONTRIBUTORS
00019  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00020  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00021  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL EMBEDDED IT
00022  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00023  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00024  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
00025  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
00026  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
00027  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
00028  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00029  *
00030  * For additional information see http://www.ethernut.de/
00031  *
00032  */
00033 
00034 /*
00035  * \file dev/keys.c
00036  * \brief Key handling driver.
00037  *
00038  * Driver for flexible key, switch and button handling.
00039  *
00040  * \verbatim
00041  *
00042  * $Log$
00043  *
00044  * Revision 0.3  2009/09/12 ulrichprinz
00045  * First checkin, new push button driver example
00046  * (currently SAM7X256 is tested only)
00047  *
00048  * \endverbatim
00049  */
00050 
00051 #include <compiler.h>
00052 #include <cfg/os.h>
00053 
00054 #include <stdlib.h>
00055 #include <string.h>
00056 #include <sys/heap.h>
00057 #include <sys/event.h>
00058 #include <sys/timer.h>
00059 #include <sys/atom.h>
00060 
00061 #include <dev/board.h>
00062 
00063 #include <dev/gpio.h>
00064 
00065 #include <sys/nutdebug.h>
00066 
00067 #include <cfg/pca9555.h>
00068 #ifdef KEY_SUPPORT_IOEXP
00069 #include <dev/pca9555.h>
00070 #else
00071 #define IOXP_PORT0 0x80
00072 #endif
00073 
00074 // #define DEBUG_KEYS
00075 #ifdef DEBUG_KEYS
00076 #include <stdio.h>
00077 #define KPRINTF(args,...) printf(args,##__VA_ARGS__)
00078 #else
00079 #define KPRINTF(args,...)
00080 #endif
00081 
00082 #include <dev/keys.h>
00083 
00088 
00089 typedef struct {
00090     void*    next;      
00091     HANDLE*  event;     
00092     int      bank;      
00093     int      pin;       
00094     int      lastState; 
00095     int      newState;  
00096     int      fx;        
00097     uint32_t fxt;       
00098     uint32_t TimeDown;  
00099 } KEYEventT;
00100 
00101 static KEYEventT *first_key;
00102 
00103 HANDLE key_tmr = NULL;
00104 HANDLE key_evt = NULL;
00105 
00119 int NutGetKeyState( HANDLE keyh)
00120 {
00121     KEYEventT *key = (KEYEventT *)keyh;
00122     int rc = (key->newState & KEY_PENDING);
00123     key->newState &= ~KEY_PENDING;
00124     return rc;
00125 }
00126 
00137 uint32_t NutGetKeyTime( HANDLE keyh)
00138 {
00139     KEYEventT *key = (KEYEventT *)keyh;
00140     uint32_t now = NutGetMillis();
00141 
00142     return (now - key->TimeDown);
00143 }
00144 
00154 void KeyTimerCb(HANDLE timer, void *arg)
00155 {
00156     NutEventPostAsync(arg);
00157 }
00158 
00165 THREAD( sys_key, arg)
00166 {
00167     KEYEventT *key;
00168     uint32_t now;
00169 #ifdef KEY_SUPPORT_IOEXP
00170     int ioxread, ioxstate;
00171 #endif
00172 
00173     NUTASSERT( arg != NULL);
00174 
00175     NutThreadSetPriority( 16);
00176     for(;;)
00177     {
00178 #ifdef KEY_SUPPORT_IOEXP
00179         ioxread = 0;
00180 #endif
00181         if( NutEventWait( arg, NUT_WAIT_INFINITE)==0) {
00182             key = first_key;
00183             now = NutGetMillis();
00184             while( key)
00185             {
00186                 /*
00187                  * Read in keys from ports
00188                  */
00189                 key->newState &= ~KEY_IS_DOWN;
00190 
00191                 if( key->bank < IOXP_PORT0) {
00192                     /* Save inverted key state (low-active) */
00193                     key->newState |= (GpioPinGet( key->bank, key->pin))?0:1;
00194                 }
00195 #ifdef KEY_SUPPORT_IOEXP
00196                 else {
00197                     /* read io-expander only on first key connected
00198                     ** and buffer the result to keep bus silent
00199                     */
00200                     if( ioxread == 0) {
00201                         IOExpRawRead( key->bank, &ioxstate);
00202                         ioxread = 1;
00203                     }
00204                     /* Save inverted key state (low-active) */
00205                     key->newState |= ((ioxstate & (1<<key->pin))?0:1);
00206                 }
00207 #endif
00208 
00209                 /*
00210                  * Process key status change
00211                  */
00212                 if( (key->newState & KEY_IS_DOWN) > (key->lastState & KEY_IS_DOWN)) {
00213                     /* key up->down change */
00214                     key->TimeDown = now;
00215                     if( key->fx == KEY_ACTION_DOWN) {
00216                         KPRINTF("KD %08lx E:%08lx\n", (uint32_t)key, (uint32_t)(key->event));
00217                         key->newState |= KEY_PENDING;
00218                         if( key->event) NutEventPost( key->event);
00219                     }
00220                 }
00221                 else if( (key->newState & KEY_IS_DOWN) < (key->lastState & KEY_IS_DOWN)) {
00222                     /* key down->up change */
00223                     key->newState &= ~KEY_IS_LOCKED;
00224                     if( key->fx == KEY_ACTION_UP) {
00225                         KPRINTF("KU %08lx E:%08lx\n", (uint32_t)key, (uint32_t)(key->event));
00226                         key->newState |= (KEY_ACTION_UP | KEY_PENDING);
00227                         if( key->event) NutEventPost( key->event);
00228                     }
00229                     else if( ( key->fx == KEY_ACTION_SHORT) && ( (now - key->TimeDown) < key->fxt)) {
00230                         KPRINTF("KS %08lx E:%08lx\n", (uint32_t)key, (uint32_t)(key->event));
00231                         key->newState |= (KEY_ACTION_SHORT | KEY_PENDING);
00232                         if( key->event) NutEventPost( key->event);
00233                     }
00234                 }
00235                 else if( (key->newState & KEY_IS_DOWN) && (key->fx==KEY_ACTION_HOLD)) {
00236                     /* key still down */
00237                     if( ((now - key->TimeDown) > key->fxt) && ((key->newState & KEY_IS_LOCKED) == 0)) {
00238                         KPRINTF("KH %08lx E:%08lx\n", (uint32_t)key, (uint32_t)(key->event));
00239                         key->newState |= (KEY_ACTION_HOLD | KEY_PENDING);
00240                         if( key->event) NutEventPost( key->event);
00241                         key->newState |= KEY_IS_LOCKED;
00242                     }
00243                 }
00244 
00245                 /* Backup new state of key */
00246                 key->lastState = key->newState;
00247                 /* Advance to next key */
00248                 key = key->next;
00249             }
00250         }
00251     }
00252 }
00253 
00261 int InitKEY( KEYEventT *key )
00262 {
00263     if( key->bank < IOXP_PORT0) {
00264         /* configure standard GPIO pin */
00265         GpioPinConfigSet( key->bank, key->pin, GPIO_CFG_PULLUP|GPIO_CFG_DEBOUNCE);
00266         return 0;
00267     }
00268 #ifdef KEY_SUPPORT_IOEXP
00269     else {
00270         /* configure externally connected GPIO pin */
00271         IOExpPinConfigSet( key->bank, key->pin, GPIO_CFG_PULLUP);
00272         return 0;
00273     }
00274 #endif
00275     return -1;
00276 }
00277 
00299 int NutRegisterKey( HANDLE *keyhp, HANDLE *event, int bank, int pin, int fx, uint32_t fxt)
00300 {
00301     KEYEventT *key;
00302 
00303     NUTASSERT( keyhp!=NULL);
00304 
00305     /* Check memory constraints and assign memory to new led struct */
00306     key = malloc( sizeof(KEYEventT));
00307     *keyhp = (void*)key;
00308 
00309     if( key == NULL) {
00310         return -1;
00311     }
00312 
00313     /* Preset new key struct */
00314     key->bank = bank;
00315     key->pin = pin;
00316     key->fx = fx;
00317     key->fxt = fxt;
00318     key->event = event;
00319     NUTASSERT( event != NULL);
00320     key->lastState = key->newState = 1;
00321     key->TimeDown = 0;
00322 
00323     /* Initalize key hardware */
00324     InitKEY( key);
00325 
00326     /* Assign the key to the key chain */
00327     NutEnterCritical();
00328     if( first_key == NULL) {
00329         /* it is the first key */
00330         first_key = key;
00331     }
00332     else {
00333         key->next = first_key;
00334         first_key = key;
00335     }
00336     NutExitCritical();
00337 
00338     if( key_tmr == NULL) {
00339         NutThreadCreate( "sys_key", sys_key, &key_evt, 192);
00340         key_tmr = NutTimerStart(10, KeyTimerCb, &key_evt, 0);
00341     }
00342 
00343     KPRINTF("KREG %08lx E:%08lx\n", (uint32_t)key, (uint32_t)(key->event));
00344 
00345     return 0;
00346 }
00347 

© 2000-2007 by egnite Software GmbH - visit http://www.ethernut.de/