diff --git a/apps/gui/list.c b/apps/gui/list.c
index 223fc2c..09117ac 100644
--- a/apps/gui/list.c
+++ b/apps/gui/list.c
@@ -1012,7 +1012,8 @@ bool gui_synclist_do_button(struct gui_synclist * lists,
#ifdef HAVE_SCROLLWHEEL
int next_item_modifier = button_apply_acceleration(get_action_data(),
- WHEEL_ACCELERATION_FACTOR);
+ global_settings.wheel_accel_start,
+ global_settings.wheelacceleration);
#else
static int next_item_modifier = 1;
static int last_accel_tick = 0;
diff --git a/apps/lang/deutsch.lang b/apps/lang/deutsch.lang
index 61c32c5..9d02200 100644
--- a/apps/lang/deutsch.lang
+++ b/apps/lang/deutsch.lang
@@ -3258,15 +3258,12 @@
user:
*: "List Acceleration Speed"
- scrollwheel: none
*: "Listenbeschleunigung"
- scrollwheel: none
*: "Listenbeschleunigung"
- scrollwheel: none
@@ -11359,3 +11356,20 @@
*: "Mitteleuropäisch"
+
+ id: LANG_WHEEL_ACCEL_START
+ desc: wheel acceleration start
+ user:
+
+ *: none
+ scrollwheel: "Wheelspeed for Acceleration"
+
+
+ *: none
+ scrollwheel: "Startwert für Listenbeschleunigung"
+
+
+ *: none
+ scrollwheel: "Startwert für Listenbeschleunigung"
+
+
diff --git a/apps/lang/english.lang b/apps/lang/english.lang
index e79f865..e0f7e9d 100644
--- a/apps/lang/english.lang
+++ b/apps/lang/english.lang
@@ -3333,15 +3333,12 @@
user:
*: "List Acceleration Speed"
- scrollwheel: none
*: "List Acceleration Speed"
- scrollwheel: none
*: "List Acceleration Speed"
- scrollwheel: none
@@ -11476,3 +11473,21 @@
*: "Say file type"
+
+ id: LANG_WHEEL_ACCEL_START
+ desc: wheel acceleration start
+ user:
+
+ *: none
+ scrollwheel: "Wheelspeed for Acceleration"
+
+
+ *: none
+ scrollwheel: "Wheelspeed for Acceleration"
+
+
+ *: none
+ scrollwheel: "Wheelspeed for Acceleration"
+
+
+
diff --git a/apps/menus/display_menu.c b/apps/menus/display_menu.c
index a68defd..ae44e38 100644
--- a/apps/menus/display_menu.c
+++ b/apps/menus/display_menu.c
@@ -252,6 +252,9 @@ MENUITEM_SETTING(jump_scroll_delay, &global_settings.jump_scroll_delay, NULL);
MENUITEM_SETTING(list_accel_start_delay,
&global_settings.list_accel_start_delay, NULL);
MENUITEM_SETTING(list_accel_wait, &global_settings.list_accel_wait, NULL);
+#else
+MENUITEM_SETTING(wheel_accel_start, &global_settings.wheel_accel_start, NULL);
+MENUITEM_SETTING(wheelacceleration, &global_settings.wheelacceleration, NULL);
#endif /* HAVE_SCROLLWHEEL */
#ifdef HAVE_LCD_BITMAP
int screenscroll_callback(int action,const struct menu_item_ex *this_item)
@@ -289,6 +292,9 @@ MAKE_MENU(scroll_settings_menu, ID2P(LANG_SCROLL_MENU), 0, Icon_NOICON,
&scroll_paginated,
#ifndef HAVE_SCROLLWHEEL
&list_accel_start_delay, &list_accel_wait
+#else
+ &wheel_accel_start,
+ &wheelacceleration
#endif
);
/* SCROLL MENU */
diff --git a/apps/settings.h b/apps/settings.h
index d4498cf..9161a20 100644
--- a/apps/settings.h
+++ b/apps/settings.h
@@ -743,6 +743,9 @@ struct user_settings
#ifndef HAVE_SCROLLWHEEL
int list_accel_start_delay; /* ms before we start increaseing step size */
int list_accel_wait; /* ms between increases */
+#else
+ unsigned int wheel_accel_start; /* value in clicks/sec from which acceleration starts */
+ unsigned int wheelacceleration; /* type of acceleration (^2/^3/^4) */
#endif
#ifdef HAVE_USBSTACK
int usb_stack_mode; /* device or host */
diff --git a/apps/settings_list.c b/apps/settings_list.c
index d1d8905..6bcfa49 100644
--- a/apps/settings_list.c
+++ b/apps/settings_list.c
@@ -242,6 +242,18 @@ static void ff_rewind_min_step_formatter(char *buffer, size_t buffer_size,
(void)unit;
snprintf(buffer, buffer_size, "%ds", ff_rewind_min_stepvals[val]);
}
+static long wheel_accel_start_getlang(int value)
+{
+ if (value == 0)
+ return LANG_OFF;
+ return TALK_ID(value, UNIT_INT);
+}
+static long wheel_accel_getlang(int value)
+{
+ if (value == 0)
+ return LANG_OFF;
+ return TALK_ID(value, UNIT_INT);
+}
static long scanaccel_getlang(int value)
{
if (value == 0)
@@ -257,6 +269,28 @@ static void scanaccel_formatter(char *buffer, size_t buffer_size,
else
snprintf(buffer, buffer_size, "2x/%ds", val);
}
+static void wheel_accel_start_formatter(char *buffer, size_t buffer_size,
+ int val, const char *unit)
+{
+ (void)unit;
+ if (val == 0)
+ strcpy(buffer, str(LANG_OFF));
+ else
+ snprintf(buffer, buffer_size, "%d °/s", val);
+}
+static void wheel_accel_formatter(char *buffer, size_t buffer_size,
+ int val, const char *unit)
+{
+ (void)unit;
+ if (val == 0)
+ strcpy(buffer, str(LANG_OFF));
+ else if (val==1)
+ snprintf(buffer, buffer_size, "(°/s)^2");
+ else if (val==2)
+ snprintf(buffer, buffer_size, "(°/s)^3");
+ else
+ snprintf(buffer, buffer_size, "(°/s)^4");
+}
static const unsigned char poweroff_idle_timer_times[] = {0,1,2,3,4,5,6,7,8,9,10,15,30,45,60};
static long poweroff_idle_timer_getlang(int value)
@@ -1269,6 +1303,13 @@ const struct settings_list settings[] = {
INT_SETTING(0, list_accel_wait, LANG_LISTACCEL_ACCEL_SPEED,
3, "list_accel_wait", UNIT_SEC, 1, 10, 1,
scanaccel_formatter, scanaccel_getlang, NULL),
+#else
+ INT_SETTING(0, wheel_accel_start, LANG_WHEEL_ACCEL_START, DEFAULT_WHEEL_ACCEL_START,
+ "wheel_accel_start", UNIT_INT, 180, 810, 90,
+ wheel_accel_start_formatter, wheel_accel_start_getlang, NULL),
+ INT_SETTING(0, wheelacceleration, LANG_LISTACCEL_ACCEL_SPEED, DEFAULT_WHEEL_ACCELERATION,
+ "wheel_acceleration", UNIT_INT, 1, 3, 1,
+ wheel_accel_formatter, wheel_accel_getlang, NULL),
#endif /* HAVE_SCROLLWHEEL */
#ifdef HAVE_USBSTACK
CHOICE_SETTING(0, usb_stack_mode, LANG_USBSTACK_MODE, 0, "usb mode",
diff --git a/firmware/drivers/button.c b/firmware/drivers/button.c
index 000c478..632776b 100644
--- a/firmware/drivers/button.c
+++ b/firmware/drivers/button.c
@@ -292,7 +292,7 @@ static void button_tick(void)
static void button_boost(bool state)
{
static bool boosted = false;
-
+
if (state && !boosted)
{
cpu_boost(true);
@@ -323,11 +323,11 @@ long button_get(bool block)
else if (pending_count > 2)
button_boost(true);
#endif
-
+
if ( block || pending_count )
{
queue_wait(&button_queue, &ev);
-
+
#if 0
/* Ignore if the event was too old and for simplicity, just
* wait for a new button_get() request. */
@@ -337,22 +337,22 @@ long button_get(bool block)
button_data = ev.data;
return ev.id;
}
-
+
return BUTTON_NONE;
}
long button_get_w_tmo(int ticks)
{
struct queue_event ev;
-
+
#ifdef HAVE_ADJUSTABLE_CPU_FREQ
/* Be sure to keep boosted state. */
if (!queue_empty(&button_queue))
return button_get(true);
-
+
button_boost(false);
#endif
-
+
queue_wait_w_tmo(&button_queue, &ev, ticks);
if (ev.id == SYS_TIMEOUT)
ev.id = BUTTON_NONE;
@@ -384,7 +384,7 @@ void button_init(void)
button_read();
lastbtn = button_read();
#endif
-
+
tick_add_task(button_tick);
reset_poweroff_timer();
@@ -395,7 +395,7 @@ void button_init(void)
filter_first_keypress = false;
#ifdef HAVE_REMOTE_LCD
remote_filter_first_keypress = false;
-#endif
+#endif
#endif
}
@@ -526,22 +526,44 @@ void button_clear_queue(void)
* data:
* [31] Use acceleration
* [30:24] Message post count (skipped + 1) (1-127)
- * [23:0] Velocity - clicks/uS - 0.24 fixed point
+ * [23:0] [23:0] Velocity - degree/sec
*
* 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
+ * Value in degree/sec -- configurable via settings -- above which
+ * the accelerated scrolling starts. Factor is internally scaled by
+ * 1<<16 in respect to the following 32bit integer operations.
*/
-int button_apply_acceleration(unsigned int data, unsigned int factor)
+ int button_apply_acceleration(const unsigned int data,
+ const unsigned int accel_start,
+ const unsigned int accel_type)
{
int delta = (data >> 24) & 0x7f;
if ((data & (1 << 31)) != 0)
{
+ /* factor = 2^16 / global_settings.wheel_accel_start */
+ unsigned int factor = (1<<16)/accel_start;
+
+ /* read driver's velocity from data */
unsigned int v = data & 0xffffff;
- v = factor * (unsigned long long)v*v / 0xffffffffffffull;
+ /* v = 28.4 fixed point */
+ v = (factor * v)>>(16-4);
+
+ /* Calculate real numbers item to scroll based upon acceleration
+ * setting, use correct roundoff */
+ switch (accel_type)
+ {
+ default:
+ v = (v*v + (1<< 7))>> 8;
+ break;
+ case 2:
+ v = (v*v*v + (1<<11))>>12;
+ break;
+ case 3:
+ v = (v*v*v*v + (1<<15))>>16;
+ break;
+ }
if (v > 1)
delta *= v;
diff --git a/firmware/export/button.h b/firmware/export/button.h
index a38385c..da02dcf 100644
--- a/firmware/export/button.h
+++ b/firmware/export/button.h
@@ -52,7 +52,9 @@ void wheel_send_events(bool send);
#endif
#ifdef HAVE_SCROLLWHEEL
-int button_apply_acceleration(unsigned int data, unsigned int factor);
+int button_apply_acceleration(const unsigned int data,
+ const unsigned int accel_start,
+ const unsigned int accel_type);
#endif
#define BUTTON_NONE 0x00000000
diff --git a/firmware/export/config-e200.h b/firmware/export/config-e200.h
index 5e9103b..a9eb132 100644
--- a/firmware/export/config-e200.h
+++ b/firmware/export/config-e200.h
@@ -97,9 +97,10 @@
/* 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)
+/* define from which rotation speed [degree/sec] on the acceleration starts */
+#define DEFAULT_WHEEL_ACCEL_START 540
+/* define type of acceleration (1 = ^2, 2 = ^3, 3 = ^4) */
+#define DEFAULT_WHEEL_ACCELERATION 1
/* define this if you have a flash memory storage */
#define HAVE_FLASH_STORAGE
diff --git a/firmware/export/config-ipod4g.h b/firmware/export/config-ipod4g.h
index 7d58992..c47effd 100644
--- a/firmware/export/config-ipod4g.h
+++ b/firmware/export/config-ipod4g.h
@@ -81,6 +81,13 @@
/* Define this for LCD backlight available */
#define HAVE_BACKLIGHT
+/* define this if the unit uses a scrollwheel for navigation */
+#define HAVE_SCROLLWHEEL
+/* define from which rotation speed [degree/sec] on the acceleration starts */
+#define DEFAULT_WHEEL_ACCEL_START 270
+/* define type of acceleration (1 = ^2, 2 = ^3, 3 = ^4) */
+#define DEFAULT_WHEEL_ACCELERATION 3
+
/* Define this if you can detect headphones */
#define HAVE_HEADPHONE_DETECTION
diff --git a/firmware/export/config-ipodcolor.h b/firmware/export/config-ipodcolor.h
index a585090..8a50268 100644
--- a/firmware/export/config-ipodcolor.h
+++ b/firmware/export/config-ipodcolor.h
@@ -70,6 +70,13 @@
/* Define this for LCD backlight available */
#define HAVE_BACKLIGHT
+/* define this if the unit uses a scrollwheel for navigation */
+#define HAVE_SCROLLWHEEL
+/* define from which rotation speed [degree/sec] on the acceleration starts */
+#define DEFAULT_WHEEL_ACCEL_START 270
+/* define type of acceleration (1 = ^2, 2 = ^3, 3 = ^4) */
+#define DEFAULT_WHEEL_ACCELERATION 3
+
/* Define this if you can detect headphones */
#define HAVE_HEADPHONE_DETECTION
diff --git a/firmware/export/config-ipodmini2g.h b/firmware/export/config-ipodmini2g.h
index 77299dd..cad1727 100644
--- a/firmware/export/config-ipodmini2g.h
+++ b/firmware/export/config-ipodmini2g.h
@@ -78,6 +78,13 @@
/* We can fade the backlight by using PWM */
#define HAVE_BACKLIGHT_PWM_FADING
+/* define this if the unit uses a scrollwheel for navigation */
+#define HAVE_SCROLLWHEEL
+/* define from which rotation speed [degree/sec] on the acceleration starts */
+#define DEFAULT_WHEEL_ACCEL_START 270
+/* define type of acceleration (1 = ^2, 2 = ^3, 3 = ^4) */
+#define DEFAULT_WHEEL_ACCELERATION 3
+
/* Define this if you can detect headphones */
#define HAVE_HEADPHONE_DETECTION
diff --git a/firmware/export/config-ipodnano.h b/firmware/export/config-ipodnano.h
index fcba445..c685251 100644
--- a/firmware/export/config-ipodnano.h
+++ b/firmware/export/config-ipodnano.h
@@ -73,6 +73,13 @@
/* We can fade the backlight by using PWM */
#define HAVE_BACKLIGHT_PWM_FADING
+/* define this if the unit uses a scrollwheel for navigation */
+#define HAVE_SCROLLWHEEL
+/* define from which rotation speed [degree/sec] on the acceleration starts */
+#define DEFAULT_WHEEL_ACCEL_START 270
+/* define type of acceleration (1 = ^2, 2 = ^3, 3 = ^4) */
+#define DEFAULT_WHEEL_ACCELERATION 3
+
/* Define this if you can detect headphones */
#define HAVE_HEADPHONE_DETECTION
diff --git a/firmware/export/config-ipodvideo.h b/firmware/export/config-ipodvideo.h
index 9ba4792..88fe899 100644
--- a/firmware/export/config-ipodvideo.h
+++ b/firmware/export/config-ipodvideo.h
@@ -73,6 +73,13 @@
/* We can fade the backlight by using PWM */
#define HAVE_BACKLIGHT_PWM_FADING
+/* define this if the unit uses a scrollwheel for navigation */
+#define HAVE_SCROLLWHEEL
+/* define from which rotation speed [degree/sec] on the acceleration starts */
+#define DEFAULT_WHEEL_ACCEL_START 270
+/* define type of acceleration (1 = ^2, 2 = ^3, 3 = ^4) */
+#define DEFAULT_WHEEL_ACCELERATION 3
+
/* Define this if you can detect headphones */
#define HAVE_HEADPHONE_DETECTION
diff --git a/firmware/target/arm/ipod/button-clickwheel.c b/firmware/target/arm/ipod/button-clickwheel.c
index 15f3cdd..38176a7 100644
--- a/firmware/target/arm/ipod/button-clickwheel.c
+++ b/firmware/target/arm/ipod/button-clickwheel.c
@@ -40,6 +40,30 @@
#include "system.h"
#include "powermgmt.h"
+#define WHEEL_FAST_OFF_TIMEOUT 250000 /* timeout for acceleration = 250ms */
+#define WHEEL_REPEAT_TIMEOUT 250000 /* timeout for button repeat = 250ms */
+#define WHEEL_UNTOUCH_TIMEOUT 150000 /* timeout for untouching wheel = 100ms */
+#define WHEELCLICKS_PER_ROTATION 96 /* wheelclicks per full rotation */
+
+/* This amount of clicks is needed for at least scrolling 1 item. Choose small values
+ * to have high sensitivity but few precision, choose large values to have less
+ * sensitivity and good precision. */
+#if defined(IPOD_NANO)
+#define WHEEL_SENSITIVITY 6 /* iPod nano has smaller wheel, lower sensitivity needed */
+#else
+#define WHEEL_SENSITIVITY 4 /* default sensitivity */
+#endif
+
+int old_wheel_value = -1;
+int new_wheel_value = 0;
+int repeat = 0;
+int wheel_delta = 0;
+bool wheel_is_touched = false;
+unsigned int accumulated_wheel_delta = 0;
+unsigned int wheel_repeat = 0;
+unsigned int wheel_velocity = 0;
+unsigned long last_wheel_usec = 0;
+
/* Variable to use for setting button status in interrupt handler */
int int_btn = BUTTON_NONE;
#ifdef HAVE_WHEEL_POSITION
@@ -82,20 +106,22 @@ static void opto_i2c_init(void)
static inline int ipod_4g_button_read(void)
{
int whl = -1;
-
+
/* The ipodlinux source had a udelay(250) here, but testing has shown that
it is not needed - tested on Nano, Color/Photo and Video. */
/* udelay(250);*/
int btn = BUTTON_NONE;
unsigned reg = 0x7000c104;
- if ((inl(0x7000c104) & 0x4000000) != 0) {
+ if ((inl(0x7000c104) & 0x4000000) != 0)
+ {
unsigned status = inl(0x7000c140);
reg = reg + 0x3C; /* 0x7000c140 */
outl(0x0, 0x7000c140); /* clear interrupt status? */
- if ((status & 0x800000ff) == 0x8000001a) {
+ if ((status & 0x800000ff) == 0x8000001a)
+ {
static int old_wheel_value IDATA_ATTR = -1;
static int wheel_repeat = 0;
@@ -109,63 +135,152 @@ static inline int ipod_4g_button_read(void)
btn |= BUTTON_PLAY;
if (status & 0x1000)
btn |= BUTTON_MENU;
- if (status & 0x40000000) {
- /* NB: highest wheel = 0x5F, clockwise increases */
- int new_wheel_value = (status << 9) >> 25;
+ if (status & 0x40000000)
+ {
+ unsigned long usec = USEC_TIMER;
+
+ /* Highest wheel = 0x5F, clockwise increases */
+ new_wheel_value = (status >> 16) & 0x7f;
whl = new_wheel_value;
+
+ /* switch on backlight (again), reset power-off timer */
backlight_on();
reset_poweroff_timer();
- /* The queue should have no other events when scrolling */
- if (queue_empty(&button_queue) && old_wheel_value >= 0) {
- /* This is for later = BUTTON_SCROLL_TOUCH;*/
- int wheel_delta = new_wheel_value - old_wheel_value;
- unsigned long data;
- int wheel_keycode;
-
- if (wheel_delta < -48)
- wheel_delta += 96; /* Forward wrapping case */
- else if (wheel_delta > 48)
- wheel_delta -= 96; /* Backward wrapping case */
+ /* Check whether the scrollwheel was untouched by accident or by will. */
+ /* This is needed because wheel may be untoched very shortly during rotation */
+ if ( (!wheel_is_touched) && TIME_AFTER(usec, last_wheel_usec + WHEEL_UNTOUCH_TIMEOUT) )
+ {
+ /* wheel has been really untouched -> reset internal variables */
+ old_wheel_value = -1;
+ wheel_velocity = 0;
+ accumulated_wheel_delta = 0;
+ wheel_repeat = BUTTON_NONE;
+ }
+ else
+ {
+ /* wheel was shortly untouched by accident -> leave internal variables */
+ wheel_is_touched = true;
+ }
- if (wheel_delta > 4) {
+ if (old_wheel_value >= 0)
+ {
+ /* This is for later = BUTTON_SCROLL_TOUCH;*/
+ wheel_delta = new_wheel_value - old_wheel_value;
+ unsigned int wheel_keycode = BUTTON_NONE;
+
+ /* Taking into account wrapping during transition from highest
+ * to lowest wheel position and back */
+ if (wheel_delta < -WHEELCLICKS_PER_ROTATION/2)
+ wheel_delta += WHEELCLICKS_PER_ROTATION; /* Forward wrapping case */
+ else if (wheel_delta > WHEELCLICKS_PER_ROTATION/2)
+ wheel_delta -= WHEELCLICKS_PER_ROTATION; /* Backward wrapping case */
+
+ /* Getting direction and wheel_keycode from wheel_delta.
+ * Need at least some clicks to be sure to avoid haptic fuzziness */
+ if (wheel_delta >= WHEEL_SENSITIVITY)
wheel_keycode = BUTTON_SCROLL_FWD;
- } else if (wheel_delta < -4) {
+ else if (wheel_delta <= -WHEEL_SENSITIVITY)
wheel_keycode = BUTTON_SCROLL_BACK;
- } else goto wheel_end;
+ else
+ wheel_keycode = BUTTON_NONE;
+
+ if (wheel_keycode != BUTTON_NONE)
+ {
+ long v = (usec - last_wheel_usec) & 0x7fffffff;
+
+ /* undo signedness */
+ wheel_delta = (wheel_delta>0) ? wheel_delta : -wheel_delta;
+
+ /* add the current wheel_delta */
+ accumulated_wheel_delta += wheel_delta;
+
+ v = v ? (1000000 * wheel_delta) / v : 0; /* clicks/sec = 1000000 * clicks/usec */
+ v = (v * 360) / WHEELCLICKS_PER_ROTATION; /* conversion to degree/sec */
+ v = (v<0) ? -v : v; /* undo signedness */
+
+ /* some velocity filtering to smooth things out */
+ wheel_velocity = (31 * wheel_velocity + v) / 32;
+ /* limit to 24 bit */
+ wheel_velocity = (wheel_velocity>0xffffff) ? 0xffffff : wheel_velocity;
+
+ /* assume REPEAT = off */
+ repeat = 0;
+
+ /* direction reversals must nullify acceleration and accumulator */
+ if (wheel_keycode != wheel_repeat)
+ {
+ wheel_repeat = wheel_keycode;
+ wheel_velocity = 0;
+ accumulated_wheel_delta = 0;
+ }
+ /* on same direction REPEAT is assumed when new click is within timeout */
+ else if (TIME_BEFORE(usec, last_wheel_usec + WHEEL_REPEAT_TIMEOUT))
+ {
+ repeat = BUTTON_REPEAT;
+ }
+ /* timeout nullifies acceleration and accumulator */
+ if (TIME_AFTER(usec, last_wheel_usec + WHEEL_FAST_OFF_TIMEOUT))
+ {
+ wheel_velocity = 0;
+ accumulated_wheel_delta = 0;
+ }
#ifdef HAVE_WHEEL_POSITION
- if (send_events)
+ if (send_events)
#endif
- {
- data = (wheel_delta << 16) | new_wheel_value;
- queue_post(&button_queue, wheel_keycode | wheel_repeat,
- data);
+ /* The queue should have no other events when scrolling */
+ if (queue_empty(&button_queue))
+ {
+ /* each WHEEL_SENSITIVITY clicks = scrolling 1 item */
+ accumulated_wheel_delta /= WHEEL_SENSITIVITY;
+#ifdef HAVE_SCROLLWHEEL
+ /* use data-format for HAVE_SCROLLWHEEL */
+ /* always use acceleration mode (1<<31) */
+ /* always set message post count to (1<<24) for iPod */
+ /* this way the scrolling is always calculated from wheel_velocity */
+ queue_post(&button_queue, wheel_keycode | repeat,
+ (1<<31) | (1 << 24) | wheel_velocity);
+
+#else
+ queue_post(&button_queue, wheel_keycode | repeat,
+ (accumulated_wheel_delta << 16) | new_wheel_value);
+#endif
+ accumulated_wheel_delta = 0;
+ }
+ last_wheel_usec = usec;
+ old_wheel_value = new_wheel_value;
}
-
- if (!wheel_repeat) wheel_repeat = BUTTON_REPEAT;
}
-
- old_wheel_value = new_wheel_value;
- } else if (old_wheel_value >= 0) {
- /* scroll wheel up */
- old_wheel_value = -1;
- wheel_repeat = 0;
+ else
+ {
+ /* scrollwheel was touched for the first time after finger lifting */
+ old_wheel_value = new_wheel_value;
+ wheel_is_touched = true;
+ }
+ }
+ else
+ {
+ /* In this case the finger was lifted from the scrollwheel. */
+ wheel_is_touched = false;
}
- } else if (status == 0xffffffff) {
+ }
+ else if (status == 0xffffffff)
+ {
opto_i2c_init();
}
}
-wheel_end:
-
- if ((inl(reg) & 0x8000000) != 0) {
+ if ((inl(reg) & 0x8000000) != 0)
+ {
outl(0xffffffff, 0x7000c120);
outl(0xffffffff, 0x7000c124);
}
/* Save the new absolute wheel position */
+#ifdef HAVE_WHEEL_POSITION
wheel_position = whl;
+#endif
return btn;
}
@@ -174,7 +289,7 @@ int wheel_status(void)
{
return wheel_position;
}
-
+
void wheel_send_events(bool send)
{
send_events = send;
@@ -184,10 +299,10 @@ void wheel_send_events(bool send)
void ipod_4g_button_int(void)
{
CPU_HI_INT_CLR = I2C_MASK;
- /* The following delay was 250 in the ipodlinux source, but 50 seems to
+ /* The following delay was 250 in the ipodlinux source, but 50 seems to
work fine - tested on Nano, Color/Photo and Video. */
- udelay(50);
- outl(0x0, 0x7000c140);
+ udelay(50);
+ outl(0x0, 0x7000c140);
int_btn = ipod_4g_button_read();
outl(inl(0x7000c104) | 0xC000000, 0x7000c104);
outl(0x400a1f00, 0x7000c100);
@@ -202,7 +317,7 @@ void button_init_device(void)
opto_i2c_init();
/* hold button - enable as input */
GPIOA_ENABLE |= 0x20;
- GPIOA_OUTPUT_EN &= ~0x20;
+ GPIOA_OUTPUT_EN &= ~0x20;
/* hold button - set interrupt levels */
GPIOA_INT_LEV = ~(GPIOA_INPUT_VAL & 0x20);
GPIOA_INT_CLR = GPIOA_INT_STAT & 0x20;
diff --git a/firmware/target/arm/sandisk/sansa-e200/button-e200.c b/firmware/target/arm/sandisk/sansa-e200/button-e200.c
index 5988e16..a74d860 100644
--- a/firmware/target/arm/sandisk/sansa-e200/button-e200.c
+++ b/firmware/target/arm/sandisk/sansa-e200/button-e200.c
@@ -27,6 +27,7 @@
#define WHEEL_REPEAT_INTERVAL 300000
#define WHEEL_FAST_ON_INTERVAL 20000
#define WHEEL_FAST_OFF_INTERVAL 60000
+#define WHEELCLICKS_PER_ROTATION 48 /* wheelclicks per full rotation */
/* Clickwheel */
#ifndef BOOTLOADER
@@ -137,10 +138,8 @@ void clickwheel_int(void)
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;
+ v = (v>0) ? 1000000 / v : 0; /* clicks/sec = 1000000 * clicks/usec */
+ v = (v>0xffffff) ? 0xffffff : v; /* limit to 24 bit */
/* some velocity filtering to smooth things out */
wheel_velocity = (7*wheel_velocity + v) / 8;
@@ -173,12 +172,12 @@ void clickwheel_int(void)
else
{
/* fast ON gets filtered to avoid inadvertent jumps to fast mode */
- if (repeat && wheel_velocity > 0xffffff/WHEEL_FAST_ON_INTERVAL)
+ if (repeat && wheel_velocity > 1000000/WHEEL_FAST_ON_INTERVAL)
{
/* moving into fast mode */
wheel_fast_mode = 1 << 31;
wheel_click_count = 0;
- wheel_velocity = 0xffffff/WHEEL_FAST_OFF_INTERVAL;
+ wheel_velocity = 1000000/WHEEL_FAST_OFF_INTERVAL;
}
else if (++wheel_click_count < 2)
{
@@ -190,7 +189,7 @@ void clickwheel_int(void)
}
if (TIME_AFTER(current_tick, next_backlight_on) ||
- v <= 0xffffff/(1000000/4))
+ v <= 4)
{
/* poke backlight to turn it on or maintain it no more often
than every 1/4 second*/
@@ -214,7 +213,7 @@ void clickwheel_int(void)
if (queue_empty(&button_queue))
{
queue_post(&button_queue, btn, wheel_fast_mode |
- (wheel_delta << 24) | wheel_velocity);
+ (wheel_delta << 24) | wheel_velocity*360/WHEELCLICKS_PER_ROTATION);
/* message posted - reset delta */
wheel_delta = 1;
}