Compare commits

..

7 Commits

Author SHA1 Message Date
1d4cf16399 update ecc 2026-01-06 14:02:18 +01:00
Kuba
38ae640f97 add a6 2026-01-06 11:20:02 +01:00
Kuba
6245cdc66d Greenland is danish, not whatever that clown thinks 2026-01-06 10:40:43 +01:00
Kuba
b2130441cf Replace 'Libya' with 'Republic of Cyprus' in e1
copilot lol
2026-01-05 22:28:54 +01:00
7bd8970434 large pi and better readme 2026-01-03 12:29:48 +01:00
71e2d4c863 script: move ert to extended 3 2026-01-03 11:33:21 +01:00
19a5483acb native build works worse than normal? 2026-01-03 11:30:55 +01:00
6 changed files with 101 additions and 60 deletions

View File

@@ -2,20 +2,11 @@ liblua:
gcc -c lua/*.c gcc -c lua/*.c
ar rcs liblua *.o ar rcs liblua *.o
rm *.o rm *.o
liblua-native:
gcc -c lua/*.c -march=native
ar rcs liblua.native *.o
rm *.o
build: liblua build: liblua
gcc -O2 -shared -static -o luahost-x86.dll plugin.c liblua -lgdi32 -luser32 -lshell32 \ gcc -O2 -shared -static -o luahost.dll plugin.c liblua -lgdi32 -luser32 -lshell32 \
-Wl,--add-stdcall-alias \ -Wl,--add-stdcall-alias \
-ffunction-sections -fdata-sections -ffunction-sections -fdata-sections
build-native: liblua install: build
gcc -O2 -shared -static -o luahost.dll plugin.c liblua.native -lgdi32 -luser32 -lshell32 -march=native \
-Wl,--add-stdcall-alias \
-ffunction-sections -fdata-sections
install: build-native
cp luahost.dll "/c/Program Files (x86)/RDS Spy/plugins" cp luahost.dll "/c/Program Files (x86)/RDS Spy/plugins"

View File

@@ -1,19 +1,26 @@
# Lua host # Lua host
This is an WIP lua host for rds spy, a plugin This is an WIP lua host for rds spy, a plugin
Compile this under MINGW32, not 64, RDS Spy lives in the past where men who couldn't count to 4294967295 still walked the planet Compile this under MINGW32, not 64, RDS Spy lives in the past where men who couldn't count to 4294967296 in a CPU word still walked the planet
Project stared 1st of January, 2026 (or 7 haha) Project started 1st of January, 2026
Aside from all that, this it loads and executes the script at "%LOCALAPPDATA%\RDS Spy\script.lua", with the api in the `plugin.lua` meta-file Aside from all that, this loads and executes the script at "%LOCALAPPDATA%\RDS Spy\script.lua", with the api in the `plugin.lua` meta-file
## Why? ## Why?
Ask Jan Kolar why his funny little rds decoder doesn't have Enchanced RT (excluding the 0x6552 to ERT mapping of course) Ask Jan Kolar why his funny little rds decoder doesn't have Enchanced RT (excluding the 0x6552 to ERT mapping of course). Yes, no eRT decoding is really why is this, because why decode RDS in C (or even delphi ughhh) when you can just do it in lua!
Also RDS Surveyor doesn't take line-in MPX input
# Scripts # Scripts
Inside of the examples folder you have `basic.lua` which mostly replaced the `basic.dll` plugin in RDS Spy
Note that you can double click on the buttons, if you try it Inside of the examples folder you have `basic.lua` which mostly replaces the `basic.dll` plugin in RDS Spy
Another note is that on menu 0 you have the PI and PS in a large font, why? democracy? or something like that ([forum post](https://pira.cz/forum/index.php?topic=1124.0)) I have also included `large_pi.lua`, while `basic.lua` already shows the PS and PI on a large font, this does only the large PI and PS but in a even larger font. event 1 toggles stickyness
# Console
You have a console window generated by this plugin which has as of now 8 buttons where the first if you double-click the "Reload" button, I don't know what it does but maybe it reloads the script?
The other 7 send events to the Lua script, you can use this with the console mode:true to display diffrent "menus" on the console, double clicking also sends a unique event

View File

@@ -93,7 +93,7 @@ local pi_ecc_to_country = {
e1 = { e1 = {
"Encoder fault", -- 0 "Encoder fault", -- 0
"Hellenic Republic (Greece)", -- 1 "Hellenic Republic (Greece)", -- 1
"Libya", -- 2 "Republic of Cyprus", -- 2
"Republic of San Marino", -- 3 "Republic of San Marino", -- 3
"Swiss Confederation", -- 4 "Swiss Confederation", -- 4
"Hashemite Kingdom of Jordan", -- 5 "Hashemite Kingdom of Jordan", -- 5
@@ -104,7 +104,7 @@ local pi_ecc_to_country = {
"United Kingdom of Great Britain and Northern Ireland (Gibraltar)", -- 10 A "United Kingdom of Great Britain and Northern Ireland (Gibraltar)", -- 10 A
"Republic of Iraq", -- 11 B "Republic of Iraq", -- 11 B
"United Kingdom of Great Britain and Northern Ireland", -- 12 C "United Kingdom of Great Britain and Northern Ireland", -- 12 C
"Unknown", -- 13 D "Libya", -- 13 D
"Romania", -- 14 E "Romania", -- 14 E
"Republic of France", -- 15 F wish i could nuke this "Republic of France", -- 15 F wish i could nuke this
}, },
@@ -180,6 +180,24 @@ local pi_ecc_to_country = {
"Unknown", -- 14 E "Unknown", -- 14 E
"Unknown", -- 15 F "Unknown", -- 15 F
}, },
e6 = {
"Encoder fault", -- 0
"Unknown", -- 1
"Unknown", -- 2
"Republic of West Poland", -- 3 coming soon
"Unknown", -- 4
"Unknown", -- 5
"Unknown", -- 6
"Unknown", -- 7
"Unknown", -- 8
"Unknown", -- 9
"Unknown", -- 10 A
"Unknown", -- 11 B
"Unknown", -- 12 C
"Unknown", -- 13 D
"Unknown", -- 14 E
"Unknown", -- 15 F
},
a0 = { a0 = {
"Encoder fault", -- 0 "Encoder fault", -- 0
"United States of America", -- 1 "United States of America", -- 1
@@ -215,7 +233,7 @@ local pi_ecc_to_country = {
"Canada", -- 12 C "Canada", -- 12 C
"Canada", -- 13 D "Canada", -- 13 D
"Cananda", -- 14 E "Cananda", -- 14 E
"Greenland", -- 15 F "Kingdom of Denmark (Greenland)", -- 15 F
}, },
a2 = { a2 = {
"Encoder fault", -- 0 "Encoder fault", -- 0
@@ -289,6 +307,24 @@ local pi_ecc_to_country = {
"United Mexican States", -- 14 E "United Mexican States", -- 14 E
"United Mexican States", -- 15 F "United Mexican States", -- 15 F
}, },
a6 = {
"Encoder fault", -- 0
"Unknown", -- 1
"Unknown", -- 2
"Unknown", -- 3
"Unknown", -- 4
"Unknown", -- 5
"Unknown", -- 6
"Unknown", -- 7
"Unknown", -- 8
"Unknown", -- 9
"Unknown", -- 10 A
"Unknown", -- 11 B
"Unknown", -- 12 C
"Unknown", -- 13 D
"Unknown", -- 14 E
"Republic of France (Saint Pierre and Miquelon)", -- 15 F
},
d0 = { d0 = {
"Encoder fault", -- 0 "Encoder fault", -- 0
"Republic of Cameroon", -- 1 "Republic of Cameroon", -- 1
@@ -548,7 +584,7 @@ local function render_menu()
out = out .. string.format("%s - %s\r\n\t", rtp_types[rtp_type2+1], current_rt:sub(rtp_start2+1, rtp_start2+rtp_len2+1)) out = out .. string.format("%s - %s\r\n\t", rtp_types[rtp_type2+1], current_rt:sub(rtp_start2+1, rtp_start2+rtp_len2+1))
else out = out .. "-\r\n\t-\r\n\t" end else out = out .. "-\r\n\t-\r\n\t" end
out = out .. string.format("RAW %d,%d,%d,%d,%d,%d\r\n", rtp_type1, rtp_start1, rtp_len1, rtp_type2, rtp_start2, rtp_len2) out = out .. string.format("RAW %d,%d,%d,%d,%d,%d\r\n", rtp_type1, rtp_start1, rtp_len1, rtp_type2, rtp_start2, rtp_len2)
elseif current_menu == 3 then elseif current_menu == 3 and not menu_extended then
local pi_code = tonumber(db.read_value("PI") or "0000", 16) local pi_code = tonumber(db.read_value("PI") or "0000", 16)
local country_id = (pi_code & 0xF000) >> 12 local country_id = (pi_code & 0xF000) >> 12
local coverage_id = (pi_code & 0xF00) >> 8 local coverage_id = (pi_code & 0xF00) >> 8
@@ -563,14 +599,14 @@ local function render_menu()
out = out .. string.format("Coverage: %s\r\n", pi_coverage[coverage_id+1]) out = out .. string.format("Coverage: %s\r\n", pi_coverage[coverage_id+1])
out = out .. string.format("Country: %s (%X)\r\n\r\n", country_name, ecc) out = out .. string.format("Country: %s (%X)\r\n\r\n", country_name, ecc)
out = out .. string.format("ERT: %s\r\n\r\n", ert_display)
local oda_string = "" local oda_string = ""
for grp, data in pairs(odas) do for grp, data in pairs(odas) do
local ver_char = (data.version == 0) and "A" or "B" local ver_char = (data.version == 0) and "A" or "B"
oda_string = oda_string .. string.format("%d%s - %04X | ", grp, ver_char, data.aid) oda_string = oda_string .. string.format("%d%s - %04X | ", grp, ver_char, data.aid)
end end
out = out .. string.format("ODA: %s\r\n", oda_string:sub(1, #oda_string-2)) out = out .. string.format("ODA: %s\r\n", oda_string:sub(1, #oda_string-2))
elseif current_menu == 3 and menu_extended then
out = out .. string.format("ERT: %s\r\n\r\n", ert_display)
elseif current_menu == 4 then elseif current_menu == 4 then
if time_display_offset > 2 then out = out .. string.format("RDS-System time offset: %d seconds\r\n", time_display_offset) if time_display_offset > 2 then out = out .. string.format("RDS-System time offset: %d seconds\r\n", time_display_offset)
else out = out .. string.format("RDS-System time offset: ~0\r\n") end else out = out .. string.format("RDS-System time offset: ~0\r\n") end

20
examples/large_pi.lua Normal file
View File

@@ -0,0 +1,20 @@
set_console_mode(true)
set_font_size(148)
local last_pi = "----"
local last_ps = "--------"
function group(...)
local pi = db.read_value("PI") or "----"
local ps = db.read_value("PS") or "--------"
if last_pi ~= pi or last_ps ~= ps then
set_console(string.format("%s\r\n%s", pi, ps))
last_pi = pi
last_ps = ps
end
end
function event(event)
if event == 1 then
set_window_stick(not get_window_stick())
end
end

View File

@@ -23,7 +23,6 @@ typedef struct {
} TRDSGroup; } TRDSGroup;
typedef struct { typedef struct {
// fuckass delphi
uint8_t len; uint8_t len;
uint8_t data[255]; uint8_t data[255];
} ShortString; } ShortString;
@@ -80,9 +79,9 @@ static const unsigned char EBU[127] = {
0x00, 0x00, 0x00, 0xFD, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xE6, 0x9C, 0x9F, 0x00 0x00, 0x00, 0x00, 0xFD, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xE6, 0x9C, 0x9F, 0x00
}; };
static unsigned short console_mode = 0; static uint8_t console_mode = 0;
static unsigned short stop_execution = 0; static uint8_t stop_execution = 0;
static unsigned short sticky = 0; static uint8_t sticky = 0;
static unsigned char workspaceFile[MAX_PATH] = ""; static unsigned char workspaceFile[MAX_PATH] = "";
const char* int_to_string(int value) { const char* int_to_string(int value) {
@@ -202,35 +201,29 @@ void AppendText(const char* text) {
} }
} }
void SetText(const char* text) {
if (hEditControl != NULL) SetWindowTextA(hEditControl, text);
}
int lua_log(lua_State* localL) { int lua_log(lua_State* localL) {
if(console_mode != 0) return luaL_error(localL, "Invalid log"); if(console_mode != 0) return luaL_error(localL, "Invalid log");
const char* data = luaL_checkstring(localL, 1); AppendText(luaL_checkstring(localL, 1));
AppendText(data);
AppendText("\r\n"); AppendText("\r\n");
return 0; return 0;
} }
int lua_set_console(lua_State* localL) { int lua_set_console(lua_State* localL) {
if(console_mode != 1) return luaL_error(localL, "Invalid log"); if(console_mode != 1) return luaL_error(localL, "Invalid log");
const char* data = luaL_checkstring(localL, 1); if (hEditControl != NULL) SetWindowTextA(hEditControl, luaL_checkstring(localL, 1));
SetText(data);
return 0; return 0;
} }
int lua_set_console_mode(lua_State* localL) { int lua_set_console_mode(lua_State* localL) {
if (!lua_isboolean(localL, 1)) return luaL_error(localL, "boolean expected, got %s", luaL_typename(localL, 1)); if (!lua_isboolean(localL, 1)) return luaL_typeerror(L, 1, lua_typename(L, LUA_TBOOLEAN));
int mode = lua_toboolean(localL, 1); int mode = lua_toboolean(localL, 1);
SetText(""); if (hEditControl != NULL) SetWindowTextA(hEditControl, "");
console_mode = mode; console_mode = mode;
return 0; return 0;
} }
int lua_set_window_stick(lua_State* localL) { int lua_set_window_stick(lua_State* localL) {
if (!lua_isboolean(localL, 1)) return luaL_error(localL, "boolean expected, got %s", luaL_typename(localL, 1)); if (!lua_isboolean(localL, 1)) return luaL_typeerror(L, 1, lua_typename(L, LUA_TBOOLEAN));
sticky = lua_toboolean(localL, 1); sticky = lua_toboolean(localL, 1);
return 0; return 0;
} }
@@ -257,9 +250,7 @@ int lua_set_font_size(lua_State* localL) {
} }
int lua_MessageBox(lua_State* localL) { int lua_MessageBox(lua_State* localL) {
const char* data = luaL_checkstring(localL, 1); MessageBoxA(NULL, luaL_checkstring(localL, 1), luaL_checkstring(localL, 2), MB_OK | MB_TOPMOST);
const char* title = luaL_checkstring(localL, 2);
MessageBoxA(NULL, data, title, MB_OK | MB_TOPMOST);
return 0; return 0;
} }
@@ -390,8 +381,7 @@ int lua_SaveString(lua_State* localL) {
WritePrivateProfileStringA(section, key, value, fullPath); WritePrivateProfileStringA(section, key, value, fullPath);
} }
} else if(lua_isnil(localL, 1)) WritePrivateProfileStringA(section, key, value, workspaceFile); } else if(lua_isnil(localL, 1)) WritePrivateProfileStringA(section, key, value, workspaceFile);
else luaL_typeerror(L, 1, lua_typename(L, LUA_TSTRING)); else return luaL_typeerror(L, 1, lua_typename(L, LUA_TSTRING));
return 0;
} }
int lua_LoadString(lua_State* localL) { int lua_LoadString(lua_State* localL) {
@@ -415,8 +405,7 @@ int lua_LoadString(lua_State* localL) {
GetPrivateProfileStringA(section, key, defaultValue, buffer, 1024, workspaceFile); GetPrivateProfileStringA(section, key, defaultValue, buffer, 1024, workspaceFile);
lua_pushstring(localL, buffer); lua_pushstring(localL, buffer);
return 1; return 1;
} else luaL_typeerror(L, 1, lua_typename(L, LUA_TSTRING)); } else return luaL_typeerror(L, 1, lua_typename(L, LUA_TSTRING));
return 0;
} }
void lua_call_command(const char* Cmd, const char* Param) { void lua_call_command(const char* Cmd, const char* Param) {
@@ -441,8 +430,8 @@ void lua_call_group() {
lua_getglobal(L, "group"); lua_getglobal(L, "group");
if (lua_isfunction(L, -1)) { if (lua_isfunction(L, -1)) {
lua_pushinteger(L, Group.RFU & 3); // TODO: find out if fuckass pira.cz meant msb or lsb, i have no clue what does "Bits: 0-1" mean lua_pushinteger(L, Group.RFU & 3);
lua_pushboolean(L, (Group.RFU & 0x100) >> 8); // just do lsb for now i guess lua_pushboolean(L, (Group.RFU & 0x100) >> 8);
lua_pushinteger(L, Group.Blk1); lua_pushinteger(L, Group.Blk1);
lua_pushinteger(L, Group.Blk2); lua_pushinteger(L, Group.Blk2);
lua_pushinteger(L, Group.Blk3); lua_pushinteger(L, Group.Blk3);
@@ -492,7 +481,6 @@ void lua_event(int event) {
__declspec(dllexport) void WINAPI RDSGroup(TRDSGroup* PRDSGroup) { __declspec(dllexport) void WINAPI RDSGroup(TRDSGroup* PRDSGroup) {
if (PRDSGroup == NULL) return; if (PRDSGroup == NULL) return;
Group = *PRDSGroup; Group = *PRDSGroup;
lua_call_group(); lua_call_group();
} }
@@ -500,21 +488,20 @@ __declspec(dllexport) void WINAPI RDSGroup(TRDSGroup* PRDSGroup) {
__declspec(dllexport) void WINAPI Command(const char* Cmd, const char* Param) { __declspec(dllexport) void WINAPI Command(const char* Cmd, const char* Param) {
if (Cmd == NULL) return; if (Cmd == NULL) return;
if (_stricmp(Cmd, "EXIT") == 0) { if (_stricmp(Cmd, "EXIT") == 0) {
if (hWnd != NULL) {
DestroyWindow(hWnd);
hWnd = NULL;
}
if(L != NULL) { if(L != NULL) {
lua_close(L); lua_close(L);
L = NULL; L = NULL;
} }
if (hWnd != NULL) {
DestroyWindow(hWnd);
hWnd = NULL;
}
} else if (_stricmp(Cmd, "CONFIGURE") == 0 || _stricmp(Cmd, "SHOW") == 0 || _stricmp(Cmd, "RESTORE") == 0) ShowWindow(hWnd, SW_SHOW); } else if (_stricmp(Cmd, "CONFIGURE") == 0 || _stricmp(Cmd, "SHOW") == 0 || _stricmp(Cmd, "RESTORE") == 0) ShowWindow(hWnd, SW_SHOW);
else if (_stricmp(Cmd, "MINIMIZE") == 0) ShowWindow(hWnd, SW_HIDE); else if (_stricmp(Cmd, "MINIMIZE") == 0) ShowWindow(hWnd, SW_HIDE);
else if (_stricmp(Cmd, "SHOWHIDE") == 0) { else if (_stricmp(Cmd, "SHOWHIDE") == 0) {
if(IsWindowVisible(hWnd)) ShowWindow(hWnd, SW_HIDE); if(IsWindowVisible(hWnd)) ShowWindow(hWnd, SW_HIDE);
else ShowWindow(hWnd, SW_SHOW); else ShowWindow(hWnd, SW_SHOW);
} } else if (_stricmp(Cmd, "OPENWORKSPACE") == 0) {
else if (_stricmp(Cmd, "OPENWORKSPACE") == 0) {
if(hWnd != NULL) { if(hWnd != NULL) {
int value = GetPrivateProfileIntA("luahost", "Visible", 0, Param); int value = GetPrivateProfileIntA("luahost", "Visible", 0, Param);
if(value == 1) ShowWindow(hWnd, SW_SHOW); if(value == 1) ShowWindow(hWnd, SW_SHOW);
@@ -524,10 +511,10 @@ __declspec(dllexport) void WINAPI Command(const char* Cmd, const char* Param) {
SetWindowPos(hWnd, NULL, x, y, 0, 0, SWP_NOSIZE); SetWindowPos(hWnd, NULL, x, y, 0, 0, SWP_NOSIZE);
} }
sticky = GetPrivateProfileIntA("luahost", "Stick", 0, Param); sticky = GetPrivateProfileIntA("luahost", "Stick", 0, Param);
lua_call_command(Cmd, Param); // still call lua_call_command(Cmd, Param);
} else if (_stricmp(Cmd, "SAVEWORKSPACE") == 0) { } else if (_stricmp(Cmd, "SAVEWORKSPACE") == 0) {
if(hWnd != NULL) { if(hWnd != NULL) {
RECT rect; // get rect RECT rect;
if (GetWindowRect(hWnd, &rect)) { if (GetWindowRect(hWnd, &rect)) {
WritePrivateProfileStringA("luahost", "Left", int_to_string(rect.left), Param); WritePrivateProfileStringA("luahost", "Left", int_to_string(rect.left), Param);
WritePrivateProfileStringA("luahost", "Top", int_to_string(rect.top), Param); WritePrivateProfileStringA("luahost", "Top", int_to_string(rect.top), Param);
@@ -537,7 +524,7 @@ __declspec(dllexport) void WINAPI Command(const char* Cmd, const char* Param) {
} }
memcpy(workspaceFile, Param, MAX_PATH); memcpy(workspaceFile, Param, MAX_PATH);
workspaceFile[MAX_PATH-1] = 0; workspaceFile[MAX_PATH-1] = 0;
lua_call_command(Cmd, Param); // still call lua_call_command(Cmd, Param);
} else if (_stricmp(Cmd, "LUASCRIPT") == 0) { // custom } else if (_stricmp(Cmd, "LUASCRIPT") == 0) { // custom
char msg_buffer[255]; char msg_buffer[255];
if (luaL_loadfile(L, Param) != LUA_OK) { if (luaL_loadfile(L, Param) != LUA_OK) {

View File

@@ -71,7 +71,7 @@ function db.read_record(index) end
---@param value string ---@param value string
function db.add_value(key, value) end function db.add_value(key, value) end
function db.reset_values(key, value) end function db.reset_values() end
---@return integer ---@return integer
function db.count_records(key, value) end function db.count_records(key, value) end