From 751e1070375eb2de593ae0ae81a79b16c9e9a84c Mon Sep 17 00:00:00 2001 From: KubaPro010 Date: Thu, 25 Dec 2025 21:22:23 +0100 Subject: [PATCH] do ert in lua --- .vscode/settings.json | 3 +- CMakeLists.txt | 39 ++++++- plugin.lua | 2 + readme.md | 257 ------------------------------------------ scripts/ert.lua | 66 +++++++++++ src/lua_rds.c | 6 - src/rds.c | 11 +- src/rds.h | 14 +-- src/rds_groups.c | 23 ---- src/rds_setters.c | 21 ---- 10 files changed, 106 insertions(+), 336 deletions(-) create mode 100644 scripts/ert.lua diff --git a/.vscode/settings.json b/.vscode/settings.json index b6d1afa..27e76d8 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -30,5 +30,6 @@ "jit": "disable", "ffi": "disable", "package": "disable" - } + }, + "C_Cpp.dimInactiveRegions": false } \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index b9df0a7..76a2d29 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,20 +22,49 @@ install(CODE " # Define the paths for the source and destination files set(PREFIX_FILE \"${CMAKE_CURRENT_SOURCE_DIR}/.script_prefix.lua\") + set(SCRIPTS_DIR \"${CMAKE_CURRENT_SOURCE_DIR}/scripts\") set(SCRIPT_FILE \"${CMAKE_CURRENT_SOURCE_DIR}/src/script.lua\") set(DEST_FILE \"/etc/rds95.lua\") + # Initialize content variable + set(FINAL_CONTENT \"\") + # Check if the optional prefix file exists if(EXISTS \${PREFIX_FILE}) - message(STATUS \"Prefix file found. Combining with script.lua.\") + message(STATUS \"Prefix file found. Adding .script_prefix.lua.\") file(READ \${PREFIX_FILE} PREFIX_CONTENT) - file(READ \${SCRIPT_FILE} SCRIPT_CONTENT) - set(FINAL_CONTENT \"\${PREFIX_CONTENT}\n\${SCRIPT_CONTENT}\") + set(FINAL_CONTENT \"\${PREFIX_CONTENT}\") else() - message(STATUS \"Prefix file not found. Using script.lua directly.\") - file(READ \${SCRIPT_FILE} FINAL_CONTENT) + message(STATUS \"Prefix file not found.\") endif() + # Check if scripts directory exists and contains .lua files + if(EXISTS \${SCRIPTS_DIR} AND IS_DIRECTORY \${SCRIPTS_DIR}) + file(GLOB LUA_SCRIPTS \"\${SCRIPTS_DIR}/*.lua\") + list(LENGTH LUA_SCRIPTS SCRIPT_COUNT) + + if(SCRIPT_COUNT GREATER 0) + message(STATUS \"Found \${SCRIPT_COUNT} Lua script(s) in scripts directory.\") + list(SORT LUA_SCRIPTS) + + foreach(LUA_SCRIPT \${LUA_SCRIPTS}) + get_filename_component(SCRIPT_NAME \${LUA_SCRIPT} NAME) + message(STATUS \"Adding script: \${SCRIPT_NAME}\") + file(READ \${LUA_SCRIPT} SCRIPT_CONTENT) + set(FINAL_CONTENT \"\${FINAL_CONTENT}\n\${SCRIPT_CONTENT}\") + endforeach() + else() + message(STATUS \"No Lua scripts found in scripts directory.\") + endif() + else() + message(STATUS \"Scripts directory not found.\") + endif() + + # Add the main script file + message(STATUS \"Adding main script.lua.\") + file(READ \${SCRIPT_FILE} MAIN_SCRIPT_CONTENT) + set(FINAL_CONTENT \"\${FINAL_CONTENT}\n\${MAIN_SCRIPT_CONTENT}\") + # Write the resulting content to the destination file message(STATUS \"Installing script file to \${DEST_FILE}\") file(WRITE \${DEST_FILE} \"\${FINAL_CONTENT}\") diff --git a/plugin.lua b/plugin.lua index 21190e0..d08b2c4 100644 --- a/plugin.lua +++ b/plugin.lua @@ -170,8 +170,10 @@ function set_rds_lps(lps) end ---@return string function get_rds_lps() end +---This is implemented externally ---@param ert string function set_rds_ert(ert) end +---This is implemented externally ---@return string function get_rds_ert() end diff --git a/readme.md b/readme.md index a96dc48..4417454 100644 --- a/readme.md +++ b/readme.md @@ -25,263 +25,6 @@ The newer standard which is the IEC one, removes these features: RDS95 is the only (as far as i can tell) encoder to transmit the 9-bit AF codes -## Commands - -### PS - -Sets the Program Service: `PS=* RDS *` - -### PI - -Sets the PI code: `PI=FFFF` - -### TP - -Sets the TP flag: `TP=1` - -### TA - -Sets the TA flag and triggers Traffic PS: `TA=0` -*May be overridden by EON* - -### CT - -Toggles the transmission of CT groups: `CT=1` - -### AF - -Sets the AF frequencies: `AF=95,89.1` -Clear the AF: `AF=` - -### TPS - -Sets the Traffic PS: `TPS=Traffic!` (default not set) -*TPS is transmitted instead of PS when TA flag is on* - -### RT1 - -Sets the first radio text: `RT1=Currently Playing: Jessie Ware - Remember Where You Are` or `TEXT=Currently Playing: Jessie Ware - Remember Where You Are` - -### RT2 - -Sets the second radio text: `RT2=Radio Nova - Best Hits around!` - -### PTY - -Sets the programme type flag: `PTY=11` - -PTY values are diffrent for RDS and RDBS, look for them online - -### ECC - -Sets the extended country code: `ECC=E2` -*Note that the ECC is depended on the first letter of the PI, for example PI:3 and ECC:E2 is poland, but PI:1 would be the czech republic* - -### RTP - -TODO: RTP - -### LPS - -Sets the LPS: `LPS=NovaFM❤️` -*Note that LPS does UTF-8, while PS, RT don't* - -### ERT - -Sets the ERT: `ERT=Currently on air we're playing: Lady Gaga - Applause` -*Note that ERT is a 128-character version of RT with UTF-8 support* - -### AFO - -Sets the AF frequencies for the ODA 9-bit version which enables AF for 64.1-88 MHz: `AFO=69.8,95.0,225` (LowerFM,FM,LF not sure if this even works) -Clear the AFO: `AFO=` - -### TEXT - -Alias for [RT1](#rt1) - -### PTYN - -Sets the programme type name: `PTYN=Football` - -### DPTY - -*Formerly DI* -Sets the DPTY flag: `DPTY=1` - -### SLCD - -The 1A group where ECC is sent can also be used to send broadcaster data: `SLCD=FFF` - -### ERTP - -This only will work if ERT is no longer than 64 characters -See [RTP](#rtp) - -### LINK - -Toggles the linkage bit in 1A groups, enable this if you have EON about a station and that station has EON about you: `LINK=1` - -### SITE - -Sets up to 2 site addresses: `SITE=44,95` - -### G - -Sends a custom group to the next group available: `G=F100FFFFFFFF` or `G=00002000AAAAAAAA` for RDS2 - -### RT1EN - -Enables RT 1: `RT1EN=1` - -### RT2EN - -Enables RT 2: `RT2EN=1` - -### RTPER - -RT Switching period, in minutes: `RTPER=5` - -### LEVEL - -Sets the RDS output level: `LEVEL=255` - -### PTYNEN - -Enables PTYN transmission: `PTYEN=1` - -### RTPRUN - -Sets the RTP Running bit, to signal if the RTP data is accurate: `RTPRUN=1` - -You can also toggle the state: `RTPRUN=1,1` - -### GRPSEQ - -Sets the group sequence for stream0, available groups: - -- 0: 4 PSs -- 1: ECC -- 2: RT -- A: PTYN -- E: EON -- X: UDG1 -- Y: UDG2 -- R: RT+ -- P: eRT+ -- S: ERT -- 3: ODA -- F: LPS -- T: Fast tuning info -- U: ODA AF - -`GRPSEQ=002222` - -### RTTYPE - -Sets the RT1/RT2 types of A/B: - -- 0: Set to A -- 1: RT1 is A, RT2 is B -- 2: Default, just toggle A/B - -### PROGRAM - -Switches the current program, so diffrent saves: `PROGRAM=1` - -### RDS2MOD - -Sets the RDS2 operation mode: - -- 0: Default, full tunnelling of stream 0 -- 1: Independent tunelling, RDS2 runs a seperate group sequence - -### GRPSEQ2 - -The Group Sequence for the RDS2 independent tunnelling mode -See [GRPSEQ](#grpseq) - -### DTTMOUT - -Default text timeout, once runs out it sets the RT1 which is saved in memory: `DTTMOUT=60` (1 hour) - -### ERTPRUN - -See [RTPRUN](#rtprun) - -### INIT - -Resets program to default settings, no arguments: `INIT` - -### VER - -If you have output, then it shows the version of the encoder - -### RESET - -Resets the internal state: `RESET` - -### EONxEN - -Enables the EON of x: `EON1EN=1` - -### EONxPI - -Sets the PI of EON x: `EON1PI=30FE` - -### EONxPS - -Sets the PS of EON x: `EON1PS=AFERA` - -### EONxPTY - -Sets the PTY of EON x: `EON1PTY=11` - -### EONxTA - -Enables the TA of EON x: `EON1TA=1` - -### EONxTP - -Sets the TP of EON x: `EON1TP=1` - -### EONxAF - -Sets the AF of EON x: `EON1AF=98.6,95.0` - -### EONxDT - -Sets the broadcaster data of EON x: `EON1DT=F` - -### UDG1 - -Sets the user defined group, max 8 groups: `UDG1=6000FFFFFFFF` - -### UDG2 - -See [UDG1](#udg1) - -### 2UDG1 - -Sets the UDG1 of RDS2, max 8 groups expects 4 blocks: `2UDG1=0000200020202020` - -### 2UDG2 - -See [2UDG1](#2udg1) - -### RDSGEN - -Sets the rds generator level: - -- 0: No streams -- 1: Stream 0 only -- 2: Stream 0 and 1 - -`RDSGEN=1` - -### Don't like the commands? -Implement them yourself then smartass, go on, look into the command.lua file - ## Disclaimer RDS95 is based on [Anthony96922](https://github.com/Anthony96922/)'s [MiniRDS](https://github.com/Anthony96922/MiniRDS) diff --git a/scripts/ert.lua b/scripts/ert.lua new file mode 100644 index 0000000..f9d85f4 --- /dev/null +++ b/scripts/ert.lua @@ -0,0 +1,66 @@ +_Ert_state = 0 +_Ert_oda_id = nil + +local function init_ert() + if _Ert_oda_id == nil then + _Ert_oda_id = register_oda(12, false, 0x6552, 1) + set_oda_handler(_Ert_oda_id, function () + if string.byte(get_userdata_offset(257, 1)) == 1 then + local new_data = get_userdata_offset(0, 128) + local new_segments = string.byte(get_userdata_offset(128, 1)) + set_userdata_offset(129, 128, new_data) + set_userdata_offset(257, 1, string.char(new_segments)) + set_userdata_offset(258, 1, string.char(0)) + _Ert_state = 0 + end + + local segments = string.byte(get_userdata_offset(257, 1)) + if segments == 0 then segments = 1 end + + local b = _Ert_state & 31 + local chunk = get_userdata_offset(129 + _Ert_state * 4, 4) + local c = (string.byte(chunk, 1) << 8) | string.byte(chunk, 2) + local d = (string.byte(chunk, 3) << 8) | string.byte(chunk, 4) + + _Ert_state = (_Ert_state + 1) % segments + return b, c, d + end) + end +end + +function set_rds_ert(ert) + if #ert == 0 then + set_userdata_offset(128, 1, string.char(0)) + set_userdata_offset(258, 1, string.char(1)) + return + end + + local data = ert .. "\r" + data = string.sub(data, 1, 128) + + local padding = (4 - (#data % 4)) % 4 + data = data .. string.rep("\0", padding) + + set_userdata_offset(0, 128, data) + + local segments = #data // 4 + if segments > 32 then segments = 32 end + + if string.byte(get_userdata_offset(257, 1)) == 0 then + init_ert() + set_userdata_offset(129, 128, data) + set_userdata_offset(257, 1, string.char(segments)) + else set_userdata_offset(258, 1, string.char(1)) end + + set_userdata_offset(128, 1, string.char(segments)) +end + +function get_rds_ert() + local data = get_userdata_offset(0, 128) + if string.byte(get_userdata_offset(128, 1)) == 0 then return "" end + return data:match("^(.-)[\r%z]*") or "" +end + +function on_state() + if string.byte(get_userdata_offset(257, 1)) ~= 0 then init_ert() end +end \ No newline at end of file diff --git a/src/lua_rds.c b/src/lua_rds.c index 19b0ec8..13aa05b 100644 --- a/src/lua_rds.c +++ b/src/lua_rds.c @@ -311,9 +311,6 @@ STR_SETTER(rt2, set_rds_rt2) STR_RAW_SETTER(lps, set_rds_lps) STR_RAW_GETTER(lps, LPS_LENGTH) -STR_RAW_SETTER(ert, set_rds_ert) -STR_RAW_GETTER(ert, ERT_LENGTH) - STR_RAW_SETTER(grp_sqc_rds2, set_rds_grpseq2) STR_RAW_GETTER(grp_sqc_rds2, 24) @@ -589,9 +586,6 @@ void init_lua(RDSModulator* rds_mod) { lua_register(L, "set_rds_lps", lua_set_rds_lps); lua_register(L, "get_rds_lps", lua_get_rds_lps); - lua_register(L, "set_rds_ert", lua_set_rds_ert); - lua_register(L, "get_rds_ert", lua_get_rds_ert); - lua_register(L, "set_rds_rtplus_tags", lua_set_rds_rtplus_tags); lua_register(L, "get_rds_rtplus_tags", lua_get_rds_rtplus_tags); lua_register(L, "toggle_rds_rtp", lua_toggle_rds_rtp); diff --git a/src/rds.c b/src/rds.c index 39efc0a..e0e18ba 100644 --- a/src/rds.c +++ b/src/rds.c @@ -14,7 +14,6 @@ void get_rds_fasttuning_group(RDSEncoder* enc, RDSGroup *group); void get_rds_rt_group(RDSEncoder* enc, RDSGroup *group); void get_rdsp_rtp_oda_group(RDSGroup *group); void get_rdsp_ertp_oda_group(RDSGroup *group); -void get_rdsp_ert_oda_group(RDSGroup *group); void get_rdsp_oda_af_oda_group(RDSGroup *group); void get_rds_oda_af_group(RDSEncoder* enc, RDSGroup *group); void get_rdsp_ct_group(RDSGroup *group, time_t now); @@ -25,7 +24,6 @@ void get_rds_ptyn_group(RDSEncoder* enc, RDSGroup *group); void get_rds_rtplus_group(RDSEncoder* enc, RDSGroup *group); void get_rds_ertplus_group(RDSEncoder* enc, RDSGroup *group); void get_rds_eon_group(RDSEncoder* enc, RDSGroup *group); -void get_rds_ert_group(RDSEncoder* enc, RDSGroup *group); uint8_t get_rds_custom_groups(RDSEncoder* enc, RDSGroup *group); uint8_t get_rds_custom_groups2(RDSEncoder* enc, RDSGroup *group); int get_rdsp_lua_group(RDSGroup *group); @@ -100,11 +98,6 @@ static void get_rds_sequence_group(RDSEncoder* enc, RDSGroup *group, char* grp, else get_rdsp_ertp_oda_group(group); TOGGLE(enc->state[enc->program].ert_oda); break; - case 'S': - if(enc->state[enc->program].ert_oda == 0) get_rds_ert_group(enc, group); - else get_rdsp_ert_oda_group(group); - TOGGLE(enc->state[enc->program].ert_oda); - break; case 'F': get_rds_lps_group(enc, group); break; @@ -145,8 +138,7 @@ static uint8_t check_rds_good_group(RDSEncoder* enc, char* grp) { if(*grp == 'X' && enc->data[enc->program].udg1_len != 0) good_group = 1; if(*grp == 'Y' && enc->data[enc->program].udg2_len != 0) good_group = 1; if(*grp == 'R' && enc->rtpData[enc->program][0].enabled) good_group = 1; - if(*grp == 'P' && enc->rtpData[enc->program][1].enabled && (_strnlen(enc->data[enc->program].ert, 65) < 64)) good_group = 1; - if(*grp == 'S' && enc->data[enc->program].ert[0] != '\0') good_group = 1; + if(*grp == 'P' && enc->rtpData[enc->program][1].enabled) good_group = 1; if(*grp == 'F' && enc->data[enc->program].lps[0] != '\0') good_group = 1; if(*grp == 'T') good_group = 1; if(*grp == 'L') good_group = 1; @@ -364,7 +356,6 @@ void reset_rds_state(RDSEncoder* enc, uint8_t program) { tempCoder.state[program].ptyn_ab = 1; set_rds_rt1(&tempCoder, enc->data[program].rt1); set_rds_rt2(&tempCoder, enc->data[program].rt2); - set_rds_ert(&tempCoder, enc->data[program].ert); set_rds_ps(&tempCoder, enc->data[program].ps); set_rds_tps(&tempCoder, enc->data[program].tps); set_rds_ptyn(&tempCoder, enc->data[program].ptyn); diff --git a/src/rds.h b/src/rds.h index 0f3b83e..19f2cec 100644 --- a/src/rds.h +++ b/src/rds.h @@ -1,6 +1,6 @@ #pragma once #include "common.h" -#define LUA_USER_DATA 512 +#define LUA_USER_DATA 768 /* The RDS error-detection code generator polynomial is * x^10 + x^8 + x^7 + x^5 + x^4 + x^3 + x^0 @@ -14,7 +14,6 @@ #define RDS_SAMPLE_RATE 4750 #define RT_LENGTH 64 -#define ERT_LENGTH 128 #define PS_LENGTH 8 #define PTYN_LENGTH 8 #define LPS_LENGTH 32 @@ -30,7 +29,6 @@ // List of ODAs: https://www.nrscstandards.org/committees/dsm/archive/rds-oda-aids.pdf #define ODA_AID_RTPLUS 0x4bd7 -#define ODA_AID_ERT 0x6552 #define ODA_AID_ERTPLUS 0x4BD8 #define ODA_AID_ODAAF 0x6365 @@ -79,10 +77,6 @@ typedef struct { char default_rt[RT_LENGTH]; char rt2[RT_LENGTH]; - uint8_t ert_switching_period; - uint8_t orignal_ert_switching_period; - char ert[ERT_LENGTH]; - uint8_t ptyn_enabled : 1; char ptyn[PTYN_LENGTH]; @@ -144,11 +138,6 @@ typedef struct { uint8_t rt_segments : 5; uint8_t rt2_segments : 5; - char ert_text[ERT_LENGTH]; - uint8_t ert_state : 6; - uint8_t ert_update : 1; - uint8_t ert_segments : 6; - char ptyn_text[PTYN_LENGTH]; uint8_t ptyn_state : 1; uint8_t ptyn_update : 1; @@ -254,7 +243,6 @@ void set_rds_rt2(RDSEncoder* enc, const char *rt2); void set_rds_ps(RDSEncoder* enc, const char *ps); void set_rds_tps(RDSEncoder* enc, const char *tps); void set_rds_lps(RDSEncoder* enc, const char *lps); -void set_rds_ert(RDSEncoder *enc, const char *ert); void set_rds_rtplus_tags(RDSEncoder *enc, uint8_t *tags); void set_rds_ertplus_tags(RDSEncoder *enc, uint8_t *tags); void set_rds_ptyn(RDSEncoder *enc, const char *ptyn); diff --git a/src/rds_groups.c b/src/rds_groups.c index 74ffa82..c79fd1e 100644 --- a/src/rds_groups.c +++ b/src/rds_groups.c @@ -148,13 +148,6 @@ void get_rdsp_ertp_oda_group(RDSGroup *group) { group->d = ODA_AID_ERTPLUS; } -void get_rdsp_ert_oda_group(RDSGroup *group) { - group->b |= 3 << 12; - group->b |= 12 << 1; - group->c = 1; // UTF-8 - group->d = ODA_AID_ERT; -} - void get_rdsp_oda_af_oda_group(RDSGroup *group) { group->b |= 3 << 12; group->b |= 7 << 1; @@ -326,22 +319,6 @@ void get_rds_eon_group(RDSEncoder* enc, RDSGroup *group) { } } -void get_rds_ert_group(RDSEncoder* enc, RDSGroup *group) { - if (enc->state[enc->program].ert_state == 0 && enc->state[enc->program].ert_update) { - memcpy(enc->state[enc->program].ert_text, enc->data[enc->program].ert, ERT_LENGTH); - enc->state[enc->program].ert_update = 0; - } - - group->b |= 12 << 12 | (enc->state[enc->program].ert_state & 31); - group->c = enc->state[enc->program].ert_text[enc->state[enc->program].ert_state * 4] << 8; - group->c |= enc->state[enc->program].ert_text[enc->state[enc->program].ert_state * 4 + 1]; - group->d = enc->state[enc->program].ert_text[enc->state[enc->program].ert_state * 4 + 2] << 8; - group->d |= enc->state[enc->program].ert_text[enc->state[enc->program].ert_state * 4 + 3]; - - enc->state[enc->program].ert_state++; - if (enc->state[enc->program].ert_state >= enc->state[enc->program].ert_segments) enc->state[enc->program].ert_state = 0; -} - uint8_t get_rds_custom_groups(RDSEncoder* enc, RDSGroup *group) { if(enc->state[enc->program].custom_group[0] == 1) { enc->state[enc->program].custom_group[0] = 0; diff --git a/src/rds_setters.c b/src/rds_setters.c index 2aae80c..50138e7 100644 --- a/src/rds_setters.c +++ b/src/rds_setters.c @@ -87,27 +87,6 @@ void set_rds_lps(RDSEncoder* enc, const char *lps) { if(enc->state[enc->program].lps_segments > 8) enc->state[enc->program].lps_segments = 8; //make sure } -void set_rds_ert(RDSEncoder* enc, const char *ert) { - uint8_t i = 0, len = 0; - - enc->state[enc->program].ert_update = 1; - - memset(enc->data[enc->program].ert, ' ', ERT_LENGTH); - while (*ert != 0 && len < ERT_LENGTH) enc->data[enc->program].ert[len++] = *ert++; - - while (len > 0 && enc->data[enc->program].ert[len - 1] == ' ') len--; - - if (len < ERT_LENGTH) { - enc->state[enc->program].ert_segments = 0; - enc->data[enc->program].ert[len++] = '\r'; - while (i < len) { - i += 4; - enc->state[enc->program].ert_segments++; - } - } else enc->state[enc->program].ert_segments = 32; - if(enc->state[enc->program].ert_segments > 32) enc->state[enc->program].ert_segments = 32; //make sure -} - inline void set_rds_rtplus_tags(RDSEncoder* enc, uint8_t *tags) { enc->rtpData[enc->program][0].type[0] = tags[0] & 0x3f; enc->rtpData[enc->program][0].start[0] = tags[1] & 0x3f;