summaryrefslogtreecommitdiffstats
path: root/firmware
diff options
context:
space:
mode:
authorMarcin Bukat <marcin.bukat@gmail.com>2010-08-23 19:56:17 +0000
committerMarcin Bukat <marcin.bukat@gmail.com>2010-08-23 19:56:17 +0000
commit8d5f159687b6abf3b5ad6b1681701a1b80423d92 (patch)
tree7d81f979b3eb106defe50036e1915b5649fdcb0c /firmware
parent1994df6844d9b478f2199d63e70e88996e3b4096 (diff)
downloadrockbox-8d5f159687b6abf3b5ad6b1681701a1b80423d92.tar.gz
rockbox-8d5f159687b6abf3b5ad6b1681701a1b80423d92.tar.bz2
rockbox-8d5f159687b6abf3b5ad6b1681701a1b80423d92.zip
Implement WHEEL_ACCELERATION for Ipod mini 1G based on code for 1G/2G.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@27865 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware')
-rw-r--r--firmware/export/config/ipodmini1g.h6
-rw-r--r--firmware/target/arm/ipod/button-mini1g.c172
2 files changed, 135 insertions, 43 deletions
diff --git a/firmware/export/config/ipodmini1g.h b/firmware/export/config/ipodmini1g.h
index 121a7fc801..85e4597b9f 100644
--- a/firmware/export/config/ipodmini1g.h
+++ b/firmware/export/config/ipodmini1g.h
@@ -79,6 +79,12 @@
#define CONFIG_KEYPAD IPOD_4G_PAD
#define HAVE_SCROLLWHEEL
+/* define to activate advanced wheel acceleration code */
+#define HAVE_WHEEL_ACCELERATION
+/* define from which rotation speed [degree/sec] on the acceleration starts */
+#define WHEEL_ACCEL_START 360
+/* define type of acceleration (1 = ^2, 2 = ^3, 3 = ^4) */
+#define WHEEL_ACCELERATION 1
/* Define this to enable morse code input */
#define HAVE_MORSE_INPUT
diff --git a/firmware/target/arm/ipod/button-mini1g.c b/firmware/target/arm/ipod/button-mini1g.c
index 5831cdfc31..d4a75c90d8 100644
--- a/firmware/target/arm/ipod/button-mini1g.c
+++ b/firmware/target/arm/ipod/button-mini1g.c
@@ -40,63 +40,150 @@
#include "power.h"
#include "powermgmt.h"
+#define WHEELCLICKS_PER_ROTATION 96
+#define WHEEL_BASE_SENSITIVITY 6 /* Compute every ... clicks */
+#define WHEEL_REPEAT_VELOCITY 45 /* deg/s */
+#define WHEEL_SMOOTHING_VELOCITY 100 /* deg/s */
+
/* Variable to use for setting button status in interrupt handler */
int int_btn = BUTTON_NONE;
-#ifdef HAVE_WHEEL_POSITION
- static int wheel_position = -1;
- static bool send_events = true;
-#endif
-static void handle_scroll_wheel(int new_scroll, int was_hold)
+static void handle_scroll_wheel(int new_scroll)
{
- int wheel_keycode = BUTTON_NONE;
- static int prev_scroll = -1;
- static int direction = 0;
- static int count = 0;
- static int scroll_state[4][4] = {
+ static const signed char scroll_state[4][4] = {
{0, 1, -1, 0},
{-1, 0, 0, 1},
{1, 0, 0, -1},
{0, -1, 1, 0}
};
+ static int prev_scroll = -1;
+ static int direction = 0;
+ static int count = 0;
+ static long next_backlight_on = 0;
+
+ int wheel_keycode = BUTTON_NONE;
+ int scroll;
+
+ static unsigned long wheel_delta = 1ul << 24;
+ static unsigned long wheel_velocity = 0;
+ static unsigned long last_wheel_usec = 0;
+ static int prev_keypost = BUTTON_NONE;
+
+ unsigned long usec;
+ unsigned long v;
+
if ( prev_scroll == -1 ) {
prev_scroll = new_scroll;
+ return;
}
- else if (direction != scroll_state[prev_scroll][new_scroll]) {
- direction = scroll_state[prev_scroll][new_scroll];
+
+ scroll = scroll_state[prev_scroll][new_scroll];
+ prev_scroll = new_scroll;
+
+ if (direction != scroll) {
+ /* direction reversal or was hold - reset all */
+ direction = scroll;
count = 0;
+ prev_keypost = BUTTON_NONE;
+ wheel_velocity = 0;
+ wheel_delta = 1ul << 24;
+ return;
}
- else if (!was_hold) {
+
+ /* poke backlight every 1/4s of activity */
+ if (TIME_AFTER(current_tick, next_backlight_on)) {
backlight_on();
reset_poweroff_timer();
- if (++count == 6) { /* reduce sensitivity */
- count = 0;
- /* Mini 1st Gen wheel has inverse direction mapping
- * compared to 1st..3rd Gen wheel. */
- switch (direction) {
- case 1:
- wheel_keycode = BUTTON_SCROLL_FWD;
- break;
- case -1:
- wheel_keycode = BUTTON_SCROLL_BACK;
- break;
- default:
- /* only happens if we get out of sync */
- break;
- }
+ next_backlight_on = current_tick + HZ/4;
+ }
+
+ if (++count < WHEEL_BASE_SENSITIVITY)
+ return;
+
+ count = 0;
+ /* Mini 1st Gen wheel has inverse direction mapping
+ * compared to 1st..3rd Gen wheel. */
+ switch (direction) {
+ case 1:
+ wheel_keycode = BUTTON_SCROLL_FWD;
+ break;
+ case -1:
+ wheel_keycode = BUTTON_SCROLL_BACK;
+ break;
+ default:
+ /* only happens if we get out of sync */
+ break;
+ }
+
+ /* have a keycode */
+
+ usec = USEC_TIMER;
+ v = usec - last_wheel_usec;
+
+ /* calculate deg/s based upon sensitivity-adjusted interrupt period */
+
+ if ((long)v <= 0) {
+ /* timer wrapped (no activity for awhile), skip acceleration */
+ v = 0;
+ wheel_delta = 1ul << 24;
+ }
+ else {
+ if (v > 0xfffffffful/WHEELCLICKS_PER_ROTATION) {
+ v = 0xfffffffful/WHEELCLICKS_PER_ROTATION; /* check overflow below */
}
+
+ v = 360000000ul*WHEEL_BASE_SENSITIVITY / (v*WHEELCLICKS_PER_ROTATION);
+
+ if (v > 0xfffffful)
+ v = 0xfffffful; /* limit to 24 bits */
}
- if (wheel_keycode != BUTTON_NONE && queue_empty(&button_queue))
- queue_post(&button_queue, wheel_keycode, 0);
- prev_scroll = new_scroll;
+
+ if (v < WHEEL_SMOOTHING_VELOCITY) {
+ /* very slow - no smoothing */
+ wheel_velocity = v;
+ /* ensure backlight never gets stuck for an extended period if tick
+ * wrapped such that next poke is very far ahead */
+ next_backlight_on = current_tick - 1;
+ }
+ else {
+ /* some velocity filtering to smooth things out */
+ wheel_velocity = (7*wheel_velocity + v) / 8;
+ }
+
+ if (queue_empty(&button_queue)) {
+ int key = wheel_keycode;
+
+ if (v >= WHEEL_REPEAT_VELOCITY && prev_keypost == key) {
+ /* quick enough and same key is being posted more than once in a
+ * row - generate repeats - use unsmoothed v to guage */
+ key |= BUTTON_REPEAT;
+ }
+
+ prev_keypost = wheel_keycode;
+
+ /* post wheel keycode with wheel data */
+ queue_post(&button_queue, key,
+ (wheel_velocity >= WHEEL_ACCEL_START ? (1ul << 31) : 0)
+ | wheel_delta | wheel_velocity);
+ /* message posted - reset delta */
+ wheel_delta = 1ul << 24;
+ }
+ else {
+ /* skipped post - increment delta and limit to 7 bits */
+ wheel_delta += 1ul << 24;
+
+ if (wheel_delta > (0x7ful << 24))
+ wheel_delta = 0x7ful << 24;
+ }
+
+ last_wheel_usec = usec;
}
/* mini 1 only, mini 2G uses iPod 4G code */
static int ipod_mini_button_read(void)
{
unsigned char source, wheel_source, state, wheel_state;
- static bool was_hold = false;
int btn = BUTTON_NONE;
/* The ipodlinux source had a udelay(250) here, but testing has shown that
@@ -119,9 +206,17 @@ static int ipod_mini_button_read(void)
GPIOA_INT_LEV = ~state;
GPIOB_INT_LEV = ~wheel_state;
+ /* ack any active interrupts */
+ if (source)
+ GPIOA_INT_CLR = source;
+ if (wheel_source)
+ GPIOB_INT_CLR = wheel_source;
+
+ if (button_hold())
+ return BUTTON_NONE;
+
/* hold switch causes all outputs to go low */
/* we shouldn't interpret these as key presses */
- if ((state & 0x20)) {
if (!(state & 0x1))
btn |= BUTTON_SELECT;
if (!(state & 0x2))
@@ -134,17 +229,8 @@ static int ipod_mini_button_read(void)
btn |= BUTTON_LEFT;
if (wheel_source & 0x30) {
- handle_scroll_wheel((wheel_state & 0x30) >> 4, was_hold);
+ handle_scroll_wheel((wheel_state & 0x30) >> 4);
}
- }
-
- was_hold = button_hold();
-
- /* ack any active interrupts */
- if (source)
- GPIOA_INT_CLR = source;
- if (wheel_source)
- GPIOB_INT_CLR = wheel_source;
return btn;
}