summaryrefslogtreecommitdiff
path: root/firmware
diff options
context:
space:
mode:
authorMichael Sevakis <jethead71@rockbox.org>2007-07-22 21:02:24 +0000
committerMichael Sevakis <jethead71@rockbox.org>2007-07-22 21:02:24 +0000
commit873e0fd1ef2ad0e8e1d74a9c9a3b0ed0cdfee35e (patch)
tree29ca956fb87b7f8c17cb5061d3afcfda70c44e4c /firmware
parent3213d4a0f5d3aea725bb9ddf34ae0ec38ca4b097 (diff)
downloadrockbox-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.c45
-rw-r--r--firmware/export/button.h6
-rw-r--r--firmware/export/config-e200.h8
-rw-r--r--firmware/target/arm/sandisk/sansa-e200/button-e200.c91
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;
}
}