diff options
Diffstat (limited to 'apps/plugins')
-rw-r--r-- | apps/plugins/lua/include_lua/rbsettings.lua | 164 | ||||
-rw-r--r-- | apps/plugins/lua/lua.make | 2 | ||||
-rw-r--r-- | apps/plugins/lua/rocklib.c | 42 | ||||
-rwxr-xr-x | apps/plugins/lua/settings_helper.pl | 5 | ||||
-rw-r--r-- | apps/plugins/lua_scripts/dump_rbsettings.lua | 49 | ||||
-rw-r--r-- | apps/plugins/lua_scripts/track_metadata.lua | 90 |
6 files changed, 342 insertions, 10 deletions
diff --git a/apps/plugins/lua/include_lua/rbsettings.lua b/apps/plugins/lua/include_lua/rbsettings.lua new file mode 100644 index 0000000000..defdb11b77 --- /dev/null +++ b/apps/plugins/lua/include_lua/rbsettings.lua | |||
@@ -0,0 +1,164 @@ | |||
1 | --[[ Lua rb settings reader | ||
2 | /*************************************************************************** | ||
3 | * __________ __ ___. | ||
4 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
5 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
6 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
7 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
8 | * \/ \/ \/ \/ \/ | ||
9 | * $Id$ | ||
10 | * | ||
11 | * Copyright (C) 2019 William Wilgus | ||
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 | ]] | ||
23 | |||
24 | rb.settings = rb.settings or {} | ||
25 | |||
26 | local var = {offset = 1, size = 2, type = 3, fields = 3} | ||
27 | |||
28 | local function bytesLE_n(str) | ||
29 | str = str or "" | ||
30 | local tbyte={str:byte(1, -1)} | ||
31 | local bpos, num = 1, 0 | ||
32 | for k = 1,#tbyte do -- (k = #t, 1, -1 for BE) | ||
33 | num = num + tbyte[k] * bpos | ||
34 | bpos = bpos * 256 --1<<8 | ||
35 | end | ||
36 | return num | ||
37 | end | ||
38 | |||
39 | local function get_var_fields(s_var) | ||
40 | -- converts member string into table | ||
41 | -- var = {offset, size, "type"} | ||
42 | s_var = s_var or "" | ||
43 | local o, s, t = string.match(s_var, "(0x%x+),%s*(%d+),%s*(.+)") | ||
44 | local tvar = {o, s, t} | ||
45 | |||
46 | return #tvar == var.fields and tvar or nil | ||
47 | end | ||
48 | |||
49 | local function format_val(val, var_type) | ||
50 | local ret, num | ||
51 | if var_type == nil then | ||
52 | return nil | ||
53 | elseif var_type == "str" then | ||
54 | -- stop at first null byte, return nil if str doesn't exist | ||
55 | return val and string.match(val, "^%Z+") or nil | ||
56 | end | ||
57 | |||
58 | num = bytesLE_n(val) | ||
59 | if string.find(var_type, "^b") then | ||
60 | if(num <= 0) then | ||
61 | ret = false | ||
62 | else | ||
63 | ret = true | ||
64 | end | ||
65 | elseif string.find(var_type, "^u_[cil]") then | ||
66 | -- Lua integers are signed so we need to do a bit of extra processing | ||
67 | ret = (string.format("%u", num)) | ||
68 | else | ||
69 | ret = num | ||
70 | end | ||
71 | |||
72 | return ret | ||
73 | end | ||
74 | |||
75 | local function dump_struct(t_settings, t_struct, n_elems, t_var) | ||
76 | --Internal function dumps structs | ||
77 | local tdata = {} | ||
78 | |||
79 | local function struct_get_elem(v, elem_offset) | ||
80 | local val, offset, tvar1 | ||
81 | tvar1 = get_var_fields(v) | ||
82 | offset = t_var[var.offset] + tvar1[var.offset] + elem_offset | ||
83 | val = t_settings(offset, tvar1[var.size]) | ||
84 | return format_val(val, tvar1[var.type]) | ||
85 | end | ||
86 | |||
87 | if n_elems > 0 then | ||
88 | -- Array of structs, struct[elems]; | ||
89 | local elemsize = (t_var[var.size] / n_elems) | ||
90 | for i = 0, n_elems - 1 do | ||
91 | tdata[i] = tdata[i] or {} | ||
92 | for k1, v1 in pairs(t_struct) do | ||
93 | tdata[i][k1] = struct_get_elem(v1, (elemsize * i)) | ||
94 | end | ||
95 | end | ||
96 | else | ||
97 | -- single struct, struct; | ||
98 | for k1, v1 in pairs(t_struct) do | ||
99 | tdata[k1] = struct_get_elem(v1, 0) | ||
100 | end | ||
101 | end | ||
102 | return tdata | ||
103 | end | ||
104 | |||
105 | local function get_array_elems(var_type) | ||
106 | --extract the number of elements, returns 0 if not found | ||
107 | local elems = string.match(var_type,".*%[(%d+)%]") | ||
108 | return tonumber(elems) or 0 | ||
109 | end | ||
110 | |||
111 | local function get_struct_name(var_type) | ||
112 | --extract the name of a struct, returns nil if not found | ||
113 | return string.match(var_type,"^s_([^%[%]%s]+)") | ||
114 | end | ||
115 | |||
116 | function rb.settings.read(s_settings, s_var, s_groupname) | ||
117 | local data, val | ||
118 | local tvar = get_var_fields(s_var) | ||
119 | if tvar == nil then return nil end | ||
120 | |||
121 | local elems = get_array_elems(tvar[var.type]) | ||
122 | local structname = get_struct_name(tvar[var.type]) | ||
123 | |||
124 | local tsettings = rb[s_settings] | ||
125 | if not tsettings then error(s_settings .. " does not exist") end | ||
126 | |||
127 | if structname and rb[s_groupname] then | ||
128 | return dump_struct(tsettings, rb[s_groupname][structname], elems, tvar) | ||
129 | end | ||
130 | |||
131 | local voffset, vsize, vtype = tvar[var.offset], tvar[var.size], tvar[var.type] | ||
132 | if elems > 0 then | ||
133 | -- Arrays of values, val[elems]; | ||
134 | data = {} | ||
135 | local elemsize = (vsize / elems) | ||
136 | |||
137 | for i = 0, elems - 1 do | ||
138 | val = tsettings(voffset + (elemsize * i), elemsize) | ||
139 | data[i] = format_val(val, vtype) | ||
140 | end | ||
141 | else | ||
142 | -- Single value, val; | ||
143 | if vtype == "ptr_char" then -- (**char) | ||
144 | vtype = "str" | ||
145 | val = tsettings(voffset, vsize, nil, true) | ||
146 | else | ||
147 | val = tsettings(voffset, vsize) | ||
148 | end | ||
149 | data = format_val(val, vtype) | ||
150 | end | ||
151 | return data | ||
152 | end | ||
153 | |||
154 | function rb.settings.dump(s_settings, s_groupname, s_structname, t_output) | ||
155 | t_output = t_output or {} | ||
156 | local tgroup = rb[s_groupname] | ||
157 | s_structname = s_structname or s_settings | ||
158 | for k, v in pairs(tgroup[s_structname]) do | ||
159 | t_output[k] = rb.settings.read(s_settings, v, s_groupname) | ||
160 | end | ||
161 | return t_output | ||
162 | end | ||
163 | |||
164 | return true | ||
diff --git a/apps/plugins/lua/lua.make b/apps/plugins/lua/lua.make index 66c1e67855..5e46692f3f 100644 --- a/apps/plugins/lua/lua.make +++ b/apps/plugins/lua/lua.make | |||
@@ -19,7 +19,7 @@ LUA_INCLUDEDIR := $(LUA_SRCDIR)/include_lua | |||
19 | LUA_INCLUDELIST := $(addprefix $(LUA_BUILDDIR)/,audio.lua blit.lua color.lua draw.lua draw_floodfill.lua draw_poly.lua \ | 19 | LUA_INCLUDELIST := $(addprefix $(LUA_BUILDDIR)/,audio.lua blit.lua color.lua draw.lua draw_floodfill.lua draw_poly.lua \ |
20 | draw_num.lua draw_text.lua image.lua image_save.lua lcd.lua math_ex.lua \ | 20 | draw_num.lua draw_text.lua image.lua image_save.lua lcd.lua math_ex.lua \ |
21 | print.lua timer.lua playlist.lua pcm.lua sound.lua \ | 21 | print.lua timer.lua playlist.lua pcm.lua sound.lua \ |
22 | rbcompat.lua poly_points.lua printtable.lua) | 22 | rbcompat.lua rbsettings.lua poly_points.lua printtable.lua) |
23 | 23 | ||
24 | 24 | ||
25 | ifndef APP_TYPE | 25 | ifndef APP_TYPE |
diff --git a/apps/plugins/lua/rocklib.c b/apps/plugins/lua/rocklib.c index 3c38440850..033975d7fe 100644 --- a/apps/plugins/lua/rocklib.c +++ b/apps/plugins/lua/rocklib.c | |||
@@ -640,8 +640,12 @@ RB_WRAP(strncasecmp) | |||
640 | return 1; | 640 | return 1; |
641 | } | 641 | } |
642 | 642 | ||
643 | static int mem_read_write(lua_State *L, uintptr_t address, size_t maxsize) | 643 | static int mem_read_write(lua_State *L, uintptr_t address, size_t maxsize, bool isstr_p) |
644 | { | 644 | { |
645 | if(isstr_p) /*pointer to string (**char)*/ | ||
646 | { | ||
647 | lua_settop(L, 2); /* no writes allowed */ | ||
648 | } | ||
645 | intptr_t offset = (intptr_t) luaL_optnumber(L, 1, 0); | 649 | intptr_t offset = (intptr_t) luaL_optnumber(L, 1, 0); |
646 | size_t size = (size_t) luaL_optnumber(L, 2, maxsize); | 650 | size_t size = (size_t) luaL_optnumber(L, 2, maxsize); |
647 | size_t written; | 651 | size_t written; |
@@ -716,6 +720,11 @@ static int mem_read_write(lua_State *L, uintptr_t address, size_t maxsize) | |||
716 | case LUA_TNIL: | 720 | case LUA_TNIL: |
717 | case LUA_TNONE: /* reader */ | 721 | case LUA_TNONE: /* reader */ |
718 | { | 722 | { |
723 | if(isstr_p && mem) | ||
724 | { | ||
725 | lua_pushstring (L, *(char**) mem); | ||
726 | return 1; | ||
727 | } | ||
719 | luaL_Buffer b; | 728 | luaL_Buffer b; |
720 | luaL_buffinit(L, &b); | 729 | luaL_buffinit(L, &b); |
721 | while(size > 0) | 730 | while(size > 0) |
@@ -746,32 +755,51 @@ RB_WRAP(global_status) | |||
746 | { | 755 | { |
747 | const uintptr_t address = (uintptr_t) rb->global_status; | 756 | const uintptr_t address = (uintptr_t) rb->global_status; |
748 | const size_t maxsize = sizeof(struct system_status); | 757 | const size_t maxsize = sizeof(struct system_status); |
749 | return mem_read_write(L, address, maxsize); | 758 | /*const bool isstr_p = lua_toboolean(L, 4);*/ |
759 | return mem_read_write(L, address, maxsize, false); | ||
750 | } | 760 | } |
751 | 761 | ||
752 | RB_WRAP(global_settings) | 762 | RB_WRAP(global_settings) |
753 | { | 763 | { |
754 | const uintptr_t address = (uintptr_t) rb->global_settings; | 764 | const uintptr_t address = (uintptr_t) rb->global_settings; |
755 | const size_t maxsize = sizeof(struct user_settings); | 765 | const size_t maxsize = sizeof(struct user_settings); |
756 | return mem_read_write(L, address, maxsize); | 766 | /*const bool isstr_p = lua_toboolean(L, 4);*/ |
767 | return mem_read_write(L, address, maxsize, false); | ||
757 | } | 768 | } |
758 | 769 | ||
759 | RB_WRAP(audio_next_track) | 770 | RB_WRAP(audio_next_track) |
760 | { | 771 | { |
761 | lua_settop(L, 2); /* no writes allowed */ | 772 | |
762 | const uintptr_t address = (uintptr_t) rb->audio_next_track(); | 773 | const uintptr_t address = (uintptr_t) rb->audio_next_track(); |
763 | const size_t maxsize = sizeof(struct mp3entry); | 774 | const size_t maxsize = sizeof(struct mp3entry); |
764 | return mem_read_write(L, address, maxsize); | 775 | const bool isstr_p = lua_toboolean(L, 4); |
776 | lua_settop(L, 2); /* no writes allowed */ | ||
777 | return mem_read_write(L, address, maxsize, isstr_p); | ||
765 | } | 778 | } |
766 | 779 | ||
767 | RB_WRAP(audio_current_track) | 780 | RB_WRAP(audio_current_track) |
768 | { | 781 | { |
769 | lua_settop(L, 2); /* no writes allowed */ | 782 | |
770 | const uintptr_t address = (uintptr_t) rb->audio_current_track(); | 783 | const uintptr_t address = (uintptr_t) rb->audio_current_track(); |
771 | const size_t maxsize = sizeof(struct mp3entry); | 784 | const size_t maxsize = sizeof(struct mp3entry); |
772 | return mem_read_write(L, address, maxsize); | 785 | const bool isstr_p = lua_toboolean(L, 4); |
786 | lua_settop(L, 2); /* no writes allowed */ | ||
787 | return mem_read_write(L, address, maxsize, isstr_p); | ||
773 | } | 788 | } |
774 | 789 | ||
790 | #if 0 | ||
791 | RB_WRAP(read_mem) | ||
792 | { | ||
793 | lua_settop(L, 2); /* no writes allowed */ | ||
794 | const uintptr_t address = lua_tonumber(L, 1); | ||
795 | const size_t maxsize = luaL_optnumber(L, 2, strlen((char *)address)); | ||
796 | luaL_argcheck(L, address > 0, 1, ERR_IDX_RANGE); | ||
797 | lua_pushnil(L); | ||
798 | lua_replace(L, -3);/* stk pos 1 is no longer offset it is starting address */ | ||
799 | return mem_read_write(L, address, maxsize, false); | ||
800 | } | ||
801 | #endif | ||
802 | |||
775 | RB_WRAP(restart_lua) | 803 | RB_WRAP(restart_lua) |
776 | { | 804 | { |
777 | /*close lua state, open a new lua state, load script @ filename */ | 805 | /*close lua state, open a new lua state, load script @ filename */ |
diff --git a/apps/plugins/lua/settings_helper.pl b/apps/plugins/lua/settings_helper.pl index 2945afd354..4a280e60c7 100755 --- a/apps/plugins/lua/settings_helper.pl +++ b/apps/plugins/lua/settings_helper.pl | |||
@@ -293,7 +293,7 @@ sub Print_Variable { | |||
293 | $type = sprintf('%s[%d]', $1, $arr); | 293 | $type = sprintf('%s[%d]', $1, $arr); |
294 | } | 294 | } |
295 | 295 | ||
296 | printf "\t%s = {0x%x, %d, \"%s\"},\n", $member, $offset, $size, $type; | 296 | printf "\t%s = \"0x%x, %d, %s\",\n", $member, $offset, $size, $type; |
297 | return 1; | 297 | return 1; |
298 | } | 298 | } |
299 | return 0; | 299 | return 0; |
@@ -303,7 +303,7 @@ if($header) #output sections to lua file [PASS 2] | |||
303 | { | 303 | { |
304 | print "-- Don't change this file!\n"; | 304 | print "-- Don't change this file!\n"; |
305 | printf "-- It is automatically generated %s\n", $svnrev; | 305 | printf "-- It is automatically generated %s\n", $svnrev; |
306 | print "-- member = {offset, size, \"type\"}\n\n"; | 306 | print "-- member = \"offset, size, type\"\n\n"; |
307 | 307 | ||
308 | print "--"; | 308 | print "--"; |
309 | foreach my $key (sort(keys %replace_type_prefix)) { | 309 | foreach my $key (sort(keys %replace_type_prefix)) { |
@@ -337,6 +337,7 @@ if($header) #output sections to lua file [PASS 2] | |||
337 | } | 337 | } |
338 | } | 338 | } |
339 | } | 339 | } |
340 | print "\nreturn false\n"; | ||
340 | #my ($user,$system,$cuser,$csystem) = times; | 341 | #my ($user,$system,$cuser,$csystem) = times; |
341 | #warn "Pass2 ".$user." ".$system." ".$cuser." ".$csystem."\n"; | 342 | #warn "Pass2 ".$user." ".$system." ".$cuser." ".$csystem."\n"; |
342 | exit; | 343 | exit; |
diff --git a/apps/plugins/lua_scripts/dump_rbsettings.lua b/apps/plugins/lua_scripts/dump_rbsettings.lua new file mode 100644 index 0000000000..2811d27487 --- /dev/null +++ b/apps/plugins/lua_scripts/dump_rbsettings.lua | |||
@@ -0,0 +1,49 @@ | |||
1 | require("rbsettings") | ||
2 | require("settings") | ||
3 | rb.metadata = nil -- remove track metadata settings | ||
4 | ------------------------------------------------------------------------------- | ||
5 | |||
6 | local function print_setting_table(t_tbl, s_sep) | ||
7 | s_sep = s_sep or "" | ||
8 | local str = "" | ||
9 | local function pfunct(t, sep, s, n) -- recursive print function | ||
10 | local vtype | ||
11 | for k, v in pairs(t) do | ||
12 | vtype = type(v) | ||
13 | if vtype == "table" then | ||
14 | local f = string.format("%s[%s]", n, k) | ||
15 | s = pfunct(v, sep, s, f) | ||
16 | elseif vtype == "boolean" then | ||
17 | v = v and "true" or "false" | ||
18 | s = string.format("%s%s[%s] = %s%s", s, n, k, v, sep) | ||
19 | elseif v then | ||
20 | s = string.format("%s%s[%s] = %s%s", s, n, k, v, sep) | ||
21 | end | ||
22 | end | ||
23 | return s | ||
24 | end | ||
25 | return pfunct(t_tbl, s_sep, str, "") | ||
26 | end | ||
27 | |||
28 | local filename = "/settings.txt" | ||
29 | local file = io.open(filename, "w+") -- overwrite | ||
30 | local t_settings | ||
31 | |||
32 | if not file then | ||
33 | rb.splash(rb.HZ, "Error writing " .. filename) | ||
34 | return | ||
35 | end | ||
36 | |||
37 | t_settings = rb.settings.dump('global_settings', "system") | ||
38 | file:write("global_settings:\n") | ||
39 | file:write(print_setting_table(t_settings, "\n")) | ||
40 | file:write("\n\n") | ||
41 | |||
42 | t_settings = rb.settings.dump('global_status', "system") | ||
43 | file:write("global_status:\n") | ||
44 | file:write(print_setting_table(t_settings, "\n")) | ||
45 | file:write("\n\n") | ||
46 | |||
47 | file:close() | ||
48 | |||
49 | rb.splash(100, "rb settings dumped: " .. filename) | ||
diff --git a/apps/plugins/lua_scripts/track_metadata.lua b/apps/plugins/lua_scripts/track_metadata.lua new file mode 100644 index 0000000000..08c1c865f3 --- /dev/null +++ b/apps/plugins/lua_scripts/track_metadata.lua | |||
@@ -0,0 +1,90 @@ | |||
1 | require("rbsettings") | ||
2 | require("settings") --settings.lua | ||
3 | rb.system = nil -- remove system settings | ||
4 | ------------------------------------------------------------------------------- | ||
5 | local track_data = rb.metadata.mp3_entry | ||
6 | local cur_trk = "audio_current_track" | ||
7 | ------------------------------------------------------------------------------- | ||
8 | local trackname = rb.settings.read(cur_trk, track_data.title) or | ||
9 | rb.settings.read(cur_trk, track_data.path) | ||
10 | if not trackname or trackname == "" then | ||
11 | os.exit(1, "No track loaded") | ||
12 | else | ||
13 | rb.splash(100, trackname) | ||
14 | end | ||
15 | ------------------------------------------------------------------------------- | ||
16 | local function dump_albumart(fileout) | ||
17 | local t_albumart = rb.settings.read(cur_trk, track_data.albumart, "metadata") | ||
18 | local t_aaext = {".bmp",".png", ".jpg"} | ||
19 | local path = rb.settings.read(cur_trk, track_data.path) | ||
20 | if t_albumart.pos > 0 and t_albumart.size > 0 and t_albumart.type > 0 then | ||
21 | |||
22 | if t_aaext[t_albumart.type] then | ||
23 | local filename = "/" .. fileout .. t_aaext[t_albumart.type] | ||
24 | local aa = io.open(filename, "w+") -- overwrite | ||
25 | if not aa then | ||
26 | rb.splash(rb.HZ, "Error writing " .. filename) | ||
27 | return | ||
28 | end | ||
29 | |||
30 | local track = io.open(path, "r") | ||
31 | if not track then | ||
32 | rb.splash(rb.HZ, "Error opening " .. path) | ||
33 | return | ||
34 | end | ||
35 | track:seek("set", t_albumart.pos ) | ||
36 | for i = 0, t_albumart.size, 32 do | ||
37 | aa:write(track:read(32)) | ||
38 | end | ||
39 | rb.splash(rb.HZ, "Saved: " .. filename) | ||
40 | track:close() | ||
41 | aa:close() | ||
42 | else | ||
43 | |||
44 | end | ||
45 | end | ||
46 | end | ||
47 | |||
48 | local function print_setting_table(t_tbl, s_sep) | ||
49 | s_sep = s_sep or "" | ||
50 | local str = "" | ||
51 | local function pfunct(t, sep, s, n) -- recursive print function | ||
52 | local vtype | ||
53 | for k, v in pairs(t) do | ||
54 | vtype = type(v) | ||
55 | if vtype == "table" then | ||
56 | local f = string.format("%s[%s]", n, k) | ||
57 | s = pfunct(v, sep, s, f) | ||
58 | elseif vtype == "boolean" then | ||
59 | v = v and "true" or "false" | ||
60 | s = string.format("%s%s[%s] = %s%s", s, n, k, v, sep) | ||
61 | elseif v then | ||
62 | s = string.format("%s%s[%s] = %s%s", s, n, k, v, sep) | ||
63 | end | ||
64 | end | ||
65 | return s | ||
66 | end | ||
67 | return pfunct(t_tbl, s_sep, str, "") | ||
68 | end | ||
69 | |||
70 | local filename = "/metadata.txt" | ||
71 | local file = io.open(filename, "w+") -- overwrite | ||
72 | local t_settings | ||
73 | |||
74 | if not file then | ||
75 | rb.splash(rb.HZ, "Error writing " .. filename) | ||
76 | return | ||
77 | end | ||
78 | |||
79 | ---[[ | ||
80 | t_settings = rb.settings.dump(cur_trk, "metadata", "mp3_entry") | ||
81 | file:write(trackname .. ":\n") | ||
82 | file:write(print_setting_table(t_settings, "\n")) | ||
83 | file:write("\n\n") | ||
84 | file:close() | ||
85 | |||
86 | rb.splash(100, "metadata dumped: " .. filename) | ||
87 | |||
88 | if rb.settings.read(cur_trk, track_data.has_embedded_albumart) then | ||
89 | dump_albumart("/albumart") | ||
90 | end | ||