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     void (*callback)(void);     
00093     int      bank;      
00094     int      pin;       
00095     int      lastState; 
00096     int      newState;  
00097     int      fx;        
00098     uint32_t fxt;       
00099     uint32_t TimeDown;  
00100 } KEYEventT;
00101 
00102 static KEYEventT *first_key;
00103 
00104 HANDLE key_tmr = NULL;
00105 HANDLE key_evt = NULL;
00106 
00120 int NutGetKeyState( HANDLE keyh)
00121 {
00122     KEYEventT *key = (KEYEventT *)keyh;
00123     int rc = key->newState;
00124     key->newState &= ~KEY_PENDING;
00125     return rc;
00126 }
00127 
00138 uint32_t NutGetKeyTime( HANDLE keyh)
00139 {
00140     KEYEventT *key = (KEYEventT *)keyh;
00141     uint32_t now = NutGetMillis();
00142 
00143     return (now - key->TimeDown);
00144 }
00145 
00155 void KeyTimerCb(HANDLE timer, void *arg)
00156 {
00157     NutEventPostAsync(arg);
00158 }
00159 
00166 THREAD( sys_key, arg)
00167 {
00168     KEYEventT *key;
00169     uint32_t now;
00170 #ifdef KEY_SUPPORT_IOEXP
00171     int ioxread, ioxstate;
00172 #endif
00173 
00174     NUTASSERT( arg != NULL);
00175 
00176     NutThreadSetPriority( 16);
00177     for(;;)
00178     {
00179 #ifdef KEY_SUPPORT_IOEXP
00180         ioxread = 0;
00181 #endif
00182         if( NutEventWait( arg, NUT_WAIT_INFINITE)==0) {
00183             key = first_key;
00184             now = NutGetMillis();
00185             while( key)
00186             {
00187                 /*
00188                  * Read in keys from ports
00189                  */
00190                 key->newState &= ~KEY_IS_DOWN;
00191 
00192                 if( key->bank < IOXP_PORT0) {
00193                     /* Save inverted key state (low-active) */
00194                     key->newState |= (GpioPinGet( key->bank, key->pin))?0:1;
00195                 }
00196 #ifdef KEY_SUPPORT_IOEXP
00197                 else {
00198                     /* read io-expander only on first key connected
00199                     ** and buffer the result to keep bus silent
00200                     */
00201                     if( ioxread == 0) {
00202                         IOExpRawRead( key->bank, &ioxstate);
00203                         ioxread = 1;
00204                     }
00205                     /* Save inverted key state (low-active) */
00206                     key->newState |= ((ioxstate & (1<<key->pin))?0:1);
00207                 }
00208 #endif
00209 
00210                 /*
00211                  * Process key status change
00212                  */
00213                 if( (key->newState & KEY_IS_DOWN) > (key->lastState & KEY_IS_DOWN)) {
00214                     /* key up->down change */
00215                     key->TimeDown = now;
00216                     if( key->fx == KEY_ACTION_DOWN) {
00217                         KPRINTF("KD %08lx E:%08lx\n", (uint32_t)key, (uint32_t)(key->event));
00218                         key->newState |= KEY_PENDING;
00219                         if( key->event) NutEventPost( key->event);
00220                         if( key->callback) (*key->callback)();
00221                     }
00222                 }
00223                 else if( (key->newState & KEY_IS_DOWN) < (key->lastState & KEY_IS_DOWN)) {
00224                     /* key down->up change */
00225                     key->newState &= ~KEY_IS_LOCKED;
00226                     if( key->fx == KEY_ACTION_UP) {
00227                         KPRINTF("KU %08lx E:%08lx\n", (uint32_t)key, (uint32_t)(key->event));
00228                         key->newState |= (KEY_ACTION_UP | KEY_PENDING);
00229                         if( key->event) NutEventPost( key->event);
00230                         if( key->callback) (*key->callback)();
00231                     }
00232                     else if( ( key->fx == KEY_ACTION_SHORT) && ( (now - key->TimeDown) < key->fxt)) {
00233                         KPRINTF("KS %08lx E:%08lx\n", (uint32_t)key, (uint32_t)(key->event));
00234                         key->newState |= (KEY_ACTION_SHORT | KEY_PENDING);
00235                         if( key->event) NutEventPost( key->event);
00236                         if( key->callback) (*key->callback)();
00237                     }
00238                 }
00239                 else if( (key->newState & KEY_IS_DOWN) && (key->fx==KEY_ACTION_HOLD)) {
00240                     /* key still down */
00241                     if( ((now - key->TimeDown) > key->fxt) && ((key->newState & KEY_IS_LOCKED) == 0)) {
00242                         KPRINTF("KH %08lx E:%08lx\n", (uint32_t)key, (uint32_t)(key->event));
00243                         key->newState |= (KEY_ACTION_HOLD | KEY_PENDING);
00244                         if( key->event) NutEventPost( key->event);
00245                         if( key->callback) (*key->callback)();
00246                         key->newState |= KEY_IS_LOCKED;
00247                     }
00248                 }
00249 
00250                 /* Backup new state of key */
00251                 key->lastState = key->newState;
00252                 /* Advance to next key */
00253                 key = key->next;
00254             }
00255         }
00256     }
00257 }
00258 
00266 int InitKEY( KEYEventT *key )
00267 {
00268     if( key->bank < IOXP_PORT0) {
00269         /* configure standard GPIO pin */
00270         GpioPinConfigSet( key->bank, key->pin, GPIO_CFG_PULLUP|GPIO_CFG_DEBOUNCE);
00271         return 0;
00272     }
00273 #ifdef KEY_SUPPORT_IOEXP
00274     else {
00275         /* configure externally connected GPIO pin as input */
00276         IOExpPinConfigSet( key->bank, key->pin, 0);
00277         return 0;
00278     }
00279 #endif
00280     return -1;
00281 }
00282 
00283 int NutAssignKeyEvt( HANDLE *keyhp, HANDLE *event)
00284 {
00285     KEYEventT *key;
00286     if( keyhp==NULL) return -1;
00287 
00288     key = (KEYEventT*)keyhp;
00289     key->event = event;
00290     key->newState &= ~KEY_PENDING;
00291     return 0;
00292 }
00293 
00294 int NutAssignKeyFkt( HANDLE *keyhp, void (*callback)(void))
00295 {
00296     KEYEventT *key;
00297     if( keyhp==NULL) return -1;
00298 
00299     key = (KEYEventT*)keyhp;
00300     key->callback = callback;
00301     key->newState &= ~KEY_PENDING;
00302     return 0;
00303 }
00304 
00326 int NutRegisterKey( HANDLE *keyhp, int bank, int pin, int fx, uint32_t fxt)
00327 {
00328     KEYEventT *key;
00329 
00330     NUTASSERT( keyhp!=NULL);
00331 
00332     /* Check memory constraints and assign memory to new led struct */
00333     key = malloc( sizeof(KEYEventT));
00334     *keyhp = (void*)key;
00335 
00336     if( key == NULL) {
00337         return -1;
00338     }
00339 
00340     /* Preset new key struct */
00341     key->bank = bank;
00342     key->pin = pin;
00343     key->fx = fx;
00344     key->fxt = fxt;
00345     key->callback = NULL;
00346     key->event = NULL;
00347     key->lastState = key->newState = 1;
00348     key->TimeDown = 0;
00349 
00350     /* Initalize key hardware */
00351     InitKEY( key);
00352 
00353     /* Assign the key to the key chain */
00354     NutEnterCritical();
00355     if( first_key == NULL) {
00356         /* it is the first key */
00357         first_key = key;
00358     }
00359     else {
00360         key->next = first_key;
00361         first_key = key;
00362     }
00363     NutExitCritical();
00364 
00365     if( key_tmr == NULL) {
00366         NutThreadCreate( "sys_key", sys_key, &key_evt, 192);
00367         key_tmr = NutTimerStart(10, KeyTimerCb, &key_evt, 0);
00368     }
00369 
00370     KPRINTF("KREG %08lx E:%08lx\n", (uint32_t)key, (uint32_t)(key->event));
00371 
00372     return 0;
00373 }
00374 

© 2000-2010 by contributors - visit http://www.ethernut.de/