summaryrefslogtreecommitdiff
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-b39acee3abd199d80b84c68ebfa7301b7e7a957e.tar.gz
rockbox-b39acee3abd199d80b84c68ebfa7301b7e7a957e.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 {
129 CONTEXT_USB_HID_MODE_PRESENTATION, 129 CONTEXT_USB_HID_MODE_PRESENTATION,
130 CONTEXT_USB_HID_MODE_BROWSER, 130 CONTEXT_USB_HID_MODE_BROWSER,
131 CONTEXT_USB_HID_MODE_MOUSE, 131 CONTEXT_USB_HID_MODE_MOUSE,
132 LAST_CONTEXT_PLACEHOLDER,
132}; 133};
133 134
134 135
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
87properties,viewers 87properties,viewers
88quake,games 88quake,games
89random_folder_advance_config,apps 89random_folder_advance_config,apps
90rb_info,demos
90remote_control,apps 91remote_control,apps
91resistor,apps 92resistor,apps
92reversi,games 93reversi,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
17main_menu_config.c 17main_menu_config.c
18properties.c 18properties.c
19random_folder_advance_config.c 19random_folder_advance_config.c
20rb_info.c
20rockblox.c 21rockblox.c
21search.c 22search.c
22settings_dumper.c 23settings_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 @@
1sha1.c 1sha1.c
2gcc-support.c 2gcc-support.c
3pluginlib_actions.c 3pluginlib_actions.c
4action_helper.c
5button_helper.c
4helper.c 6helper.c
5icon_helper.c 7icon_helper.c
6arg_helper.c 8arg_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 @@
1/***************************************************************************
2* __________ __ ___.
3* Open \______ \ ____ ____ | | _\_ |__ _______ ___
4* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7* \/ \/ \/ \/ \/
8* $Id$
9*
10* Copyright (C) 2021 William Wilgus
11*
12*
13* This program is free software; you can redistribute it and/or
14* modify it under the terms of the GNU General Public License
15* as published by the Free Software Foundation; either version 2
16* of the License, or (at your option) any later version.
17*
18* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19* KIND, either express or implied.
20*
21****************************************************************************/
22/* action_helper provides a way to turn numeric action/context into strings
23* the file action_helper.c is generated at compile time
24* ACTION_ and CONTEXT_ are stripped from the strings and replaced when
25* action_name and context_name are called,
26* NOTE: both share the same static buffer sized as the largest string possible
27*/
28#ifndef _ACTION_HELPER_H_
29#define _ACTION_HELPER_H_
30
31char* action_name(int action);
32char* context_name(int context);
33
34#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 @@
1#!/usr/bin/env perl
2############################################################################
3# __________ __ ___.
4# Open \______ \ ____ ____ | | _\_ |__ _______ ___
5# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
6# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
7# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
8# \/ \/ \/ \/ \/
9# $action_helper$
10#
11# Copyright (C) 2021 William Wilgus
12#
13# All files in this archive are subject to the GNU General Public License.
14# See the file COPYING in the source tree root for full license agreement.
15#
16# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
17# KIND, either express or implied.
18#
19############################################################################
20#expects -E source input on STDIN
21use strict;
22use warnings;
23
24my @actions = ();
25my @contexts = ();
26my @action_offset = ();
27my @context_offset = ();
28my $action_ct = 0;
29my $context_ct = 0;
30my $len_max_action = 0;
31my $len_max_context = 0;
32my $len_min_action = -1;
33my $len_min_context = -1;
34while(my $line = <STDIN>)
35{
36 chomp($line);
37 if($line =~ /^\s*(ACTION_[^\s]+)(\s*=.*)?,\s*$/)
38 {
39 $actions[$action_ct] = $1;
40 $action_ct++;
41 }
42 elsif($line =~ /^\s*(LAST_ACTION_PLACEHOLDER)(\s*=.*)?,\s*$/)
43 { #special case don't save actual name
44 $actions[$action_ct] = "";
45 $action_ct++;
46 }
47 elsif($line =~ /^\s*(PLA_[^\s]+)(\s*=.*)?,\s*$/)
48 {
49 $actions[$action_ct] = $1;
50 $action_ct++;
51 }
52 elsif($line =~ /^\s*(CONTEXT_[^\s]+)(\s*=.*)?,\s*$/)
53 {
54 $contexts[$context_ct] = $1;
55 $context_ct++;
56 }
57}
58
59print <<EOF
60/* Don't change this file! */
61/* It is automatically generated of action.h */
62#include "plugin.h"
63#include "action_helper.h"
64EOF
65;
66#dump actions
67my $offset = 0;
68print "static const char action_names[]= \n";
69for(my $i = 0; $i < $action_ct; $i++){
70 my $act = $actions[$i];
71 $act =~ s/ACTION_USB_HID_/%s/ig; # strip the common part
72 $act =~ s/ACTION_/%s/ig; # strip the common part
73 my $actlen = length($act);
74 if ($actlen < $len_min_action or $len_min_action == -1){
75 $len_min_action = $actlen;
76 }
77 if ($actions[$i] ne $act){
78 printf "/*%s*/\"%s\\0\"\n", substr($actions[$i], 0, -($actlen - 2)), $act;
79 } else {
80 print "\"$act\\0\" \n";
81 }
82 my $slen = length($actions[$i]) + 1; #NULL terminator
83 if ($slen > $len_max_action) { $len_max_action = $slen; }
84 push(@action_offset, {'name' => $actions[$i], 'offset' => $offset});
85 $offset += length($act) + 1; # NULL terminator
86}
87printf "\"\";/* %d + \\0 */\n\n", $offset;
88@actions = ();
89
90#dump contexts
91$offset = 0;
92print "static const char context_names[]= \n";
93for(my $i = 0; $i < $context_ct; $i++){
94 my $ctx = $contexts[$i];
95 $ctx =~ s/CONTEXT_/%s/ig; # strip the common part
96 my $ctxlen = length($ctx);
97
98 if ($ctxlen < 5){
99 $ctx = $contexts[$i];
100 $ctxlen = length($ctx);
101 }
102
103 if ($ctxlen < $len_min_context or $len_min_context == -1){
104 $len_min_context = $ctxlen;
105 }
106 if ($contexts[$i] ne $ctx){
107 printf "/*%s*/\"%s\\0\"\n", substr($contexts[$i], 0, -($ctxlen - 2)), $ctx;
108 } else {
109 print "\"$ctx\\0\" \n";
110 }
111 my $slen = length($contexts[$i]) + 1; # NULL terminator
112 if ($slen > $len_max_context) { $len_max_context = $slen; }
113 push(@context_offset, {'name' => $contexts[$i], 'offset' => $offset});
114 $offset += length($ctx) + 1; # NULL terminator
115}
116printf "\"\";/* %d + \\0 */\n\n", $offset;
117@contexts = ();
118
119printf "#define ACTION_CT %d\n", $action_ct;
120print "static const uint16_t action_offsets[ACTION_CT] = {\n";
121foreach my $define (@action_offset)
122{
123 printf("%d, /*%s*/\n", @$define{'offset'}, @$define{'name'});
124}
125print "};\n\n";
126@action_offset = ();
127
128printf "#define CONTEXT_CT %d\n", $context_ct;
129print "#if 0 /* context_names is small enough to walk the string instead */\n";
130print "static const uint16_t context_offsets[CONTEXT_CT] = {\n";
131foreach my $define (@context_offset)
132{
133 printf("%d, /*%s*/\n", @$define{'offset'}, @$define{'name'});
134}
135print "};\n#endif\n\n";
136@context_offset = ();
137
138printf "#define ACTIONBUFSZ %d\n", $len_max_action;
139printf "#define CONTEXTBUFSZ %d\n\n", $len_max_context;
140
141if ($len_max_action > $len_max_context)
142{
143 print "static char name_buf[ACTIONBUFSZ];\n";
144}
145else
146{
147 print "static char name_buf[CONTEXTBUFSZ];\n";
148}
149print <<EOF
150
151char* action_name(int action)
152{
153 if (action >= 0 && action < ACTION_CT)
154 {
155 uint16_t offset = action_offsets[action];
156 const char *act = &action_names[offset];
157 if (action < ACTION_USB_HID_FIRST)
158 rb->snprintf(name_buf, ACTIONBUFSZ, act, "ACTION_");
159 else
160 rb->snprintf(name_buf, ACTIONBUFSZ, act, "ACTION_USB_HID_");
161 }
162 else
163 rb->snprintf(name_buf, ACTIONBUFSZ, "ACTION_UNKNOWN");
164 return name_buf;
165}
166
167/* walk string increment offset for each NULL if desired offset found, return */
168static const char *context_getoffset(int offset)
169{
170 const char *names = context_names;
171 const size_t len = sizeof(context_names) - 1;
172 int current = 0;
173 if (offset > 0)
174 {
175 const char *pos = names;
176 const char *end = names + len;
177 while (pos < end)
178 {
179 if (*pos++ == '\\0')
180 {
181 current++;
182 if (offset == current)
183 return pos;
184 pos += $len_min_context; /* each string is at least this long */
185 }
186 }
187 }
188 return names;
189}
190
191char* context_name(int context)
192{
193 const char *ctx;
194 if (context >= 0 && context < CONTEXT_CT)
195 {
196#if 0
197 uint16_t offset = context_offsets[context];
198 ctx = &context_names[offset];
199#else
200 ctx = context_getoffset(context);
201#endif
202 }
203 else
204 ctx = "%sUNKNOWN";
205 rb->snprintf(name_buf, CONTEXTBUFSZ, ctx, "CONTEXT_");
206 return name_buf;
207}
208EOF
209;
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 @@
1/***************************************************************************
2* __________ __ ___.
3* Open \______ \ ____ ____ | | _\_ |__ _______ ___
4* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7* \/ \/ \/ \/ \/
8* $Id$
9*
10* Copyright (C) 2021 William Wilgus
11*
12*
13* This program is free software; you can redistribute it and/or
14* modify it under the terms of the GNU General Public License
15* as published by the Free Software Foundation; either version 2
16* of the License, or (at your option) any later version.
17*
18* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19* KIND, either express or implied.
20*
21****************************************************************************/
22#ifndef _BUTTON_HELPER_H_
23#define _BUTTON_HELPER_H_
24struct available_button
25{
26 const char* name;
27 unsigned long value;
28};
29
30/* *available_buttons is holding a pointer to the first element of an array
31 * of struct available_button it is set up in such a way due to the file being
32 * generated at compile time you can still call it as such though
33* eg available_buttons[0] or available_buttons[available_button_count] (NULL SENTINEL, 0)*/
34
35extern const struct available_button * const available_buttons;
36extern const int available_button_count;
37int get_button_names(char *buf, size_t bufsz, unsigned long button);
38#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 @@
1#!/usr/bin/env perl
2############################################################################
3# __________ __ ___.
4# Open \______ \ ____ ____ | | _\_ |__ _______ ___
5# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
6# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
7# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
8# \/ \/ \/ \/ \/
9# $Id$
10#
11# Copyright (C) 2009 by Maurus Cuelenaere
12# Copyright (C) 2021 by William Wilgus
13#
14# All files in this archive are subject to the GNU General Public License.
15# See the file COPYING in the source tree root for full license agreement.
16#
17# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18# KIND, either express or implied.
19#
20############################################################################
21#expects -dM -E source input on STDIN
22use strict;
23use warnings;
24my $svnrev = '$Revision$';
25my @buttons = ();
26my $count = 1; #null sentinel
27my $val;
28my $def;
29while(my $line = <STDIN>)
30{
31 chomp($line);
32 if($line =~ /^#define (BUTTON_[^\s]+) (.+)$/)
33 {
34 $def = "{\"$1\", $2},\n";
35 $val = $2;
36 if($val =~ /^0/)
37 {
38 $val = oct($val)
39 }
40 else
41 {
42 $val = 0xFFFFFFFF; #only used for sorting
43 }
44 push(@buttons, {'name' => $1, 'value' => $val, 'def' => $def});
45 $count = $count + 1;
46 }
47}
48my @sorted = sort { @$a{'value'} <=> @$b{'value'} } @buttons;
49print <<EOF
50/* Don't change this file! */
51/* It is automatically generated of button.h */
52#include "plugin.h"
53#include "button.h"
54#include "button_helper.h"
55
56static const struct available_button buttons[$count] = {
57EOF
58;
59$count--; # don't count the sentinel
60foreach my $button (@sorted)
61{
62 printf " %s", @$button{'def'};
63}
64
65print <<EOF
66 {"\\0", 0} /* sentinel */
67};
68const int available_button_count = $count;
69const struct available_button * const available_buttons = buttons;
70
71int get_button_names(char *buf, size_t bufsz, unsigned long button)
72{
73 int len = 0;
74 buf[0] = '\\0';
75 const struct available_button *btn = buttons;
76 while(btn->name[0] != '\\0')
77 {
78 if(btn->value == 0)
79 {
80 if (button == 0)
81 {
82 buf[0] = '\\0';
83 len = rb->strlcat(buf, btn->name, bufsz);
84 return len;
85 }
86 }
87 else if ((button & btn->value) == btn->value)
88 {
89 if (len > 0)
90 rb->strlcat(buf, " | ", bufsz);
91 len = rb->strlcat(buf, btn->name, bufsz);
92 }
93 btn++;
94 }
95 return len;
96}
97EOF
98;
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
101 PLUGINLIBFLAGS = $(PLUGINFLAGS) -ffunction-sections -fdata-sections 101 PLUGINLIBFLAGS = $(PLUGINFLAGS) -ffunction-sections -fdata-sections
102endif 102endif
103 103
104ROOT_PLUGINSLIB_DIR := $(ROOTDIR)/apps/plugins/lib
105BUILD_PLUGINSLIB_DIR := $(BUILDDIR)/apps/plugins/lib
106
107# action_helper #
108ACTION_REQ := $(addprefix $(ROOT_PLUGINSLIB_DIR)/,action_helper.pl action_helper.h) \
109 $(BUILD_PLUGINSLIB_DIR)/pluginlib_actions.o
110
111# special rule for generating and compiling action_helper
112$(BUILD_PLUGINSLIB_DIR)/action_helper.o: $(ACTION_REQ)
113 $(SILENT)mkdir -p $(dir $@)
114 $(call PRINTS,GEN $(@F))$(CC) $(PLUGINFLAGS) $(INCLUDES) -E -P \
115 $(ROOT_PLUGINSLIB_DIR)/pluginlib_actions.h - < /dev/null | $< > $(basename $@).c
116 $(call PRINTS,CC $(subst $(ROOTDIR)/,,$<))$(CC) -I$(ROOT_PLUGINSLIB_DIR) \
117 $(PLUGINLIBFLAGS) -c $(basename $@).c -o $@
118
119# button_helper #
120BUTTON_REQ := $(addprefix $(ROOT_PLUGINSLIB_DIR)/,button_helper.pl button_helper.h) \
121 $(BUILD_PLUGINSLIB_DIR)/action_helper.o
122
123# special rule for generating and compiling button_helper
124$(BUILD_PLUGINSLIB_DIR)/button_helper.o: $(BUTTON_REQ) $(ROOTDIR)/firmware/export/button.h
125 $(SILENT)mkdir -p $(dir $@)
126 $(call PRINTS,GEN $(@F))$(CC) $(PLUGINFLAGS) $(INCLUDES) -dM -E -P \
127 $(addprefix -include ,button-target.h button.h) - < /dev/null | $< > $(basename $@).c
128 $(call PRINTS,CC $(subst $(ROOTDIR)/,,$<))$(CC) -I$(ROOT_PLUGINSLIB_DIR) \
129 $(PLUGINLIBFLAGS) -c $(basename $@).c -o $@
130
104# special pattern rule for compiling plugin lib (with function and data sections) 131# special pattern rule for compiling plugin lib (with function and data sections)
105$(BUILDDIR)/apps/plugins/lib/%.o: $(ROOTDIR)/apps/plugins/lib/%.c 132$(BUILD_PLUGINSLIB_DIR)/%.o: $(ROOT_PLUGINSLIB_DIR)/%.c
106 $(SILENT)mkdir -p $(dir $@) 133 $(SILENT)mkdir -p $(dir $@)
107 $(call PRINTS,CC $(subst $(ROOTDIR)/,,$<))$(CC) -I$(dir $<) $(PLUGINLIBFLAGS) -c $< -o $@ 134 $(call PRINTS,CC $(subst $(ROOTDIR)/,,$<))$(CC) -I$(dir $<) $(PLUGINLIBFLAGS) -c $< -o $@
108 135
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 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// __ \_/ ___\| |/ /| __ \ / __ \ \/ /
5 * Jukebox | | ( (__) ) \___| ( | \_\ ( (__) ) (
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2020 William Wilgus
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22/* WIP rb_info common info that you wonder about when rockboxing?
23 */
24
25#include "plugin.h"
26#include "lang_enum.h"
27#include "../open_plugin.h"
28#include "logf.h"
29#include "lib/action_helper.h"
30#include "lib/button_helper.h"
31#include "lib/pluginlib_actions.h"
32
33#define MENU_ID(x) (((void*)&"RPBUTACNGX\0" + x))
34enum {
35 M_ROOT = 0,
36 M_PATHS,
37 M_BUFFERS,
38 M_BUTTONS,
39 M_BTNTEST,
40 M_ACTIONS,
41 M_CONTEXTS,
42 M_ACTTEST,
43 M_PLUGINS,
44 M_EXIT,
45 M_LAST_ITEM //ITEM COUNT
46};
47
48#define MENU_ID_PLUGINS_ITEMS 5
49
50/*Action test and Button test*/
51static struct menu_test_t {
52 int count;
53 int context;
54 int last_btn_or_act;
55} m_test;
56
57struct menu_buffer_t { const char *name; size_t size;};
58static const struct menu_buffer_t m_buffer[] =
59{
60#ifndef MAX_LOGF_SIZE
61#define MAX_LOGF_SIZE (0)
62#endif
63#ifndef CACHE_SIZE
64#define CACHE_SIZE (0)
65#endif
66 {"thread stack", DEFAULT_STACK_SIZE},
67 {"plugin buffer", PLUGIN_BUFFER_SIZE},
68 {"frame_buffer", FRAMEBUFFER_SIZE},
69 {"codec_buffer", CODEC_SIZE},
70 {"logf_buffer", MAX_LOGF_SIZE},
71 {"cache", CACHE_SIZE},
72};
73
74/* stringify the macro value */
75#define MACROVAL(x) MACROSTR(x)
76#define MACROSTR(x) #x
77static int main_last_sel = 0;
78static struct gui_synclist lists;
79static void synclist_set(char*, int, int, int);
80
81struct paths { const char *name; const char *path; };
82static const struct paths paths[] = {
83 {"Home", ""HOME_DIR},
84 {"Rockbox", ""ROCKBOX_DIR},
85 {"Plugins", ""PLUGIN_DIR},
86 {"Codecs", ""CODECS_DIR},
87 {"WPS", ""WPS_DIR},
88 {"SBS", ""SBS_DIR},
89 {"Theme", ""THEME_DIR},
90 {"Font", ""FONT_DIR},
91 {"Icon", ""ICON_DIR},
92 {"Backdrop", ""BACKDROP_DIR},
93 {"Eq", ""EQS_DIR},
94 {"Rec Presets", ""RECPRESETS_DIR},
95 {"Recordings", ""REC_BASE_DIR,},
96 {"Fm Presets", ""FMPRESET_PATH},
97 {"MAX_PATH", ""MACROVAL(MAX_PATH)" bytes"},
98};
99
100struct mainmenu { const char *name; void *menuid; int items;};
101static struct mainmenu mainmenu[M_LAST_ITEM] = {
102#define MENU_ITEM(ID, NAME, COUNT) [ID]{NAME, MENU_ID(ID), (int)COUNT}
103MENU_ITEM(M_ROOT, "Rockbox Info Plugin", M_LAST_ITEM),
104MENU_ITEM(M_PATHS, ID2P(LANG_SHOW_PATH), ARRAYLEN(paths)),
105MENU_ITEM(M_BUFFERS, ID2P(LANG_BUFFER_STAT), ARRAYLEN(m_buffer)),
106MENU_ITEM(M_BUTTONS, "Buttons", -1), /* Set at runtime in plugin_start: */
107MENU_ITEM(M_BTNTEST, "Button test", 2),
108MENU_ITEM(M_ACTIONS, "Actions", LAST_ACTION_PLACEHOLDER),
109MENU_ITEM(M_CONTEXTS, "Contexts", LAST_CONTEXT_PLACEHOLDER ),
110MENU_ITEM(M_ACTTEST, "Action test", 3),
111MENU_ITEM(M_PLUGINS, ID2P(LANG_PLUGINS), MENU_ID_PLUGINS_ITEMS),
112MENU_ITEM(M_EXIT, ID2P(LANG_MENU_QUIT), 0),
113#undef MENU_ITEM
114};
115
116static const struct mainmenu *mainitem(int selected_item)
117{
118 static const struct mainmenu empty = {0};
119 if (selected_item >= 0 && selected_item < (int) ARRAYLEN(mainmenu))
120 return &mainmenu[selected_item];
121 else
122 return &empty;
123}
124
125static void cleanup(void *parameter)
126{
127 (void)parameter;
128
129}
130
131static const char *menu_plugin_name_cb(int selected_item, void* data,
132 char* buf, size_t buf_len)
133{
134 (void)data;
135 buf[0] = '\0';
136 switch(selected_item)
137 {
138 case 0:
139 rb->snprintf(buf, buf_len, "%s: [%d bytes] ", "plugin_api", (int)sizeof(struct plugin_api));
140 break;
141 case 1:
142 rb->snprintf(buf, buf_len, "%s: [%d bytes] ", "plugin buffer", PLUGIN_BUFFER_SIZE);
143 break;
144 case 2:
145 rb->snprintf(buf, buf_len, "%s: [%d bytes] ", "frame_buffer", (int)FRAMEBUFFER_SIZE);
146 break;
147 case 3:
148 rb->snprintf(buf, buf_len, "%s: [W: %d H:%d] ", "LCD", LCD_WIDTH, LCD_HEIGHT);
149 break;
150 case 4:
151 rb->snprintf(buf, buf_len, "%s: [%d bits] ", "fb_data", (int)(sizeof(fb_data) * CHAR_BIT));
152 break;
153 case 5:
154 break;
155 }
156 return buf;
157}
158
159static const char *menu_button_test_name_cb(int selected_item, void* data,
160 char* buf, size_t buf_len)
161{
162 (void)data;
163 int curbtn = BUTTON_NONE;
164 buf[0] = '\0';
165 switch(selected_item)
166 {
167 case 0:
168 rb->snprintf(buf, buf_len, "%s: [%s] ", "Button test",
169 m_test.count > 0 ? "true":"false");
170 break;
171 case 1:
172 if (m_test.count > 0)
173 {
174 if (m_test.count <= 2)
175 curbtn = rb->button_get_w_tmo(HZ * 2);
176 else
177 m_test.last_btn_or_act = BUTTON_NONE;
178 if (curbtn == BUTTON_NONE)
179 {
180 m_test.count--;
181 }
182 else
183 m_test.last_btn_or_act = curbtn;
184 }
185 get_button_names(buf, buf_len, m_test.last_btn_or_act);
186
187 break;
188 }
189 return buf;
190}
191
192static const char *menu_action_test_name_cb(int selected_item, void* data,
193 char* buf, size_t buf_len)
194{
195 (void)data;
196 const char *fmtstr;
197 int curact = ACTION_NONE;
198 buf[0] = '\0';
199 switch(selected_item)
200 {
201 case 0:
202 rb->snprintf(buf, buf_len, "%s: [%s] ", "Action test",
203 m_test.count > 0 ? "true":"false");
204 break;
205 case 1:
206 if (m_test.count <= 0)
207 {
208 if (m_test.context <= 0)
209 fmtstr = "%s > ";
210 else if (m_test.context >= LAST_CONTEXT_PLACEHOLDER - 1)
211 fmtstr = "< %s ";
212 else
213 fmtstr = "< %s > ";
214 }
215 else
216 fmtstr = "%s";
217
218 rb->snprintf(buf, buf_len, fmtstr, context_name(m_test.context));
219 break;
220 case 2:
221 if (m_test.count > 0)
222 {
223 if (m_test.count <= 2)
224 curact = rb->get_action(m_test.context, HZ * 2);
225 else
226 m_test.last_btn_or_act = ACTION_NONE;
227 if (curact == ACTION_NONE && rb->button_get(false) == BUTTON_NONE)
228 {
229 m_test.count--;
230 }
231 else
232 {
233 m_test.last_btn_or_act = curact;
234 m_test.count = 2;
235 }
236 }
237 return action_name(m_test.last_btn_or_act);
238
239 break;
240 }
241 return buf;
242}
243
244static const char* list_get_name_cb(int selected_item, void* data,
245 char* buf, size_t buf_len)
246{
247 buf[0] = '\0';
248 if (data == MENU_ID(M_ROOT))
249 return mainitem(selected_item)->name;
250 else if (selected_item == 0) /*header text*/
251 return mainitem(main_last_sel)->name;
252 else if (selected_item >= mainitem(main_last_sel)->items - 1)
253 return ID2P(LANG_BACK);
254
255 if (data == MENU_ID(M_PATHS))
256 {
257 selected_item--;
258 if (selected_item >= 0 && selected_item < mainitem(M_PATHS)->items)
259 {
260 const struct paths *cur = &paths[selected_item];
261 rb->snprintf(buf, buf_len, "%s: [%s] ", cur->name, cur->path);
262 return buf;
263 }
264 }
265 else if (data == MENU_ID(M_BUTTONS))
266 {
267 const struct available_button *btn = &available_buttons[selected_item - 1];
268 rb->snprintf(buf, buf_len, "%s: [0x%X] ", btn->name, (unsigned int) btn->value);
269 return buf;
270 }
271 else if (data == MENU_ID(M_BTNTEST))
272 return menu_button_test_name_cb(selected_item - 1, data, buf, buf_len);
273 else if (data == MENU_ID(M_ACTIONS))
274 return action_name(selected_item - 1);
275 else if (data == MENU_ID(M_CONTEXTS))
276 return context_name(selected_item - 1);
277 else if (data == MENU_ID(M_ACTTEST))
278 return menu_action_test_name_cb(selected_item - 1, data, buf, buf_len);
279 else if (data == MENU_ID(M_BUFFERS))
280 {
281 const struct menu_buffer_t *bufm = &m_buffer[selected_item - 1];
282 rb->snprintf(buf, buf_len, "%s: [%ld bytes] ", bufm->name, (long)bufm->size);
283 return buf;
284 }
285 else if (data == MENU_ID(M_PLUGINS))
286 {
287 return menu_plugin_name_cb(selected_item - 1, data, buf, buf_len);
288 }
289 return buf;
290}
291
292static int list_voice_cb(int list_index, void* data)
293{
294 if (!rb->global_settings->talk_menu)
295 return -1;
296
297 if (data == MENU_ID(M_ROOT))
298 {
299 const char * name = mainitem(list_index)->name;
300 long id = P2ID((const unsigned char *)name);
301 if(id>=0)
302 rb->talk_id(id, true);
303 else
304 rb->talk_spell(name, true);
305 }
306 else if (data == MENU_ID(M_BUFFERS) || data == MENU_ID(M_PLUGINS))
307 {
308 char buf[64];
309 const char* name = list_get_name_cb(list_index, data, buf, sizeof(buf));
310 long id = P2ID((const unsigned char *)name);
311 if(id>=0)
312 rb->talk_id(id, true);
313 else
314 {
315 char* bytstr = rb->strcasestr(name, "bytes");
316 if (bytstr != NULL)
317 *bytstr = '\0';
318 rb->talk_spell(name, true);
319 }
320 }
321 else
322 {
323 char buf[64];
324 const char* name = list_get_name_cb(list_index, data, buf, sizeof(buf));
325 long id = P2ID((const unsigned char *)name);
326 if(id>=0)
327 rb->talk_id(id, true);
328 else
329 rb->talk_spell(name, true);
330 }
331 return 0;
332}
333
334int menu_action_cb(int action, int selected_item, bool* exit, struct gui_synclist *lists)
335{
336 if (lists->data == MENU_ID(M_ACTTEST))
337 {
338 if (selected_item == 2) /* context */
339 {
340 int ctx = m_test.context;
341 if (action == ACTION_STD_OK)
342 m_test.context++;
343 else if (action == ACTION_STD_CANCEL)
344 m_test.context--;
345
346 if (m_test.context < 0)
347 m_test.context = 0;
348 else if (m_test.context >= LAST_CONTEXT_PLACEHOLDER)
349 m_test.context = LAST_CONTEXT_PLACEHOLDER - 1;
350
351 if (ctx != m_test.context)
352 rb->gui_synclist_speak_item(lists);
353
354 goto default_handler;
355 }
356 if (action == ACTION_STD_OK)
357 {
358 if (selected_item == 1 || selected_item == 3)
359 {
360 m_test.count = 3;
361 rb->gui_synclist_select_item(lists, 3);
362 }
363 }
364 }
365 else if (lists->data == MENU_ID(M_BTNTEST))
366 {
367 if (action == ACTION_STD_OK)
368 {
369 if (selected_item == 1 || selected_item == 2)
370 {
371 m_test.count = 3;
372 rb->gui_synclist_select_item(lists, 2);
373 }
374 }
375 }
376 if (action == ACTION_STD_OK)
377 {
378 if (lists->data == MENU_ID(M_ROOT))
379 {
380 rb->memset(&m_test, 0, sizeof(struct menu_test_t));
381 const struct mainmenu *cur = mainitem(selected_item);
382 if (cur->menuid == NULL || cur->menuid == MENU_ID(M_EXIT))
383 *exit = true;
384 else
385 {
386 main_last_sel = selected_item;
387 synclist_set(cur->menuid, 1, cur->items, 1);
388 rb->gui_synclist_draw(lists);
389 }
390 }
391 else if (selected_item <= 0) /* title */
392 {
393 rb->gui_synclist_select_item(lists, 1);
394 }
395 else if (selected_item >= (mainitem(main_last_sel)->items) - 1)/*back*/
396 {
397 action = ACTION_STD_CANCEL;
398 }
399 else if (lists->data == MENU_ID(M_ACTIONS) ||
400 lists->data == MENU_ID(M_CONTEXTS))
401 {
402 char buf[MAX_PATH];
403 const char *name = list_get_name_cb(selected_item, lists->data, buf, sizeof(buf));
404 /* splash long enough to get fingers off button then wait for new button press */
405 rb->splashf(HZ / 2, "%s %d (0x%X)", name, selected_item -1, selected_item -1);
406 rb->button_get(true);
407 }
408 }
409 if (action == ACTION_STD_CANCEL)
410 {
411 if (lists->data != MENU_ID(M_ROOT))
412 {
413 const struct mainmenu *mainm = &mainmenu[0];
414 synclist_set(mainm->menuid, main_last_sel, mainm->items, 1);
415 rb->gui_synclist_draw(lists);
416 }
417 else
418 *exit = true;
419 }
420default_handler:
421 if (rb->default_event_handler_ex(action, cleanup, NULL) == SYS_USB_CONNECTED)
422 {
423 *exit = true;
424 return PLUGIN_USB_CONNECTED;
425 }
426 return PLUGIN_OK;
427}
428
429static void synclist_set(char* menu_id, int selected_item, int items, int sel_size)
430{
431 if (items <= 0)
432 return;
433 if (selected_item < 0)
434 selected_item = 0;
435
436 list_voice_cb(0, menu_id);
437 rb->gui_synclist_init(&lists,list_get_name_cb,
438 menu_id, false, sel_size, NULL);
439
440 rb->gui_synclist_set_icon_callback(&lists,NULL);
441 rb->gui_synclist_set_voice_callback(&lists, list_voice_cb);
442 rb->gui_synclist_set_nb_items(&lists,items);
443 rb->gui_synclist_limit_scroll(&lists,true);
444 rb->gui_synclist_select_item(&lists, selected_item);
445
446}
447
448enum plugin_status plugin_start(const void* parameter)
449{
450 int ret = PLUGIN_OK;
451 int selected_item = -1;
452 int action;
453 bool redraw = true;
454 bool exit = false;
455 if (parameter)
456 {
457 //
458 }
459 mainmenu[M_BUTTONS].items = available_button_count;
460 /* add header and back item to each submenu */
461 for (int i = 1; i < M_LAST_ITEM; i++)
462 mainmenu[i].items += 2;
463
464 if (!exit)
465 {
466 const struct mainmenu *mainm = &mainmenu[0];
467 synclist_set(mainm->menuid, main_last_sel, mainm->items, 1);
468 rb->gui_synclist_draw(&lists);
469
470 while (!exit)
471 {
472 action = rb->get_action(CONTEXT_LIST, HZ / 10);
473 if (m_test.count > 0)
474 action = ACTION_REDRAW;
475
476 if (action == ACTION_NONE)
477 {
478 if (redraw)
479 {
480 action = ACTION_REDRAW;
481 redraw = false;
482 }
483 }
484 else
485 redraw = true;
486 if (rb->gui_synclist_do_button(&lists,&action,LIST_WRAP_UNLESS_HELD))
487 continue;
488 selected_item = rb->gui_synclist_get_sel_pos(&lists);
489 ret = menu_action_cb(action, selected_item, &exit, &lists);
490 }
491 }
492
493 return ret;
494}