Index: firmware/export/config-h10.h =================================================================== --- firmware/export/config-h10.h (revision 16083) +++ firmware/export/config-h10.h (working copy) @@ -95,6 +95,10 @@ /* Define this for LCD backlight available */ #define HAVE_BACKLIGHT +/* Define this to make the sliderbar on the front do more than a simple up/down + * button above/below the middle of it */ +#define HAVE_TOUCHPAD + #define AB_REPEAT_ENABLE 1 #define BATTERY_CAPACITY_DEFAULT 1550 /* default battery capacity */ Index: firmware/export/config-h10_5gb.h =================================================================== --- firmware/export/config-h10_5gb.h (revision 16083) +++ firmware/export/config-h10_5gb.h (working copy) @@ -72,6 +72,10 @@ /* WM8731 has no tone controls, so we use the software ones */ #define HAVE_SW_TONE_CONTROLS +/* Define this to make the sliderbar on the front do more than a simple up/down + * button above/below the middle of it */ +#define HAVE_TOUCHPAD + #define AB_REPEAT_ENABLE 1 /* FM Tuner */ Index: firmware/target/arm/iriver/h10/button-h10.c =================================================================== --- firmware/target/arm/iriver/h10/button-h10.c (revision 16083) +++ firmware/target/arm/iriver/h10/button-h10.c (working copy) @@ -35,10 +35,10 @@ { /* Enable REW, FF, Play, Left, Right, Hold buttons */ GPIO_SET_BITWISE(GPIOA_ENABLE, 0xfc); - + /* Enable POWER button */ GPIO_SET_BITWISE(GPIOB_ENABLE, 0x01); - + /* We need to output to pin 6 of GPIOD when reading the scroll pad value */ GPIO_SET_BITWISE(GPIOD_ENABLE, 0x40); GPIO_SET_BITWISE(GPIOD_OUTPUT_EN, 0x40); @@ -67,7 +67,38 @@ static bool remote_hold_button = false; bool hold_button_old; bool remote_hold_button_old; + bool touched = false; +#ifdef HAVE_TOUCHPAD + /* + * the position on the slider when it was first pressed or the value of + * the slider when we last returned a DOWN/UP button pressed state + */ + static int latched_slider_pos = -1; + + /* + * the number of times this function has been called with the user's + * finger resting on the slider in one position + */ + static int call_count_while_touching = 0; + static bool have_slided = false; + + /* + * the amount that the slider value has to change before returning another + * down/up pressed state + */ + #define SLIDER_PAD_INITIAL_MOVE_THRESHOLD 0x100 + static int slide_down_treshold = SLIDER_PAD_INITIAL_MOVE_THRESHOLD; + static int slide_up_treshold = SLIDER_PAD_INITIAL_MOVE_THRESHOLD; + + /* values on the scroll pad below this are considered the "down" button */ + #define DOWN_BUTTON_ZONE (0x14A+0x20) /* the lower 30% of the slider */ + + /* values on the scroll pad above this are considered the "up" button */ + #define UP_BUTTON_ZONE 0x2B6 /* the upper 30% of the slider */ + +#endif + /* Hold */ hold_button_old = hold_button; hold_button = button_hold(); @@ -90,10 +121,10 @@ if ((state & 0x20) == 0) btn |= BUTTON_REW; if ((state & 0x40) == 0) btn |= BUTTON_RIGHT; if ((state & 0x80) == 0) btn |= BUTTON_LEFT; - + /* Read power button */ if (GPIOB_INPUT_VAL & 0x1) btn |= BUTTON_POWER; - + /* Read scroller */ if ( GPIOD_INPUT_VAL & 0x20 ) { @@ -101,16 +132,141 @@ udelay(250); data = adc_scan(ADC_SCROLLPAD); GPIO_SET_BITWISE(GPIOD_OUTPUT_VAL, 0x40); - + if(data > 0x20) + touched = true; + } + + if(touched) + { +#ifdef HAVE_TOUCHPAD + /* + * New slider bar functionality + * + * Note: since this function is called simply to get the current + * state of the buttons it is called very frequently. If we want + * to simulate the user pressing up/down very rapidly, then this + * function has to return a button-released state followed by a + * button-pressed state to fool the caller into thinking that the + * user is just pressing the up/down button repeatedly. If we + * don't return the button-release state between button-press + * states, then the auto-repeat logic in the calling code kicks + * in which is not what we want. + * + * $data is is the position of the user's finger on the scroll pad + * its range returned by the hardware is 0x20 to 0x400 (32 to 1024) + */ + + /* + * the user just placed their finger on the slider since releasing + * it (or for the first time) + */ + if(latched_slider_pos == -1) + latched_slider_pos = data; + + /* + * The logic below handles that the user must initially move + * SLIDER_PAD_INITIAL_MOVE_THRESHOLD units up/down before the + * button pressed state is returned. After that only a 1/6th + * of the units is required, but the full number of units is still + * required to start moving in the other direction. + * + * The reason for this is that we need a large area for their thumb + * to wiggle around on before moving anything, but after they get + * going, we scroll in the direction they're moving. + * + * And if the the user rests their finger in the upper or lower + * zones of the slider for a while, the it will return a button + * down state to activate the auto-repeat for either + * up or down respective to which zone their finger is resting in + */ + + if((latched_slider_pos-data) > slide_down_treshold) + { + btn |= BUTTON_SCROLL_DOWN; + latched_slider_pos = data; + call_count_while_touching = 0; + have_slided = true; + + /* require half the change for subsequent moves */ + if(slide_down_treshold == SLIDER_PAD_INITIAL_MOVE_THRESHOLD) + slide_down_treshold /= 10; + slide_up_treshold = SLIDER_PAD_INITIAL_MOVE_THRESHOLD; + } + else if((data-latched_slider_pos) > slide_up_treshold) + { + btn |= BUTTON_SCROLL_UP; + latched_slider_pos = data; + call_count_while_touching = 0; + have_slided = true; + + /* require half the change for subsequent moves */ + if(slide_up_treshold == SLIDER_PAD_INITIAL_MOVE_THRESHOLD) + slide_up_treshold /= 10; + slide_down_treshold = SLIDER_PAD_INITIAL_MOVE_THRESHOLD; + } + else + { + slide_up_treshold = SLIDER_PAD_INITIAL_MOVE_THRESHOLD; + slide_down_treshold = SLIDER_PAD_INITIAL_MOVE_THRESHOLD; + call_count_while_touching++; + + /* + * the user is leaving their finger pressed on the slider + * so return a up or down button pressed state so that the + * auto-repeat logic will kick in in the calling code. + */ + if(call_count_while_touching>70) + { + if(dataUP_BUTTON_ZONE) + btn |= BUTTON_SCROLL_UP; + } + } +#else + /* original simple implementation of sliderpad (up/down buttons) */ if(data < 0x224) { btn |= BUTTON_SCROLL_DOWN; } else { btn |= BUTTON_SCROLL_UP; } +#endif } + else + { /* the user's finger is not on the scrollpad */ +#ifdef HAVE_TOUCHPAD + /* + * if the user didn't slide their finger since placing it on the + * slider, then generate a button up/down pressed event if the + * slider was pressed within the top or bottom 30% + */ + if(!have_slided && latched_slider_pos>0) + { + if(latched_slider_posUP_BUTTON_ZONE) + btn |= BUTTON_SCROLL_UP; + #if 0 /* might be cool to tap middle for select + .. perhaps use middle 20% instead */ + else /* middle */ + btn |= BUTTON_RIGHT; /* user tapped middle */ + #endif + } + + /* + * reset intermediate state values to when the scroll pad is no + * longer being touched + */ + latched_slider_pos = -1; + call_count_while_touching = 0; + have_slided = false; + slide_down_treshold = SLIDER_PAD_INITIAL_MOVE_THRESHOLD; + slide_up_treshold = SLIDER_PAD_INITIAL_MOVE_THRESHOLD; +#endif + } } - + /* remote buttons */ remote_hold_button_old = remote_hold_button; @@ -142,6 +298,6 @@ /* remote play button should be dead if hold */ if (!remote_hold_button && !(GPIOA_INPUT_VAL & 0x1)) btn |= BUTTON_RC_PLAY; - + return btn; }