diff --git a/.vscode/settings.json b/.vscode/settings.json index 3f82eaa..b6d1afa 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -22,50 +22,6 @@ "ranges": "c", "span": "c" }, - "Lua.diagnostics.globals": [ - "set_rds_pi", - "set_rds_ecc", - "str", - "cmd", - "set_rds_pty", - "set_rds_slc_data", - "set_rds_ct", - "set_rds_dpty", - "set_rds_tp", - "set_rds_ta", - "set_rds_rt1_enabled", - "set_rds_rt2_enabled", - "set_rds_ptyn_enabled", - "set_rds_rt_type", - "set_rds_rds2mod", - "set_rds_rdsgen", - "set_rds_ptyn", - "set_rds_ps", - "core_version", - "set_rds_tps", - "data", - "set_rds_rt2", - "set_rds_rt1", - "set_rds_lps", - "set_rds_ert", - "set_rds_link", - "set_rds_rt_switching_period", - "set_rds_program", - "set_rds_level", - "set_rds_rt_text_timeout", - "set_rds_program_defaults", - "reset_rds", - "max_programs", - "on_init", - "get_rds_pi", - "get_rds_ecc", - "get_rds_pty", - "get_rds_slc_data", - "get_rds_ct", - "get_rds_dpty", - "get_rds_tp", - "get_rds_ta" - ], "Lua.runtime.plugin": "plugin.lua", "Lua.runtime.builtin": { "io": "disable", diff --git a/CMakeLists.txt b/CMakeLists.txt index 06755b6..b9df0a7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,27 +21,31 @@ install(TARGETS rds95 DESTINATION ${CMAKE_INSTALL_PREFIX}/bin) install(CODE " # Define the paths for the source and destination files - set(PREFIX_FILE \"${CMAKE_CURRENT_SOURCE_DIR}/.command_prefix.lua\") - set(COMMAND_FILE \"${CMAKE_CURRENT_SOURCE_DIR}/src/command.lua\") - # The $ENV{HOME} variable is evaluated at install time, not configure time - set(DEST_FILE \"$ENV{HOME}/.rds95.command.lua\") + set(PREFIX_FILE \"${CMAKE_CURRENT_SOURCE_DIR}/.script_prefix.lua\") + set(SCRIPT_FILE \"${CMAKE_CURRENT_SOURCE_DIR}/src/script.lua\") + set(DEST_FILE \"/etc/rds95.lua\") # Check if the optional prefix file exists if(EXISTS \${PREFIX_FILE}) - # If it exists, read the prefix and the main command file - message(STATUS \"Prefix file found. Combining with command.lua.\") + message(STATUS \"Prefix file found. Combining with script.lua.\") file(READ \${PREFIX_FILE} PREFIX_CONTENT) - file(READ \${COMMAND_FILE} COMMAND_CONTENT) - # Concatenate them, with the prefix content first - set(FINAL_CONTENT \"\${PREFIX_CONTENT}\n\${COMMAND_CONTENT}\") + file(READ \${SCRIPT_FILE} SCRIPT_CONTENT) + set(FINAL_CONTENT \"\${PREFIX_CONTENT}\n\${SCRIPT_CONTENT}\") else() - # Otherwise, just use the content of the main command file - message(STATUS \"Prefix file not found. Using command.lua directly.\") - file(READ \${COMMAND_FILE} FINAL_CONTENT) + message(STATUS \"Prefix file not found. Using script.lua directly.\") + file(READ \${SCRIPT_FILE} FINAL_CONTENT) endif() # Write the resulting content to the destination file - message(STATUS \"Installing command file to \${DEST_FILE}\") + message(STATUS \"Installing script file to \${DEST_FILE}\") file(WRITE \${DEST_FILE} \"\${FINAL_CONTENT}\") + + # Change ownership to the user who invoked sudo (if applicable) + if(DEFINED ENV{SUDO_USER}) + message(STATUS \"Changing ownership of \${DEST_FILE} to \$ENV{SUDO_USER}\") + execute_process(COMMAND chown \$ENV{SUDO_USER}:\$ENV{SUDO_USER} \${DEST_FILE}) + else() + message(STATUS \"No SUDO_USER detected, skipping chown\") + endif() " ) \ No newline at end of file diff --git a/plugin.lua b/plugin.lua index e130cea..21190e0 100644 --- a/plugin.lua +++ b/plugin.lua @@ -7,6 +7,8 @@ core_version = "" eon_count = 0 ---@type integer max_programs = 0 +---@type integer +user_data_len = 0 ---Starts the initialization sequence, also calls the on_init function ---@return nil @@ -16,6 +18,10 @@ function set_rds_program_defaults() end ---@return nil function reset_rds() end +---Forces encoder and modulator data to be saved to disc +---@return nil +function force_save() end + ---This function is called by the C core after we reset data, or have no data in general ---It should be defined by the user in the script. ---@return nil @@ -111,14 +117,14 @@ function get_rds_rt_type() end -- Modulation & Generation ---@param mode boolean -function set_rds_rds2mod(mode) end +function set_rds2_mode(mode) end ---@return boolean -function get_rds_rds2mod() end +function get_rds2_mode() end ----@param rdsgen integer -function set_rds_rdsgen(rdsgen) end +---@param streams integer +function set_rds_streams(streams) end ---@return integer -function get_rds_rdsgen() end +function get_rds_streams() end ---@param level number function set_rds_level(level) end @@ -281,4 +287,22 @@ function register_oda(group, group_version, id, id_data) end ---You are asked to set groups B last 5 bits, leave rest 0 ---@param oda_id integer The ID returned by register_oda ---@param fun ODAHandler -function set_oda_handler(oda_id, fun) end \ No newline at end of file +function set_oda_handler(oda_id, fun) end + +---Data is allocated in each program's data for lua data, note that this overwrites existing data +---@param data string +function set_userdata(data) end +---Writes to the userdata at the offset, size does not have to match the length of the string, if the string is less than size then the rest of the string will be padded with zeroes until it is size +---@param offset integer +---@param size integer +---@param data string +function set_userdata_offset(offset, size, data) end + +---Returns all of the data saved as user data +---@return string +function get_userdata() end +---Gets data from userdata but at the specified offset +---@param offset integer +---@param size integer +---@return string +function get_userdata_offset(offset, size) end \ No newline at end of file diff --git a/src/lua_rds.c b/src/lua_rds.c index d3f76ba..23c3466 100644 --- a/src/lua_rds.c +++ b/src/lua_rds.c @@ -6,6 +6,45 @@ static lua_State *L = NULL; static pthread_mutex_t lua_mutex; static uint8_t unload_refs[33] = {LUA_REFNIL}; +int lua_get_userdata(lua_State *localL) { + lua_pushlstring(localL, &mod->enc->data[mod->enc->program].lua_data, LUA_USER_DATA); + return 1; +} +int lua_get_userdata_offset(lua_State *localL) { + uint8_t offset = luaL_checkinteger(localL, 1); + uint8_t size = luaL_checkinteger(localL, 2); + if((offset+size) > LUA_USER_DATA) return luaL_error(localL, "data exceeds limit"); + lua_pushlstring(localL, (&mod->enc->data[mod->enc->program].lua_data)+offset, size); + return 1; +} +int lua_set_userdata(lua_State *localL) { + size_t len; + const char *data = luaL_checklstring(localL, 1, &len); + if(len > LUA_USER_DATA) return luaL_error(localL, "data exceeds limit"); + memset(&mod->enc->data[mod->enc->program].lua_data, 0, LUA_USER_DATA); + memcpy(&mod->enc->data[mod->enc->program].lua_data, data, len); + + return 0; +} +int lua_set_userdata_offset(lua_State *localL) { + uint8_t offset = luaL_checkinteger(localL, 1); + uint8_t size = luaL_checkinteger(localL, 2); + + size_t len; + const char *data = luaL_checklstring(localL, 3, &len); + if(len > size || (offset + size) > LUA_USER_DATA) return luaL_error(localL, "data exceeds limit"); + memset((&mod->enc->data[mod->enc->program].lua_data)+offset, 0, size); + memcpy((&mod->enc->data[mod->enc->program].lua_data)+offset, data, len); + + return 0; +} + +int lua_force_save(lua_State *localL) { + encoder_saveToFile(mod->enc); + Modulator_saveToFile(&mod->params); + return 0; +} + int lua_set_rds_program_defaults(lua_State *localL) { (void)localL; for (int i = 1; i < *unload_refs; i++) luaL_unref(L, LUA_REGISTRYINDEX, unload_refs[i]); @@ -129,20 +168,20 @@ BOOL_GETTER(ptyn_enabled) INT_SETTER(rt_type) INT_GETTER(rt_type) -int lua_set_rds_rds2mod(lua_State *localL) { +int lua_set_rds2_mode(lua_State *localL) { if (!lua_isboolean(localL, 1)) return luaL_error(localL, "boolean expected, got %s", luaL_typename(localL, 1)); mod->enc->encoder_data.rds2_mode = lua_toboolean(localL, 1); return 0; } -int lua_get_rds_rds2mod(lua_State *localL) { +int lua_get_rds2_mode(lua_State *localL) { lua_pushboolean(localL, mod->enc->encoder_data.rds2_mode); return 1; } -int lua_set_rds_rdsgen(lua_State *localL) { +int lua_set_rds_streams(lua_State *localL) { mod->params.rdsgen = luaL_checkinteger(localL, 1); return 0; } -int lua_get_rds_rdsgen(lua_State *localL) { +int lua_get_rds_streams(lua_State *localL) { lua_pushinteger(localL, mod->params.rdsgen); return 1; } @@ -454,6 +493,7 @@ void init_lua(RDSModulator* rds_mod) { static int mutex_initialized = 0; mod = rds_mod; L = luaL_newstate(); + print("Initializing %s\n", LUA_COPYRIGHT); luaL_requiref(L, "_G", luaopen_base, 1); luaL_requiref(L, LUA_STRLIBNAME, luaopen_string, 1); @@ -469,9 +509,12 @@ void init_lua(RDSModulator* rds_mod) { lua_setglobal(L, "max_programs"); lua_pushinteger(L, EONs); lua_setglobal(L, "eon_count"); + lua_pushinteger(L, LUA_USER_DATA); + lua_setglobal(L, "user_data_len"); lua_register(L, "set_rds_program_defaults", lua_set_rds_program_defaults); lua_register(L, "reset_rds", lua_reset_rds); + lua_register(L, "force_save", lua_force_save); lua_register(L, "set_rds_pi", lua_set_rds_pi); lua_register(L, "get_rds_pi", lua_get_rds_pi); @@ -509,11 +552,11 @@ void init_lua(RDSModulator* rds_mod) { lua_register(L, "set_rds_rt_type", lua_set_rds_rt_type); lua_register(L, "get_rds_rt_type", lua_get_rds_rt_type); - lua_register(L, "set_rds_rds2mod", lua_set_rds_rds2mod); - lua_register(L, "get_rds_rds2mod", lua_get_rds_rds2mod); + lua_register(L, "set_rds2_mode", lua_set_rds2_mode); + lua_register(L, "get_rds2_mode", lua_get_rds2_mode); - lua_register(L, "set_rds_rdsgen", lua_set_rds_rdsgen); - lua_register(L, "get_rds_rdsgen", lua_get_rds_rdsgen); + lua_register(L, "set_rds_streams", lua_set_rds_streams); + lua_register(L, "get_rds_streams", lua_get_rds_streams); lua_register(L, "set_rds_grpseq", lua_set_rds_grp_sqc); lua_register(L, "get_rds_grpseq", lua_get_rds_grp_sqc); @@ -570,12 +613,12 @@ void init_lua(RDSModulator* rds_mod) { lua_register(L, "register_oda", lua_register_oda); lua_register(L, "set_oda_handler", lua_set_oda_handler); - char path[128]; - const char *home = getenv("HOME"); - if (!home) return; - snprintf(path, sizeof(path), "%s/.rds95.command.lua", home); + lua_register(L, "set_userdata", lua_set_userdata); + lua_register(L, "set_userdata_offset", lua_set_userdata_offset); + lua_register(L, "get_userdata", lua_get_userdata); + lua_register(L, "get_userdata_offset", lua_get_userdata_offset); - if (luaL_loadfile(L, path) != LUA_OK) { + if (luaL_loadfile(L, "/etc/rds95.lua") != LUA_OK) { fprintf(stderr, "Lua error loading file: %s\n", lua_tostring(L, -1)); lua_pop(L, 1); return; @@ -585,7 +628,6 @@ void init_lua(RDSModulator* rds_mod) { lua_pop(L, 1); } } - lua_pushvalue(L, 1); if(mutex_initialized == 0) { pthread_mutex_init(&lua_mutex, NULL); mutex_initialized = 1; diff --git a/src/rds.h b/src/rds.h index 7c9ca8e..0f3b83e 100644 --- a/src/rds.h +++ b/src/rds.h @@ -1,5 +1,6 @@ #pragma once #include "common.h" +#define LUA_USER_DATA 512 /* The RDS error-detection code generator polynomial is * x^10 + x^8 + x^7 + x^5 + x^4 + x^3 + x^0 @@ -107,6 +108,8 @@ typedef struct { uint16_t udg2_rds2[8][4]; RDSEON eon[EONs]; + + uint8_t lua_data[LUA_USER_DATA]; } RDSData; typedef struct { uint8_t af_state : 6; diff --git a/src/command.lua b/src/script.lua similarity index 98% rename from src/command.lua rename to src/script.lua index 1589066..b141853 100644 --- a/src/command.lua +++ b/src/script.lua @@ -21,8 +21,8 @@ function data_handle(data) elseif data == "rt2en" then return string.format("RT2EN=%s\r\n", string.format("%d", (get_rds_rt2_enabled() and 1 or 0))) elseif data == "ptynen" then return string.format("PTYNEN=%s\r\n", string.format("%d", (get_rds_ptyn_enabled() and 1 or 0))) elseif data == "rttype" then return string.format("RTTYPE=%s\r\n", string.format("%d", get_rds_rt_type())) - elseif data == "rds2mod" then return string.format("RDS2MOD=%s\r\n", string.format("%d", (get_rds_rds2mod() and 1 or 0))) - elseif data == "rdsgen" then return string.format("RDSGEN=%s\r\n", string.format("%d",get_rds_rdsgen())) + elseif data == "rds2mod" then return string.format("RDS2MOD=%s\r\n", string.format("%d", (get_rds2_mode() and 1 or 0))) + elseif data == "rdsgen" then return string.format("RDSGEN=%s\r\n", string.format("%d", get_rds_streams())) elseif data == "level" then return string.format("LEVEL=%s\r\n", string.format("%d", get_rds_level() * 255)) elseif data == "link" then return string.format("LINK=%s\r\n", string.format("%d", (get_rds_link() and 1 or 0))) elseif data == "rtp" then @@ -225,12 +225,12 @@ function data_handle(data) elseif cmd == "rds2mod" then local type = tonumber(value) if not type then return "-" end - set_rds_rds2mod(type ~= 0) + set_rds2_mode(type ~= 0) return "+" elseif cmd == "rdsgen" then local type = tonumber(value) if not type then return "-" end - set_rds_rdsgen(type) + set_rds_streams(type) return "+" elseif cmd == "ptyn" then set_rds_ptyn(value)