summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWilliam Wilgus <wilgus.william@gmail.com>2021-11-12 20:50:20 -0500
committerWilliam Wilgus <me.theuser@yahoo.com>2021-11-22 21:39:45 -0500
commitb39acee3abd199d80b84c68ebfa7301b7e7a957e (patch)
tree5e0ed2b152acd41d4b7e8335f31ba8b65d6e5f06
parent3d07ec46eed738e6dac6109598766f6568ac4669 (diff)
downloadrockbox-b39acee3ab.tar.gz
rockbox-b39acee3ab.zip
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
-rw-r--r--apps/action.h1
-rw-r--r--apps/plugins/CATEGORIES1
-rw-r--r--apps/plugins/SOURCES1
-rw-r--r--apps/plugins/lib/SOURCES2
-rw-r--r--apps/plugins/lib/action_helper.c1
-rw-r--r--apps/plugins/lib/action_helper.h34
-rwxr-xr-xapps/plugins/lib/action_helper.pl209
-rw-r--r--apps/plugins/lib/button_helper.c1
-rw-r--r--apps/plugins/lib/button_helper.h38
-rwxr-xr-xapps/plugins/lib/button_helper.pl98
-rw-r--r--apps/plugins/plugins.make29
-rw-r--r--apps/plugins/rb_info.c494
12 files changed, 908 insertions, 1 deletions
diff --git a/apps/action.h b/apps/action.h
index ad91f31535..f94dd3086c 100644
--- a/apps/action.h
+++ b/apps/action.h
@@ -129,6 +129,7 @@ enum {
CONTEXT_USB_HID_MODE_PRESENTATION,
CONTEXT_USB_HID_MODE_BROWSER,
CONTEXT_USB_HID_MODE_MOUSE,
+ LAST_CONTEXT_PLACEHOLDER,
};
diff --git a/apps/plugins/CATEGORIES b/apps/plugins/CATEGORIES
index 5b672fc8ab..bb0960f501 100644
--- a/apps/plugins/CATEGORIES
+++ b/apps/plugins/CATEGORIES
@@ -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
diff --git a/apps/plugins/SOURCES b/apps/plugins/SOURCES
index 0635a62d83..ab77dcde58 100644
--- a/apps/plugins/SOURCES
+++ b/apps/plugins/SOURCES
@@ -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
diff --git a/apps/plugins/lib/SOURCES b/apps/plugins/lib/SOURCES
index bdea07315e..1cd092f8df 100644
--- a/apps/plugins/lib/SOURCES
+++ b/apps/plugins/lib/SOURCES
@@ -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
diff --git a/apps/plugins/lib/action_helper.c b/apps/plugins/lib/action_helper.c
new file mode 100644
index 0000000000..906051c1ea
--- /dev/null
+++ b/apps/plugins/lib/action_helper.c
@@ -0,0 +1 @@
+/*DUMMY_FILE_DONT_CHANGEME*/
diff --git a/apps/plugins/lib/action_helper.h b/apps/plugins/lib/action_helper.h
new file mode 100644
index 0000000000..58d9c6c303
--- /dev/null
+++ b/apps/plugins/lib/action_helper.h
@@ -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_ */
diff --git a/apps/plugins/lib/action_helper.pl b/apps/plugins/lib/action_helper.pl
new file mode 100755
index 0000000000..1dfdcfd070
--- /dev/null
+++ b/apps/plugins/lib/action_helper.pl
@@ -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
+;
diff --git a/apps/plugins/lib/button_helper.c b/apps/plugins/lib/button_helper.c
new file mode 100644
index 0000000000..906051c1ea
--- /dev/null
+++ b/apps/plugins/lib/button_helper.c
@@ -0,0 +1 @@
+/*DUMMY_FILE_DONT_CHANGEME*/
diff --git a/apps/plugins/lib/button_helper.h b/apps/plugins/lib/button_helper.h
new file mode 100644
index 0000000000..1197b172b0
--- /dev/null
+++ b/apps/plugins/lib/button_helper.h
@@ -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_ */
diff --git a/apps/plugins/lib/button_helper.pl b/apps/plugins/lib/button_helper.pl
new file mode 100755
index 0000000000..45c3fd9073
--- /dev/null
+++ b/apps/plugins/lib/button_helper.pl
@@ -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
+;
diff --git a/apps/plugins/plugins.make b/apps/plugins/plugins.make
index ac94a04c59..b430bd2792 100644
--- a/apps/plugins/plugins.make
+++ b/apps/plugins/plugins.make
@@ -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 $@
diff --git a/apps/plugins/rb_info.c b/apps/plugins/rb_info.c
new file mode 100644
index 0000000000..f82c80c0cf
--- /dev/null
+++ b/apps/plugins/rb_info.c
@@ -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 &empty;
+}
+
+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;
+}