+/* Copyright (c)2007, 2008 Martin Thomas, BSD license */\r
+\r
+#ifndef KEY_IO_H_\r
+#define KEY_IO_H_\r
+\r
+#include <stdint.h>\r
+#include <avr/io.h>\r
+\r
+#include "timebase.h" /* for TIMEBASE_DELTAT_MS */\r
+\r
+#define KEY_IO_KEYSA_DDR DDRC\r
+#define KEY_IO_KEYSA_PORT PORTC\r
+#define KEY_IO_KEYSA_PIN PINC\r
+#define KEY_IO_KEYA1_BIT PC0 /* SW0 */\r
+#define KEY_IO_KEYA2_BIT PC1 /* SW1 */\r
+#define KEY_IO_KEYA3_BIT PC6 /* SW2 */\r
+#define KEY_IO_KEYA4_BIT PC7 /* SW3 */\r
+#define KEY_IO_KEYSB_DDR DDRD\r
+#define KEY_IO_KEYSB_PORT PORTD\r
+#define KEY_IO_KEYSB_PIN PIND\r
+#define KEY_IO_KEYB1_BIT PD5 /* Power button */\r
+\r
+#define KEY_IO_KEY_SW0 (1<<0)\r
+#define KEY_IO_KEY_SW1 (1<<1)\r
+#define KEY_IO_KEY_SW2 (1<<2)\r
+#define KEY_IO_KEY_SW3 (1<<3)\r
+#define KEY_IO_KEY_POWER (1<<4)\r
+#define KEY_IO_KEY_ALL \\r
+ ( KEY_IO_KEY_SW0 | \\r
+ KEY_IO_KEY_SW1 | \\r
+ KEY_IO_KEY_SW2 | \\r
+ KEY_IO_KEY_SW3 | \\r
+ KEY_IO_KEY_POWER )\r
+\r
+\r
+static inline uint8_t key_io_state_hardware(void)\r
+{\r
+ uint8_t tmp1, tmp2, tmp3;\r
+ tmp1 = KEY_IO_KEYSA_PIN & ( (1<<KEY_IO_KEYA1_BIT) | (1<<KEY_IO_KEYA2_BIT) );\r
+ tmp2 = KEY_IO_KEYSA_PIN & ( (1<<KEY_IO_KEYA3_BIT) | (1<<KEY_IO_KEYA4_BIT) );\r
+ tmp2 >>= 4;\r
+ tmp3 = KEY_IO_KEYSB_PIN & (1<<KEY_IO_KEYB1_BIT);\r
+ tmp3 >>= 1;\r
+ return ( tmp1 | tmp2 | tmp3 );\r
+}\r
+\r
+/* debounce/repeat code based on an example from Peter Dannegger,\r
+ modified for better integration and volatiles added */\r
+\r
+//#define KEY_IO_REPEAT_MASK ( KEY_IO_KEY_DOWN | KEY_IO_KEY_UP )\r
+#define KEY_IO_REPEAT_MASK ( KEY_IO_KEY_ALL )\r
+#define KEY_IO_REPEAT_START ( 500/*ms*/ / TIMEBASE_DELTAT_MS )\r
+#define KEY_IO_REPEAT_NEXT ( 100/*ms*/ / TIMEBASE_DELTAT_MS )\r
+\r
+// debounced and inverted key state, bit = 1: key pressed\r
+extern volatile uint8_t key_io_state; \r
+// key press detect\r
+extern volatile uint8_t key_io_press;\r
+// key long press and repeat\r
+extern volatile uint8_t key_io_rpt;\r
+\r
+/* The following callback-function has to be \r
+ called frequently from timer-ISR. Implemented \r
+ in this header-file as static inline to \r
+ indicate to the compiler that the function \r
+ should be inlined into the ISR-code. Tested with \r
+ avr-gcc 4.2.1: inlined - o.k. */\r
+static inline void key_io_callback(void)\r
+{\r
+ static uint8_t ct0, ct1, rpt;\r
+ uint8_t i, mystate;\r
+\r
+ mystate = key_io_state;\r
+\r
+ i = mystate ^ ~( key_io_state_hardware() ); // keys changed ?\r
+ ct0 = ~(ct0 & i); // reset or count ct0\r
+ ct1 = ct0 ^ (ct1 & i); // reset or count ct1\r
+ i &= ct0 & ct1; // count until roll over ?\r
+ mystate ^= i; // then toggle debounced state\r
+ key_io_press |= mystate & i; // 0->1: key press detect\r
+\r
+ if( (mystate & KEY_IO_REPEAT_MASK) == 0 ) { // check repeat function\r
+ rpt = KEY_IO_REPEAT_START; // start delay\r
+ }\r
+ if( --rpt == 0 ) {\r
+ rpt = KEY_IO_REPEAT_NEXT; // repeat delay\r
+ key_io_rpt |= mystate & KEY_IO_REPEAT_MASK;\r
+ }\r
+\r
+ key_io_state = mystate;\r
+}\r
+\r
+void key_io_init(void);\r
+\r
+uint8_t key_io_get_press( uint8_t key_mask );\r
+uint8_t key_io_get_rpt( uint8_t key_mask );\r
+uint8_t key_io_get_longpress( uint8_t key_mask );\r
+/* only returns "true" after key has been released: */\r
+uint8_t key_io_get_was_short( uint8_t key_mask );\r
+\r
+#endif\r