From 9d66b5459ecb9f85ffb194194abca5d46535774f Mon Sep 17 00:00:00 2001 From: William Wilgus Date: Sat, 15 Dec 2018 13:50:00 -0600 Subject: Lua add read/write access to global_status, global_settings, audio_current_track moved items to rb.system added read access to audio_current_track and audio_next_track Change-Id: Ia055b8cb3848e540067818f596ffd1058da057fb --- apps/plugins/lua/lua.make | 7 +- apps/plugins/lua/rocklib.c | 137 +++++++++++++ apps/plugins/lua/settings_helper.pl | 397 ++++++++++++++++++++++++++++++++++++ 3 files changed, 540 insertions(+), 1 deletion(-) create mode 100755 apps/plugins/lua/settings_helper.pl (limited to 'apps') diff --git a/apps/plugins/lua/lua.make b/apps/plugins/lua/lua.make index a464bddace..ef9705a63d 100644 --- a/apps/plugins/lua/lua.make +++ b/apps/plugins/lua/lua.make @@ -35,11 +35,16 @@ else ROCKS += $(LUA_BUILDDIR)/lua.rock endif -$(LUA_BUILDDIR)/lua.rock: $(LUA_OBJ) $(TLSFLIB) $(LUA_BUILDDIR)/actions.lua $(LUA_BUILDDIR)/buttons.lua $(LUA_BUILDDIR)/rocklib_aux.o $(LUA_INCLUDELIST) +$(LUA_BUILDDIR)/lua.rock: $(LUA_OBJ) $(TLSFLIB) $(LUA_BUILDDIR)/actions.lua $(LUA_BUILDDIR)/buttons.lua $(LUA_BUILDDIR)/settings.lua $(LUA_BUILDDIR)/rocklib_aux.o $(LUA_INCLUDELIST) $(LUA_BUILDDIR)/actions.lua: $(LUA_OBJ) $(LUA_SRCDIR)/action_helper.pl $(call PRINTS,GEN $(@F))$(CC) $(PLUGINFLAGS) $(INCLUDES) -E $(APPSDIR)/plugins/lib/pluginlib_actions.h | $(LUA_SRCDIR)/action_helper.pl > $(LUA_BUILDDIR)/actions.lua +$(LUA_BUILDDIR)/settings.lua: $(LUA_OBJ) $(LUA_SRCDIR)/settings_helper.pl + $(SILENT)$(CC) $(INCLUDES) -E $(TARGET) $(CFLAGS) -include plugin.h -include cuesheet.h - < /dev/null | $(LUA_SRCDIR)/settings_helper.pl | \ + $(CC) $(INCLUDES) $(TARGET) $(CFLAGS) -S -x c -include config.h -include plugin.h -o $(LUA_BUILDDIR)/settings_helper.s - + $(call PRINTS,GEN $(@F))$(LUA_SRCDIR)/settings_helper.pl < $(LUA_BUILDDIR)/settings_helper.s > $(LUA_BUILDDIR)/settings.lua + HOST_INCLUDES := $(filter-out %/libc/include,$(INCLUDES)) $(LUA_BUILDDIR)/buttons.lua: $(LUA_OBJ) $(LUA_SRCDIR)/button_helper.pl $(SILENT)$(CC) $(INCLUDES) -dM -E -include button-target.h - < /dev/null | $(LUA_SRCDIR)/button_helper.pl | $(HOSTCC) -fno-builtin $(HOST_INCLUDES) -x c -o $(LUA_BUILDDIR)/button_helper - diff --git a/apps/plugins/lua/rocklib.c b/apps/plugins/lua/rocklib.c index a6a23f3381..6c96f37a94 100644 --- a/apps/plugins/lua/rocklib.c +++ b/apps/plugins/lua/rocklib.c @@ -564,6 +564,137 @@ RB_WRAP(strncasecmp) return 1; } +static int mem_read_write(lua_State *L, uintptr_t address, size_t maxsize) +{ + intptr_t offset = (intptr_t) luaL_optint(L, 1, 0); + size_t size = (size_t) luaL_optint(L, 2, maxsize); + size_t written; + int type = lua_type(L, 3); + + if(offset < 0) + { + /* allows pointer within structure to be calculated offset */ + offset = -(address + offset); + size = (size_t) maxsize - offset; + } + + luaL_argcheck(L, ((uintptr_t) offset) + size <= maxsize, 2, ERR_IDX_RANGE); + + char *mem = (char*) address + ((uintptr_t) offset); + const void *value = NULL; + + lua_Integer var_luaint; +#ifdef UINT64_MAX + int64_t var_64; +#endif + int32_t var_32; + int16_t var_16; + int8_t var_8; + bool var_bool; + + switch(type) + { + case LUA_TSTRING: + { + size_t len; + const char* str = lua_tolstring (L, 3, &len); + + luaL_argcheck(L, len + 1 <= size, 3, ERR_DATA_OVF); + size = len + 1; /* include \0 */ + value = str; + break; + } + case LUA_TBOOLEAN: + { + var_bool = (bool) lua_toboolean(L, 3); + value = &var_bool; + break; + } + case LUA_TNUMBER: + { + var_luaint = lua_tointeger(L, 3); + switch(size) + { + case sizeof(var_8): + var_8 = (int8_t) var_luaint; + value = &var_8; + break; + case sizeof(var_16): + var_16 = (int16_t) var_luaint; + value = &var_16; + break; + case sizeof(var_32): + var_32 = (int32_t) var_luaint; + value = &var_32; + break; +#ifdef UINT64_MAX + case sizeof(var_64): + var_64 = (int64_t) var_luaint; + value = &var_64; + break; +#endif + } /* switch size */ + break; + } + case LUA_TNIL: + case LUA_TNONE: /* reader */ + { + luaL_Buffer b; + luaL_buffinit(L, &b); + while(size > 0) + { + written = MIN(LUAL_BUFFERSIZE, size); + luaL_addlstring (&b, mem, written); + mem += written; + size -= written; + } + + luaL_pushresult(&b); + return 1; + } + + default: + break; + } /* switch type */ + + /* writer */ + luaL_argcheck(L, value != NULL, 3, "Unknown Type"); + rb->memcpy(mem, value, size); + lua_pushinteger(L, 1); + + return 1; +} + +RB_WRAP(global_status) +{ + const uintptr_t address = (uintptr_t) rb->global_status; + const size_t maxsize = sizeof(struct system_status); + return mem_read_write(L, address, maxsize); +} + +RB_WRAP(global_settings) +{ + const uintptr_t address = (uintptr_t) rb->global_settings; + const size_t maxsize = sizeof(struct user_settings); + return mem_read_write(L, address, maxsize); +} + +RB_WRAP(audio_next_track) +{ + lua_settop(L, 2); /* no writes allowed */ + const uintptr_t address = (uintptr_t) rb->audio_next_track(); + const size_t maxsize = sizeof(struct mp3entry); + return mem_read_write(L, address, maxsize); +} + +RB_WRAP(audio_current_track) +{ + lua_settop(L, 2); /* no writes allowed */ + const uintptr_t address = (uintptr_t) rb->audio_current_track(); + const size_t maxsize = sizeof(struct mp3entry); + return mem_read_write(L, address, maxsize); +} + #define RB_FUNC(func) {#func, rock_##func} #define RB_ALIAS(name, func) {name, rock_##func} static const luaL_Reg rocklib[] = @@ -625,6 +756,12 @@ static const luaL_Reg rocklib[] = RB_FUNC(utf8encode), RB_FUNC(strncasecmp), + /* ROCKBOX SETTINGS / INFO */ + RB_FUNC(global_status), + RB_FUNC(global_settings), + RB_FUNC(audio_next_track), + RB_FUNC(audio_current_track), + {NULL, NULL} }; #undef RB_FUNC diff --git a/apps/plugins/lua/settings_helper.pl b/apps/plugins/lua/settings_helper.pl new file mode 100755 index 0000000000..215d3a2a3c --- /dev/null +++ b/apps/plugins/lua/settings_helper.pl @@ -0,0 +1,397 @@ +#!/usr/bin/env perl +############################################################################ +# __________ __ ___. +# Open \______ \ ____ ____ | | _\_ |__ _______ ___ +# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / +# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < +# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ +# \/ \/ \/ \/ \/ +# $Id$ +# +# Copyright (C) 2018 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. +# +############################################################################ + +# Extracts members from c struct +# places them in a lua array 'member = {offset,size,"type"}' +# requires two passes +# first pass outputs a c file that shall be compiled with the -S option +# second pass extracts the member, offset, size, type from the assembly + +my $svnrev = '$Revision$'; +my $helper_name = 'LUA_RB_SETTINGS_H_HELPER'; + +############# configuration ############# +my @sections = ( + '', + 'struct system_status', + 'struct user_settings', + 'struct replaygain_settings', + 'struct eq_band_setting', + 'struct compressor_settings', + 'struct mp3_enc_config', + '', + 'struct mp3entry', + 'struct mp3_albumart', + 'struct embedded_cuesheet', + #'struct cuesheet', + #'struct cue_track_info', +); + +my @sections_lua = ( + 'rb.system', + 'rb.system.global_status', + 'rb.system.global_settings', + 'rb.system.replaygain_settings', + 'rb.system.eq_band_setting', + 'rb.system.compressor_settings', + 'rb.system.mp3_enc_config', + 'rb.metadata', + 'rb.metadata.mp3_entry', + 'rb.metadata.mp3_albumart', + 'rb.metadata.embedded_cuesheet', + #'rb.metadata.cuesheet', + #'rb.metadata.cue_track_info', +); + +# structs will have their dependencies included automagically +my @includes = (); + +my $section_lua_suffix = ''; + +my %replace_type_prefix = ( + unsigned => 'u_', + signed => '', + struct => 's_', + const => 'const_', + enum => 'e_', + '#pointer#' => 'ptr_', +); + +my %replace_type = ( + int => 'i', + uint => 'u_i', + long => 'l', + char => 'c', + bool => 'b', + double => 'd', + '#string#' => 'str', +); + +############# internal ############# +my @section_count = (); #variables found +my @section_found = (); #{} bracket matches +my @section_lists = (); #variable declarations +my @section_asm_regex = (); +my @section_begin_regex = (); + +my $header = ''; +my $array_marker = '_typeisarray_'; +my $pointer_marker = '_typeisptr_'; +my $current_include; + +############# precompile regex for speed ############# +my $array_mark_regex = qr/^.*${array_marker}$/; +my $pointer_mark_regex = qr/^(.*)${pointer_marker}.*$/; + +my $incl_regex = qr/^.*\".+\/(.+\.h)\".*$/; +my $extern_regex = qr/^extern\b.*$/; + +#type var ????; +my $decl_regex = qr/^(.+?\s.+;)/; +my $typevar_regex = qr/\W*(?.*?)\W*(?[^\s\[]+)(?)\W*;/; +my$typevar_array_regex = qr/\W*(?.*?)\W*(?[^\s\[]+)\W*(?\[.+\]).*;/; + +#.."section",.."member"..=..offset,..size,..type,..arrayct +my $asm_regex = qr/.*?,.*?(\".+?\".*?=.*?,.+?,.+?\".+\".*?,.*);/; +my $asmMOST_regex = qr/\"(?.+)\"=(?\d+),(?\d+),\"(?.+)\",(?\d+).*/; + +for(my $i = 0; $i < @sections; $i++) +{ + $section_asm_regex[$i] = qr/\"$sections[$i]\"${asm_regex}/; + $section_begin_regex[$i] = qr/^$sections[$i]\b\s*+[^\*;]*$/; + $section_count[$i] = 0; + $section_found[$i] = 0; + $section_lists[$i] = ''; +} + +my $section_end_regex = qr/}\s*;.*$/; + +####################################################### +#extract all the variables within the structs(sections) +####################################################### +while(my $line = ) +{ + next if($line =~ /^\s+$/); + + chomp($line); + + if($header) #second pass + { + for(my $i = 0; $i < @sections; $i++) + { + next if(!$sections[$i]); + + if($line =~ $section_asm_regex[$i]) + { + $section_lists[$i] .= $1.'@'; + $section_count[$i]++; + last; + } + } + } + elsif($line =~ s/$helper_name\W*//) #is this the second pass? + { + $header = $line; + #warn $header."\n"; + for(my $i = 0; $i < @sections; $i++) + { + @section_lists[$i] = ''; + @section_count[$i] = 0; + } + } + else #first pass + { + if($line =~ $incl_regex){$current_include = $1; next;} + elsif($line =~ $extern_regex){next;} + + for(my $i = 0; $i < @sections; $i++) + { + next if(!$sections[$i]); + + if($section_found[$i] > 0) + { + # variable declaration? + if($line =~ $decl_regex) + { + $section_lists[$i] .= $1.'@'; + $section_count[$i]++; + } + + # struct end? + if($line =~ $section_end_regex) + { + $section_found[$i]--; + } + last; + } + elsif($line =~ $section_begin_regex[$i]) # struct begin? + { + if($current_include) + { + push (@includes, $current_include); + $current_include = ''; + } + $section_found[$i]++; + $section_lists[$i] = ''; + $section_count[$i] = 0; + last; + } + } + }#else +} + +for(my $i = 0; $i < @sections; $i++) +{ + if($section_found[$i]) + { + warn "$0 Warning formatting error in: $sections[$i]\n"; + } +} + +sub Extract_Variable { + #extracts the member, offset, size, and type from the include file + my $sinput = $_[0]; + my ($type, $var, $arr); + + $sinput =~ s{\s*\*\s*}{${pointer_marker}}gx; + if($sinput =~ $typevar_array_regex) #arrays + { + $type = $+{type}; + $var = $+{var}; + $arr = $+{var}; + if($sinput =~ s/\bchar\b//){$type = $replace_type{'#string#'};} + else{$type .= ${array_marker};} #for identification of array .. stripped later + } + elsif($sinput =~ $typevar_regex) + { + $type = $+{type}; + $var = $+{var}; + $arr = $+{var}; + } + else { return ('', '', ''); } + + $type =~ s/^(unsigned|signed|struct)/$replace_type_prefix{$1}/x; + $type =~ s/\b(const|enum)\b/$replace_type_prefix{$1}/gx; + $type =~ s/^(?:.?+)(bool)\b/$replace_type{lc $1}/ix; + $type =~ s/^(uint|int)(?:\d\d_t)\b/$replace_type{lc $1}/ix; + $type =~ s/\b(int|long|char|double)(${array_marker}.*)?\b/$replace_type{$1}$2/; + $type =~ s{\s+}{}gx; + + $var =~ s{[^\w\d_]+}{}gx; #strip non conforming chars + + $arr =~ s{[^\[\d\]]+}{}gx; + + return ($type, $var, $arr); +} + +sub Print_Variable { + #prints the member, offset, size, and type from the assembly file + my $sinput = $_[0]; + my ($member, $offset, $size, $type, $arr); + + $sinput =~ s{[^\w\d_,=\"\*]+}{}gx; + if($sinput =~ $asmMOST_regex) + { + $member = $+{member}; + $offset = $+{offset}; + $size = $+{size}; + $type = $+{type}; + $arr = $+{arr}; + + if($type =~ /^(.*)${array_marker}$/) #strip array marker add [n] + { + $type = sprintf('%s[%d]', $1, $arr); + } + + printf "\t%s = {0x%x, %d, \"%s\"},\n", $member, $offset, $size, $type; + return 1; + } + return 0; +} + +if($header) #output sections to lua file +{ + print "-- Don't change this file!\n"; + printf "-- It is automatically generated %s\n", $svnrev; + print "-- member = {offset, size, \"type\"}\n\n"; + + print "--"; + foreach my $key (sort(keys %replace_type_prefix)) { + print $key, '= \'', $replace_type_prefix{$key}, '\', '; + } + print "\n--"; + foreach my $key (sort(keys %replace_type)) { + print $key, '= \'', $replace_type{$key}, '\', '; + } + print "\n\n"; + + for(my $i = 0; $i < @sections_lua; $i++) + { + if($sections_lua[$i]) + { + print "$sections_lua[$i]$section_lua_suffix = {\n"; + + my @members=split('@', $section_lists[$i]); + $section_lists[$i] = ''; + + foreach my $memb(@members) + { + $section_count[$i] -= Print_Variable($memb); + } + + print "}\n\n"; + + if($sections[$i] && $section_count[$i] ne 0) + { + warn "$0 Warning: Failed to extract '$sections[$i]'\n"; + } + } + } + #my ($user,$system,$cuser,$csystem) = times; + #warn "Pass2 ".$user." ".$system." ".$cuser." ".$csystem."\n"; + exit; +} + +#else output sections to .c file +my $header = join(", ", $helper_name, @sections); +my $print_variable = 'PRINT_M_O_S_T'; +my $print_array = 'PRINT_ARRAY_M_O_S_T'; +my $emit_asm = 'ASM_EMIT_M_O_S_T'; + +foreach my $incl(@includes) +{ + printf "#include \"%s\"\n", $incl; +} + +print < /* offsetof */ +#include + +/* (ab)uses the compiler to emit member offset and size to asm comments */ +/* GAS supports C-style comments in asm files other compilers may not */ +/* "NAME", "MEMBER" = ?OFFSET, ?SIZE, "TYPE, ?ARRAYCT"; + NOTE: ? may differ between machines */ + +#undef ${emit_asm} +#define ${emit_asm}(name, member, type, offset, size, elems) asm volatile\\ +("/* "#name ", " #member " = %0, %1, " #type ", %2; */\\n" : : \\ +"n"(offset), "n"(size), "n"(elems)) + +#undef ${print_variable} +#define ${print_variable}(name, member, value, type) ${emit_asm}(#name, \\ +#member, #type, offsetof(name, member), sizeof(value), 0) + +#undef ${print_array} +#define ${print_array}(name, member, value, type) ${emit_asm}(#name, \\ +#member, #type, offsetof(name, member), sizeof(value), sizeof(value)/sizeof(value[0])) + +int main(void) +{ + +/* GAS supports C-style comments in asm files other compilers may not */ +/* This header identifies assembler output for second pass */ +asm volatile("/* $header; */"); + +EOF +; +my $section_prefix = "section_"; +my $format_asm = " %s(%s, %s, ${section_prefix}%d.%s, %s);\n"; + + +for(my $i = 0; $i < @sections; $i++) +{ + if($sections[$i] && $section_lists[$i]) + { + printf "%s %s%d;\n", $sections[$i], $section_prefix, $i; #create variable for each section + my @members=split('@', $section_lists[$i]); + $section_lists[$i] = ''; + + foreach my $memb(@members) + { + my ($type, $var, $arr) = Extract_Variable($memb); + my $call = ${print_variable}; + + if($var =~ $pointer_mark_regex) #strip pointer marker + { + $type = $type.$1; + $var =~ s{.*${pointer_marker}}{}gx; + $type = $replace_type_prefix{'#pointer#'}.$type; + } + + if($type && $var) + { + if($type =~ $array_mark_regex){$call = ${print_array};} + printf $format_asm, $call, $sections[$i], $var, $i, $var, $type; + } + } + } +} +print <