Xduoo X3 Add tree scrolling FS#13240, Emulate Multibutton presses

Fixes deficiencies with the button system on the X3

  The x3 has an interesting button layout.
  Multiple key presses are NOT supported unless
  [BUTTON_POWER] is one of the combined keys

  As you can imagine this causes problems as the power button takes
  precedence in the button system and initiates a shutdown if the
  key is held too long
  instead of BUTTON_POWER use BUTTON_PWRALT in combination with other keys
  IF using as a prerequsite button then BUTTON_POWER should be used

  Multiple buttons are emulated by button_read_device but there are a few
  caveats to be aware of:

  Button Order Matters!
   different keys have different priorities, higher priority keys 'overide'
   the lower priority keys
  VOLUP[7] VOLDN[6] PREV[5] NEXT[4] PLAY[3] OPTION[2] HOME[1]

  There will be no true release or repeat events, the user can let off the
   button pressed initially and it will still continue to appear to be
   pressed as long as the second key is held

Tree scrolling is PLAY+NEXT or PLAY+PREV

Change-Id: I88dfee1c70a6a99659e8227f5becacc50cc43910
This commit is contained in:
William Wilgus 2020-09-12 05:03:12 -04:00 committed by William Wilgus
parent 6b674a6a0a
commit c62493e98a
14 changed files with 101 additions and 34 deletions

View file

@ -21,6 +21,29 @@
/* Button Code Definitions for xDuoo X3 target */ /* Button Code Definitions for xDuoo X3 target */
/* NOTE X3 Button system
* The x3 has an interesting button layout. Multiple key presses are
* NOT supported unless [BUTTON_POWER] is one of the combined keys
* as you can imagine this causes problems as the power button takes
* precedence in the button system and initiates a shutdown if the
* key is held too long
* instead of BUTTON_POWER use BUTTON_PWRALT in combination with other keys
* IF using as a prerequsite button then BUTTON_POWER should be used
*
* Multiple buttons are emulated by button_read_device but there are a few
* caveats to be aware of:
*
* Button Order Matters!
* different keys have different priorities, higher priority keys 'overide' the
* lower priority keys
* VOLUP[7] VOLDN[6] PREV[5] NEXT[4] PLAY[3] OPTION[2] HOME[1]
*
* There will be no true release or repeat events, the user can let off the button
* pressed initially and it will still continue to appear to be pressed as long as
* the second key is held
* */
#include "config.h" #include "config.h"
#include "action.h" #include "action.h"
#include "button.h" #include "button.h"
@ -67,9 +90,9 @@ static const struct button_mapping button_context_wps[] = {
{ ACTION_WPS_QUICKSCREEN, BUTTON_OPTION|BUTTON_REPEAT, BUTTON_OPTION }, { ACTION_WPS_QUICKSCREEN, BUTTON_OPTION|BUTTON_REPEAT, BUTTON_OPTION },
{ ACTION_WPS_HOTKEY, BUTTON_HOME|BUTTON_REPEAT, BUTTON_HOME }, { ACTION_WPS_HOTKEY, BUTTON_HOME|BUTTON_REPEAT, BUTTON_HOME },
{ ACTION_WPS_ABSETB_NEXTDIR, BUTTON_POWER|BUTTON_NEXT, BUTTON_POWER }, { ACTION_WPS_ABSETB_NEXTDIR, BUTTON_PWRALT|BUTTON_NEXT, BUTTON_POWER },
{ ACTION_WPS_ABSETA_PREVDIR, BUTTON_POWER|BUTTON_PREV, BUTTON_POWER }, { ACTION_WPS_ABSETA_PREVDIR, BUTTON_PWRALT|BUTTON_PREV, BUTTON_POWER },
{ ACTION_WPS_ABRESET, BUTTON_POWER|BUTTON_PLAY, BUTTON_POWER }, { ACTION_WPS_ABRESET, BUTTON_PWRALT|BUTTON_PLAY, BUTTON_POWER },
LAST_ITEM_IN_LIST LAST_ITEM_IN_LIST
}; /* button_context_wps */ }; /* button_context_wps */
@ -173,11 +196,21 @@ static const struct button_mapping button_context_settings_vol_is_inc[] = {
static const struct button_mapping button_context_tree[] = { static const struct button_mapping button_context_tree[] = {
{ ACTION_TREE_WPS, BUTTON_POWER|BUTTON_REL, BUTTON_POWER }, { ACTION_TREE_WPS, BUTTON_POWER|BUTTON_REL, BUTTON_POWER },
{ ACTION_TREE_STOP, BUTTON_POWER|BUTTON_REPEAT, BUTTON_POWER }, { ACTION_TREE_STOP, BUTTON_POWER|BUTTON_REPEAT, BUTTON_POWER },
{ ACTION_TREE_HOTKEY, BUTTON_HOME|BUTTON_REPEAT, BUTTON_HOME }, { ACTION_TREE_HOTKEY, BUTTON_HOME|BUTTON_REPEAT, BUTTON_HOME},
LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_LIST) LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_LIST)
}; /* button_context_tree */ }; /* button_context_tree */
static const struct button_mapping button_context_listtree_scroll_with_combo[] = {
{ ACTION_NONE, BUTTON_POWER, BUTTON_NONE },
{ ACTION_TREE_PGLEFT, BUTTON_PLAY|BUTTON_PREV, BUTTON_NONE },
{ ACTION_TREE_PGLEFT, BUTTON_PLAY|BUTTON_PREV|BUTTON_REPEAT, BUTTON_NONE },
{ ACTION_TREE_PGRIGHT, BUTTON_PLAY|BUTTON_NEXT, BUTTON_NONE },
{ ACTION_TREE_PGRIGHT, BUTTON_PLAY|BUTTON_NEXT|BUTTON_REPEAT, BUTTON_NONE },
LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_CUSTOM|CONTEXT_TREE),
}; /* button_context_listtree_scroll_with_combo */
/** Yes/No Screen **/ /** Yes/No Screen **/
static const struct button_mapping button_context_yesnoscreen[] = { static const struct button_mapping button_context_yesnoscreen[] = {
{ ACTION_YESNO_ACCEPT, BUTTON_PLAY, BUTTON_NONE }, { ACTION_YESNO_ACCEPT, BUTTON_PLAY, BUTTON_NONE },
@ -256,8 +289,11 @@ const struct button_mapping* get_context_mapping(int context)
case CONTEXT_SETTINGS_RECTRIGGER: case CONTEXT_SETTINGS_RECTRIGGER:
return button_context_settings_vol_is_inc; return button_context_settings_vol_is_inc;
case CONTEXT_TREE: case CONTEXT_TREE:
return button_context_listtree_scroll_with_combo;
case CONTEXT_MAINMENU: case CONTEXT_MAINMENU:
return button_context_tree; return button_context_tree;
case CONTEXT_CUSTOM|CONTEXT_TREE:
return button_context_tree;
case CONTEXT_WPS: case CONTEXT_WPS:
return button_context_wps; return button_context_wps;
case CONTEXT_YESNOSCREEN: case CONTEXT_YESNOSCREEN:

View file

@ -561,7 +561,7 @@ void I_ShutdownGraphics(void)
#define DOOMBUTTON_LEFT BUTTON_PREV #define DOOMBUTTON_LEFT BUTTON_PREV
#define DOOMBUTTON_RIGHT BUTTON_NEXT #define DOOMBUTTON_RIGHT BUTTON_NEXT
#define DOOMBUTTON_SHOOT BUTTON_PLAY #define DOOMBUTTON_SHOOT BUTTON_PLAY
#define DOOMBUTTON_OPEN (BUTTON_HOME | BUTTON_POWER) #define DOOMBUTTON_OPEN (BUTTON_HOME | BUTTON_PWRALT)
#define DOOMBUTTON_ESC BUTTON_POWER #define DOOMBUTTON_ESC BUTTON_POWER
#define DOOMBUTTON_ENTER BUTTON_PLAY #define DOOMBUTTON_ENTER BUTTON_PLAY
#define DOOMBUTTON_WEAPON BUTTON_VOL_UP #define DOOMBUTTON_WEAPON BUTTON_VOL_UP

View file

@ -330,7 +330,7 @@ GREY_INFO_STRUCT
# define FFT_NEXT_GRAPH BUTTON_NEXT # define FFT_NEXT_GRAPH BUTTON_NEXT
# define FFT_ORIENTATION BUTTON_HOME # define FFT_ORIENTATION BUTTON_HOME
# define FFT_FREQ_SCALE BUTTON_OPTION # define FFT_FREQ_SCALE BUTTON_OPTION
# define FFT_WINDOW (BUTTON_HOME|BUTTON_POWER) # define FFT_WINDOW (BUTTON_HOME|BUTTON_PWRALT)
# define FFT_AMP_SCALE BUTTON_PLAY # define FFT_AMP_SCALE BUTTON_PLAY
# define FFT_QUIT BUTTON_POWER # define FFT_QUIT BUTTON_POWER

View file

@ -441,7 +441,7 @@
#define GBN_BUTTON_MENU BUTTON_POWER #define GBN_BUTTON_MENU BUTTON_POWER
#define GBN_BUTTON_PLAY BUTTON_PLAY | BUTTON_REL #define GBN_BUTTON_PLAY BUTTON_PLAY | BUTTON_REL
#define GBN_BUTTON_CONTEXT BUTTON_PLAY | BUTTON_REPEAT #define GBN_BUTTON_CONTEXT BUTTON_PLAY | BUTTON_REPEAT
#define GBN_BUTTON_NEXT_VAR BUTTON_HOME | BUTTON_POWER #define GBN_BUTTON_NEXT_VAR BUTTON_HOME | BUTTON_PWRALT
#elif (CONFIG_KEYPAD == XDUOO_X3II_PAD) #elif (CONFIG_KEYPAD == XDUOO_X3II_PAD)
#define GBN_BUTTON_UP BUTTON_HOME #define GBN_BUTTON_UP BUTTON_HOME

View file

@ -474,7 +474,7 @@
#define IMGVIEW_PREVIOUS BUTTON_VOL_DOWN #define IMGVIEW_PREVIOUS BUTTON_VOL_DOWN
#define IMGVIEW_PREVIOUS_REPEAT (BUTTON_VOL_DOWN|BUTTON_REPEAT) #define IMGVIEW_PREVIOUS_REPEAT (BUTTON_VOL_DOWN|BUTTON_REPEAT)
#define IMGVIEW_MENU BUTTON_POWER #define IMGVIEW_MENU BUTTON_POWER
#define IMGVIEW_SLIDE_SHOW (BUTTON_HOME|BUTTON_POWER) #define IMGVIEW_SLIDE_SHOW (BUTTON_HOME|BUTTON_PWRALT)
#elif CONFIG_KEYPAD == XDUOO_X3II_PAD #elif CONFIG_KEYPAD == XDUOO_X3II_PAD
#define IMGVIEW_ZOOM_PRE BUTTON_PLAY #define IMGVIEW_ZOOM_PRE BUTTON_PLAY

View file

@ -612,7 +612,7 @@ CONFIG_KEYPAD == MROBE500_PAD
#elif CONFIG_KEYPAD == XDUOO_X3_PAD #elif CONFIG_KEYPAD == XDUOO_X3_PAD
#define PEGBOX_SELECT BUTTON_PLAY #define PEGBOX_SELECT BUTTON_PLAY
#define PEGBOX_QUIT BUTTON_POWER #define PEGBOX_QUIT BUTTON_POWER
#define PEGBOX_RESTART (BUTTON_POWER | BUTTON_HOME) #define PEGBOX_RESTART (BUTTON_PWRALT | BUTTON_HOME)
#define PEGBOX_LVL_UP BUTTON_VOL_UP #define PEGBOX_LVL_UP BUTTON_VOL_UP
#define PEGBOX_LVL_DOWN BUTTON_VOL_DOWN #define PEGBOX_LVL_DOWN BUTTON_VOL_DOWN
#define PEGBOX_UP BUTTON_HOME #define PEGBOX_UP BUTTON_HOME

View file

@ -330,7 +330,7 @@
#elif CONFIG_KEYPAD == XDUOO_X3_PAD #elif CONFIG_KEYPAD == XDUOO_X3_PAD
#define ROCKPAINT_QUIT BUTTON_POWER #define ROCKPAINT_QUIT BUTTON_POWER
#define ROCKPAINT_DRAW BUTTON_PLAY #define ROCKPAINT_DRAW BUTTON_PLAY
#define ROCKPAINT_MENU (BUTTON_HOME | BUTTON_POWER) #define ROCKPAINT_MENU (BUTTON_HOME | BUTTON_PWRALT)
#define ROCKPAINT_TOOLBAR BUTTON_VOL_UP #define ROCKPAINT_TOOLBAR BUTTON_VOL_UP
#define ROCKPAINT_TOOLBAR2 BUTTON_VOL_DOWN #define ROCKPAINT_TOOLBAR2 BUTTON_VOL_DOWN
#define ROCKPAINT_UP BUTTON_HOME #define ROCKPAINT_UP BUTTON_HOME

View file

@ -309,7 +309,7 @@ CONFIG_KEYPAD == MROBE500_PAD
#define PUZZLE_RIGHT BUTTON_NEXT #define PUZZLE_RIGHT BUTTON_NEXT
#define PUZZLE_UP BUTTON_HOME #define PUZZLE_UP BUTTON_HOME
#define PUZZLE_DOWN BUTTON_OPTION #define PUZZLE_DOWN BUTTON_OPTION
#define PUZZLE_SHUFFLE (BUTTON_HOME | BUTTON_POWER) #define PUZZLE_SHUFFLE (BUTTON_HOME | BUTTON_PWRALT)
#define PUZZLE_PICTURE BUTTON_PLAY #define PUZZLE_PICTURE BUTTON_PLAY
#elif (CONFIG_KEYPAD == XDUOO_X3II_PAD) #elif (CONFIG_KEYPAD == XDUOO_X3II_PAD)

View file

@ -623,7 +623,7 @@
#define SOKOBAN_MENU BUTTON_POWER #define SOKOBAN_MENU BUTTON_POWER
#define SOKOBAN_UNDO_PRE BUTTON_PLAY #define SOKOBAN_UNDO_PRE BUTTON_PLAY
#define SOKOBAN_UNDO (BUTTON_PLAY | BUTTON_REL) #define SOKOBAN_UNDO (BUTTON_PLAY | BUTTON_REL)
#define SOKOBAN_REDO (BUTTON_POWER | BUTTON_PLAY) #define SOKOBAN_REDO (BUTTON_PWRALT | BUTTON_PLAY)
#define SOKOBAN_LEVEL_DOWN BUTTON_VOL_DOWN #define SOKOBAN_LEVEL_DOWN BUTTON_VOL_DOWN
#define SOKOBAN_LEVEL_REPEAT (BUTTON_PLAY | BUTTON_NEXT) #define SOKOBAN_LEVEL_REPEAT (BUTTON_PLAY | BUTTON_NEXT)
#define SOKOBAN_LEVEL_UP BUTTON_VOL_UP #define SOKOBAN_LEVEL_UP BUTTON_VOL_UP

View file

@ -402,7 +402,7 @@
#define SUDOKU_BUTTON_ALTTOGGLE BUTTON_PLAY #define SUDOKU_BUTTON_ALTTOGGLE BUTTON_PLAY
#define SUDOKU_BUTTON_MENU_PRE BUTTON_POWER #define SUDOKU_BUTTON_MENU_PRE BUTTON_POWER
#define SUDOKU_BUTTON_MENU (BUTTON_POWER | BUTTON_REL) #define SUDOKU_BUTTON_MENU (BUTTON_POWER | BUTTON_REL)
#define SUDOKU_BUTTON_POSSIBLE (BUTTON_HOME | BUTTON_POWER) #define SUDOKU_BUTTON_POSSIBLE (BUTTON_HOME | BUTTON_PWRALT)
#elif CONFIG_KEYPAD == XDUOO_X3II_PAD #elif CONFIG_KEYPAD == XDUOO_X3II_PAD
#define SUDOKU_BUTTON_QUIT_PRE BUTTON_POWER #define SUDOKU_BUTTON_QUIT_PRE BUTTON_POWER

View file

@ -504,7 +504,7 @@
#define TV_SCREEN_LEFT BUTTON_PREV #define TV_SCREEN_LEFT BUTTON_PREV
#define TV_SCREEN_RIGHT BUTTON_NEXT #define TV_SCREEN_RIGHT BUTTON_NEXT
#define TV_MENU BUTTON_PLAY #define TV_MENU BUTTON_PLAY
#define TV_AUTOSCROLL (BUTTON_POWER | BUTTON_HOME) #define TV_AUTOSCROLL (BUTTON_PWRALT | BUTTON_HOME)
#define TV_LINE_UP BUTTON_HOME #define TV_LINE_UP BUTTON_HOME
#define TV_LINE_DOWN BUTTON_OPTION #define TV_LINE_DOWN BUTTON_OPTION
#define TV_BOOKMARK (BUTTON_OPTION | BUTTON_PLAY) #define TV_BOOKMARK (BUTTON_OPTION | BUTTON_PLAY)

View file

@ -360,7 +360,7 @@ CONFIG_KEYPAD == MROBE500_PAD
#define BTN_DIR_RIGHT BUTTON_NEXT #define BTN_DIR_RIGHT BUTTON_NEXT
#define BTN_STARTPAUSE BUTTON_PLAY #define BTN_STARTPAUSE BUTTON_PLAY
#define BTN_QUIT BUTTON_POWER #define BTN_QUIT BUTTON_POWER
#define BTN_STOPRESET (BUTTON_HOME | BUTTON_POWER) #define BTN_STOPRESET (BUTTON_HOME | BUTTON_PWRALT)
#elif CONFIG_KEYPAD == XDUOO_X3II_PAD #elif CONFIG_KEYPAD == XDUOO_X3II_PAD
#define BTN_DIR_UP BUTTON_HOME #define BTN_DIR_UP BUTTON_HOME

View file

@ -32,7 +32,7 @@
#define BUTTON_PLAY 0x00000020 #define BUTTON_PLAY 0x00000020
#define BUTTON_VOL_UP 0x00000040 #define BUTTON_VOL_UP 0x00000040
#define BUTTON_VOL_DOWN 0x00000080 #define BUTTON_VOL_DOWN 0x00000080
#define BUTTON_PWRALT 0x00000100 /* BUTTON_POWER combo with other buttons */
#define BUTTON_LEFT 0 #define BUTTON_LEFT 0
#define BUTTON_RIGHT 0 #define BUTTON_RIGHT 0

View file

@ -56,6 +56,8 @@
#define ADC_MASK 0x0FFF #define ADC_MASK 0x0FFF
static volatile unsigned short bat_val, key_val; static volatile unsigned short bat_val, key_val;
static volatile int btn_last = BUTTON_NONE;
static volatile long btn_last_tick;
bool headphones_inserted(void) bool headphones_inserted(void)
{ {
@ -108,52 +110,82 @@ bool button_hold(void)
} }
/* NOTE: Due to how this is wired, button combinations are not allowed /* NOTE: Due to how this is wired, button combinations are not allowed
unless one of the two buttons is the POWER * unless one of the two buttons is the POWER
*/ *
* Note --Update 2020
* by toggling BOP common I was able to remove BACK, OPTION, PLAY from the
* loop selectively and test which keys were pressed but this took two adc rounds
* and proved to be minimally useful for the added overhead
*
* NOW multiple button presses are emulated but button priority needs to be taken
* into consideration; higher priority keys 'overide' the lower priority keys
* VOLUP[7] VOLDN[6] PREV[5] NEXT[4] PLAY[3] OPTION[2] HOME[1]
*/
int button_read_device(void) int button_read_device(void)
{ {
unsigned short key;
int btn = BUTTON_NONE; int btn = BUTTON_NONE;
unsigned short key = (key_val & ADC_MASK); int btn_pwr = BUTTON_NONE;
if (button_hold()) if (button_hold())
return BUTTON_NONE; return BUTTON_NONE;
if (KEY_IS_DOWN(PIN_BTN_POWER)) if (KEY_IS_DOWN(PIN_BTN_POWER))
btn |= BUTTON_POWER; btn_pwr = BUTTON_POWER;
if (!KEY_IS_DOWN(PIN_KEY_INT)) if (!KEY_IS_DOWN(PIN_KEY_INT))
return btn; {
__intc_mask_irq(IRQ_SADC);
REG_SADC_ADENA &= ~ADENA_AUXEN;
return btn_pwr;
}
key = (key_val & ADC_MASK);
/* Don't initiate a new request if we have one pending */
if(!(REG_SADC_ADENA & (ADENA_AUXEN)))
{
REG_SADC_ADENA |= ADENA_AUXEN;
}
if (key < 261) if (key < 261)
btn |= BUTTON_VOL_UP; btn = BUTTON_VOL_UP;
else else
if (key < 653) if (key < 653)
btn |= BUTTON_VOL_DOWN; btn = BUTTON_VOL_DOWN;
else else
if (key < 1101) if (key < 1101)
btn |= BUTTON_PREV; btn = BUTTON_PREV;
else else
if (key < 1498) if (key < 1498)
btn |= BUTTON_NEXT; btn = BUTTON_NEXT;
else else
if (key < 1839) if (key < 1839)
btn |= BUTTON_PLAY; btn = BUTTON_PLAY;
else else
if (key < 2213) if (key < 2213)
btn |= BUTTON_OPTION; btn = BUTTON_OPTION;
else else
if (key < 2600) if (key < 2600)
btn |= BUTTON_HOME; btn = BUTTON_HOME;
return btn; if (btn_last == BUTTON_NONE && TIME_AFTER(current_tick, btn_last_tick + HZ/20))
btn_last = btn;
if (btn_pwr != BUTTON_NONE)
btn |= BUTTON_PWRALT;
return btn | btn_last;
} }
/* called on button press interrupt */ /* called on button press interrupt */
void KEY_INT_IRQ(void) void KEY_INT_IRQ(void)
{ {
/* Don't initiate a new request if we have one pending */ btn_last = BUTTON_NONE;
if(!(REG_SADC_ADENA & (ADENA_AUXEN))) key_val = ADC_MASK;
REG_SADC_ADENA |= ADENA_AUXEN; __intc_unmask_irq(IRQ_SADC);
REG_SADC_ADENA |= ADENA_AUXEN;
btn_last_tick = current_tick;
} }
/* Notes on batteries /* Notes on batteries
@ -238,6 +270,7 @@ void adc_init(void)
REG_SADC_ADCFG = ADCFG_VBAT_SEL | ADCFG_CMD_AUX(1); /* VBAT_SEL is undocumented but required! */ REG_SADC_ADCFG = ADCFG_VBAT_SEL | ADCFG_CMD_AUX(1); /* VBAT_SEL is undocumented but required! */
REG_SADC_ADCLK = (199 << 16) | (1 << 8) | 61; REG_SADC_ADCLK = (199 << 16) | (1 << 8) | 61;
system_enable_irq(IRQ_SADC); system_enable_irq(IRQ_SADC);
REG_SADC_ADENA |= ADENA_AUXEN | ADENA_VBATEN;
} }
void adc_close(void) void adc_close(void)
@ -260,8 +293,6 @@ void SADC(void)
if(state & ADCTRL_ARDYM) if(state & ADCTRL_ARDYM)
{ {
key_val = REG_SADC_ADADAT; key_val = REG_SADC_ADADAT;
if (KEY_IS_DOWN(PIN_KEY_INT)) /* key(s) are down kick off another read */
REG_SADC_ADENA = ADENA_AUXEN;
} }
else if(UNLIKELY(state & ADCTRL_VRDYM)) else if(UNLIKELY(state & ADCTRL_VRDYM))
{ {