diff options
| author | Michael Sevakis <jethead71@rockbox.org> | 2007-07-22 21:02:24 +0000 |
|---|---|---|
| committer | Michael Sevakis <jethead71@rockbox.org> | 2007-07-22 21:02:24 +0000 |
| commit | 873e0fd1ef2ad0e8e1d74a9c9a3b0ed0cdfee35e (patch) | |
| tree | 29ca956fb87b7f8c17cb5061d3afcfda70c44e4c /firmware | |
| parent | 3213d4a0f5d3aea725bb9ddf34ae0ec38ca4b097 (diff) | |
| download | rockbox-873e0fd1ef2ad0e8e1d74a9c9a3b0ed0cdfee35e.zip rockbox-873e0fd1ef2ad0e8e1d74a9c9a3b0ed0cdfee35e.tar.gz rockbox-873e0fd1ef2ad0e8e1d74a9c9a3b0ed0cdfee35e.tar.bz2 rockbox-873e0fd1ef2ad0e8e1d74a9c9a3b0ed0cdfee35e.tar.xz | |
Wheel acceleration for e200. A general acceleration interface intended for use on any scroll target and by any code. A general interface to obtain data associated with most recently dequeued button presses and actions. Use #define HAVE_SCROLLWHEEL and set appropriate constants, values in the scroller driver that feel right.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@13959 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware')
| -rw-r--r-- | firmware/drivers/button.c | 45 | ||||
| -rw-r--r-- | firmware/export/button.h | 6 | ||||
| -rw-r--r-- | firmware/export/config-e200.h | 8 | ||||
| -rw-r--r-- | firmware/target/arm/sandisk/sansa-e200/button-e200.c | 91 |
4 files changed, 123 insertions, 27 deletions
diff --git a/firmware/drivers/button.c b/firmware/drivers/button.c index f9f355c..715d4d3 100644 --- a/firmware/drivers/button.c +++ b/firmware/drivers/button.c @@ -49,6 +49,7 @@ struct event_queue button_queue; static long lastbtn; /* Last valid button status */ static long last_read; /* Last button status, for debouncing/filtering */ +static intptr_t button_data; /* data value from last message dequeued */ #ifdef HAVE_LCD_BITMAP static bool flipped; /* buttons can be flipped to match the LCD flip */ #endif @@ -309,7 +310,7 @@ long button_get(bool block) if (current_tick - ev.tick > MAX_EVENT_AGE) return BUTTON_NONE; #endif - + button_data = ev.data; return ev.id; } @@ -329,7 +330,17 @@ long button_get_w_tmo(int ticks) #endif queue_wait_w_tmo(&button_queue, &ev, ticks); - return (ev.id != SYS_TIMEOUT)? ev.id: BUTTON_NONE; + if (ev.id == SYS_TIMEOUT) + ev.id = BUTTON_NONE; + else + button_data = ev.data; + + return ev.id; +} + +intptr_t button_get_data(void) +{ + return button_data; } void button_init(void) @@ -470,3 +481,33 @@ void button_clear_queue(void) { queue_clear(&button_queue); } + +#ifdef HAVE_SCROLLWHEEL +/** + * data: + * [31] Use acceleration + * [30:24] Message post count (skipped + 1) (1-127) + * [23:0] Velocity - clicks/uS - 0.24 fixed point + * + * factor: + * Wheel acceleration scaling factor - x.24 fixed point - + * no greater than what will not overflow 64 bits when multiplied + * by the driver's maximum velocity in (clicks/usec)^2 in 0.24 + */ +int button_apply_acceleration(unsigned int data, unsigned int factor) +{ + int delta = (data >> 24) & 0x7f; + + if ((data & (1 << 31)) != 0) + { + unsigned int v = data & 0xffffff; + + v = factor * (unsigned long long)v*v / 0xffffffffffffull; + + if (v > 1) + delta *= v; + } + + return delta; +} +#endif /* HAVE_SCROLLWHEEL */ diff --git a/firmware/export/button.h b/firmware/export/button.h index f675824..8b8c966 100644 --- a/firmware/export/button.h +++ b/firmware/export/button.h @@ -20,6 +20,7 @@ #define _BUTTON_H_ #include <stdbool.h> +#include <inttypes.h> #include "config.h" #include "button-target.h" @@ -28,6 +29,7 @@ extern struct event_queue button_queue; void button_init (void); long button_get (bool block); long button_get_w_tmo(int ticks); +intptr_t button_get_data(void); int button_status(void); void button_clear_queue(void); #ifdef HAVE_LCD_BITMAP @@ -48,6 +50,10 @@ int wheel_status(void); void wheel_send_events(bool send); #endif +#ifdef HAVE_SCROLLWHEEL +int button_apply_acceleration(unsigned int data, unsigned int factor); +#endif + #define BUTTON_NONE 0x00000000 /* Button modifiers */ diff --git a/firmware/export/config-e200.h b/firmware/export/config-e200.h index 6edab71..c7f058e 100644 --- a/firmware/export/config-e200.h +++ b/firmware/export/config-e200.h @@ -170,4 +170,10 @@ #define ICODE_ATTR_TREMOR_NOT_MDCT -#endif +/* define this if the unit uses a scrollwheel for navigation */ +#define HAVE_SCROLLWHEEL +/* define wheel acceleration scaling factor */ +/* Range for this target: 0xffffff*(0.0-16.000000894069724921567733381255) */ +#define WHEEL_ACCELERATION_FACTOR (0xffffff*7) + +#endif /* SIMULATOR */ diff --git a/firmware/target/arm/sandisk/sansa-e200/button-e200.c b/firmware/target/arm/sandisk/sansa-e200/button-e200.c index 5e2c38e..734416b 100644 --- a/firmware/target/arm/sandisk/sansa-e200/button-e200.c +++ b/firmware/target/arm/sandisk/sansa-e200/button-e200.c @@ -23,19 +23,21 @@ #include "button.h" #include "backlight.h" -#define WHEEL_REPEAT_INTERVAL 30 -#define WHEEL_FAST_ON_INTERVAL 2 -#define WHEEL_FAST_OFF_INTERVAL 6 +#define WHEEL_REPEAT_INTERVAL 300000 +#define WHEEL_FAST_ON_INTERVAL 20000 +#define WHEEL_FAST_OFF_INTERVAL 60000 /* Clickwheel */ #ifndef BOOTLOADER static unsigned int old_wheel_value = 0; static unsigned int wheel_repeat = BUTTON_NONE; static unsigned int wheel_click_count = 0; +static unsigned int wheel_delta = 0; static int wheel_fast_mode = 0; -static unsigned long last_wheel_tick = 0; -static unsigned long last_wheel_post = 0; -static unsigned long next_backlight_on = 0; +static unsigned long last_wheel_usec = 0; +static unsigned long wheel_velocity = 0; +static long last_wheel_post = 0; +static long next_backlight_on = 0; /* Buttons */ static bool hold_button = false; static bool hold_button_old = false; @@ -64,8 +66,8 @@ void button_init_device(void) GPIOH_INT_EN &= ~0xc0; /* Get current tick before enabling button interrupts */ - last_wheel_tick = current_tick; - last_wheel_post = current_tick; + last_wheel_usec = USEC_TIMER; + last_wheel_post = last_wheel_usec; GPIOH_ENABLE |= 0xc0; GPIOH_OUTPUT_EN &= ~0xc0; @@ -130,38 +132,67 @@ void clickwheel_int(void) if (btn != BUTTON_NONE) { - int repeat = 1; + int repeat = 1; /* assume repeat */ + unsigned long usec = USEC_TIMER; + unsigned v = (usec - last_wheel_usec) & 0x7fffffff; + + /* wheel velocity in 0.24 fixed point - clicks/uS */ + + /* velocity cap to 18 bits to allow up to x16 scaling */ + v = (v < 0x40) ? 0xffffff / 0x40 : 0xffffff / v; + + /* some velocity filtering to smooth things out */ + wheel_velocity = (7*wheel_velocity + v) / 8; if (btn != wheel_repeat) { + /* direction reversals nullify all fast mode states */ wheel_repeat = btn; repeat = wheel_fast_mode = + wheel_velocity = wheel_click_count = 0; } - if (wheel_fast_mode) + if (wheel_fast_mode != 0) { - if (TIME_AFTER(current_tick, - last_wheel_tick + WHEEL_FAST_OFF_INTERVAL)) + /* fast OFF happens immediately when velocity drops below + threshold */ + if (TIME_AFTER(usec, + last_wheel_usec + WHEEL_FAST_OFF_INTERVAL)) { - if (++wheel_click_count < 2) - btn = BUTTON_NONE; + /* moving out of fast mode */ wheel_fast_mode = 0; + /* reset velocity */ + wheel_velocity = 0; + /* wheel_delta is always 1 in slow mode */ + wheel_delta = 1; } } else { - if (repeat && TIME_BEFORE(current_tick, - last_wheel_tick + WHEEL_FAST_ON_INTERVAL)) - wheel_fast_mode = 1; + /* fast ON gets filtered to avoid inadvertent jumps to fast mode */ + if (repeat && wheel_velocity > 0xffffff/WHEEL_FAST_ON_INTERVAL) + { + /* moving into fast mode */ + wheel_fast_mode = 1 << 31; + wheel_click_count = 0; + wheel_velocity = 0xffffff/WHEEL_FAST_OFF_INTERVAL; + } else if (++wheel_click_count < 2) + { btn = BUTTON_NONE; + } + + /* wheel_delta is always 1 in slow mode */ + wheel_delta = 1; } - if (TIME_AFTER(current_tick, next_backlight_on)) + if (TIME_AFTER(usec, next_backlight_on)) { - next_backlight_on = current_tick + HZ/4; + /* poke backlight to turn it on or maintain it no more often + than every 1/4 second*/ + next_backlight_on = usec + 1000000/4; backlight_on(); button_backlight_on(); } @@ -170,17 +201,29 @@ void clickwheel_int(void) { wheel_click_count = 0; - if (repeat && TIME_BEFORE(current_tick, - last_wheel_post + WHEEL_REPEAT_INTERVAL)) + /* generate repeats if quick enough */ + if (repeat && TIME_BEFORE(usec, + last_wheel_post + WHEEL_REPEAT_INTERVAL)) btn |= BUTTON_REPEAT; - last_wheel_post = current_tick; + last_wheel_post = usec; if (queue_empty(&button_queue)) - queue_post(&button_queue, btn, 0); + { + queue_post(&button_queue, btn, wheel_fast_mode | + (wheel_delta << 24) | wheel_velocity); + /* message posted - reset delta */ + wheel_delta = 1; + } + else + { + /* skipped post - increment delta */ + if (++wheel_delta > 0x7f) + wheel_delta = 0x7f; + } } - last_wheel_tick = current_tick; + last_wheel_usec = usec; } } |