keys.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385
  1. /*
  2. * Copyright (C) 2001-2009 by egnite Software GmbH. All rights reserved.
  3. * Copyright (C) 2009 by Ulrich Prinz (uprinz2@netscape.net)
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. *
  9. * 1. Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. * 2. Redistributions in binary form must reproduce the above copyright
  12. * notice, this list of conditions and the following disclaimer in the
  13. * documentation and/or other materials provided with the distribution.
  14. * 3. Neither the name of the copyright holders nor the names of
  15. * contributors may be used to endorse or promote products derived
  16. * from this software without specific prior written permission.
  17. *
  18. * THIS SOFTWARE IS PROVIDED BY EMBEDDED IT AND CONTRIBUTORS
  19. * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  20. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  21. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL EMBEDDED IT
  22. * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  23. * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  24. * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
  25. * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  26. * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  27. * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  28. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  29. *
  30. * For additional information see http://www.ethernut.de/
  31. *
  32. */
  33. /*
  34. * \file dev/keys.c
  35. * \brief Key handling driver.
  36. *
  37. * Driver for flexible key, switch and button handling.
  38. *
  39. * \verbatim
  40. *
  41. * $Log$
  42. *
  43. * Revision 0.3 2009/09/12 ulrichprinz
  44. * First checkin, new push button driver example
  45. * (currently SAM7X256 is tested only)
  46. *
  47. * \endverbatim
  48. */
  49. #include <compiler.h>
  50. #include <cfg/os.h>
  51. #include <stdlib.h>
  52. #include <string.h>
  53. #include <sys/heap.h>
  54. #include <sys/event.h>
  55. #include <sys/timer.h>
  56. #include <sys/atom.h>
  57. #include <dev/board.h>
  58. #include <dev/gpio.h>
  59. #include <sys/nutdebug.h>
  60. #include <cfg/pca9555.h>
  61. #ifdef KEY_SUPPORT_IOEXP
  62. #include <dev/pca9555.h>
  63. #else
  64. #define IOXP_PORT0 0x80
  65. #endif
  66. //#define DEBUG_KEYS
  67. #ifdef DEBUG_KEYS
  68. #include <stdio.h>
  69. #define KPRINTF(args,...) printf(args,##__VA_ARGS__)
  70. #else
  71. #define KPRINTF(args,...)
  72. #endif
  73. #include <dev/keys.h>
  74. /*!
  75. * \addtogroup xgDevKeys
  76. */
  77. /*@{*/
  78. // TODO: [UP] This struct could be smaller without increasing addressing overhead
  79. typedef struct {
  80. void* next; /**< Pointer to next key or NULL on last key */
  81. HANDLE* event; /**< Handle for key event */
  82. void (*callback)(void); /**< Function Pointer if key is activated */
  83. int bank; /**< GPIO bank of key */
  84. int pin; /**< GPIO pin of key */
  85. int lastState; /**< last state sampled from port */
  86. int newState; /**< current state sampled from port */
  87. int fx; /**< Action type of key */
  88. uint32_t fxt; /**< time for action */
  89. uint32_t TimeDown; /**< System time in ms at key down recognized */
  90. } KEYEventT;
  91. static KEYEventT *first_key;
  92. HANDLE key_tmr = NULL;
  93. HANDLE key_evt = NULL;
  94. /*!
  95. * \brief reads actual state of a key
  96. *
  97. * Applications can call this functions to determine which key issued
  98. * the event to a calling thread. This helps if more than ome key has
  99. * been assigned to a single event mutex. If the key was the one which
  100. * raised the event, it has bit 1 set. This bit will be cleared on calling
  101. * this function.
  102. *
  103. * \param keyh Handle of the key to query.
  104. *
  105. * \return bit 0: 1 if key still pressed, bit 1: 1 if key raised the event.
  106. */
  107. int NutGetKeyState( HANDLE *keyhp)
  108. {
  109. KEYEventT *key = (KEYEventT *)keyhp;
  110. int rc = -1;
  111. if( keyhp==NULL) goto error_out;
  112. rc = key->newState;
  113. key->newState &= ~KEY_PENDING;
  114. error_out:
  115. return rc;
  116. }
  117. /*!
  118. * \brief reads the time in ms of how long the key is or was pressed
  119. *
  120. * Applications can call this functions to determine how long a key
  121. * is pressed.
  122. *
  123. * \param keyh Handle of the key to query.
  124. *
  125. * \return time key was pressed in ms or -1 in case of error.
  126. */
  127. int NutGetKeyTime( HANDLE *keyhp)
  128. {
  129. KEYEventT *key = (KEYEventT *)keyhp;
  130. int rc = -1;
  131. if( keyhp==NULL) goto error_out;
  132. rc = (int)(NutGetMillis() - key->TimeDown);
  133. error_out:
  134. return rc;
  135. }
  136. /*!
  137. * \brief Key-Timer callback handler.
  138. *
  139. * This is an internal function called by NutRegisterKey() and the
  140. * EventTimer for key handling.
  141. *
  142. * \param timer Internal Handle of the key timer.
  143. * \param arg Not used.
  144. */
  145. void KeyTimerCb(HANDLE timer, void *arg)
  146. {
  147. NutEventPostAsync(arg);
  148. }
  149. /*!
  150. * \brief Key-Thread.
  151. *
  152. * This is the internal key thread triggered by the key event timer.
  153. *
  154. */
  155. THREAD( sys_key, arg)
  156. {
  157. KEYEventT *key;
  158. uint32_t now;
  159. #ifdef KEY_SUPPORT_IOEXP
  160. int ioxread, ioxstate;
  161. #endif
  162. NUTASSERT( arg != NULL);
  163. NutThreadSetPriority( 16);
  164. for(;;)
  165. {
  166. #ifdef KEY_SUPPORT_IOEXP
  167. ioxread = 0;
  168. #endif
  169. if( NutEventWait( arg, NUT_WAIT_INFINITE)==0) {
  170. key = first_key;
  171. now = NutGetMillis();
  172. while( key ) {
  173. /*
  174. * Read in keys from ports
  175. */
  176. key->newState &= ~KEY_IS_DOWN;
  177. #ifndef KEY_SUPPORT_IOEXP
  178. /* Save inverted key state (low-active) */
  179. key->newState |= (GpioPinGet( key->bank, key->pin))?KEY_NOT_PRESSED:KEY_IS_DOWN;
  180. #else
  181. if( key->bank < IOXP_PORT0) {
  182. /* Save inverted key state (low-active) */
  183. key->newState |= (GpioPinGet( key->bank, key->pin))?KEY_NOT_PRESSED:KEY_IS_DOWN;
  184. }
  185. else {
  186. /* read io-expander only on first key connected
  187. ** and buffer the result to keep bus silent
  188. */
  189. if( ioxread == 0) {
  190. IOExpRawRead( key->bank, &ioxstate);
  191. ioxread = 1;
  192. }
  193. /* Save inverted key state (low-active) */
  194. key->newState |= ((ioxstate & (1<<key->pin))?0:1);
  195. }
  196. #endif
  197. /*
  198. * Process key status change
  199. */
  200. if( (key->newState & KEY_IS_DOWN) > (key->lastState & KEY_IS_DOWN)) {
  201. /* key up->down change */
  202. key->TimeDown = now;
  203. if( key->fx == KEY_ACTION_DOWN) {
  204. KPRINTF("KD %08lx E:%08lx\n", (uint32_t)key, (uint32_t)(key->event));
  205. key->newState |= KEY_PENDING;
  206. if( key->event) NutEventPost( key->event);
  207. if( key->callback) (*key->callback)();
  208. }
  209. }
  210. else if( (key->newState & KEY_IS_DOWN) < (key->lastState & KEY_IS_DOWN)) {
  211. /* key down->up change */
  212. key->newState &= ~KEY_IS_LOCKED;
  213. if( key->fx == KEY_ACTION_UP) {
  214. KPRINTF("KU %08lx E:%08lx\n", (uint32_t)key, (uint32_t)(key->event));
  215. key->newState |= (KEY_ACTION_UP | KEY_PENDING);
  216. if( key->event) NutEventPost( key->event);
  217. if( key->callback) (*key->callback)();
  218. }
  219. else if( ( key->fx == KEY_ACTION_SHORT) && ( (now - key->TimeDown) < key->fxt)) {
  220. KPRINTF("KS %08lx E:%08lx\n", (uint32_t)key, (uint32_t)(key->event));
  221. key->newState |= (KEY_ACTION_SHORT | KEY_PENDING);
  222. if( key->event) NutEventPost( key->event);
  223. if( key->callback) (*key->callback)();
  224. }
  225. }
  226. else if( (key->newState & KEY_IS_DOWN) && (key->fx==KEY_ACTION_HOLD)) {
  227. /* key still down */
  228. if( ((now - key->TimeDown) > key->fxt) && ((key->newState & KEY_IS_LOCKED) == 0)) {
  229. KPRINTF("KH %08lx E:%08lx\n", (uint32_t)key, (uint32_t)(key->event));
  230. key->newState |= (KEY_ACTION_HOLD | KEY_PENDING);
  231. if( key->event) NutEventPost( key->event);
  232. if( key->callback) (*key->callback)();
  233. key->newState |= KEY_IS_LOCKED;
  234. }
  235. }
  236. /* Backup new state of key */
  237. key->lastState = key->newState;
  238. /* Advance to next key */
  239. key = key->next;
  240. }
  241. }
  242. }
  243. }
  244. /*!
  245. * \brief Internal functionn to setup a GPIO port for reading a connected key.
  246. *
  247. * \param key Handle to the key, the port will be assigned to.
  248. *
  249. * \return 0 if key could be set up, -1 if not.
  250. */
  251. int InitKEY( KEYEventT *key )
  252. {
  253. if( key->bank < IOXP_PORT0) {
  254. /* configure standard GPIO pin */
  255. GpioPinConfigSet( key->bank, key->pin, GPIO_CFG_PULLUP|GPIO_CFG_DEBOUNCE);
  256. return 0;
  257. }
  258. #ifdef KEY_SUPPORT_IOEXP
  259. else {
  260. /* configure externally connected GPIO pin as input */
  261. IOExpPinConfigSet( key->bank, key->pin, 0);
  262. return 0;
  263. }
  264. #endif
  265. return -1;
  266. }
  267. int NutAssignKeyEvt( HANDLE *keyhp, HANDLE *event)
  268. {
  269. KEYEventT *key;
  270. if( keyhp==NULL) return -1;
  271. key = (KEYEventT*)keyhp;
  272. key->event = event;
  273. key->newState &= ~KEY_PENDING;
  274. return 0;
  275. }
  276. int NutAssignKeyFkt( HANDLE *keyhp, void (*callback)(void))
  277. {
  278. KEYEventT *key;
  279. if( keyhp==NULL) return -1;
  280. key = (KEYEventT*)keyhp;
  281. key->callback = callback;
  282. key->newState &= ~KEY_PENDING;
  283. return 0;
  284. }
  285. /*!
  286. * \brief register a key and describe its function
  287. *
  288. * \param keyh The handle to the LED that should be controlled.
  289. * \param event The event handle for locking a task until the key is active.
  290. * \param bank The GPIO or PCA9555 port, where key is connected to.
  291. * \param pin Pin of the bank, where key is connected to.
  292. * \param fx Action of key for releasing the event.
  293. * \param fxt Time parameter for action.
  294. *
  295. * \return 0 on success, -1 on any error.
  296. *
  297. * \note Following actions can be assigned to a key:
  298. * <table>
  299. * <tr><th>fx</th> <th>fxt</th><th>Event released</th></tr>
  300. * <tr><td>>KEY_ACTION_DOWN</td> <td>0</td> <td>on Key press</td></tr>
  301. * <tr><td>>KEY_ACTION_UP</td> <td>0</td> <td>on Key release</td></tr>
  302. * <tr><td>>KEY_ACTION_HOLD</td> <td>n</td> <td>on Key pressed for n ms</td></tr>
  303. * <tr><td>>KEY_ACTION_SHORT</td><td>n</td> <td>on Key released before n ms</td></tr>
  304. * </table>
  305. */
  306. int NutRegisterKey( HANDLE *keyhp, int bank, int pin, int fx, uint32_t fxt)
  307. {
  308. KEYEventT *key;
  309. NUTASSERT( keyhp!=NULL);
  310. /* Check memory constraints and assign memory to new led struct */
  311. key = malloc( sizeof(KEYEventT));
  312. *keyhp = (void*)key;
  313. if( key == NULL) {
  314. return -1;
  315. }
  316. /* Preset new key struct */
  317. key->bank = bank;
  318. key->pin = pin;
  319. key->fx = fx;
  320. key->fxt = fxt;
  321. key->callback = NULL;
  322. key->event = NULL;
  323. key->lastState = key->newState = 1;
  324. key->TimeDown = 0;
  325. /* Initalize key hardware */
  326. InitKEY( key);
  327. /* Assign the key to the key chain */
  328. NutEnterCritical();
  329. if( first_key == NULL) {
  330. /* it is the first key */
  331. first_key = key;
  332. }
  333. else {
  334. key->next = first_key;
  335. first_key = key;
  336. }
  337. NutExitCritical();
  338. if( key_tmr == NULL) {
  339. NutThreadCreate( "sys_key", sys_key, &key_evt, 256);
  340. key_tmr = NutTimerStart(10, KeyTimerCb, &key_evt, 0);
  341. }
  342. KPRINTF("KREG %08lx E:%08lx\n", (uint32_t)key, (uint32_t)(key->event));
  343. return 0;
  344. }
  345. /*@}*/