Nut/OS  4.10.3
API Reference
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