rb_info plugin and button,action+context name helper
rb_info is just a test plugin just some info from the running rockbox install the real star here is the generator scripts to make actions_helper.c and button_helper.c Change-Id: I23f7bbdae3f2cffca2490c4df40bb13b0b5d5064
This commit is contained in:
parent
3d07ec46ee
commit
b39acee3ab
12 changed files with 908 additions and 1 deletions
|
@ -129,6 +129,7 @@ enum {
|
|||
CONTEXT_USB_HID_MODE_PRESENTATION,
|
||||
CONTEXT_USB_HID_MODE_BROWSER,
|
||||
CONTEXT_USB_HID_MODE_MOUSE,
|
||||
LAST_CONTEXT_PLACEHOLDER,
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -87,6 +87,7 @@ ppm,viewers
|
|||
properties,viewers
|
||||
quake,games
|
||||
random_folder_advance_config,apps
|
||||
rb_info,demos
|
||||
remote_control,apps
|
||||
resistor,apps
|
||||
reversi,games
|
||||
|
|
|
@ -17,6 +17,7 @@ mosaique.c
|
|||
main_menu_config.c
|
||||
properties.c
|
||||
random_folder_advance_config.c
|
||||
rb_info.c
|
||||
rockblox.c
|
||||
search.c
|
||||
settings_dumper.c
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
sha1.c
|
||||
gcc-support.c
|
||||
pluginlib_actions.c
|
||||
action_helper.c
|
||||
button_helper.c
|
||||
helper.c
|
||||
icon_helper.c
|
||||
arg_helper.c
|
||||
|
|
1
apps/plugins/lib/action_helper.c
Normal file
1
apps/plugins/lib/action_helper.c
Normal file
|
@ -0,0 +1 @@
|
|||
/*DUMMY_FILE_DONT_CHANGEME*/
|
34
apps/plugins/lib/action_helper.h
Normal file
34
apps/plugins/lib/action_helper.h
Normal file
|
@ -0,0 +1,34 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2021 William Wilgus
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
/* action_helper provides a way to turn numeric action/context into strings
|
||||
* the file action_helper.c is generated at compile time
|
||||
* ACTION_ and CONTEXT_ are stripped from the strings and replaced when
|
||||
* action_name and context_name are called,
|
||||
* NOTE: both share the same static buffer sized as the largest string possible
|
||||
*/
|
||||
#ifndef _ACTION_HELPER_H_
|
||||
#define _ACTION_HELPER_H_
|
||||
|
||||
char* action_name(int action);
|
||||
char* context_name(int context);
|
||||
|
||||
#endif /* _ACTION_HELPER_H_ */
|
209
apps/plugins/lib/action_helper.pl
Executable file
209
apps/plugins/lib/action_helper.pl
Executable file
|
@ -0,0 +1,209 @@
|
|||
#!/usr/bin/env perl
|
||||
############################################################################
|
||||
# __________ __ ___.
|
||||
# Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
# \/ \/ \/ \/ \/
|
||||
# $action_helper$
|
||||
#
|
||||
# Copyright (C) 2021 William Wilgus
|
||||
#
|
||||
# All files in this archive are subject to the GNU General Public License.
|
||||
# See the file COPYING in the source tree root for full license agreement.
|
||||
#
|
||||
# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
# KIND, either express or implied.
|
||||
#
|
||||
############################################################################
|
||||
#expects -E source input on STDIN
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
my @actions = ();
|
||||
my @contexts = ();
|
||||
my @action_offset = ();
|
||||
my @context_offset = ();
|
||||
my $action_ct = 0;
|
||||
my $context_ct = 0;
|
||||
my $len_max_action = 0;
|
||||
my $len_max_context = 0;
|
||||
my $len_min_action = -1;
|
||||
my $len_min_context = -1;
|
||||
while(my $line = <STDIN>)
|
||||
{
|
||||
chomp($line);
|
||||
if($line =~ /^\s*(ACTION_[^\s]+)(\s*=.*)?,\s*$/)
|
||||
{
|
||||
$actions[$action_ct] = $1;
|
||||
$action_ct++;
|
||||
}
|
||||
elsif($line =~ /^\s*(LAST_ACTION_PLACEHOLDER)(\s*=.*)?,\s*$/)
|
||||
{ #special case don't save actual name
|
||||
$actions[$action_ct] = "";
|
||||
$action_ct++;
|
||||
}
|
||||
elsif($line =~ /^\s*(PLA_[^\s]+)(\s*=.*)?,\s*$/)
|
||||
{
|
||||
$actions[$action_ct] = $1;
|
||||
$action_ct++;
|
||||
}
|
||||
elsif($line =~ /^\s*(CONTEXT_[^\s]+)(\s*=.*)?,\s*$/)
|
||||
{
|
||||
$contexts[$context_ct] = $1;
|
||||
$context_ct++;
|
||||
}
|
||||
}
|
||||
|
||||
print <<EOF
|
||||
/* Don't change this file! */
|
||||
/* It is automatically generated of action.h */
|
||||
#include "plugin.h"
|
||||
#include "action_helper.h"
|
||||
EOF
|
||||
;
|
||||
#dump actions
|
||||
my $offset = 0;
|
||||
print "static const char action_names[]= \n";
|
||||
for(my $i = 0; $i < $action_ct; $i++){
|
||||
my $act = $actions[$i];
|
||||
$act =~ s/ACTION_USB_HID_/%s/ig; # strip the common part
|
||||
$act =~ s/ACTION_/%s/ig; # strip the common part
|
||||
my $actlen = length($act);
|
||||
if ($actlen < $len_min_action or $len_min_action == -1){
|
||||
$len_min_action = $actlen;
|
||||
}
|
||||
if ($actions[$i] ne $act){
|
||||
printf "/*%s*/\"%s\\0\"\n", substr($actions[$i], 0, -($actlen - 2)), $act;
|
||||
} else {
|
||||
print "\"$act\\0\" \n";
|
||||
}
|
||||
my $slen = length($actions[$i]) + 1; #NULL terminator
|
||||
if ($slen > $len_max_action) { $len_max_action = $slen; }
|
||||
push(@action_offset, {'name' => $actions[$i], 'offset' => $offset});
|
||||
$offset += length($act) + 1; # NULL terminator
|
||||
}
|
||||
printf "\"\";/* %d + \\0 */\n\n", $offset;
|
||||
@actions = ();
|
||||
|
||||
#dump contexts
|
||||
$offset = 0;
|
||||
print "static const char context_names[]= \n";
|
||||
for(my $i = 0; $i < $context_ct; $i++){
|
||||
my $ctx = $contexts[$i];
|
||||
$ctx =~ s/CONTEXT_/%s/ig; # strip the common part
|
||||
my $ctxlen = length($ctx);
|
||||
|
||||
if ($ctxlen < 5){
|
||||
$ctx = $contexts[$i];
|
||||
$ctxlen = length($ctx);
|
||||
}
|
||||
|
||||
if ($ctxlen < $len_min_context or $len_min_context == -1){
|
||||
$len_min_context = $ctxlen;
|
||||
}
|
||||
if ($contexts[$i] ne $ctx){
|
||||
printf "/*%s*/\"%s\\0\"\n", substr($contexts[$i], 0, -($ctxlen - 2)), $ctx;
|
||||
} else {
|
||||
print "\"$ctx\\0\" \n";
|
||||
}
|
||||
my $slen = length($contexts[$i]) + 1; # NULL terminator
|
||||
if ($slen > $len_max_context) { $len_max_context = $slen; }
|
||||
push(@context_offset, {'name' => $contexts[$i], 'offset' => $offset});
|
||||
$offset += length($ctx) + 1; # NULL terminator
|
||||
}
|
||||
printf "\"\";/* %d + \\0 */\n\n", $offset;
|
||||
@contexts = ();
|
||||
|
||||
printf "#define ACTION_CT %d\n", $action_ct;
|
||||
print "static const uint16_t action_offsets[ACTION_CT] = {\n";
|
||||
foreach my $define (@action_offset)
|
||||
{
|
||||
printf("%d, /*%s*/\n", @$define{'offset'}, @$define{'name'});
|
||||
}
|
||||
print "};\n\n";
|
||||
@action_offset = ();
|
||||
|
||||
printf "#define CONTEXT_CT %d\n", $context_ct;
|
||||
print "#if 0 /* context_names is small enough to walk the string instead */\n";
|
||||
print "static const uint16_t context_offsets[CONTEXT_CT] = {\n";
|
||||
foreach my $define (@context_offset)
|
||||
{
|
||||
printf("%d, /*%s*/\n", @$define{'offset'}, @$define{'name'});
|
||||
}
|
||||
print "};\n#endif\n\n";
|
||||
@context_offset = ();
|
||||
|
||||
printf "#define ACTIONBUFSZ %d\n", $len_max_action;
|
||||
printf "#define CONTEXTBUFSZ %d\n\n", $len_max_context;
|
||||
|
||||
if ($len_max_action > $len_max_context)
|
||||
{
|
||||
print "static char name_buf[ACTIONBUFSZ];\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
print "static char name_buf[CONTEXTBUFSZ];\n";
|
||||
}
|
||||
print <<EOF
|
||||
|
||||
char* action_name(int action)
|
||||
{
|
||||
if (action >= 0 && action < ACTION_CT)
|
||||
{
|
||||
uint16_t offset = action_offsets[action];
|
||||
const char *act = &action_names[offset];
|
||||
if (action < ACTION_USB_HID_FIRST)
|
||||
rb->snprintf(name_buf, ACTIONBUFSZ, act, "ACTION_");
|
||||
else
|
||||
rb->snprintf(name_buf, ACTIONBUFSZ, act, "ACTION_USB_HID_");
|
||||
}
|
||||
else
|
||||
rb->snprintf(name_buf, ACTIONBUFSZ, "ACTION_UNKNOWN");
|
||||
return name_buf;
|
||||
}
|
||||
|
||||
/* walk string increment offset for each NULL if desired offset found, return */
|
||||
static const char *context_getoffset(int offset)
|
||||
{
|
||||
const char *names = context_names;
|
||||
const size_t len = sizeof(context_names) - 1;
|
||||
int current = 0;
|
||||
if (offset > 0)
|
||||
{
|
||||
const char *pos = names;
|
||||
const char *end = names + len;
|
||||
while (pos < end)
|
||||
{
|
||||
if (*pos++ == '\\0')
|
||||
{
|
||||
current++;
|
||||
if (offset == current)
|
||||
return pos;
|
||||
pos += $len_min_context; /* each string is at least this long */
|
||||
}
|
||||
}
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
||||
char* context_name(int context)
|
||||
{
|
||||
const char *ctx;
|
||||
if (context >= 0 && context < CONTEXT_CT)
|
||||
{
|
||||
#if 0
|
||||
uint16_t offset = context_offsets[context];
|
||||
ctx = &context_names[offset];
|
||||
#else
|
||||
ctx = context_getoffset(context);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
ctx = "%sUNKNOWN";
|
||||
rb->snprintf(name_buf, CONTEXTBUFSZ, ctx, "CONTEXT_");
|
||||
return name_buf;
|
||||
}
|
||||
EOF
|
||||
;
|
1
apps/plugins/lib/button_helper.c
Normal file
1
apps/plugins/lib/button_helper.c
Normal file
|
@ -0,0 +1 @@
|
|||
/*DUMMY_FILE_DONT_CHANGEME*/
|
38
apps/plugins/lib/button_helper.h
Normal file
38
apps/plugins/lib/button_helper.h
Normal file
|
@ -0,0 +1,38 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2021 William Wilgus
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
#ifndef _BUTTON_HELPER_H_
|
||||
#define _BUTTON_HELPER_H_
|
||||
struct available_button
|
||||
{
|
||||
const char* name;
|
||||
unsigned long value;
|
||||
};
|
||||
|
||||
/* *available_buttons is holding a pointer to the first element of an array
|
||||
* of struct available_button it is set up in such a way due to the file being
|
||||
* generated at compile time you can still call it as such though
|
||||
* eg available_buttons[0] or available_buttons[available_button_count] (NULL SENTINEL, 0)*/
|
||||
|
||||
extern const struct available_button * const available_buttons;
|
||||
extern const int available_button_count;
|
||||
int get_button_names(char *buf, size_t bufsz, unsigned long button);
|
||||
#endif /* _BUTTON_HELPER_H_ */
|
98
apps/plugins/lib/button_helper.pl
Executable file
98
apps/plugins/lib/button_helper.pl
Executable file
|
@ -0,0 +1,98 @@
|
|||
#!/usr/bin/env perl
|
||||
############################################################################
|
||||
# __________ __ ___.
|
||||
# Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
# \/ \/ \/ \/ \/
|
||||
# $Id$
|
||||
#
|
||||
# Copyright (C) 2009 by Maurus Cuelenaere
|
||||
# Copyright (C) 2021 by William Wilgus
|
||||
#
|
||||
# All files in this archive are subject to the GNU General Public License.
|
||||
# See the file COPYING in the source tree root for full license agreement.
|
||||
#
|
||||
# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
# KIND, either express or implied.
|
||||
#
|
||||
############################################################################
|
||||
#expects -dM -E source input on STDIN
|
||||
use strict;
|
||||
use warnings;
|
||||
my $svnrev = '$Revision$';
|
||||
my @buttons = ();
|
||||
my $count = 1; #null sentinel
|
||||
my $val;
|
||||
my $def;
|
||||
while(my $line = <STDIN>)
|
||||
{
|
||||
chomp($line);
|
||||
if($line =~ /^#define (BUTTON_[^\s]+) (.+)$/)
|
||||
{
|
||||
$def = "{\"$1\", $2},\n";
|
||||
$val = $2;
|
||||
if($val =~ /^0/)
|
||||
{
|
||||
$val = oct($val)
|
||||
}
|
||||
else
|
||||
{
|
||||
$val = 0xFFFFFFFF; #only used for sorting
|
||||
}
|
||||
push(@buttons, {'name' => $1, 'value' => $val, 'def' => $def});
|
||||
$count = $count + 1;
|
||||
}
|
||||
}
|
||||
my @sorted = sort { @$a{'value'} <=> @$b{'value'} } @buttons;
|
||||
print <<EOF
|
||||
/* Don't change this file! */
|
||||
/* It is automatically generated of button.h */
|
||||
#include "plugin.h"
|
||||
#include "button.h"
|
||||
#include "button_helper.h"
|
||||
|
||||
static const struct available_button buttons[$count] = {
|
||||
EOF
|
||||
;
|
||||
$count--; # don't count the sentinel
|
||||
foreach my $button (@sorted)
|
||||
{
|
||||
printf " %s", @$button{'def'};
|
||||
}
|
||||
|
||||
print <<EOF
|
||||
{"\\0", 0} /* sentinel */
|
||||
};
|
||||
const int available_button_count = $count;
|
||||
const struct available_button * const available_buttons = buttons;
|
||||
|
||||
int get_button_names(char *buf, size_t bufsz, unsigned long button)
|
||||
{
|
||||
int len = 0;
|
||||
buf[0] = '\\0';
|
||||
const struct available_button *btn = buttons;
|
||||
while(btn->name[0] != '\\0')
|
||||
{
|
||||
if(btn->value == 0)
|
||||
{
|
||||
if (button == 0)
|
||||
{
|
||||
buf[0] = '\\0';
|
||||
len = rb->strlcat(buf, btn->name, bufsz);
|
||||
return len;
|
||||
}
|
||||
}
|
||||
else if ((button & btn->value) == btn->value)
|
||||
{
|
||||
if (len > 0)
|
||||
rb->strlcat(buf, " | ", bufsz);
|
||||
len = rb->strlcat(buf, btn->name, bufsz);
|
||||
}
|
||||
btn++;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
EOF
|
||||
;
|
|
@ -101,8 +101,35 @@ else
|
|||
PLUGINLIBFLAGS = $(PLUGINFLAGS) -ffunction-sections -fdata-sections
|
||||
endif
|
||||
|
||||
ROOT_PLUGINSLIB_DIR := $(ROOTDIR)/apps/plugins/lib
|
||||
BUILD_PLUGINSLIB_DIR := $(BUILDDIR)/apps/plugins/lib
|
||||
|
||||
# action_helper #
|
||||
ACTION_REQ := $(addprefix $(ROOT_PLUGINSLIB_DIR)/,action_helper.pl action_helper.h) \
|
||||
$(BUILD_PLUGINSLIB_DIR)/pluginlib_actions.o
|
||||
|
||||
# special rule for generating and compiling action_helper
|
||||
$(BUILD_PLUGINSLIB_DIR)/action_helper.o: $(ACTION_REQ)
|
||||
$(SILENT)mkdir -p $(dir $@)
|
||||
$(call PRINTS,GEN $(@F))$(CC) $(PLUGINFLAGS) $(INCLUDES) -E -P \
|
||||
$(ROOT_PLUGINSLIB_DIR)/pluginlib_actions.h - < /dev/null | $< > $(basename $@).c
|
||||
$(call PRINTS,CC $(subst $(ROOTDIR)/,,$<))$(CC) -I$(ROOT_PLUGINSLIB_DIR) \
|
||||
$(PLUGINLIBFLAGS) -c $(basename $@).c -o $@
|
||||
|
||||
# button_helper #
|
||||
BUTTON_REQ := $(addprefix $(ROOT_PLUGINSLIB_DIR)/,button_helper.pl button_helper.h) \
|
||||
$(BUILD_PLUGINSLIB_DIR)/action_helper.o
|
||||
|
||||
# special rule for generating and compiling button_helper
|
||||
$(BUILD_PLUGINSLIB_DIR)/button_helper.o: $(BUTTON_REQ) $(ROOTDIR)/firmware/export/button.h
|
||||
$(SILENT)mkdir -p $(dir $@)
|
||||
$(call PRINTS,GEN $(@F))$(CC) $(PLUGINFLAGS) $(INCLUDES) -dM -E -P \
|
||||
$(addprefix -include ,button-target.h button.h) - < /dev/null | $< > $(basename $@).c
|
||||
$(call PRINTS,CC $(subst $(ROOTDIR)/,,$<))$(CC) -I$(ROOT_PLUGINSLIB_DIR) \
|
||||
$(PLUGINLIBFLAGS) -c $(basename $@).c -o $@
|
||||
|
||||
# special pattern rule for compiling plugin lib (with function and data sections)
|
||||
$(BUILDDIR)/apps/plugins/lib/%.o: $(ROOTDIR)/apps/plugins/lib/%.c
|
||||
$(BUILD_PLUGINSLIB_DIR)/%.o: $(ROOT_PLUGINSLIB_DIR)/%.c
|
||||
$(SILENT)mkdir -p $(dir $@)
|
||||
$(call PRINTS,CC $(subst $(ROOTDIR)/,,$<))$(CC) -I$(dir $<) $(PLUGINLIBFLAGS) -c $< -o $@
|
||||
|
||||
|
|
494
apps/plugins/rb_info.c
Normal file
494
apps/plugins/rb_info.c
Normal file
|
@ -0,0 +1,494 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// __ \_/ ___\| |/ /| __ \ / __ \ \/ /
|
||||
* Jukebox | | ( (__) ) \___| ( | \_\ ( (__) ) (
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2020 William Wilgus
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/* WIP rb_info common info that you wonder about when rockboxing?
|
||||
*/
|
||||
|
||||
#include "plugin.h"
|
||||
#include "lang_enum.h"
|
||||
#include "../open_plugin.h"
|
||||
#include "logf.h"
|
||||
#include "lib/action_helper.h"
|
||||
#include "lib/button_helper.h"
|
||||
#include "lib/pluginlib_actions.h"
|
||||
|
||||
#define MENU_ID(x) (((void*)&"RPBUTACNGX\0" + x))
|
||||
enum {
|
||||
M_ROOT = 0,
|
||||
M_PATHS,
|
||||
M_BUFFERS,
|
||||
M_BUTTONS,
|
||||
M_BTNTEST,
|
||||
M_ACTIONS,
|
||||
M_CONTEXTS,
|
||||
M_ACTTEST,
|
||||
M_PLUGINS,
|
||||
M_EXIT,
|
||||
M_LAST_ITEM //ITEM COUNT
|
||||
};
|
||||
|
||||
#define MENU_ID_PLUGINS_ITEMS 5
|
||||
|
||||
/*Action test and Button test*/
|
||||
static struct menu_test_t {
|
||||
int count;
|
||||
int context;
|
||||
int last_btn_or_act;
|
||||
} m_test;
|
||||
|
||||
struct menu_buffer_t { const char *name; size_t size;};
|
||||
static const struct menu_buffer_t m_buffer[] =
|
||||
{
|
||||
#ifndef MAX_LOGF_SIZE
|
||||
#define MAX_LOGF_SIZE (0)
|
||||
#endif
|
||||
#ifndef CACHE_SIZE
|
||||
#define CACHE_SIZE (0)
|
||||
#endif
|
||||
{"thread stack", DEFAULT_STACK_SIZE},
|
||||
{"plugin buffer", PLUGIN_BUFFER_SIZE},
|
||||
{"frame_buffer", FRAMEBUFFER_SIZE},
|
||||
{"codec_buffer", CODEC_SIZE},
|
||||
{"logf_buffer", MAX_LOGF_SIZE},
|
||||
{"cache", CACHE_SIZE},
|
||||
};
|
||||
|
||||
/* stringify the macro value */
|
||||
#define MACROVAL(x) MACROSTR(x)
|
||||
#define MACROSTR(x) #x
|
||||
static int main_last_sel = 0;
|
||||
static struct gui_synclist lists;
|
||||
static void synclist_set(char*, int, int, int);
|
||||
|
||||
struct paths { const char *name; const char *path; };
|
||||
static const struct paths paths[] = {
|
||||
{"Home", ""HOME_DIR},
|
||||
{"Rockbox", ""ROCKBOX_DIR},
|
||||
{"Plugins", ""PLUGIN_DIR},
|
||||
{"Codecs", ""CODECS_DIR},
|
||||
{"WPS", ""WPS_DIR},
|
||||
{"SBS", ""SBS_DIR},
|
||||
{"Theme", ""THEME_DIR},
|
||||
{"Font", ""FONT_DIR},
|
||||
{"Icon", ""ICON_DIR},
|
||||
{"Backdrop", ""BACKDROP_DIR},
|
||||
{"Eq", ""EQS_DIR},
|
||||
{"Rec Presets", ""RECPRESETS_DIR},
|
||||
{"Recordings", ""REC_BASE_DIR,},
|
||||
{"Fm Presets", ""FMPRESET_PATH},
|
||||
{"MAX_PATH", ""MACROVAL(MAX_PATH)" bytes"},
|
||||
};
|
||||
|
||||
struct mainmenu { const char *name; void *menuid; int items;};
|
||||
static struct mainmenu mainmenu[M_LAST_ITEM] = {
|
||||
#define MENU_ITEM(ID, NAME, COUNT) [ID]{NAME, MENU_ID(ID), (int)COUNT}
|
||||
MENU_ITEM(M_ROOT, "Rockbox Info Plugin", M_LAST_ITEM),
|
||||
MENU_ITEM(M_PATHS, ID2P(LANG_SHOW_PATH), ARRAYLEN(paths)),
|
||||
MENU_ITEM(M_BUFFERS, ID2P(LANG_BUFFER_STAT), ARRAYLEN(m_buffer)),
|
||||
MENU_ITEM(M_BUTTONS, "Buttons", -1), /* Set at runtime in plugin_start: */
|
||||
MENU_ITEM(M_BTNTEST, "Button test", 2),
|
||||
MENU_ITEM(M_ACTIONS, "Actions", LAST_ACTION_PLACEHOLDER),
|
||||
MENU_ITEM(M_CONTEXTS, "Contexts", LAST_CONTEXT_PLACEHOLDER ),
|
||||
MENU_ITEM(M_ACTTEST, "Action test", 3),
|
||||
MENU_ITEM(M_PLUGINS, ID2P(LANG_PLUGINS), MENU_ID_PLUGINS_ITEMS),
|
||||
MENU_ITEM(M_EXIT, ID2P(LANG_MENU_QUIT), 0),
|
||||
#undef MENU_ITEM
|
||||
};
|
||||
|
||||
static const struct mainmenu *mainitem(int selected_item)
|
||||
{
|
||||
static const struct mainmenu empty = {0};
|
||||
if (selected_item >= 0 && selected_item < (int) ARRAYLEN(mainmenu))
|
||||
return &mainmenu[selected_item];
|
||||
else
|
||||
return ∅
|
||||
}
|
||||
|
||||
static void cleanup(void *parameter)
|
||||
{
|
||||
(void)parameter;
|
||||
|
||||
}
|
||||
|
||||
static const char *menu_plugin_name_cb(int selected_item, void* data,
|
||||
char* buf, size_t buf_len)
|
||||
{
|
||||
(void)data;
|
||||
buf[0] = '\0';
|
||||
switch(selected_item)
|
||||
{
|
||||
case 0:
|
||||
rb->snprintf(buf, buf_len, "%s: [%d bytes] ", "plugin_api", (int)sizeof(struct plugin_api));
|
||||
break;
|
||||
case 1:
|
||||
rb->snprintf(buf, buf_len, "%s: [%d bytes] ", "plugin buffer", PLUGIN_BUFFER_SIZE);
|
||||
break;
|
||||
case 2:
|
||||
rb->snprintf(buf, buf_len, "%s: [%d bytes] ", "frame_buffer", (int)FRAMEBUFFER_SIZE);
|
||||
break;
|
||||
case 3:
|
||||
rb->snprintf(buf, buf_len, "%s: [W: %d H:%d] ", "LCD", LCD_WIDTH, LCD_HEIGHT);
|
||||
break;
|
||||
case 4:
|
||||
rb->snprintf(buf, buf_len, "%s: [%d bits] ", "fb_data", (int)(sizeof(fb_data) * CHAR_BIT));
|
||||
break;
|
||||
case 5:
|
||||
break;
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
static const char *menu_button_test_name_cb(int selected_item, void* data,
|
||||
char* buf, size_t buf_len)
|
||||
{
|
||||
(void)data;
|
||||
int curbtn = BUTTON_NONE;
|
||||
buf[0] = '\0';
|
||||
switch(selected_item)
|
||||
{
|
||||
case 0:
|
||||
rb->snprintf(buf, buf_len, "%s: [%s] ", "Button test",
|
||||
m_test.count > 0 ? "true":"false");
|
||||
break;
|
||||
case 1:
|
||||
if (m_test.count > 0)
|
||||
{
|
||||
if (m_test.count <= 2)
|
||||
curbtn = rb->button_get_w_tmo(HZ * 2);
|
||||
else
|
||||
m_test.last_btn_or_act = BUTTON_NONE;
|
||||
if (curbtn == BUTTON_NONE)
|
||||
{
|
||||
m_test.count--;
|
||||
}
|
||||
else
|
||||
m_test.last_btn_or_act = curbtn;
|
||||
}
|
||||
get_button_names(buf, buf_len, m_test.last_btn_or_act);
|
||||
|
||||
break;
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
static const char *menu_action_test_name_cb(int selected_item, void* data,
|
||||
char* buf, size_t buf_len)
|
||||
{
|
||||
(void)data;
|
||||
const char *fmtstr;
|
||||
int curact = ACTION_NONE;
|
||||
buf[0] = '\0';
|
||||
switch(selected_item)
|
||||
{
|
||||
case 0:
|
||||
rb->snprintf(buf, buf_len, "%s: [%s] ", "Action test",
|
||||
m_test.count > 0 ? "true":"false");
|
||||
break;
|
||||
case 1:
|
||||
if (m_test.count <= 0)
|
||||
{
|
||||
if (m_test.context <= 0)
|
||||
fmtstr = "%s > ";
|
||||
else if (m_test.context >= LAST_CONTEXT_PLACEHOLDER - 1)
|
||||
fmtstr = "< %s ";
|
||||
else
|
||||
fmtstr = "< %s > ";
|
||||
}
|
||||
else
|
||||
fmtstr = "%s";
|
||||
|
||||
rb->snprintf(buf, buf_len, fmtstr, context_name(m_test.context));
|
||||
break;
|
||||
case 2:
|
||||
if (m_test.count > 0)
|
||||
{
|
||||
if (m_test.count <= 2)
|
||||
curact = rb->get_action(m_test.context, HZ * 2);
|
||||
else
|
||||
m_test.last_btn_or_act = ACTION_NONE;
|
||||
if (curact == ACTION_NONE && rb->button_get(false) == BUTTON_NONE)
|
||||
{
|
||||
m_test.count--;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_test.last_btn_or_act = curact;
|
||||
m_test.count = 2;
|
||||
}
|
||||
}
|
||||
return action_name(m_test.last_btn_or_act);
|
||||
|
||||
break;
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
static const char* list_get_name_cb(int selected_item, void* data,
|
||||
char* buf, size_t buf_len)
|
||||
{
|
||||
buf[0] = '\0';
|
||||
if (data == MENU_ID(M_ROOT))
|
||||
return mainitem(selected_item)->name;
|
||||
else if (selected_item == 0) /*header text*/
|
||||
return mainitem(main_last_sel)->name;
|
||||
else if (selected_item >= mainitem(main_last_sel)->items - 1)
|
||||
return ID2P(LANG_BACK);
|
||||
|
||||
if (data == MENU_ID(M_PATHS))
|
||||
{
|
||||
selected_item--;
|
||||
if (selected_item >= 0 && selected_item < mainitem(M_PATHS)->items)
|
||||
{
|
||||
const struct paths *cur = &paths[selected_item];
|
||||
rb->snprintf(buf, buf_len, "%s: [%s] ", cur->name, cur->path);
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
else if (data == MENU_ID(M_BUTTONS))
|
||||
{
|
||||
const struct available_button *btn = &available_buttons[selected_item - 1];
|
||||
rb->snprintf(buf, buf_len, "%s: [0x%X] ", btn->name, (unsigned int) btn->value);
|
||||
return buf;
|
||||
}
|
||||
else if (data == MENU_ID(M_BTNTEST))
|
||||
return menu_button_test_name_cb(selected_item - 1, data, buf, buf_len);
|
||||
else if (data == MENU_ID(M_ACTIONS))
|
||||
return action_name(selected_item - 1);
|
||||
else if (data == MENU_ID(M_CONTEXTS))
|
||||
return context_name(selected_item - 1);
|
||||
else if (data == MENU_ID(M_ACTTEST))
|
||||
return menu_action_test_name_cb(selected_item - 1, data, buf, buf_len);
|
||||
else if (data == MENU_ID(M_BUFFERS))
|
||||
{
|
||||
const struct menu_buffer_t *bufm = &m_buffer[selected_item - 1];
|
||||
rb->snprintf(buf, buf_len, "%s: [%ld bytes] ", bufm->name, (long)bufm->size);
|
||||
return buf;
|
||||
}
|
||||
else if (data == MENU_ID(M_PLUGINS))
|
||||
{
|
||||
return menu_plugin_name_cb(selected_item - 1, data, buf, buf_len);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
static int list_voice_cb(int list_index, void* data)
|
||||
{
|
||||
if (!rb->global_settings->talk_menu)
|
||||
return -1;
|
||||
|
||||
if (data == MENU_ID(M_ROOT))
|
||||
{
|
||||
const char * name = mainitem(list_index)->name;
|
||||
long id = P2ID((const unsigned char *)name);
|
||||
if(id>=0)
|
||||
rb->talk_id(id, true);
|
||||
else
|
||||
rb->talk_spell(name, true);
|
||||
}
|
||||
else if (data == MENU_ID(M_BUFFERS) || data == MENU_ID(M_PLUGINS))
|
||||
{
|
||||
char buf[64];
|
||||
const char* name = list_get_name_cb(list_index, data, buf, sizeof(buf));
|
||||
long id = P2ID((const unsigned char *)name);
|
||||
if(id>=0)
|
||||
rb->talk_id(id, true);
|
||||
else
|
||||
{
|
||||
char* bytstr = rb->strcasestr(name, "bytes");
|
||||
if (bytstr != NULL)
|
||||
*bytstr = '\0';
|
||||
rb->talk_spell(name, true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
char buf[64];
|
||||
const char* name = list_get_name_cb(list_index, data, buf, sizeof(buf));
|
||||
long id = P2ID((const unsigned char *)name);
|
||||
if(id>=0)
|
||||
rb->talk_id(id, true);
|
||||
else
|
||||
rb->talk_spell(name, true);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int menu_action_cb(int action, int selected_item, bool* exit, struct gui_synclist *lists)
|
||||
{
|
||||
if (lists->data == MENU_ID(M_ACTTEST))
|
||||
{
|
||||
if (selected_item == 2) /* context */
|
||||
{
|
||||
int ctx = m_test.context;
|
||||
if (action == ACTION_STD_OK)
|
||||
m_test.context++;
|
||||
else if (action == ACTION_STD_CANCEL)
|
||||
m_test.context--;
|
||||
|
||||
if (m_test.context < 0)
|
||||
m_test.context = 0;
|
||||
else if (m_test.context >= LAST_CONTEXT_PLACEHOLDER)
|
||||
m_test.context = LAST_CONTEXT_PLACEHOLDER - 1;
|
||||
|
||||
if (ctx != m_test.context)
|
||||
rb->gui_synclist_speak_item(lists);
|
||||
|
||||
goto default_handler;
|
||||
}
|
||||
if (action == ACTION_STD_OK)
|
||||
{
|
||||
if (selected_item == 1 || selected_item == 3)
|
||||
{
|
||||
m_test.count = 3;
|
||||
rb->gui_synclist_select_item(lists, 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (lists->data == MENU_ID(M_BTNTEST))
|
||||
{
|
||||
if (action == ACTION_STD_OK)
|
||||
{
|
||||
if (selected_item == 1 || selected_item == 2)
|
||||
{
|
||||
m_test.count = 3;
|
||||
rb->gui_synclist_select_item(lists, 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (action == ACTION_STD_OK)
|
||||
{
|
||||
if (lists->data == MENU_ID(M_ROOT))
|
||||
{
|
||||
rb->memset(&m_test, 0, sizeof(struct menu_test_t));
|
||||
const struct mainmenu *cur = mainitem(selected_item);
|
||||
if (cur->menuid == NULL || cur->menuid == MENU_ID(M_EXIT))
|
||||
*exit = true;
|
||||
else
|
||||
{
|
||||
main_last_sel = selected_item;
|
||||
synclist_set(cur->menuid, 1, cur->items, 1);
|
||||
rb->gui_synclist_draw(lists);
|
||||
}
|
||||
}
|
||||
else if (selected_item <= 0) /* title */
|
||||
{
|
||||
rb->gui_synclist_select_item(lists, 1);
|
||||
}
|
||||
else if (selected_item >= (mainitem(main_last_sel)->items) - 1)/*back*/
|
||||
{
|
||||
action = ACTION_STD_CANCEL;
|
||||
}
|
||||
else if (lists->data == MENU_ID(M_ACTIONS) ||
|
||||
lists->data == MENU_ID(M_CONTEXTS))
|
||||
{
|
||||
char buf[MAX_PATH];
|
||||
const char *name = list_get_name_cb(selected_item, lists->data, buf, sizeof(buf));
|
||||
/* splash long enough to get fingers off button then wait for new button press */
|
||||
rb->splashf(HZ / 2, "%s %d (0x%X)", name, selected_item -1, selected_item -1);
|
||||
rb->button_get(true);
|
||||
}
|
||||
}
|
||||
if (action == ACTION_STD_CANCEL)
|
||||
{
|
||||
if (lists->data != MENU_ID(M_ROOT))
|
||||
{
|
||||
const struct mainmenu *mainm = &mainmenu[0];
|
||||
synclist_set(mainm->menuid, main_last_sel, mainm->items, 1);
|
||||
rb->gui_synclist_draw(lists);
|
||||
}
|
||||
else
|
||||
*exit = true;
|
||||
}
|
||||
default_handler:
|
||||
if (rb->default_event_handler_ex(action, cleanup, NULL) == SYS_USB_CONNECTED)
|
||||
{
|
||||
*exit = true;
|
||||
return PLUGIN_USB_CONNECTED;
|
||||
}
|
||||
return PLUGIN_OK;
|
||||
}
|
||||
|
||||
static void synclist_set(char* menu_id, int selected_item, int items, int sel_size)
|
||||
{
|
||||
if (items <= 0)
|
||||
return;
|
||||
if (selected_item < 0)
|
||||
selected_item = 0;
|
||||
|
||||
list_voice_cb(0, menu_id);
|
||||
rb->gui_synclist_init(&lists,list_get_name_cb,
|
||||
menu_id, false, sel_size, NULL);
|
||||
|
||||
rb->gui_synclist_set_icon_callback(&lists,NULL);
|
||||
rb->gui_synclist_set_voice_callback(&lists, list_voice_cb);
|
||||
rb->gui_synclist_set_nb_items(&lists,items);
|
||||
rb->gui_synclist_limit_scroll(&lists,true);
|
||||
rb->gui_synclist_select_item(&lists, selected_item);
|
||||
|
||||
}
|
||||
|
||||
enum plugin_status plugin_start(const void* parameter)
|
||||
{
|
||||
int ret = PLUGIN_OK;
|
||||
int selected_item = -1;
|
||||
int action;
|
||||
bool redraw = true;
|
||||
bool exit = false;
|
||||
if (parameter)
|
||||
{
|
||||
//
|
||||
}
|
||||
mainmenu[M_BUTTONS].items = available_button_count;
|
||||
/* add header and back item to each submenu */
|
||||
for (int i = 1; i < M_LAST_ITEM; i++)
|
||||
mainmenu[i].items += 2;
|
||||
|
||||
if (!exit)
|
||||
{
|
||||
const struct mainmenu *mainm = &mainmenu[0];
|
||||
synclist_set(mainm->menuid, main_last_sel, mainm->items, 1);
|
||||
rb->gui_synclist_draw(&lists);
|
||||
|
||||
while (!exit)
|
||||
{
|
||||
action = rb->get_action(CONTEXT_LIST, HZ / 10);
|
||||
if (m_test.count > 0)
|
||||
action = ACTION_REDRAW;
|
||||
|
||||
if (action == ACTION_NONE)
|
||||
{
|
||||
if (redraw)
|
||||
{
|
||||
action = ACTION_REDRAW;
|
||||
redraw = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
redraw = true;
|
||||
if (rb->gui_synclist_do_button(&lists,&action,LIST_WRAP_UNLESS_HELD))
|
||||
continue;
|
||||
selected_item = rb->gui_synclist_get_sel_pos(&lists);
|
||||
ret = menu_action_cb(action, selected_item, &exit, &lists);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
Loading…
Reference in a new issue