0
1
mirror of https://github.com/radio95-rnt/rds95.git synced 2026-02-26 20:33:53 +01:00

massive lua api refactor

This commit is contained in:
2026-01-20 19:50:04 +01:00
parent 97f9b3069c
commit 53c9169330
15 changed files with 976 additions and 776 deletions

View File

@@ -30,5 +30,8 @@
"ffi": "disable", "ffi": "disable",
"package": "disable" "package": "disable"
}, },
"C_Cpp.dimInactiveRegions": false "C_Cpp.dimInactiveRegions": false,
"Lua.diagnostics.disable": [
"duplicate-set-field"
]
} }

View File

@@ -3,48 +3,62 @@
-- Global Variables -- Global Variables
---@type string ---@type string
core_version = "" core_version = ""
---@type integer
eon_count = 0
---@type integer
max_programs = 0
---@type integer
user_data_len = 0
--#region Functions implemented or used in C --#region Functions implemented or used in C
---Executes a CRC-16 CCIIT dp = {}
---@type integer
dp.max_programs = 0
---Executes a CRC-16 CCIIT on given data
---@param data string ---@param data string
---@return integer ---@return integer
function crc16(data) end function dp.crc16(data) end
---Starts the initialization sequence, also calls the on_init function ---Starts the initialization sequence, also calls the on_init function
---@return nil ---@return nil
function set_rds_program_defaults() end function dp.set_rds_program_defaults() end
---Saves, loads and resets the state of the data, you might as well restart the whole program ---Saves, loads and resets the state of the data, you might as well restart the whole program
---@return nil ---@return nil
function reset_rds() end function dp.reset_rds() end
---Forces encoder and modulator data to be saved to disc ---Forces encoder and modulator data to be saved to disc
---@return nil ---@return nil
function force_save() end function dp.force_save() end
---@param program_idx integer 0 to (max_programs - 1)
function dp.set_rds_program(program_idx) end
---@return integer
function dp.get_rds_program() end
---This function is called by the C core after we reset data, or have no data in general ---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. ---It should be defined by the user in the script.
---@return nil ---@return nil
function on_init() end function on_init() end
on_inits = {}
---This function is called by the C core after we initialize the encoder (always, every start) ---This function is called by the C core after we initialize the encoder (always, every start)
---It should be defined by the user in the script. ---It should be defined by the user in the script.
---@return nil ---@return nil
function on_start() end function on_start() end
on_starts = {}
---This function is called every time when the state resets, register your odas here ---This function is called every time when the state resets, register your odas here
---It should be defined by the user in the script. ---It should be defined by the user in the script.
---@return nil ---@return nil
function on_state() end function on_state() end
on_states = {}
---This function is called every second ---This function is called every second
---It should be defined by the user in the script. ---It should be defined by the user in the script.
---@return nil ---@return nil
function tick() end function tick() end
ticks = {}
-- Every function with with the s suffixed table means that other versions of that function can be in that list-table, and each one will be called
---This function is called in order to handle UDP data ---This function is called in order to handle UDP data
---It should be defined by the user in the script. ---It should be defined by the user in the script.
---@param data string ---@param data string
@@ -70,72 +84,77 @@ function group(group) end
---@return integer d ---@return integer d
function rds2_group(stream) end function rds2_group(stream) end
rds = {}
---@type integer
rds.eon_count = 0
---@param pi integer ---@param pi integer
function set_rds_pi(pi) end function rds.set_pi(pi) end
---@return integer ---@return integer
function get_rds_pi() end function rds.get_pi() end
---@param pty integer ---@param pty integer
function set_rds_pty(pty) end function rds.set_pty(pty) end
---@return integer ---@return integer
function get_rds_pty() end function rds.get_pty() end
---@param ecc integer ---@param ecc integer
function set_rds_ecc(ecc) end function rds.set_ecc(ecc) end
---@return integer ---@return integer
function get_rds_ecc() end function rds.get_ecc() end
---@param slc_data integer ---@param slc_data integer
function set_rds_slc_data(slc_data) end function rds.set_slc_data(slc_data) end
---@return integer ---@return integer
function get_rds_slc_data() end function rds.get_slc_data() end
---@param ct boolean ---@param ct boolean
function set_rds_ct(ct) end function rds.set_ct(ct) end
---@return boolean ---@return boolean
function get_rds_ct() end function rds.get_ct() end
---@param dpty boolean ---@param dpty boolean
function set_rds_dpty(dpty) end function rds.set_dpty(dpty) end
---@return boolean ---@return boolean
function get_rds_dpty() end function rds.get_dpty() end
---@param tp boolean ---@param tp boolean
function set_rds_tp(tp) end function rds.set_tp(tp) end
---@return boolean ---@return boolean
function get_rds_tp() end function rds.get_tp() end
---@param ta boolean ---@param ta boolean
function set_rds_ta(ta) end function rds.set_ta(ta) end
---@return boolean ---@return boolean
function get_rds_ta() end function rds.get_ta() end
-- Feature Flags -- Feature Flags
---@param enabled boolean ---@param enabled boolean
function set_rds_rt1_enabled(enabled) end function rds.set_rt1_enabled(enabled) end
---@return boolean ---@return boolean
function get_rds_rt1_enabled() end function rds.get_rt1_enabled() end
---@param enabled boolean ---@param enabled boolean
function set_rds_rt2_enabled(enabled) end function rds.set_rt2_enabled(enabled) end
---@return boolean ---@return boolean
function get_rds_rt2_enabled() end function rds.get_rt2_enabled() end
---@param enabled boolean ---@param enabled boolean
function set_rds_ptyn_enabled(enabled) end function rds.set_ptyn_enabled(enabled) end
---@return boolean ---@return boolean
function get_rds_ptyn_enabled() end function rds.get_ptyn_enabled() end
---@param rt_type integer ---@param rt_type integer
function set_rds_rt_type(rt_type) end function rds.set_rt_type(rt_type) end
---@return integer ---@return integer
function get_rds_rt_type() end function rds.get_rt_type() end
-- Modulation & Generation -- Modulation & Generation
---@param mode integer ---@param mode integer
function set_rds2_mode(mode) end function rds.set_rds2_mode(mode) end
---@return integer ---@return integer
function get_rds2_mode() end function rds.get_rds2_mode() end
---@param streams integer ---@param streams integer
function set_rds_streams(streams) end function set_rds_streams(streams) end
@@ -152,72 +171,67 @@ function get_rds_level() end
-- Program & Linking -- Program & Linking
---@param linkage boolean ---@param linkage boolean
function set_rds_link(linkage) end function rds.set_link(linkage) end
---@return boolean ---@return boolean
function get_rds_link() end function rds.get_link() end
---@param program_idx integer 0 to (max_programs - 1)
function set_rds_program(program_idx) end
---@return integer
function get_rds_program() end
-- Timeouts and Periods -- Timeouts and Periods
---@param period integer in seconds ---@param period integer in seconds
function set_rds_rt_switching_period(period) end function rds.set_rt_switching_period(period) end
---@return integer ---@return integer
function get_rds_rt_switching_period() end function rds.get_rt_switching_period() end
---For a RT1, this sets the timeout period before setting RT1 into "Default RT" (not literally) ---For a RT1, this sets the timeout period before setting RT1 into "Default RT" (not literally)
---@param timeout integer in seconds ---@param timeout integer in seconds
function set_rds_rt_text_timeout(timeout) end function rds.set_rt_text_timeout(timeout) end
---@return integer ---@return integer
function get_rds_rt_text_timeout() end function rds.get_rt_text_timeout() end
-- String Setters (Charset converted) -- String Setters (Charset converted)
---@param ptyn string Program Type Name (max 8 chars) ---@param ptyn string Program Type Name (max 8 chars)
function set_rds_ptyn(ptyn) end function rds.set_ptyn(ptyn) end
---@param ps string Program Service (8 chars) ---@param ps string Program Service (8 chars)
function set_rds_ps(ps) end function rds.set_ps(ps) end
---@param tps string Traffic PS ---@param tps string Traffic PS
function set_rds_tps(tps) end function rds.set_tps(tps) end
---@param rt1 string Radio Text 1 (max 64 chars) ---@param rt1 string Radio Text 1 (max 64 chars)
function set_rds_rt1(rt1) end function rds.set_rt1(rt1) end
---@param rt2 string Radio Text 2 (max 64 chars) ---@param rt2 string Radio Text 2 (max 64 chars)
function set_rds_rt2(rt2) end function rds.set_rt2(rt2) end
---@param rt string Default radio text - max 64 characters ---@param rt string Default radio text - max 64 characters
function set_rds_default_rt(rt) end function rds.set_default_rt(rt) end
---@param lps string ---@param lps string
function set_rds_lps(lps) end function rds.set_lps(lps) end
---@return string ---@return string
function get_rds_lps() end function rds.get_lps() end
---@param grpseq string ---@param grpseq string
function set_rds_grpseq(grpseq) end function rds.set_grpseq(grpseq) end
---@return string ---@return string
function get_rds_grpseq() end function rds.get_grpseq() end
---@param grpseq2 string ---@param grpseq2 string
function set_rds_grpseq2(grpseq2) end function rds.set_grpseq2(grpseq2) end
---@return string ---@return string
function get_rds_grpseq2() end function rds.get_grpseq2() end
---Puts in a RDS1 group in the buffer, note that block A is filled in always ---Puts in a RDS1 group in the buffer, note that block A is filled in always
---@param b integer ---@param b integer
---@param c integer ---@param c integer
---@param d integer ---@param d integer
function put_rds_custom_group(b, c, d) end function rds.put_custom_group(b, c, d) end
---Puts in a RDS2 group in the buffer ---Puts in a RDS2 group in the buffer
---@param a integer ---@param a integer
---@param b integer ---@param b integer
---@param c integer ---@param c integer
---@param d integer ---@param d integer
function put_rds2_custom_group(a, b, c, d) end function rds.put_rds2_custom_group(a, b, c, d) end
---Sets the AFs included in group 0 ---Sets the AFs included in group 0
---@param afs table ---@param afs table
function set_rds_af_group0(afs) end function rds.set_af(afs) end
---Sets data about the EON ---Sets data about the EON
---@param eon integer Index of the EON we are setting ---@param eon integer Index of the EON we are setting
@@ -229,7 +243,7 @@ function set_rds_af_group0(afs) end
---@param ps string ---@param ps string
---@param afs table ---@param afs table
---@param data integer ---@param data integer
function set_rds_eon(eon, enabled, pi, tp, ta, pty, ps, afs, data) end function rds.set_eon(eon, enabled, pi, tp, ta, pty, ps, afs, data) end
---Gets the same data set_rds_eon sets, yes this returns 8 arguments ---Gets the same data set_rds_eon sets, yes this returns 8 arguments
---@param eon integer ---@param eon integer
@@ -241,37 +255,45 @@ function set_rds_eon(eon, enabled, pi, tp, ta, pty, ps, afs, data) end
---@return string ps ---@return string ps
---@return table _ this is empty, getting afs is not supported yet ---@return table _ this is empty, getting afs is not supported yet
---@return integer data ---@return integer data
function get_rds_eon(eon) end function rds.get_eon(eon) end
---Sets the X/Y of the UDG ---Sets the X/Y of the UDG
---@param xy boolean ---@param xy boolean
---@param groups table Table of tables, this should be up to 8 tables containing 3 integers ---@param groups table Table of tables, this should be up to 8 tables containing 3 integers
function set_rds_udg(xy, groups) end function rds.set_udg(xy, groups) end
---Sets the X/Y of the UDG for RDS2 ---Sets the X/Y of the UDG for RDS2
---@param xy boolean ---@param xy boolean
---@param groups table Table of tables, this should be up to 8 tables containing 4 integers ---@param groups table Table of tables, this should be up to 8 tables containing 4 integers
function set_rds_udg2(xy, groups) end function rds.set_udg2(xy, groups) end
userdata = {}
---@type integer
userdata.len = 0
---Data is allocated in each program's data for lua data (per program, diffrent program, diffrent data), note that this overwrites existing data over the whole userdata string ---Data is allocated in each program's data for lua data (per program, diffrent program, diffrent data), note that this overwrites existing data over the whole userdata string
---@param data string ---@param data string
function set_userdata(data) end function userdata.set(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 ---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 offset integer
---@param size integer ---@param size integer
---@param data string ---@param data string
function set_userdata_offset(offset, size, data) end function userdata.set_offset(offset, size, data) end
---Returns all of the data saved as user data ---Returns all of the data saved as user data
---@return string ---@return string
function get_userdata() end function userdata.get() end
---Gets data from userdata but at the specified offset ---Gets data from userdata but at the specified offset
---@param offset integer ---@param offset integer
---@param size integer ---@param size integer
---@return string ---@return string
function get_userdata_offset(offset, size) end function userdata.get_offset(offset, size) end
--#endregion --#endregion
ext = {}
rds.ext = {}
-- RT Plus Tags -- RT Plus Tags
---Sets RT+ tags: type1, start1, len1, type2, start2, len2 ---Sets RT+ tags: type1, start1, len1, type2, start2, len2
---@param ertp boolean ---@param ertp boolean
@@ -281,29 +303,29 @@ function get_userdata_offset(offset, size) end
---@param t2 integer ---@param t2 integer
---@param s2 integer ---@param s2 integer
---@param l2 integer ---@param l2 integer
function set_rds_rtplus_tags(ertp, t1, s1, l1, t2, s2, l2) end function rds.ext.set_rtplus_tags(ertp, t1, s1, l1, t2, s2, l2) end
---Gets RT+ tags: type1, start1, len1, type2, start2, len2 ---Gets RT+ tags: type1, start1, len1, type2, start2, len2
---@param ertp boolean ---@param ertp boolean
---@return integer type1, integer start1, integer len1, integer type2, integer start2, integer len2 ---@return integer type1, integer start1, integer len1, integer type2, integer start2, integer len2
function get_rds_rtplus_tags(ertp) end function rds.ext.get_rtplus_tags(ertp) end
---Toggles RTP or ERTP's toggle switch ---Toggles RTP or ERTP's toggle switch
---@param ertp boolean ---@param ertp boolean
function toggle_rds_rtp(ertp) end function rds.ext.toggle_rtp(ertp) end
---Sets the metadata of RTP or ERTP ---Sets the metadata of RTP or ERTP
---@param ertp boolean ---@param ertp boolean
---@param running boolean ---@param running boolean
function set_rds_rtp_meta(ertp, running) end function rds.ext.set_rtp_meta(ertp, running) end
---Gets the metadata of RTP and ERTP ---Gets the metadata of RTP and ERTP
---@param ertp boolean ---@param ertp boolean
---@return boolean running ---@return boolean running
function get_rds_rtp_meta(ertp) end function rds.ext.get_rtp_meta(ertp) end
---Sets the AFs included in the ODA ---Sets the AFs included in the ODA
---@param afs table ---@param afs table
function set_rds_af_oda(afs) end function rds.ext.set_af_oda(afs) end
---Registers an ODA to be used in the O of the group sequence. ODAs are stored as state data, thus running reset_rds will clear it ---Registers an ODA to be used in the O of the group sequence. ODAs are stored as state data, thus running reset_rds will clear it
---Groups 14, 15, 2, 0 cannot be registered either version, groups 10, 4, 1 can be only registered as B, any other is free to take ---Groups 14, 15, 2, 0 cannot be registered either version, groups 10, 4, 1 can be only registered as B, any other is free to take
@@ -313,16 +335,16 @@ function set_rds_af_oda(afs) end
---@param aid integer ---@param aid integer
---@param data integer ---@param data integer
---@return integer oda_id ---@return integer oda_id
function register_oda(group, group_version, aid, data) end function ext.register_oda(group, group_version, aid, data) end
---Unregisters an ODA, this stops the handler or AID being called/sent ---Unregisters an ODA, this stops the handler or AID being called/sent
---@param oda_id integer ---@param oda_id integer
function unregister_oda(oda_id) end function ext.unregister_oda(oda_id) end
---Sets the data for a existing ODA group ---Sets the data for a existing ODA group
---@param oda_id integer ---@param oda_id integer
---@param data integer ---@param data integer
function set_oda_id_data(oda_id, data) end function ext.set_oda_id_data(oda_id, data) end
---The callback function for an ODA handler ---The callback function for an ODA handler
---@alias ODAHandler fun(): (boolean, integer, integer, integer) ---@alias ODAHandler fun(): (boolean, integer, integer, integer)
@@ -334,7 +356,7 @@ function set_oda_id_data(oda_id, data) end
---You are asked to set groups B last 5 bits, leave rest 0 ---You are asked to set groups B last 5 bits, leave rest 0
---@param oda_id integer The ID returned by register_oda ---@param oda_id integer The ID returned by register_oda
---@param fun ODAHandler ---@param fun ODAHandler
function set_oda_handler(oda_id, fun) end function ext.set_oda_handler(oda_id, fun) end
---The callback function for an ODA handler ---The callback function for an ODA handler
---@alias RDS2_ODAHandler fun(integer): (boolean, integer, integer, integer, integer) ---@alias RDS2_ODAHandler fun(integer): (boolean, integer, integer, integer, integer)
@@ -342,23 +364,23 @@ function set_oda_handler(oda_id, fun) end
---You are asked to not fill in the channel id in block A, however you are asked to fill in the function number (if you do not know what is that, just OR block A with (1 << 14)) ---You are asked to not fill in the channel id in block A, however you are asked to fill in the function number (if you do not know what is that, just OR block A with (1 << 14))
---@param oda_id integer ---@param oda_id integer
---@param func RDS2_ODAHandler ---@param func RDS2_ODAHandler
function set_oda_handler_rds2(oda_id, func) end function ext.set_oda_handler_rds2(oda_id, func) end
---@param oda_id integer ---@param oda_id integer
---@param data integer ---@param data integer
function set_oda_id_data_rds2(oda_id, data) end function ext.set_oda_id_data_rds2(oda_id, data) end
---@param aid integer ---@param aid integer
---@param data integer ---@param data integer
---@param file_related boolean ---@param file_related boolean
---@return integer oda_id ---@return integer oda_id
function register_oda_rds2(aid, data, file_related) end function ext.register_oda_rds2(aid, data, file_related) end
---Unregisters an RDS 2 ODA, this stops the handler or AID being called/sent ---Unregisters an RDS 2 ODA, this stops the handler or AID being called/sent
---@param oda_id integer ---@param oda_id integer
function unregister_oda_rds2(oda_id) end function ext.unregister_oda_rds2(oda_id) end
---@param ert string ---@param ert string
function set_rds_ert(ert) end function rds.ext.set_ert(ert) end
---@return string ---@return string
function get_rds_ert() end function rds.ext.get_ert() end

View File

@@ -17,7 +17,7 @@ local _RDS_ODA_pointer = 1
---@param aid integer ---@param aid integer
---@param data integer ---@param data integer
---@return integer oda_id ---@return integer oda_id
function register_oda(group, group_version, aid, data) function ext.register_oda(group, group_version, aid, data)
if group == 14 or group == 15 or group == 2 or group == 0 then error("Group is incorrect", 2) end if group == 14 or group == 15 or group == 2 or group == 0 then error("Group is incorrect", 2) end
if (group == 10 or group == 4 or group == 1) and group_version then error("Group is incorrect", 2) end if (group == 10 or group == 4 or group == 1) and group_version then error("Group is incorrect", 2) end
local oda = _ODA.new(group, group_version, aid, data, false) local oda = _ODA.new(group, group_version, aid, data, false)
@@ -33,7 +33,7 @@ end
---Unregisters an ODA, this stops the handler or AID being called/sent ---Unregisters an ODA, this stops the handler or AID being called/sent
---@param oda_id integer ---@param oda_id integer
function unregister_oda(oda_id) function ext.unregister_oda(oda_id)
if oda_id < 1 or oda_id > #_RDS_ODAs or _RDS_ODAs[oda_id] == false then error("Invalid ODA ID: " .. tostring(oda_id), 2) end if oda_id < 1 or oda_id > #_RDS_ODAs or _RDS_ODAs[oda_id] == false then error("Invalid ODA ID: " .. tostring(oda_id), 2) end
_RDS_ODAs[oda_id] = false _RDS_ODAs[oda_id] = false
@@ -45,7 +45,7 @@ end
---Sets the id_data for a existing ODA group ---Sets the id_data for a existing ODA group
---@param oda_id integer ---@param oda_id integer
---@param data integer ---@param data integer
function set_oda_id_data(oda_id, data) function ext.set_oda_id_data(oda_id, data)
if oda_id < 1 or oda_id > #_RDS_ODAs or _RDS_ODAs[oda_id] == false then error("Invalid ODA ID: " .. tostring(oda_id), 2) end if oda_id < 1 or oda_id > #_RDS_ODAs or _RDS_ODAs[oda_id] == false then error("Invalid ODA ID: " .. tostring(oda_id), 2) end
_RDS_ODAs[oda_id].data = data _RDS_ODAs[oda_id].data = data
end end
@@ -57,7 +57,7 @@ end
---You are asked to set groups B last 5 bits, leave rest 0 ---You are asked to set groups B last 5 bits, leave rest 0
---@param oda_id integer The ID returned by register_oda ---@param oda_id integer The ID returned by register_oda
---@param fun ODAHandler ---@param fun ODAHandler
function set_oda_handler(oda_id, fun) function ext.set_oda_handler(oda_id, fun)
if oda_id < 1 or oda_id > #_RDS_ODAs or _RDS_ODAs[oda_id] == false then error("Invalid ODA ID: " .. tostring(oda_id), 2) end if oda_id < 1 or oda_id > #_RDS_ODAs or _RDS_ODAs[oda_id] == false then error("Invalid ODA ID: " .. tostring(oda_id), 2) end
if _RDS_ODAs[oda_id].group == 3 then error("3A ODAs cannot have handlers.", 2) end if _RDS_ODAs[oda_id].group == 3 then error("3A ODAs cannot have handlers.", 2) end
_RDS_ODAs[oda_id].handler = fun _RDS_ODAs[oda_id].handler = fun
@@ -113,18 +113,13 @@ function group(group_type)
if #_RDS_ODAs == 0 then return false, 0, 0, 0 end if #_RDS_ODAs == 0 then return false, 0, 0, 0 end
if _RDS_ODA_pointer > #_RDS_ODAs or _RDS_ODA_pointer < 1 then _RDS_ODA_pointer = 1 end if _RDS_ODA_pointer > #_RDS_ODAs or _RDS_ODA_pointer < 1 then _RDS_ODA_pointer = 1 end
if group_type == "O" then if group_type == "O" then return get_aid()
return get_aid() elseif group_type == "K" then return get_data() end
elseif group_type == "K" then
return get_data()
end
end end
return false, 0, 0, 0 return false, 0, 0, 0
end end
local _old_on_state_oda = on_state table.insert(on_states, function ()
function on_state()
_RDS_ODAs = {} _RDS_ODAs = {}
_RDS_ODA_pointer = 1 _RDS_ODA_pointer = 1
if type(_old_on_state_oda) == "function" then _old_on_state_oda() end end)
end

View File

@@ -14,7 +14,7 @@ _RDS2_ODA_pointer = 1
---@param data integer ---@param data integer
---@param file_related boolean ---@param file_related boolean
---@return integer oda_id ---@return integer oda_id
function register_oda_rds2(aid, data, file_related) function ext.register_oda_rds2(aid, data, file_related)
local oda = _RDS2_ODA.new(aid, data, false, file_related) local oda = _RDS2_ODA.new(aid, data, false, file_related)
for i = 1, #_RDS2_ODAs do for i = 1, #_RDS2_ODAs do
if _RDS2_ODAs[i] == false then if _RDS2_ODAs[i] == false then
@@ -28,7 +28,7 @@ end
---Unregisters an RDS 2 ODA, this stops the handler or AID being called/sent ---Unregisters an RDS 2 ODA, this stops the handler or AID being called/sent
---@param oda_id integer ---@param oda_id integer
function unregister_oda_rds2(oda_id) function ext.unregister_oda_rds2(oda_id)
if oda_id < 1 or oda_id > #_RDS2_ODAs or _RDS2_ODAs[oda_id] == false then error("Invalid ODA ID: " .. tostring(oda_id), 2) end if oda_id < 1 or oda_id > #_RDS2_ODAs or _RDS2_ODAs[oda_id] == false then error("Invalid ODA ID: " .. tostring(oda_id), 2) end
_RDS2_ODAs[oda_id] = false _RDS2_ODAs[oda_id] = false
@@ -39,14 +39,14 @@ end
---@param oda_id integer ---@param oda_id integer
---@param data integer ---@param data integer
function set_oda_id_data_rds2(oda_id, data) function ext.set_oda_id_data_rds2(oda_id, data)
if oda_id < 1 or oda_id > #_RDS2_ODAs or _RDS2_ODAs[oda_id] == false then error("Invalid ODA ID: " .. tostring(oda_id), 2) end if oda_id < 1 or oda_id > #_RDS2_ODAs or _RDS2_ODAs[oda_id] == false then error("Invalid ODA ID: " .. tostring(oda_id), 2) end
_RDS2_ODAs[oda_id].data = data _RDS2_ODAs[oda_id].data = data
end end
---@param oda_id integer ---@param oda_id integer
---@param func RDS2_ODAHandler ---@param func RDS2_ODAHandler
function set_oda_handler_rds2(oda_id, func) function ext.set_oda_handler_rds2(oda_id, func)
if oda_id < 1 or oda_id > #_RDS2_ODAs or _RDS2_ODAs[oda_id] == false then error("Invalid ODA ID: " .. tostring(oda_id), 2) end if oda_id < 1 or oda_id > #_RDS2_ODAs or _RDS2_ODAs[oda_id] == false then error("Invalid ODA ID: " .. tostring(oda_id), 2) end
_RDS2_ODAs[oda_id].handler = func _RDS2_ODAs[oda_id].handler = func
end end
@@ -125,10 +125,8 @@ function rds2_group(stream)
end end
end end
local _old_on_state_oda_rds2 = on_state table.insert(on_states, function ()
function on_state()
_RDS2_ODAs = {} _RDS2_ODAs = {}
_RDS2_ODA_aid = 0 _RDS2_ODA_aid = 0
_RDS2_ODA_pointer = 1 _RDS2_ODA_pointer = 1
if type(_old_on_state_oda_rds2) == "function" then _old_on_state_oda_rds2() end end)
end

View File

@@ -55,8 +55,8 @@ end
local function init_af_oda() local function init_af_oda()
if _Af_Oda_id == nil then if _Af_Oda_id == nil then
_Af_Oda_id = register_oda(7, false, 0x6365, 0) _Af_Oda_id = ext.register_oda(7, false, 0x6365, 0)
set_oda_handler(_Af_Oda_id, function() ext.set_oda_handler(_Af_Oda_id, function()
local b, c, d = get_next_af_oda_group() local b, c, d = get_next_af_oda_group()
return true, b, c, d return true, b, c, d
end) end)
@@ -69,7 +69,7 @@ local function save_af_to_userdata(afs)
local payload = string.pack("B", count) local payload = string.pack("B", count)
for i = 1, count do payload = payload .. string.pack("f", afs[i]) end for i = 1, count do payload = payload .. string.pack("f", afs[i]) end
set_userdata_offset(USERDATA_ODA_OFFSET, #payload, payload) userdata.set_offset(USERDATA_ODA_OFFSET, #payload, payload)
end end
local function _process_af_list(afs) local function _process_af_list(afs)
@@ -86,13 +86,13 @@ local function _process_af_list(afs)
end end
local function load_af_from_userdata() local function load_af_from_userdata()
local header = get_userdata_offset(USERDATA_ODA_OFFSET, 1) local header = userdata.get_offset(USERDATA_ODA_OFFSET, 1)
if header == "" or header == nil then return end if header == "" or header == nil then return end
local count = string.unpack("B", header) local count = string.unpack("B", header)
if count == 0 or count > 25 then return end if count == 0 or count > 25 then return end
local data = get_userdata_offset(USERDATA_ODA_OFFSET + 1, count * 4) local data = userdata.get_offset(USERDATA_ODA_OFFSET + 1, count * 4)
if #data < (count * 4) then return end if #data < (count * 4) then return end
local afs = {} local afs = {}
@@ -106,14 +106,12 @@ end
---Sets the AFs included in the ODA and saves them ---Sets the AFs included in the ODA and saves them
---@param afs table List of numbers (e.g., {98.1, 102.5}) ---@param afs table List of numbers (e.g., {98.1, 102.5})
function set_rds_af_oda(afs) function rds.ext.set_af_oda(afs)
_process_af_list(afs) _process_af_list(afs)
save_af_to_userdata(afs) save_af_to_userdata(afs)
end end
local _old_on_state_af = on_state table.insert(on_states, function ()
function on_state()
load_af_from_userdata() load_af_from_userdata()
if _Af_Oda_len ~= 0 then init_af_oda() end if _Af_Oda_len ~= 0 then init_af_oda() end
if type(_old_on_state_af) == "function" then _old_on_state_af() end end)
end

View File

@@ -6,25 +6,25 @@ local USERDATA_ERT_OFFSET = 0
local function init_ert() local function init_ert()
if _Ert_oda_id == nil then if _Ert_oda_id == nil then
_Ert_oda_id = register_oda(13, false, 0x6552, 1) _Ert_oda_id = ext.register_oda(13, false, 0x6552, 1)
set_oda_handler(_Ert_oda_id, function () ext.set_oda_handler(_Ert_oda_id, function ()
if string.byte(get_userdata_offset(USERDATA_ERT_OFFSET+258, 1)) == 1 then if string.byte(userdata.get_offset(USERDATA_ERT_OFFSET+258, 1)) == 1 then
local new_data = get_userdata_offset(USERDATA_ERT_OFFSET, 128) local new_data = userdata.get_offset(USERDATA_ERT_OFFSET, 128)
local new_segments = string.byte(get_userdata_offset(USERDATA_ERT_OFFSET+128, 1)) local new_segments = string.byte(userdata.get_offset(USERDATA_ERT_OFFSET+128, 1))
set_userdata_offset(USERDATA_ERT_OFFSET+129, 128, new_data) userdata.set_offset(USERDATA_ERT_OFFSET+129, 128, new_data)
set_userdata_offset(USERDATA_ERT_OFFSET+257, 1, string.char(new_segments)) userdata.set_offset(USERDATA_ERT_OFFSET+257, 1, string.char(new_segments))
set_userdata_offset(USERDATA_ERT_OFFSET+258, 1, string.char(0)) userdata.set_offset(USERDATA_ERT_OFFSET+258, 1, string.char(0))
_Ert_state = 0 _Ert_state = 0
end end
local segments = string.byte(get_userdata_offset(USERDATA_ERT_OFFSET+257, 1)) local segments = string.byte(userdata.get_offset(USERDATA_ERT_OFFSET+257, 1))
if segments == 0 then return false, 0, 0, 0 end if segments == 0 then return false, 0, 0, 0 end
if _Ert_state >= segments then _Ert_state = 0 end if _Ert_state >= segments then _Ert_state = 0 end
local b = _Ert_state & 31 local b = _Ert_state & 31
local chunk = get_userdata_offset(USERDATA_ERT_OFFSET + 129 + _Ert_state * 4, 4) local chunk = userdata.get_offset(USERDATA_ERT_OFFSET + 129 + _Ert_state * 4, 4)
local c = (string.byte(chunk, 1) << 8) | string.byte(chunk, 2) local c = (string.byte(chunk, 1) << 8) | string.byte(chunk, 2)
local d = (string.byte(chunk, 3) << 8) | string.byte(chunk, 4) local d = (string.byte(chunk, 3) << 8) | string.byte(chunk, 4)
@@ -36,16 +36,16 @@ end
function unregister_ert() function unregister_ert()
if _Ert_oda_id ~= nil then if _Ert_oda_id ~= nil then
unregister_oda(_Ert_oda_id) ext.unregister_oda(_Ert_oda_id)
_Ert_oda_id = nil _Ert_oda_id = nil
end end
end end
function set_rds_ert(ert) function rds.ext.set_ert(ert)
if #ert == 0 then if #ert == 0 then
set_userdata_offset(USERDATA_ERT_OFFSET, 128, "") userdata.set_offset(USERDATA_ERT_OFFSET, 128, "")
set_userdata_offset(USERDATA_ERT_OFFSET+128, 1, string.char(0)) userdata.set_offset(USERDATA_ERT_OFFSET+128, 1, string.char(0))
set_userdata_offset(USERDATA_ERT_OFFSET+258, 1, string.char(1)) userdata.set_offset(USERDATA_ERT_OFFSET+258, 1, string.char(1))
return return
end end
@@ -55,33 +55,31 @@ function set_rds_ert(ert)
local padding = (4 - (#data % 4)) % 4 local padding = (4 - (#data % 4)) % 4
data = data .. string.rep("\0", padding) data = data .. string.rep("\0", padding)
set_userdata_offset(USERDATA_ERT_OFFSET, 128, data) userdata.set_offset(USERDATA_ERT_OFFSET, 128, data)
local segments = #data // 4 local segments = #data // 4
if segments > 32 then segments = 32 end if segments > 32 then segments = 32 end
set_userdata_offset(USERDATA_ERT_OFFSET+128, 1, string.char(segments)) userdata.set_offset(USERDATA_ERT_OFFSET+128, 1, string.char(segments))
if string.byte(get_userdata_offset(USERDATA_ERT_OFFSET+257, 1)) == 0 then if string.byte(userdata.get_offset(USERDATA_ERT_OFFSET+257, 1)) == 0 then
init_ert() init_ert()
set_userdata_offset(USERDATA_ERT_OFFSET+129, 128, data) userdata.set_offset(USERDATA_ERT_OFFSET+129, 128, data)
set_userdata_offset(USERDATA_ERT_OFFSET+257, 1, string.char(segments)) userdata.set_offset(USERDATA_ERT_OFFSET+257, 1, string.char(segments))
_Ert_state = 0 _Ert_state = 0
else set_userdata_offset(USERDATA_ERT_OFFSET+258, 1, string.char(1)) end else userdata.set_offset(USERDATA_ERT_OFFSET+258, 1, string.char(1)) end
if _Ert_oda_id == nil then init_ert() end if _Ert_oda_id == nil then init_ert() end
end end
function get_rds_ert() function rds.ext.get_ert()
local segments = string.byte(get_userdata_offset(USERDATA_ERT_OFFSET+128, 1)) local segments = string.byte(userdata.get_offset(USERDATA_ERT_OFFSET+128, 1))
if segments == 0 then return "" end if segments == 0 then return "" end
local data = get_userdata_offset(USERDATA_ERT_OFFSET, 128) local data = userdata.get_offset(USERDATA_ERT_OFFSET, 128)
return data:match("^(.-)[\r%z]*") or "" return data:match("^(.-)[\r%z]*") or ""
end end
local _old_on_state_ert = on_state table.insert(on_states, function ()
function on_state() if string.byte(userdata.get_offset(USERDATA_ERT_OFFSET+257, 1)) ~= 0 then init_ert() end
if string.byte(get_userdata_offset(USERDATA_ERT_OFFSET+257, 1)) ~= 0 then init_ert() end end)
if type(_old_on_state_ert) == "function" then _old_on_state_ert() end
end

View File

@@ -43,7 +43,7 @@ end
function RftInstance:stop() function RftInstance:stop()
if self.oda_id ~= nil and self.aid ~= 0 then if self.oda_id ~= nil and self.aid ~= 0 then
unregister_oda_rds2(self.oda_id) ext.unregister_oda_rds2(self.oda_id)
self.oda_id = nil self.oda_id = nil
end end
@@ -59,9 +59,9 @@ end
---@private ---@private
function RftInstance:start() function RftInstance:start()
if self.oda_id == nil and self.aid ~= 0 then if self.oda_id == nil and self.aid ~= 0 then
self.oda_id = register_oda_rds2(self.aid, 0, true) self.oda_id = ext.register_oda_rds2(self.aid, 0, true)
set_oda_handler_rds2(self.oda_id, function(stream) ext.set_oda_handler_rds2(self.oda_id, function(stream)
if #self.file_data == 0 or self.paused then if #self.file_data == 0 or self.paused then
return false, 0, 0, 0, 0 return false, 0, 0, 0, 0
end end
@@ -138,7 +138,7 @@ function RftInstance:sendFile(aid, path, id, crc, once)
local f_size = #self.file_data local f_size = #self.file_data
if crc == 0 then if crc == 0 then
self.crc_mode = 0 self.crc_mode = 0
self.crc_full_file = crc16(self.file_data) self.crc_full_file = dp.crc16(self.file_data)
elseif crc == true or crc == 7 then elseif crc == true or crc == 7 then
if f_size <= 40960 then self.crc_mode = 1 if f_size <= 40960 then self.crc_mode = 1
elseif f_size > 40960 and f_size <= 81920 then self.crc_mode = 2 elseif f_size > 40960 and f_size <= 81920 then self.crc_mode = 2
@@ -153,7 +153,7 @@ function RftInstance:sendFile(aid, path, id, crc, once)
local chunk_size = 5 * multiplier local chunk_size = 5 * multiplier
for i = 1, f_size, chunk_size do for i = 1, f_size, chunk_size do
local chunk = string.sub(self.file_data, i, i + chunk_size - 1) local chunk = string.sub(self.file_data, i, i + chunk_size - 1)
local v = crc16(chunk) local v = dp.crc16(chunk)
self.crc_data = self.crc_data .. string.char(v >> 8, v & 0xff) self.crc_data = self.crc_data .. string.char(v >> 8, v & 0xff)
end end
end end
@@ -161,7 +161,7 @@ function RftInstance:sendFile(aid, path, id, crc, once)
if f_size > (0x3ffff * 5) then error("File too large") end if f_size > (0x3ffff * 5) then error("File too large") end
if self.oda_id == nil then self:start() end if self.oda_id == nil then self:start() end
set_oda_id_data_rds2(self.oda_id, f_size | (id & 63) << 18 | (self.version & 7) << 24 | (self.crc_enabled and 1 or 0) << 27) ext.set_oda_id_data_rds2(self.oda_id, f_size | (id & 63) << 18 | (self.version & 7) << 24 | (self.crc_enabled and 1 or 0) << 27)
self.last_id = id self.last_id = id
self.paused = false self.paused = false
return interrupted return interrupted

View File

@@ -8,11 +8,11 @@ local USERDATA_RTP_OFFSET = 259
local function init_rtp() local function init_rtp()
if _Rtp_oda_id == nil then if _Rtp_oda_id == nil then
_Rtp_oda_id = register_oda(11, false, 0x4BD7, 0) _Rtp_oda_id = ext.register_oda(11, false, 0x4BD7, 0)
set_oda_handler(_Rtp_oda_id, function () ext.set_oda_handler(_Rtp_oda_id, function ()
local b = (_Rtp_toggle and 1 or 0) << 4 | string.byte(get_userdata_offset(USERDATA_RTP_OFFSET, 1)) << 3 local b = (_Rtp_toggle and 1 or 0) << 4 | string.byte(userdata.get_offset(USERDATA_RTP_OFFSET, 1)) << 3
local data_0 = get_userdata_offset(USERDATA_RTP_OFFSET+1, 3) local data_0 = userdata.get_offset(USERDATA_RTP_OFFSET+1, 3)
local data_1 = get_userdata_offset(USERDATA_RTP_OFFSET+4, 3) local data_1 = userdata.get_offset(USERDATA_RTP_OFFSET+4, 3)
b = b | (string.byte(data_0, 1) & 0xf8) >> 3 b = b | (string.byte(data_0, 1) & 0xf8) >> 3
local c = (string.byte(data_0, 1) & 0x7) << 13 local c = (string.byte(data_0, 1) & 0x7) << 13
@@ -31,11 +31,11 @@ end
local function init_ertp() local function init_ertp()
if _Ertp_oda_id == nil then if _Ertp_oda_id == nil then
_Ertp_oda_id = register_oda(12, false, 0x4BD8, 0) _Ertp_oda_id = ext.register_oda(12, false, 0x4BD8, 0)
set_oda_handler(_Ertp_oda_id, function () ext.set_oda_handler(_Ertp_oda_id, function ()
local b = (_Ertp_toggle and 1 or 0) << 4 | string.byte(get_userdata_offset(USERDATA_RTP_OFFSET+7, 1)) << 3 local b = (_Ertp_toggle and 1 or 0) << 4 | string.byte(userdata.get_offset(USERDATA_RTP_OFFSET+7, 1)) << 3
local data_0 = get_userdata_offset(USERDATA_RTP_OFFSET+8, 3) local data_0 = userdata.get_offset(USERDATA_RTP_OFFSET+8, 3)
local data_1 = get_userdata_offset(USERDATA_RTP_OFFSET+11, 3) local data_1 = userdata.get_offset(USERDATA_RTP_OFFSET+11, 3)
b = b | (string.byte(data_0, 1) & 0xf8) >> 3 b = b | (string.byte(data_0, 1) & 0xf8) >> 3
local c = (string.byte(data_0, 1) & 0x7) << 13 local c = (string.byte(data_0, 1) & 0x7) << 13
@@ -52,46 +52,44 @@ local function init_ertp()
end end
end end
function set_rds_rtp_meta(ertp, running) function rds.ext.set_rtp_meta(ertp, running)
if ertp then if ertp then
if running and _Ertp_oda_id == nil then init_ertp() end if running and _Ertp_oda_id == nil then init_ertp() end
set_userdata_offset(USERDATA_RTP_OFFSET+7, 1, string.char(running and 1 or 0)) userdata.set_offset(USERDATA_RTP_OFFSET+7, 1, string.char(running and 1 or 0))
else else
if running and _Rtp_oda_id == nil then init_rtp() end if running and _Rtp_oda_id == nil then init_rtp() end
set_userdata_offset(USERDATA_RTP_OFFSET, 1, string.char(running and 1 or 0)) userdata.set_offset(USERDATA_RTP_OFFSET, 1, string.char(running and 1 or 0))
end end
end end
function get_rds_rtp_meta(ertp) function rds.ext.get_rtp_meta(ertp)
local offset = ertp and (USERDATA_RTP_OFFSET+7) or USERDATA_RTP_OFFSET local offset = ertp and (USERDATA_RTP_OFFSET+7) or USERDATA_RTP_OFFSET
return string.byte(get_userdata_offset(offset, 1)) ~= 0 return string.byte(userdata.get_offset(offset, 1)) ~= 0
end end
function toggle_rds_rtp(ertp) function rds.ext.toggle_rtp(ertp)
if ertp then _Ertp_toggle = not _Ertp_toggle if ertp then _Ertp_toggle = not _Ertp_toggle
else _Rtp_toggle = not _Rtp_toggle end else _Rtp_toggle = not _Rtp_toggle end
end end
function set_rds_rtplus_tags(ertp, t1, s1, l1, t2, s2, l2) function rds.ext.set_rtplus_tags(ertp, t1, s1, l1, t2, s2, l2)
set_rds_rtp_meta(ertp, true) rds.ext.set_rds_rtp_meta(ertp, true)
toggle_rds_rtp(ertp) rds.ext.toggle_rds_rtp(ertp)
set_userdata_offset(ertp and (USERDATA_RTP_OFFSET+8) or (USERDATA_RTP_OFFSET+1), 6, string.char(t1, s1, l1, t2, s2, l2)) userdata.set_offset(ertp and (USERDATA_RTP_OFFSET+8) or (USERDATA_RTP_OFFSET+1), 6, string.char(t1, s1, l1, t2, s2, l2))
end end
function get_rds_rtplus_tags(ertp) function rds.ext.get_rtplus_tags(ertp)
return string.byte(get_userdata_offset(ertp and (USERDATA_RTP_OFFSET+8) or (USERDATA_RTP_OFFSET+1), 6), 1, 6) return string.byte(userdata.get_offset(ertp and (USERDATA_RTP_OFFSET+8) or (USERDATA_RTP_OFFSET+1), 6), 1, 6)
end end
function unregister_rtp(ertp) function unregister_rtp(ertp)
if ertp and _Ertp_oda_id ~= nil then if ertp and _Ertp_oda_id ~= nil then
unregister_oda(_Ertp_oda_id) ext.unregister_oda(_Ertp_oda_id)
_Ertp_oda_id = nil _Ertp_oda_id = nil
elseif _Rtp_oda_id ~= nil then elseif _Rtp_oda_id ~= nil then
unregister_oda(_Rtp_oda_id) ext.unregister_oda(_Rtp_oda_id)
_Rtp_oda_id = nil _Rtp_oda_id = nil
end end
end end
local _old_on_state_rtp = on_state table.insert(on_states, function ()
function on_state() if rds.ext.get_rtp_meta(false) then init_rtp() end
if get_rds_rtp_meta(false) then init_rtp() end if rds.ext.get_rtp_meta(true) then init_ertp() end
if get_rds_rtp_meta(true) then init_ertp() end end)
if type(_old_on_state_rtp) == "function" then _old_on_state_rtp() end
end

View File

@@ -40,52 +40,52 @@ function data_handle(data)
data = data:lower() data = data:lower()
if data == "ver" then return string.format("rds95 core v. %s - (C) 2025 radio95 - lua parser\r\n", core_version) if data == "ver" then return string.format("rds95 core v. %s - (C) 2025 radio95 - lua parser\r\n", core_version)
elseif data == "init" then elseif data == "init" then
set_rds_program_defaults() dp.set_rds_program_defaults()
return "+\r\n" return "+\r\n"
elseif data == "reset" then elseif data == "reset" then
reset_rds() dp.reset_rds()
return "+\r\n" return "+\r\n"
elseif data == "pi" then return string.format("PI=%s\r\n", string.format("%x", get_rds_pi())) elseif data == "pi" then return string.format("PI=%s\r\n", string.format("%x", rds.get_pi()))
elseif data == "pty" then return string.format("PTY=%s\r\n", string.format("%d", get_rds_pty())) elseif data == "pty" then return string.format("PTY=%s\r\n", string.format("%d", rds.get_pty()))
elseif data == "ecc" then return string.format("ECC=%s\r\n", string.format("%x", get_rds_ecc())) elseif data == "ecc" then return string.format("ECC=%s\r\n", string.format("%x", rds.get_ecc()))
elseif data == "slcd" then return string.format("SLCD=%s\r\n", string.format("%x", get_rds_slc_data())) elseif data == "slcd" then return string.format("SLCD=%s\r\n", string.format("%x", rds.get_slc_data()))
elseif data == "ct" then return string.format("CT=%s\r\n", string.format("%d", (get_rds_ct() and 1 or 0))) elseif data == "ct" then return string.format("CT=%s\r\n", string.format("%d", (rds.get_ct() and 1 or 0)))
elseif data == "dpty" then return string.format("DPTY=%s\r\n", string.format("%d", (get_rds_dpty() and 1 or 0))) elseif data == "dpty" then return string.format("DPTY=%s\r\n", string.format("%d", (rds.get_dpty() and 1 or 0)))
elseif data == "tp" then return string.format("TP=%s\r\n", string.format("%d", (get_rds_tp() and 1 or 0))) elseif data == "tp" then return string.format("TP=%s\r\n", string.format("%d", (rds.get_tp() and 1 or 0)))
elseif data == "ta" then return string.format("TA=%s\r\n", string.format("%d", (get_rds_ta() and 1 or 0))) elseif data == "ta" then return string.format("TA=%s\r\n", string.format("%d", (rds.get_ta() and 1 or 0)))
elseif data == "rt1en" then return string.format("RT1EN=%s\r\n", string.format("%d", (get_rds_rt1_enabled() and 1 or 0))) elseif data == "rt1en" then return string.format("RT1EN=%s\r\n", string.format("%d", (rds.get_rt1_enabled() and 1 or 0)))
elseif data == "rt2en" then return string.format("RT2EN=%s\r\n", string.format("%d", (get_rds_rt2_enabled() and 1 or 0))) elseif data == "rt2en" then return string.format("RT2EN=%s\r\n", string.format("%d", (rds.get_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 == "ptynen" then return string.format("PTYNEN=%s\r\n", string.format("%d", (rds.get_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 == "rttype" then return string.format("RTTYPE=%s\r\n", string.format("%d", rds.get_rt_type()))
elseif data == "rds2mod" then return string.format("RDS2MOD=%s\r\n", string.format("%d", get_rds2_mode())) elseif data == "rds2mod" then return string.format("RDS2MOD=%s\r\n", string.format("%d", rds.get_rds2_mode()))
elseif data == "rdsgen" then return string.format("RDSGEN=%s\r\n", string.format("%d", get_rds_streams())) 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 == "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 == "link" then return string.format("LINK=%s\r\n", string.format("%d", (rds.get_link() and 1 or 0)))
elseif data == "rtp" then elseif data == "rtp" then
local t1, s1, l1, t2, s2, l2 = get_rds_rtplus_tags(false) local t1, s1, l1, t2, s2, l2 = rds.ext.get_rtplus_tags(false)
return string.format("RTP=%d,%d,%d,%d,%d,%d\r\n", t1, s1, l1, t2, s2, l2) return string.format("RTP=%d,%d,%d,%d,%d,%d\r\n", t1, s1, l1, t2, s2, l2)
elseif data == "ertp" then elseif data == "ertp" then
local t1, s1, l1, t2, s2, l2 = get_rds_rtplus_tags(true) local t1, s1, l1, t2, s2, l2 = rds.ext.get_rtplus_tags(true)
return string.format("ERTP=%d,%d,%d,%d,%d,%d\r\n", t1, s1, l1, t2, s2, l2) return string.format("ERTP=%d,%d,%d,%d,%d,%d\r\n", t1, s1, l1, t2, s2, l2)
elseif data == "rtprun" then elseif data == "rtprun" then
local running = get_rds_rtp_meta(false) local running = rds.ext.get_rtp_meta(false)
local f1 = 2 or (running and 1 or 0) local f1 = 2 or (running and 1 or 0)
return string.format("RTPRUN=%d\r\n", f1) return string.format("RTPRUN=%d\r\n", f1)
elseif data == "ertprun" then elseif data == "ertprun" then
local running = get_rds_rtp_meta(true) local running = rds.ext.get_rtp_meta(true)
local f1 = 2 or (running and 1 or 0) local f1 = 2 or (running and 1 or 0)
return string.format("ERTPRUN=%d\r\n", f1) return string.format("ERTPRUN=%d\r\n", f1)
elseif data == "lps" then return string.format("LPS=%s\r\n", get_rds_lps()) elseif data == "lps" then return string.format("LPS=%s\r\n", rds.get_lps())
elseif data == "ert" then return string.format("ERT=%s\r\n", get_rds_ert()) elseif data == "ert" then return string.format("ERT=%s\r\n", rds.ext.get_ert())
elseif data == "grpseq" then return string.format("GRPSEQ=%s\r\n", get_rds_grpseq()) elseif data == "grpseq" then return string.format("GRPSEQ=%s\r\n", rds.get_grpseq())
elseif data == "grpseq2" then return string.format("GRPSEQ2=%s\r\n", get_rds_grpseq2()) elseif data == "grpseq2" then return string.format("GRPSEQ2=%s\r\n", rds.get_grpseq2())
else else
local eon_cmd, eon_num = data:match("^eon(%d+)([a-z]+)$") local eon_cmd, eon_num = data:match("^eon(%d+)([a-z]+)$")
if eon_cmd then if eon_cmd then
local eon_idx = tonumber(eon_cmd) local eon_idx = tonumber(eon_cmd)
if not eon_idx or eon_idx < 1 or eon_idx > eon_count then return "?\r\n" end if not eon_idx or eon_idx < 1 or eon_idx > rds.eon_count then return "?\r\n" end
eon_idx = eon_idx - 1 eon_idx = eon_idx - 1
local enabled, pi, tp, ta, pty, ps, afs, data_val = get_rds_eon(eon_idx) local enabled, pi, tp, ta, pty, ps, afs, data_val = rds.get_eon(eon_idx)
if eon_num == "en" then return string.format("EON%dEN=%d\r\n", eon_idx + 1, enabled and 1 or 0) if eon_num == "en" then return string.format("EON%dEN=%d\r\n", eon_idx + 1, enabled and 1 or 0)
elseif eon_num == "pi" then return string.format("EON%dPI=%x\r\n", eon_idx + 1, pi) elseif eon_num == "pi" then return string.format("EON%dPI=%x\r\n", eon_idx + 1, pi)
@@ -106,48 +106,48 @@ function data_handle(data)
local eon_num, eon_type = cmd:match("^eon(%d+)([a-z]+)$") local eon_num, eon_type = cmd:match("^eon(%d+)([a-z]+)$")
if eon_num then if eon_num then
local eon_idx = tonumber(eon_num) local eon_idx = tonumber(eon_num)
if not eon_idx or eon_idx < 1 or eon_idx > eon_count then return "?\r\n" end if not eon_idx or eon_idx < 1 or eon_idx > rds.eon_count then return "?\r\n" end
eon_idx = eon_idx - 1 eon_idx = eon_idx - 1
local enabled, pi, tp, ta, pty, ps, afs, data_val = get_rds_eon(eon_idx) local enabled, pi, tp, ta, pty, ps, afs, data_val = rds.get_eon(eon_idx)
if eon_type == "en" then if eon_type == "en" then
local en_val = tonumber(value) local en_val = tonumber(value)
if not en_val then return "-\r\n" end if not en_val then return "-\r\n" end
enabled = (en_val ~= 0) enabled = (en_val ~= 0)
set_rds_eon(eon_idx, enabled, pi, tp, ta, pty, ps, afs, data_val) rds.set_eon(eon_idx, enabled, pi, tp, ta, pty, ps, afs, data_val)
return "+\r\n" return "+\r\n"
elseif eon_type == "pi" then elseif eon_type == "pi" then
local pi_val = tonumber(value, 16) local pi_val = tonumber(value, 16)
if not pi_val then return "-\r\n" end if not pi_val then return "-\r\n" end
set_rds_eon(eon_idx, enabled, pi_val, tp, ta, pty, ps, afs, data_val) rds.set_eon(eon_idx, enabled, pi_val, tp, ta, pty, ps, afs, data_val)
return "+\r\n" return "+\r\n"
elseif eon_type == "ps" then elseif eon_type == "ps" then
local ps_val = value:sub(1, 24) local ps_val = value:sub(1, 24)
set_rds_eon(eon_idx, enabled, pi, tp, ta, pty, ps_val, afs, data_val) rds.set_eon(eon_idx, enabled, pi, tp, ta, pty, ps_val, afs, data_val)
return "+\r\n" return "+\r\n"
elseif eon_type == "pty" then elseif eon_type == "pty" then
local pty_val = tonumber(value) local pty_val = tonumber(value)
if not pty_val then return "-\r\n" end if not pty_val then return "-\r\n" end
set_rds_eon(eon_idx, enabled, pi, tp, ta, pty_val, ps, afs, data_val) rds.set_eon(eon_idx, enabled, pi, tp, ta, pty_val, ps, afs, data_val)
return "+\r\n" return "+\r\n"
elseif eon_type == "ta" then elseif eon_type == "ta" then
if not enabled or not tp then return "-\r\n" end if not enabled or not tp then return "-\r\n" end
local ta_val = tonumber(value) local ta_val = tonumber(value)
if not ta_val then return "-\r\n" end if not ta_val then return "-\r\n" end
ta = (ta_val ~= 0) ta = (ta_val ~= 0)
set_rds_eon(eon_idx, enabled, pi, tp, ta, pty, ps, afs, data_val) rds.set_eon(eon_idx, enabled, pi, tp, ta, pty, ps, afs, data_val)
if ta then set_rds_ta(true) end if ta then rds.set_ta(true) end
return "+\r\n" return "+\r\n"
elseif eon_type == "tp" then elseif eon_type == "tp" then
local tp_val = tonumber(value) local tp_val = tonumber(value)
if not tp_val then return "-\r\n" end if not tp_val then return "-\r\n" end
tp = (tp_val ~= 0) tp = (tp_val ~= 0)
set_rds_eon(eon_idx, enabled, pi, tp, ta, pty, ps, afs, data_val) rds.set_eon(eon_idx, enabled, pi, tp, ta, pty, ps, afs, data_val)
return "+\r\n" return "+\r\n"
elseif eon_type == "af" then elseif eon_type == "af" then
local af_table = {} local af_table = {}
if value == "" or value == "0" then if value == "" or value == "0" then
set_rds_eon(eon_idx, enabled, pi, tp, ta, pty, ps, {}, data_val) rds.set_eon(eon_idx, enabled, pi, tp, ta, pty, ps, {}, data_val)
return "+\r\n" return "+\r\n"
end end
for freq_str in value:gmatch("([^,]+)") do for freq_str in value:gmatch("([^,]+)") do
@@ -156,12 +156,12 @@ function data_handle(data)
else return "-\r\n" end else return "-\r\n" end
end end
if #af_table > 25 then return "-\r\n" end if #af_table > 25 then return "-\r\n" end
set_rds_eon(eon_idx, enabled, pi, tp, ta, pty, ps, af_table, data_val) rds.set_eon(eon_idx, enabled, pi, tp, ta, pty, ps, af_table, data_val)
return "+\r\n" return "+\r\n"
elseif eon_type == "dt" then elseif eon_type == "dt" then
local dt_val = tonumber(value, 16) local dt_val = tonumber(value, 16)
if not dt_val then return "-\r\n" end if not dt_val then return "-\r\n" end
set_rds_eon(eon_idx, enabled, pi, tp, ta, pty, ps, afs, dt_val) rds.set_eon(eon_idx, enabled, pi, tp, ta, pty, ps, afs, dt_val)
return "+\r\n" return "+\r\n"
else return "?\r\n" end else return "?\r\n" end
end end
@@ -179,7 +179,7 @@ function data_handle(data)
end end
if #groups > 8 or #groups == 0 then return "-\r\n" end if #groups > 8 or #groups == 0 then return "-\r\n" end
set_rds_udg(xy, groups) rds.set_udg(xy, groups)
return "+\r\n" return "+\r\n"
end end
if udg2_num then if udg2_num then
@@ -193,7 +193,7 @@ function data_handle(data)
end end
if #groups > 8 or #groups == 0 then return "-" end if #groups > 8 or #groups == 0 then return "-" end
set_rds_udg2(xy, groups) rds.set_udg2(xy, groups)
return "+\r\n" return "+\r\n"
end end
@@ -201,67 +201,67 @@ function data_handle(data)
local pi = tonumber(value, 16) local pi = tonumber(value, 16)
if not pi then return "-\r\n" end if not pi then return "-\r\n" end
if (pi & 0xF000) == 0 then return "-\r\n" end if (pi & 0xF000) == 0 then return "-\r\n" end
set_rds_pi(pi) rds.set_pi(pi)
return "+\r\n" return "+\r\n"
elseif cmd == "ecc" then elseif cmd == "ecc" then
local ecc = tonumber(value, 16) local ecc = tonumber(value, 16)
if not ecc then return "-\r\n" end if not ecc then return "-\r\n" end
set_rds_ecc(ecc) rds.set_ecc(ecc)
return "+\r\n" return "+\r\n"
elseif cmd == "pty" then elseif cmd == "pty" then
local pty = tonumber(value) local pty = tonumber(value)
if not pty then return "-\r\n" end if not pty then return "-\r\n" end
set_rds_pty(pty) rds.set_pty(pty)
return "+\r\n" return "+\r\n"
elseif cmd == "slcd" then elseif cmd == "slcd" then
local slc_data = tonumber(value, 16) local slc_data = tonumber(value, 16)
if not slc_data then return "-\r\n" end if not slc_data then return "-\r\n" end
set_rds_slc_data(slc_data) rds.set_slc_data(slc_data)
return "+\r\n" return "+\r\n"
elseif cmd == "ct" then elseif cmd == "ct" then
local ct = tonumber(value) local ct = tonumber(value)
if not ct then return "-\r\n" end if not ct then return "-\r\n" end
set_rds_ct(ct ~= 0) rds.set_ct(ct ~= 0)
return "+\r\n" return "+\r\n"
elseif cmd == "dpty" then elseif cmd == "dpty" then
local dpty = tonumber(value) local dpty = tonumber(value)
if not dpty then return "-\r\n" end if not dpty then return "-\r\n" end
set_rds_dpty(dpty ~= 0) rds.set_dpty(dpty ~= 0)
return "+\r\n" return "+\r\n"
elseif cmd == "tp" then elseif cmd == "tp" then
local tp = tonumber(value) local tp = tonumber(value)
if not tp then return "-\r\n" end if not tp then return "-\r\n" end
set_rds_tp(tp ~= 0) rds.set_tp(tp ~= 0)
return "+\r\n" return "+\r\n"
elseif cmd == "ta" then elseif cmd == "ta" then
local ta = tonumber(value) local ta = tonumber(value)
if not ta then return "-\r\n" end if not ta then return "-\r\n" end
set_rds_ta(ta ~= 0) rds.set_ta(ta ~= 0)
return "+\r\n" return "+\r\n"
elseif cmd == "rt1en" then elseif cmd == "rt1en" then
local en = tonumber(value) local en = tonumber(value)
if not en then return "-\r\n" end if not en then return "-\r\n" end
set_rds_rt1_enabled(en ~= 0) rds.set_rt1_enabled(en ~= 0)
return "+\r\n" return "+\r\n"
elseif cmd == "rt2en" then elseif cmd == "rt2en" then
local en = tonumber(value) local en = tonumber(value)
if not en then return "-\r\n" end if not en then return "-\r\n" end
set_rds_rt2_enabled(en ~= 0) rds.set_rt2_enabled(en ~= 0)
return "+\r\n" return "+\r\n"
elseif cmd == "ptynen" then elseif cmd == "ptynen" then
local en = tonumber(value) local en = tonumber(value)
if not en then return "-\r\n" end if not en then return "-\r\n" end
set_rds_ptyn_enabled(en ~= 0) rds.set_ptyn_enabled(en ~= 0)
return "+\r\n" return "+\r\n"
elseif cmd == "rttype" then elseif cmd == "rttype" then
local type = tonumber(value) local type = tonumber(value)
if not type then return "-\r\n" end if not type then return "-\r\n" end
set_rds_rt_type(type) rds.set_rt_type(type)
return "+\r\n" return "+\r\n"
elseif cmd == "rds2mod" then elseif cmd == "rds2mod" then
local type = tonumber(value) local type = tonumber(value)
if not type then return "-\r\n" end if not type then return "-\r\n" end
set_rds2_mode(type) rds.set_rds2_mode(type)
return "+\r\n" return "+\r\n"
elseif cmd == "rdsgen" then elseif cmd == "rdsgen" then
local type = tonumber(value) local type = tonumber(value)
@@ -269,42 +269,42 @@ function data_handle(data)
set_rds_streams(type) set_rds_streams(type)
return "+\r\n" return "+\r\n"
elseif cmd == "ptyn" then elseif cmd == "ptyn" then
set_rds_ptyn(value) rds.set_ptyn(value)
return "+\r\n" return "+\r\n"
elseif cmd == "ps" then elseif cmd == "ps" then
set_rds_ps(value) rds.set_ps(value)
return "+\r\n" return "+\r\n"
elseif cmd == "tps" then elseif cmd == "tps" then
set_rds_tps(value) rds.set_tps(value)
return "+\r\n" return "+\r\n"
elseif cmd == "rt1" or cmd == "text" then elseif cmd == "rt1" or cmd == "text" then
set_rds_rt1(value) rds.set_rt1(value)
return "+\r\n" return "+\r\n"
elseif cmd == "rt2" then elseif cmd == "rt2" then
set_rds_rt2(value) rds.set_rt2(value)
return "+\r\n" return "+\r\n"
elseif cmd == "lps" then elseif cmd == "lps" then
set_rds_lps(value) rds.set_lps(value)
return "+\r\n" return "+\r\n"
elseif cmd == "ert" then elseif cmd == "ert" then
set_rds_ert(value) rds.ext.set_ert(value)
return "+\r\n" return "+\r\n"
elseif cmd == "link" then elseif cmd == "link" then
local link = tonumber(value) local link = tonumber(value)
if not link then return "-\r\n" end if not link then return "-\r\n" end
set_rds_link(link ~= 0) rds.set_link(link ~= 0)
return "+\r\n" return "+\r\n"
elseif cmd == "rtper" then elseif cmd == "rtper" then
local period = tonumber(value) local period = tonumber(value)
if not period then return "-\r\n" end if not period then return "-\r\n" end
set_rds_rt_switching_period(period*60) rds.set_rt_switching_period(period*60)
return "+\r\n" return "+\r\n"
elseif cmd == "program" then elseif cmd == "program" then
local program = tonumber(value) local program = tonumber(value)
if not program then return "-\r\n" end if not program then return "-\r\n" end
if program < 1 or program > max_programs then return "-\r\n" end if program < 1 or program > dp.max_programs then return "-\r\n" end
set_rds_program(program-1) dp.set_rds_program(program-1)
set_rds_ta(false) rds.set_ta(false)
return "+\r\n" return "+\r\n"
elseif cmd == "level" then elseif cmd == "level" then
local level = tonumber(value) local level = tonumber(value)
@@ -314,20 +314,20 @@ function data_handle(data)
elseif cmd == "dttmout" then elseif cmd == "dttmout" then
local timeout = tonumber(value) local timeout = tonumber(value)
if not timeout then return "-\r\n" end if not timeout then return "-\r\n" end
set_rds_rt_text_timeout(timeout*60) rds.set_rt_text_timeout(timeout*60)
return "+\r\n" return "+\r\n"
elseif cmd == "grpseq" then elseif cmd == "grpseq" then
set_rds_grpseq(value) rds.set_grpseq(value)
return "+\r\n" return "+\r\n"
elseif cmd == "grpseq2" then elseif cmd == "grpseq2" then
set_rds_grpseq2(value) rds.set_grpseq2(value)
return "+\r\n" return "+\r\n"
elseif cmd == "rtp" or cmd == "ertp" then elseif cmd == "rtp" or cmd == "ertp" then
local is_ertp = (cmd == "ertp") local is_ertp = (cmd == "ertp")
local t1, s1, l1, t2, s2, l2 = value:match("(%d+),(%d+),(%d+),(%d+),(%d+),(%d+)") local t1, s1, l1, t2, s2, l2 = value:match("(%d+),(%d+),(%d+),(%d+),(%d+),(%d+)")
if not l2 then return "-\r\n" end if not l2 then return "-\r\n" end
set_rds_rtplus_tags( rds.ext.set_rtplus_tags(
is_ertp, is_ertp,
---@diagnostic disable-next-line: param-type-mismatch ---@diagnostic disable-next-line: param-type-mismatch
tonumber(t1), tonumber(s1), tonumber(l1), tonumber(t2), tonumber(s2), tonumber(l2) tonumber(t1), tonumber(s1), tonumber(l1), tonumber(t2), tonumber(s2), tonumber(l2)
@@ -336,13 +336,13 @@ function data_handle(data)
elseif cmd == "g" then elseif cmd == "g" then
local a, b, c, d = value:match("^(%x%x%x%x)(%x%x%x%x)(%x%x%x%x)(%x%x%x%x)$") local a, b, c, d = value:match("^(%x%x%x%x)(%x%x%x%x)(%x%x%x%x)(%x%x%x%x)$")
if a and b and c and d then if a and b and c and d then
put_rds2_custom_group(tonumber(a, 16), tonumber(b, 16), tonumber(c, 16), tonumber(d, 16)) rds.put_rds2_custom_group(tonumber(a, 16), tonumber(b, 16), tonumber(c, 16), tonumber(d, 16))
return "+\r\n" return "+\r\n"
end end
local b1, c1, d1 = value:match("^(%x%x%x%x)(%x%x%x%x)(%x%x%x%x)$") local b1, c1, d1 = value:match("^(%x%x%x%x)(%x%x%x%x)(%x%x%x%x)$")
if b1 and c1 and d1 then if b1 and c1 and d1 then
put_rds_custom_group(tonumber(b1, 16), tonumber(c1, 16), tonumber(d1, 16)) rds.put_custom_group(tonumber(b1, 16), tonumber(c1, 16), tonumber(d1, 16))
return "+\r\n" return "+\r\n"
end end
@@ -357,14 +357,14 @@ function data_handle(data)
local f2 = tonumber(f2_str) or 0 local f2 = tonumber(f2_str) or 0
local running = (f1 & 1) ~= 0 local running = (f1 & 1) ~= 0
set_rds_rtp_meta(is_ertp, running) rds.ext.set_rtp_meta(is_ertp, running)
if f2 ~= 0 then toggle_rds_rtp(is_ertp) end if f2 ~= 0 then rds.ext.toggle_rtp(is_ertp) end
return "+\r\n" return "+\r\n"
elseif cmd == "af" then elseif cmd == "af" then
local af_table = {} local af_table = {}
if value == "" or value == "0" then if value == "" or value == "0" then
set_rds_af_group0({}) rds.set_af({})
return "+\r\n" return "+\r\n"
end end
@@ -376,13 +376,13 @@ function data_handle(data)
if #af_table > 25 then return "-\r\n" end if #af_table > 25 then return "-\r\n" end
set_rds_af_group0(af_table) rds.set_af(af_table)
return "+\r\n" return "+\r\n"
elseif cmd == "afo" then elseif cmd == "afo" then
local af_table = {} local af_table = {}
if value == "" or value == "0" then if value == "" or value == "0" then
set_rds_af_oda({}) rds.ext.set_af_oda({})
return "+\r\n" return "+\r\n"
end end
@@ -394,7 +394,7 @@ function data_handle(data)
if #af_table > 25 then return "-\r\n" end if #af_table > 25 then return "-\r\n" end
set_rds_af_oda(af_table) rds.ext.set_af_oda(af_table)
return "+\r\n" return "+\r\n"
else else
return "?\r\n" return "?\r\n"

425
src/lua_api.c Normal file
View File

@@ -0,0 +1,425 @@
#include "lua_api.h"
#include "lua_rds.h"
static int in_set_defaults = 0;
extern lua_State *L;
extern RDSModulator* mod;
extern uint8_t unload_refs[33];
int lua_get_userdata(lua_State *localL) {
lua_pushlstring(localL, (const char*)&mod->enc->data[mod->enc->program].lua_data, LUA_USER_DATA);
return 1;
}
int lua_get_userdata_offset(lua_State *localL) {
uint16_t offset = luaL_checkinteger(localL, 1);
uint16_t size = luaL_checkinteger(localL, 2);
if((offset+size) > LUA_USER_DATA) return luaL_error(localL, "data exceeds limit");
lua_pushlstring(localL, (const char*)&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) {
uint16_t offset = luaL_checkinteger(localL, 1);
uint16_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) {
(void)localL;
encoder_saveToFile(mod->enc);
Modulator_saveToFile(&mod->params);
return 0;
}
int lua_set_rds_program_defaults(lua_State *localL) {
(void)localL;
if (in_set_defaults) {
fprintf(stderr, "Warning: Recursive call to lua_set_rds_program_defaults blocked\n");
return 0;
}
in_set_defaults = 1;
for (int i = 1; i < *unload_refs; i++) luaL_unref(L, LUA_REGISTRYINDEX, unload_refs[i]);
unload_refs[0] = 1;
set_rds_defaults(mod->enc, mod->enc->program);
lua_call_tfunction_nolock("on_init");
lua_call_tfunction_nolock("on_state");
in_set_defaults = 0;
return 0;
}
int lua_reset_rds(lua_State *localL) {
(void)localL;
for (int i = 1; i < *unload_refs; i++) luaL_unref(L, LUA_REGISTRYINDEX, unload_refs[i]);
unload_refs[0] = 1;
encoder_saveToFile(mod->enc);
Modulator_saveToFile(&mod->params);
encoder_loadFromFile(mod->enc);
for(int i = 0; i < PROGRAMS; i++) reset_rds_state(mod->enc, i);
Modulator_loadFromFile(&mod->params);
lua_call_tfunction_nolock("on_state");
return 0;
}
#define BOOL_SETTER(name) \
int lua_set_rds_##name(lua_State *localL) { \
if (!lua_isboolean(localL, 1)) return luaL_error(localL, "boolean expected, got %s", luaL_typename(localL, 1)); \
mod->enc->data[mod->enc->program].name = lua_toboolean(localL, 1); \
return 0; \
}
#define INT_SETTER(name) \
int lua_set_rds_##name(lua_State *localL) { \
mod->enc->data[mod->enc->program].name = luaL_checkinteger(localL, 1); \
return 0; \
}
#define STR_SETTER(name, function) \
int lua_set_rds_##name(lua_State *localL) { \
const char* str = luaL_checklstring(localL, 1, NULL); \
function(mod->enc, convert_to_rdscharset(str)); \
return 0; \
}
#define STR_RAW_SETTER(name, function) \
int lua_set_rds_##name(lua_State *localL) { \
const char* str = luaL_checklstring(localL, 1, NULL); \
function(mod->enc, str); \
return 0; \
}
#define AF_SETTER(name, af_field, af_struct, add_func) \
int lua_set_rds_##name(lua_State *localL) { \
luaL_checktype(localL, 1, LUA_TTABLE); \
\
int n = lua_rawlen(localL, 1); \
if (n == 0) { \
memset(&(mod->enc->data[mod->enc->program].af_field), 0, sizeof(af_struct)); \
return 0; \
} \
if(n > 25) return luaL_error(localL, "table length over 25"); \
\
af_struct new_af; \
memset(&new_af, 0, sizeof(af_struct)); \
\
for (int i = 1; i <= n; i++) { \
lua_rawgeti(localL, 1, i); \
if (lua_isnumber(localL, -1)) add_func(&new_af, lua_tonumber(localL, -1)); \
else return luaL_error(localL, "number expected, got %s", luaL_typename(localL, -1)); \
lua_pop(localL, 1); \
} \
memcpy(&(mod->enc->data[mod->enc->program].af_field), &new_af, sizeof(new_af)); \
\
return 0; \
}
#define INT_GETTER(name) \
int lua_get_rds_##name(lua_State *localL) { \
lua_pushinteger(localL, mod->enc->data[mod->enc->program].name); \
return 1; \
}
#define BOOL_GETTER(name) \
int lua_get_rds_##name(lua_State *localL) { \
lua_pushboolean(localL, mod->enc->data[mod->enc->program].name); \
return 1; \
}
#define STR_RAW_GETTER(name, length) \
int lua_get_rds_##name(lua_State *localL) { \
lua_pushlstring(localL, mod->enc->data[mod->enc->program].name, length); \
return 1; \
}
INT_SETTER(pi)
INT_GETTER(pi)
INT_SETTER(pty)
INT_GETTER(pty)
INT_SETTER(ecc)
INT_GETTER(ecc)
INT_SETTER(slc_data)
INT_GETTER(slc_data)
BOOL_SETTER(ct)
BOOL_GETTER(ct)
BOOL_SETTER(dpty)
BOOL_GETTER(dpty)
BOOL_SETTER(tp)
BOOL_GETTER(tp)
BOOL_SETTER(ta)
BOOL_GETTER(ta)
BOOL_SETTER(rt1_enabled)
BOOL_GETTER(rt1_enabled)
BOOL_SETTER(rt2_enabled)
BOOL_GETTER(rt2_enabled)
BOOL_SETTER(ptyn_enabled)
BOOL_GETTER(ptyn_enabled)
INT_SETTER(rt_type)
INT_GETTER(rt_type)
int lua_set_rds2_mode(lua_State *localL) {
mod->enc->encoder_data.rds2_mode = luaL_checkinteger(localL, 1);
return 0;
}
int lua_get_rds2_mode(lua_State *localL) {
lua_pushinteger(localL, mod->enc->encoder_data.rds2_mode);
return 1;
}
int lua_set_rds_streams(lua_State *localL) {
mod->params.rdsgen = luaL_checkinteger(localL, 1);
return 0;
}
int lua_get_rds_streams(lua_State *localL) {
lua_pushinteger(localL, mod->params.rdsgen);
return 1;
}
int lua_set_rds_link(lua_State *localL) {
if (!lua_isboolean(localL, 1)) return luaL_error(localL, "boolean expected, got %s", luaL_typename(localL, 1));
mod->enc->state[mod->enc->program].eon_linkage = lua_toboolean(localL, 1);
return 0;
}
int lua_get_rds_link(lua_State *localL) {
lua_pushboolean(localL, mod->enc->state[mod->enc->program].eon_linkage);
return 1;
}
int lua_set_rds_program(lua_State *localL) {
int program = luaL_checkinteger(localL, 1);
if(program >= PROGRAMS) program = (PROGRAMS-1);
if(program < 0) program = 0;
if(mod->enc->program == program) return 0;
mod->enc->data[mod->enc->program].ta = 0;
mod->enc->data[(uint8_t)program].ta = 0;
mod->enc->program = (uint8_t)program;
return 0;
}
int lua_get_rds_program(lua_State *localL) {
lua_pushinteger(localL, mod->enc->program);
return 1;
}
int lua_set_rds_rt_switching_period(lua_State *localL) {
mod->enc->data[mod->enc->program].rt_switching_period = luaL_checkinteger(localL, 1);
mod->enc->state[mod->enc->program].rt_switching_period_state = mod->enc->data[mod->enc->program].rt_switching_period;
return 0;
}
INT_GETTER(rt_switching_period)
int lua_set_rds_rt_text_timeout(lua_State *localL) {
mod->enc->data[mod->enc->program].rt_text_timeout = luaL_checkinteger(localL, 1);
mod->enc->state[mod->enc->program].rt_text_timeout_state = mod->enc->data[mod->enc->program].rt_text_timeout;
return 0;
}
INT_GETTER(rt_text_timeout)
int lua_set_rds_level(lua_State *localL) {
mod->params.level = luaL_checknumber(localL, 1);
return 0;
}
int lua_get_rds_level(lua_State *localL) {
lua_pushnumber(localL, mod->params.level);
return 1;
}
int lua_put_rds_custom_group(lua_State *localL) {
mod->enc->state[mod->enc->program].custom_group[0] = 1;
mod->enc->state[mod->enc->program].custom_group[1] = luaL_checkinteger(localL, 1);
mod->enc->state[mod->enc->program].custom_group[2] = luaL_checkinteger(localL, 2);
mod->enc->state[mod->enc->program].custom_group[3] = luaL_checkinteger(localL, 3);
return 0;
}
int lua_put_rds2_custom_group(lua_State *localL) {
mod->enc->state[mod->enc->program].custom_group2[0] = 1;
mod->enc->state[mod->enc->program].custom_group2[1] = luaL_checkinteger(localL, 1);
mod->enc->state[mod->enc->program].custom_group2[2] = luaL_checkinteger(localL, 2);
mod->enc->state[mod->enc->program].custom_group2[3] = luaL_checkinteger(localL, 3);
mod->enc->state[mod->enc->program].custom_group2[4] = luaL_checkinteger(localL, 4);
return 0;
}
STR_SETTER(ptyn, set_rds_ptyn)
STR_SETTER(ps, set_rds_ps)
STR_SETTER(tps, set_rds_tps)
STR_SETTER(rt1, set_rds_rt1)
STR_SETTER(rt2, set_rds_rt2)
STR_SETTER(default_rt, set_rds_default_rt)
STR_RAW_SETTER(lps, set_rds_lps)
STR_RAW_GETTER(lps, LPS_LENGTH)
STR_RAW_SETTER(grp_sqc_rds2, set_rds_grpseq2)
STR_RAW_GETTER(grp_sqc_rds2, 32)
int lua_set_rds_grp_sqc(lua_State *localL) {
const char* str = luaL_checklstring(localL, 1, NULL);
if(_strnlen(str, 2) < 1) set_rds_grpseq(mod->enc, DEFAULT_GRPSQC);
else set_rds_grpseq(mod->enc, str);
return 0;
}
STR_RAW_GETTER(grp_sqc, 32)
AF_SETTER(af_group0, af, RDSAFs, add_rds_af)
int lua_set_rds_eon(lua_State *localL) {
int eon = luaL_checkinteger(localL, 1);
if(eon >= EONs) return luaL_error(localL, "eon index exceeded");
if (!lua_isboolean(localL, 2)) return luaL_error(localL, "boolean expected, got %s", luaL_typename(localL, 2));
if (!lua_isboolean(localL, 4)) return luaL_error(localL, "boolean expected, got %s", luaL_typename(localL, 4));
if (!lua_isboolean(localL, 5)) return luaL_error(localL, "boolean expected, got %s", luaL_typename(localL, 5));
luaL_checktype(localL, 8, LUA_TTABLE);
mod->enc->data[mod->enc->program].eon[eon].enabled = lua_toboolean(localL, 2);
mod->enc->data[mod->enc->program].eon[eon].pi = luaL_checkinteger(localL, 3);
mod->enc->data[mod->enc->program].eon[eon].tp = lua_toboolean(localL, 4);
mod->enc->data[mod->enc->program].eon[eon].ta = lua_toboolean(localL, 5);
mod->enc->data[mod->enc->program].eon[eon].pty = luaL_checkinteger(localL, 6);
_strncpy(mod->enc->data[mod->enc->program].eon[eon].ps, luaL_checklstring(localL, 7, NULL), 8);
int n = lua_rawlen(localL, 8);
if (n == 0) {
memset(&(mod->enc->data[mod->enc->program].eon[eon].af), 0, sizeof(RDSAFs));
return 0;
}
if(n > 25) return luaL_error(localL, "table length over 25");
RDSAFs new_af;
memset(&new_af, 0, sizeof(RDSAFs));
for (int i = 1; i <= n; i++) {
lua_rawgeti(localL, 8, i);
if (lua_isnumber(localL, -1)) add_rds_af(&new_af, lua_tonumber(localL, -1));
else return luaL_error(localL, "number expected, got %s", luaL_typename(localL, -1));
lua_pop(localL, 1);
}
memcpy(&(mod->enc->data[mod->enc->program].eon[eon].af), &new_af, sizeof(new_af));
mod->enc->data[mod->enc->program].eon[eon].data = luaL_checkinteger(localL, 9);
return 0;
}
int lua_get_rds_eon(lua_State *localL) {
int eon = luaL_checkinteger(localL, 1);
if(eon >= EONs) return luaL_error(localL, "eon index exceeded");
lua_pushboolean(localL, mod->enc->data[mod->enc->program].eon[eon].enabled);
lua_pushinteger(localL, mod->enc->data[mod->enc->program].eon[eon].pi);
lua_pushboolean(localL, mod->enc->data[mod->enc->program].eon[eon].tp);
lua_pushboolean(localL, mod->enc->data[mod->enc->program].eon[eon].ta);
lua_pushinteger(localL, mod->enc->data[mod->enc->program].eon[eon].pty);
lua_pushlstring(localL, mod->enc->data[mod->enc->program].eon[eon].ps, 8);
lua_createtable(localL, 0, 0); // don't have decoding for AF, so just return empty table
lua_pushinteger(localL, mod->enc->data[mod->enc->program].eon[eon].data);
return 8;
}
int lua_set_rds_udg(lua_State *localL) {
if (!lua_isboolean(localL, 1)) return luaL_error(localL, "boolean expected, got %s", luaL_typename(localL, 1));
int xy = lua_toboolean(localL, 1);
luaL_checktype(localL, 2, LUA_TTABLE);
int n = lua_rawlen(localL, 2);
if(n > 8) return luaL_error(localL, "table length over 8");
uint16_t blocks[8][3] = {0};
for (int i = 1; i <= n; i++) {
lua_rawgeti(localL, 2, i);
if(lua_istable(localL, -1)) {
int n2 = lua_rawlen(localL, -1);
if(n2 > 3) return luaL_error(localL, "table length over 3");
for(int j = 1; j <= n2; j++) {
lua_rawgeti(localL, -1, j);
if (lua_isinteger(localL, -1)) blocks[i-1][j-1] = lua_tointeger(localL, -1);
else return luaL_error(localL, "integer expected, got %s", luaL_typename(localL, -1));
lua_pop(localL, 1);
}
}
else return luaL_error(localL, "table expected, got %s", luaL_typename(localL, -1));
lua_pop(localL, 1);
}
if(xy) {
memcpy(&(mod->enc->data[mod->enc->program].udg2), blocks, n * sizeof(uint16_t[3]));
mod->enc->data[mod->enc->program].udg2_len = n;
} else {
memcpy(&(mod->enc->data[mod->enc->program].udg1), blocks, n * sizeof(uint16_t[3]));
mod->enc->data[mod->enc->program].udg1_len = n;
}
return 0;
}
int lua_set_rds_udg2(lua_State *localL) {
if (!lua_isboolean(localL, 1)) return luaL_error(localL, "boolean expected, got %s", luaL_typename(localL, 1));
int xy = lua_toboolean(localL, 1);
luaL_checktype(localL, 2, LUA_TTABLE);
int n = lua_rawlen(localL, 2);
if(n > 8) return luaL_error(localL, "table length over 8");
uint16_t blocks[8][4] = {0};
for (int i = 1; i <= n; i++) {
lua_rawgeti(localL, 2, i);
if(lua_istable(localL, -1)) {
int n2 = lua_rawlen(localL, -1);
if(n2 > 4) return luaL_error(localL, "table length over 4");
for(int j = 1; j <= n2; j++) {
lua_rawgeti(localL, -1, j);
if (lua_isinteger(localL, -1)) blocks[i-1][j-1] = lua_tointeger(localL, -1);
else return luaL_error(localL, "integer expected, got %s", luaL_typename(localL, -1));
lua_pop(localL, 1);
}
}
else return luaL_error(localL, "table expected, got %s", luaL_typename(localL, -1));
lua_pop(localL, 1);
}
if(xy) {
memcpy(&(mod->enc->data[mod->enc->program].udg2_rds2), blocks, n * sizeof(uint16_t[4]));
mod->enc->data[mod->enc->program].udg2_len_rds2 = n;
} else {
memcpy(&(mod->enc->data[mod->enc->program].udg1_rds2), blocks, n * sizeof(uint16_t[4]));
mod->enc->data[mod->enc->program].udg1_len_rds2 = n;
}
return 0;
}
int lua_get_available_rds_streams(lua_State *localL) {
lua_pushinteger(localL, mod->num_streams);
return 1;
}
int lua_crc16(lua_State *localL) {
size_t len;
const char* data = luaL_checklstring(localL, 1, &len);
lua_pushinteger(localL, crc16_ccitt(data, len));
return 1;
}

101
src/lua_api.h Normal file
View File

@@ -0,0 +1,101 @@
#pragma once
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
#include "rds.h"
#include "fs.h"
#include "modulator.h"
int lua_get_userdata(lua_State *localL);
int lua_get_userdata_offset(lua_State *localL);
int lua_set_userdata(lua_State *localL);
int lua_set_userdata_offset(lua_State *localL);
int lua_force_save(lua_State *localL);
int lua_set_rds_program_defaults(lua_State *localL);
int lua_reset_rds(lua_State *localL);
int lua_set_rds_pi(lua_State *localL);
int lua_get_rds_pi(lua_State *localL);
int lua_set_rds_pty(lua_State *localL);
int lua_get_rds_pty(lua_State *localL);
int lua_set_rds_ecc(lua_State *localL);
int lua_get_rds_ecc(lua_State *localL);
int lua_set_rds_slc_data(lua_State *localL);
int lua_get_rds_slc_data(lua_State *localL);
int lua_set_rds_ct(lua_State *localL);
int lua_get_rds_ct(lua_State *localL);
int lua_set_rds_dpty(lua_State *localL);
int lua_get_rds_dpty(lua_State *localL);
int lua_set_rds_tp(lua_State *localL);
int lua_get_rds_tp(lua_State *localL);
int lua_set_rds_ta(lua_State *localL);
int lua_get_rds_ta(lua_State *localL);
int lua_set_rds_rt1_enabled(lua_State *localL);
int lua_get_rds_rt1_enabled(lua_State *localL);
int lua_set_rds_rt2_enabled(lua_State *localL);
int lua_get_rds_rt2_enabled(lua_State *localL);
int lua_set_rds_ptyn_enabled(lua_State *localL);
int lua_get_rds_ptyn_enabled(lua_State *localL);
int lua_set_rds_rt_type(lua_State *localL);
int lua_get_rds_rt_type(lua_State *localL);
int lua_set_rds2_mode(lua_State *localL);
int lua_get_rds2_mode(lua_State *localL);
int lua_set_rds_streams(lua_State *localL);
int lua_get_rds_streams(lua_State *localL);
int lua_get_available_rds_streams(lua_State *localL);
int lua_set_rds_grp_sqc(lua_State *localL);
int lua_get_rds_grp_sqc(lua_State *localL);
int lua_set_rds_grp_sqc_rds2(lua_State *localL);
int lua_get_rds_grp_sqc_rds2(lua_State *localL);
int lua_set_rds_link(lua_State *localL);
int lua_get_rds_link(lua_State *localL);
int lua_set_rds_program(lua_State *localL);
int lua_get_rds_program(lua_State *localL);
int lua_set_rds_rt_switching_period(lua_State *localL);
int lua_get_rds_rt_switching_period(lua_State *localL);
int lua_set_rds_rt_text_timeout(lua_State *localL);
int lua_get_rds_rt_text_timeout(lua_State *localL);
int lua_set_rds_level(lua_State *localL);
int lua_get_rds_level(lua_State *localL);
int lua_put_rds_custom_group(lua_State *localL);
int lua_put_rds2_custom_group(lua_State *localL);
int lua_set_rds_lps(lua_State *localL);
int lua_get_rds_lps(lua_State *localL);
int lua_set_rds_af_group0(lua_State *localL);
int lua_set_rds_default_rt(lua_State *localL);
int lua_set_rds_rt2(lua_State *localL);
int lua_set_rds_rt1(lua_State *localL);
int lua_set_rds_tps(lua_State *localL);
int lua_set_rds_ps(lua_State *localL);
int lua_set_rds_ptyn(lua_State *localL);
int lua_set_rds_grp_sqc(lua_State *localL);
int lua_set_rds_eon(lua_State *localL);
int lua_get_rds_eon(lua_State *localL);
int lua_set_rds_udg(lua_State *localL);
int lua_set_rds_udg2(lua_State *localL);
int lua_crc16(lua_State *localL);

View File

@@ -1,418 +1,13 @@
#include "lua_rds.h" #include "lua_rds.h"
#include <pthread.h> #include <pthread.h>
#include "lua_api.h"
static RDSModulator* mod = NULL; RDSModulator* mod = NULL;
static lua_State *L = NULL; lua_State *L = NULL;
static pthread_mutex_t lua_mutex; static pthread_mutex_t lua_mutex;
static uint8_t unload_refs[33] = {LUA_REFNIL}; uint8_t unload_refs[33] = {LUA_REFNIL};
static int in_set_defaults = 0;
int lua_get_userdata(lua_State *localL) {
lua_pushlstring(localL, (const char*)&mod->enc->data[mod->enc->program].lua_data, LUA_USER_DATA);
return 1;
}
int lua_get_userdata_offset(lua_State *localL) {
uint16_t offset = luaL_checkinteger(localL, 1);
uint16_t size = luaL_checkinteger(localL, 2);
if((offset+size) > LUA_USER_DATA) return luaL_error(localL, "data exceeds limit");
lua_pushlstring(localL, (const char*)&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) {
uint16_t offset = luaL_checkinteger(localL, 1);
uint16_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) {
(void)localL;
encoder_saveToFile(mod->enc);
Modulator_saveToFile(&mod->params);
return 0;
}
int lua_set_rds_program_defaults(lua_State *localL) {
(void)localL;
if (in_set_defaults) {
fprintf(stderr, "Warning: Recursive call to lua_set_rds_program_defaults blocked\n");
return 0;
}
in_set_defaults = 1;
for (int i = 1; i < *unload_refs; i++) luaL_unref(L, LUA_REGISTRYINDEX, unload_refs[i]);
unload_refs[0] = 1;
set_rds_defaults(mod->enc, mod->enc->program);
lua_call_function_nolock("on_init");
lua_call_function_nolock("on_state");
in_set_defaults = 0;
return 0;
}
int lua_reset_rds(lua_State *localL) {
(void)localL;
for (int i = 1; i < *unload_refs; i++) luaL_unref(L, LUA_REGISTRYINDEX, unload_refs[i]);
unload_refs[0] = 1;
encoder_saveToFile(mod->enc);
Modulator_saveToFile(&mod->params);
encoder_loadFromFile(mod->enc);
for(int i = 0; i < PROGRAMS; i++) reset_rds_state(mod->enc, i);
Modulator_loadFromFile(&mod->params);
lua_call_function_nolock("on_state");
return 0;
}
#define BOOL_SETTER(name) \
int lua_set_rds_##name(lua_State *localL) { \
if (!lua_isboolean(localL, 1)) return luaL_error(localL, "boolean expected, got %s", luaL_typename(localL, 1)); \
mod->enc->data[mod->enc->program].name = lua_toboolean(localL, 1); \
return 0; \
}
#define INT_SETTER(name) \
int lua_set_rds_##name(lua_State *localL) { \
mod->enc->data[mod->enc->program].name = luaL_checkinteger(localL, 1); \
return 0; \
}
#define STR_SETTER(name, function) \
int lua_set_rds_##name(lua_State *localL) { \
const char* str = luaL_checklstring(localL, 1, NULL); \
function(mod->enc, convert_to_rdscharset(str)); \
return 0; \
}
#define STR_RAW_SETTER(name, function) \
int lua_set_rds_##name(lua_State *localL) { \
const char* str = luaL_checklstring(localL, 1, NULL); \
function(mod->enc, str); \
return 0; \
}
#define AF_SETTER(name, af_field, af_struct, add_func) \
int lua_set_rds_##name(lua_State *localL) { \
luaL_checktype(localL, 1, LUA_TTABLE); \
\
int n = lua_rawlen(localL, 1); \
if (n == 0) { \
memset(&(mod->enc->data[mod->enc->program].af_field), 0, sizeof(af_struct)); \
return 0; \
} \
if(n > 25) return luaL_error(localL, "table length over 25"); \
\
af_struct new_af; \
memset(&new_af, 0, sizeof(af_struct)); \
\
for (int i = 1; i <= n; i++) { \
lua_rawgeti(localL, 1, i); \
if (lua_isnumber(localL, -1)) add_func(&new_af, lua_tonumber(localL, -1)); \
else return luaL_error(localL, "number expected, got %s", luaL_typename(localL, -1)); \
lua_pop(localL, 1); \
} \
memcpy(&(mod->enc->data[mod->enc->program].af_field), &new_af, sizeof(new_af)); \
\
return 0; \
}
#define INT_GETTER(name) \
int lua_get_rds_##name(lua_State *localL) { \
lua_pushinteger(localL, mod->enc->data[mod->enc->program].name); \
return 1; \
}
#define BOOL_GETTER(name) \
int lua_get_rds_##name(lua_State *localL) { \
lua_pushboolean(localL, mod->enc->data[mod->enc->program].name); \
return 1; \
}
#define STR_RAW_GETTER(name, length) \
int lua_get_rds_##name(lua_State *localL) { \
lua_pushlstring(localL, mod->enc->data[mod->enc->program].name, length); \
return 1; \
}
INT_SETTER(pi)
INT_GETTER(pi)
INT_SETTER(pty)
INT_GETTER(pty)
INT_SETTER(ecc)
INT_GETTER(ecc)
INT_SETTER(slc_data)
INT_GETTER(slc_data)
BOOL_SETTER(ct)
BOOL_GETTER(ct)
BOOL_SETTER(dpty)
BOOL_GETTER(dpty)
BOOL_SETTER(tp)
BOOL_GETTER(tp)
BOOL_SETTER(ta)
BOOL_GETTER(ta)
BOOL_SETTER(rt1_enabled)
BOOL_GETTER(rt1_enabled)
BOOL_SETTER(rt2_enabled)
BOOL_GETTER(rt2_enabled)
BOOL_SETTER(ptyn_enabled)
BOOL_GETTER(ptyn_enabled)
INT_SETTER(rt_type)
INT_GETTER(rt_type)
int lua_set_rds2_mode(lua_State *localL) {
mod->enc->encoder_data.rds2_mode = luaL_checkinteger(localL, 1);
return 0;
}
int lua_get_rds2_mode(lua_State *localL) {
lua_pushinteger(localL, mod->enc->encoder_data.rds2_mode);
return 1;
}
int lua_set_rds_streams(lua_State *localL) {
mod->params.rdsgen = luaL_checkinteger(localL, 1);
return 0;
}
int lua_get_rds_streams(lua_State *localL) {
lua_pushinteger(localL, mod->params.rdsgen);
return 1;
}
int lua_set_rds_link(lua_State *localL) {
if (!lua_isboolean(localL, 1)) return luaL_error(localL, "boolean expected, got %s", luaL_typename(localL, 1));
mod->enc->state[mod->enc->program].eon_linkage = lua_toboolean(localL, 1);
return 0;
}
int lua_get_rds_link(lua_State *localL) {
lua_pushboolean(localL, mod->enc->state[mod->enc->program].eon_linkage);
return 1;
}
int lua_set_rds_program(lua_State *localL) {
int program = luaL_checkinteger(localL, 1);
if(program >= PROGRAMS) program = (PROGRAMS-1);
if(program < 0) program = 0;
if(mod->enc->program == program) return 0;
mod->enc->data[mod->enc->program].ta = 0;
mod->enc->data[(uint8_t)program].ta = 0;
mod->enc->program = (uint8_t)program;
return 0;
}
int lua_get_rds_program(lua_State *localL) {
lua_pushinteger(localL, mod->enc->program);
return 1;
}
int lua_set_rds_rt_switching_period(lua_State *localL) {
mod->enc->data[mod->enc->program].rt_switching_period = luaL_checkinteger(localL, 1);
mod->enc->state[mod->enc->program].rt_switching_period_state = mod->enc->data[mod->enc->program].rt_switching_period;
return 0;
}
INT_GETTER(rt_switching_period)
int lua_set_rds_rt_text_timeout(lua_State *localL) {
mod->enc->data[mod->enc->program].rt_text_timeout = luaL_checkinteger(localL, 1);
mod->enc->state[mod->enc->program].rt_text_timeout_state = mod->enc->data[mod->enc->program].rt_text_timeout;
return 0;
}
INT_GETTER(rt_text_timeout)
int lua_set_rds_level(lua_State *localL) {
mod->params.level = luaL_checknumber(localL, 1);
return 0;
}
int lua_get_rds_level(lua_State *localL) {
lua_pushnumber(localL, mod->params.level);
return 1;
}
int lua_put_rds_custom_group(lua_State *localL) {
mod->enc->state[mod->enc->program].custom_group[0] = 1;
mod->enc->state[mod->enc->program].custom_group[1] = luaL_checkinteger(localL, 1);
mod->enc->state[mod->enc->program].custom_group[2] = luaL_checkinteger(localL, 2);
mod->enc->state[mod->enc->program].custom_group[3] = luaL_checkinteger(localL, 3);
return 0;
}
int lua_put_rds2_custom_group(lua_State *localL) {
mod->enc->state[mod->enc->program].custom_group2[0] = 1;
mod->enc->state[mod->enc->program].custom_group2[1] = luaL_checkinteger(localL, 1);
mod->enc->state[mod->enc->program].custom_group2[2] = luaL_checkinteger(localL, 2);
mod->enc->state[mod->enc->program].custom_group2[3] = luaL_checkinteger(localL, 3);
mod->enc->state[mod->enc->program].custom_group2[4] = luaL_checkinteger(localL, 4);
return 0;
}
STR_SETTER(ptyn, set_rds_ptyn)
STR_SETTER(ps, set_rds_ps)
STR_SETTER(tps, set_rds_tps)
STR_SETTER(rt1, set_rds_rt1)
STR_SETTER(rt2, set_rds_rt2)
STR_SETTER(default_rt, set_rds_default_rt)
STR_RAW_SETTER(lps, set_rds_lps)
STR_RAW_GETTER(lps, LPS_LENGTH)
STR_RAW_SETTER(grp_sqc_rds2, set_rds_grpseq2)
STR_RAW_GETTER(grp_sqc_rds2, 32)
int lua_set_rds_grp_sqc(lua_State *localL) {
const char* str = luaL_checklstring(localL, 1, NULL);
if(_strnlen(str, 2) < 1) set_rds_grpseq(mod->enc, DEFAULT_GRPSQC);
else set_rds_grpseq(mod->enc, str);
return 0;
}
STR_RAW_GETTER(grp_sqc, 32)
AF_SETTER(af_group0, af, RDSAFs, add_rds_af)
int lua_set_rds_eon(lua_State *localL) {
int eon = luaL_checkinteger(localL, 1);
if(eon >= EONs) return luaL_error(localL, "eon index exceeded");
if (!lua_isboolean(localL, 2)) return luaL_error(localL, "boolean expected, got %s", luaL_typename(localL, 2));
if (!lua_isboolean(localL, 4)) return luaL_error(localL, "boolean expected, got %s", luaL_typename(localL, 4));
if (!lua_isboolean(localL, 5)) return luaL_error(localL, "boolean expected, got %s", luaL_typename(localL, 5));
luaL_checktype(localL, 8, LUA_TTABLE);
mod->enc->data[mod->enc->program].eon[eon].enabled = lua_toboolean(localL, 2);
mod->enc->data[mod->enc->program].eon[eon].pi = luaL_checkinteger(localL, 3);
mod->enc->data[mod->enc->program].eon[eon].tp = lua_toboolean(localL, 4);
mod->enc->data[mod->enc->program].eon[eon].ta = lua_toboolean(localL, 5);
mod->enc->data[mod->enc->program].eon[eon].pty = luaL_checkinteger(localL, 6);
_strncpy(mod->enc->data[mod->enc->program].eon[eon].ps, luaL_checklstring(localL, 7, NULL), 8);
int n = lua_rawlen(localL, 8);
if (n == 0) {
memset(&(mod->enc->data[mod->enc->program].eon[eon].af), 0, sizeof(RDSAFs));
return 0;
}
if(n > 25) return luaL_error(localL, "table length over 25");
RDSAFs new_af;
memset(&new_af, 0, sizeof(RDSAFs));
for (int i = 1; i <= n; i++) {
lua_rawgeti(localL, 8, i);
if (lua_isnumber(localL, -1)) add_rds_af(&new_af, lua_tonumber(localL, -1));
else return luaL_error(localL, "number expected, got %s", luaL_typename(localL, -1));
lua_pop(localL, 1);
}
memcpy(&(mod->enc->data[mod->enc->program].eon[eon].af), &new_af, sizeof(new_af));
mod->enc->data[mod->enc->program].eon[eon].data = luaL_checkinteger(localL, 9);
return 0;
}
int lua_get_rds_eon(lua_State *localL) {
int eon = luaL_checkinteger(localL, 1);
if(eon >= EONs) return luaL_error(localL, "eon index exceeded");
lua_pushboolean(localL, mod->enc->data[mod->enc->program].eon[eon].enabled);
lua_pushinteger(localL, mod->enc->data[mod->enc->program].eon[eon].pi);
lua_pushboolean(localL, mod->enc->data[mod->enc->program].eon[eon].tp);
lua_pushboolean(localL, mod->enc->data[mod->enc->program].eon[eon].ta);
lua_pushinteger(localL, mod->enc->data[mod->enc->program].eon[eon].pty);
lua_pushlstring(localL, mod->enc->data[mod->enc->program].eon[eon].ps, 8);
lua_createtable(localL, 0, 0); // don't have decoding for AF, so just return empty table
lua_pushinteger(localL, mod->enc->data[mod->enc->program].eon[eon].data);
return 8;
}
int lua_set_rds_udg(lua_State *localL) {
if (!lua_isboolean(localL, 1)) return luaL_error(localL, "boolean expected, got %s", luaL_typename(localL, 1));
int xy = lua_toboolean(localL, 1);
luaL_checktype(localL, 2, LUA_TTABLE);
int n = lua_rawlen(localL, 2);
if(n > 8) return luaL_error(localL, "table length over 8");
uint16_t blocks[8][3] = {0};
for (int i = 1; i <= n; i++) {
lua_rawgeti(localL, 2, i);
if(lua_istable(localL, -1)) {
int n2 = lua_rawlen(localL, -1);
if(n2 > 3) return luaL_error(localL, "table length over 3");
for(int j = 1; j <= n2; j++) {
lua_rawgeti(localL, -1, j);
if (lua_isinteger(localL, -1)) blocks[i-1][j-1] = lua_tointeger(localL, -1);
else return luaL_error(localL, "integer expected, got %s", luaL_typename(localL, -1));
lua_pop(localL, 1);
}
}
else return luaL_error(localL, "table expected, got %s", luaL_typename(localL, -1));
lua_pop(localL, 1);
}
if(xy) {
memcpy(&(mod->enc->data[mod->enc->program].udg2), blocks, n * sizeof(uint16_t[3]));
mod->enc->data[mod->enc->program].udg2_len = n;
} else {
memcpy(&(mod->enc->data[mod->enc->program].udg1), blocks, n * sizeof(uint16_t[3]));
mod->enc->data[mod->enc->program].udg1_len = n;
}
return 0;
}
int lua_set_rds_udg2(lua_State *localL) {
if (!lua_isboolean(localL, 1)) return luaL_error(localL, "boolean expected, got %s", luaL_typename(localL, 1));
int xy = lua_toboolean(localL, 1);
luaL_checktype(localL, 2, LUA_TTABLE);
int n = lua_rawlen(localL, 2);
if(n > 8) return luaL_error(localL, "table length over 8");
uint16_t blocks[8][4] = {0};
for (int i = 1; i <= n; i++) {
lua_rawgeti(localL, 2, i);
if(lua_istable(localL, -1)) {
int n2 = lua_rawlen(localL, -1);
if(n2 > 4) return luaL_error(localL, "table length over 4");
for(int j = 1; j <= n2; j++) {
lua_rawgeti(localL, -1, j);
if (lua_isinteger(localL, -1)) blocks[i-1][j-1] = lua_tointeger(localL, -1);
else return luaL_error(localL, "integer expected, got %s", luaL_typename(localL, -1));
lua_pop(localL, 1);
}
}
else return luaL_error(localL, "table expected, got %s", luaL_typename(localL, -1));
lua_pop(localL, 1);
}
if(xy) {
memcpy(&(mod->enc->data[mod->enc->program].udg2_rds2), blocks, n * sizeof(uint16_t[4]));
mod->enc->data[mod->enc->program].udg2_len_rds2 = n;
} else {
memcpy(&(mod->enc->data[mod->enc->program].udg1_rds2), blocks, n * sizeof(uint16_t[4]));
mod->enc->data[mod->enc->program].udg1_len_rds2 = n;
}
return 0;
}
int lua_get_available_rds_streams(lua_State *localL) {
lua_pushinteger(localL, mod->num_streams);
return 1;
}
int lua_crc16(lua_State *localL) {
size_t len;
const char* data = luaL_checklstring(localL, 1, &len);
lua_pushinteger(localL, crc16_ccitt(data, len));
return 1;
}
#define lua_registertotable(L,n,f) (lua_pushcfunction(L, (f)), lua_setfield(L, -2, (n)))
void init_lua(RDSModulator* rds_mod) { void init_lua(RDSModulator* rds_mod) {
static int mutex_initialized = 0; static int mutex_initialized = 0;
mod = rds_mod; mod = rds_mod;
@@ -430,109 +25,131 @@ void init_lua(RDSModulator* rds_mod) {
lua_pushstring(L, VERSION); lua_pushstring(L, VERSION);
lua_setglobal(L, "core_version"); lua_setglobal(L, "core_version");
lua_pushinteger(L, PROGRAMS);
lua_setglobal(L, "max_programs"); lua_newtable(L);
lua_pushinteger(L, EONs); lua_setglobal(L, "ext");
lua_setglobal(L, "eon_count");
lua_newtable(L);
lua_setglobal(L, "on_inits");
lua_newtable(L);
lua_setglobal(L, "on_starts");
lua_newtable(L);
lua_setglobal(L, "on_states");
lua_newtable(L);
lua_setglobal(L, "ticks");
lua_newtable(L);
lua_registertotable(L, "get", lua_get_userdata);
lua_registertotable(L, "get_offset", lua_get_userdata_offset);
lua_registertotable(L, "set", lua_set_userdata);
lua_registertotable(L, "set_offset", lua_set_userdata_offset);
lua_pushinteger(L, LUA_USER_DATA); lua_pushinteger(L, LUA_USER_DATA);
lua_setglobal(L, "user_data_len"); lua_setfield(L, -2, "len");
lua_setglobal(L, "userdata");
lua_register(L, "set_rds_program_defaults", lua_set_rds_program_defaults); lua_newtable(L);
lua_register(L, "reset_rds", lua_reset_rds); lua_registertotable(L, "crc16", lua_crc16);
lua_register(L, "force_save", lua_force_save); lua_registertotable(L, "force_save", lua_force_save);
lua_registertotable(L, "reset_rds", lua_reset_rds);
lua_registertotable(L, "set_rds_program_defaults", lua_set_rds_program_defaults);
lua_pushinteger(L, PROGRAMS);
lua_setfield(L, -2, "max_programs");
lua_registertotable(L, "set_rds_program", lua_set_rds_program);
lua_registertotable(L, "get_rds_program", lua_get_rds_program);
lua_setglobal(L, "dp");
lua_register(L, "set_rds_pi", lua_set_rds_pi); lua_newtable(L);
lua_register(L, "get_rds_pi", lua_get_rds_pi);
lua_register(L, "set_rds_pty", lua_set_rds_pty); lua_newtable(L);
lua_register(L, "get_rds_pty", lua_get_rds_pty); lua_setfield(L, -2, "ext");
lua_register(L, "set_rds_ecc", lua_set_rds_ecc); lua_pushinteger(L, EONs);
lua_register(L, "get_rds_ecc", lua_get_rds_ecc); lua_setfield(L, -2, "eon_count");
lua_register(L, "set_rds_slc_data", lua_set_rds_slc_data); lua_registertotable(L, "set_pi", lua_set_rds_pi);
lua_register(L, "get_rds_slc_data", lua_get_rds_slc_data); lua_registertotable(L, "get_pi", lua_get_rds_pi);
lua_register(L, "set_rds_ct", lua_set_rds_ct); lua_registertotable(L, "set_pty", lua_set_rds_pty);
lua_register(L, "get_rds_ct", lua_get_rds_ct); lua_registertotable(L, "get_pty", lua_get_rds_pty);
lua_register(L, "set_rds_dpty", lua_set_rds_dpty); lua_registertotable(L, "set_ecc", lua_set_rds_ecc);
lua_register(L, "get_rds_dpty", lua_get_rds_dpty); lua_registertotable(L, "get_ecc", lua_get_rds_ecc);
lua_register(L, "set_rds_tp", lua_set_rds_tp); lua_registertotable(L, "set_slc_data", lua_set_rds_slc_data);
lua_register(L, "get_rds_tp", lua_get_rds_tp); lua_registertotable(L, "get_slc_data", lua_get_rds_slc_data);
lua_register(L, "set_rds_ta", lua_set_rds_ta); lua_registertotable(L, "set_ct", lua_set_rds_ct);
lua_register(L, "get_rds_ta", lua_get_rds_ta); lua_registertotable(L, "get_ct", lua_get_rds_ct);
lua_register(L, "set_rds_rt1_enabled", lua_set_rds_rt1_enabled); lua_registertotable(L, "set_dpty", lua_set_rds_dpty);
lua_register(L, "get_rds_rt1_enabled", lua_get_rds_rt1_enabled); lua_registertotable(L, "get_dpty", lua_get_rds_dpty);
lua_register(L, "set_rds_rt2_enabled", lua_set_rds_rt2_enabled); lua_registertotable(L, "set_tp", lua_set_rds_tp);
lua_register(L, "get_rds_rt2_enabled", lua_get_rds_rt2_enabled); lua_registertotable(L, "get_tp", lua_get_rds_tp);
lua_register(L, "set_rds_ptyn_enabled", lua_set_rds_ptyn_enabled); lua_registertotable(L, "set_ta", lua_set_rds_ta);
lua_register(L, "get_rds_ptyn_enabled", lua_get_rds_ptyn_enabled); lua_registertotable(L, "get_ta", lua_get_rds_ta);
lua_register(L, "set_rds_rt_type", lua_set_rds_rt_type); lua_registertotable(L, "set_rt1_enabled", lua_set_rds_rt1_enabled);
lua_register(L, "get_rds_rt_type", lua_get_rds_rt_type); lua_registertotable(L, "get_rt1_enabled", lua_get_rds_rt1_enabled);
lua_register(L, "set_rds2_mode", lua_set_rds2_mode); lua_registertotable(L, "set_rt2_enabled", lua_set_rds_rt2_enabled);
lua_register(L, "get_rds2_mode", lua_get_rds2_mode); lua_registertotable(L, "get_rt2_enabled", lua_get_rds_rt2_enabled);
lua_registertotable(L, "set_ptyn_enabled", lua_set_rds_ptyn_enabled);
lua_registertotable(L, "get_ptyn_enabled", lua_get_rds_ptyn_enabled);
lua_registertotable(L, "set_rt_type", lua_set_rds_rt_type);
lua_registertotable(L, "get_rt_type", lua_get_rds_rt_type);
lua_registertotable(L, "set_rds2_mode", lua_set_rds2_mode);
lua_registertotable(L, "get_rds2_mode", lua_get_rds2_mode);
lua_registertotable(L, "set_link", lua_set_rds_link);
lua_registertotable(L, "get_link", lua_get_rds_link);
lua_registertotable(L, "set_rt_switching_period", lua_set_rds_rt_switching_period);
lua_registertotable(L, "get_rt_switching_period", lua_get_rds_rt_switching_period);
lua_registertotable(L, "set_rt_text_timeout", lua_set_rds_rt_text_timeout);
lua_registertotable(L, "get_rt_text_timeout", lua_get_rds_rt_text_timeout);
lua_registertotable(L, "set_ptyn", lua_set_rds_ptyn);
lua_registertotable(L, "set_ps", lua_set_rds_ps);
lua_registertotable(L, "set_tps", lua_set_rds_tps);
lua_registertotable(L, "set_rt1", lua_set_rds_rt1);
lua_registertotable(L, "set_rt2", lua_set_rds_rt2);
lua_registertotable(L, "set_default_rt", lua_set_rds_default_rt);
lua_registertotable(L, "set_lps", lua_set_rds_lps);
lua_registertotable(L, "get_lps", lua_get_rds_lps);
lua_registertotable(L, "set_grpseq", lua_set_rds_grp_sqc);
lua_registertotable(L, "get_grpseq", lua_get_rds_grp_sqc);
lua_registertotable(L, "set_grpseq2", lua_set_rds_grp_sqc_rds2);
lua_registertotable(L, "get_grpseq2", lua_get_rds_grp_sqc_rds2);
lua_registertotable(L, "put_custom_group", lua_put_rds_custom_group);
lua_registertotable(L, "put_rds2_custom_group", lua_put_rds2_custom_group);
lua_registertotable(L, "set_af", lua_set_rds_af_group0);
lua_registertotable(L, "set_eon", lua_set_rds_eon);
lua_registertotable(L, "get_eon", lua_get_rds_eon);
lua_registertotable(L, "set_udg", lua_set_rds_udg);
lua_registertotable(L, "set_udg2", lua_set_rds_udg2);
lua_setglobal(L, "rds");
lua_register(L, "set_rds_streams", lua_set_rds_streams); lua_register(L, "set_rds_streams", lua_set_rds_streams);
lua_register(L, "get_rds_streams", lua_get_rds_streams); lua_register(L, "get_rds_streams", lua_get_rds_streams);
lua_register(L, "get_available_rds_streams", lua_get_available_rds_streams); lua_register(L, "get_available_rds_streams", lua_get_available_rds_streams);
lua_register(L, "set_rds_grpseq", lua_set_rds_grp_sqc);
lua_register(L, "get_rds_grpseq", lua_get_rds_grp_sqc);
lua_register(L, "set_rds_grpseq2", lua_set_rds_grp_sqc_rds2);
lua_register(L, "get_rds_grpseq2", lua_get_rds_grp_sqc_rds2);
lua_register(L, "set_rds_link", lua_set_rds_link);
lua_register(L, "get_rds_link", lua_get_rds_link);
lua_register(L, "set_rds_program", lua_set_rds_program);
lua_register(L, "get_rds_program", lua_get_rds_program);
lua_register(L, "set_rds_rt_switching_period", lua_set_rds_rt_switching_period);
lua_register(L, "get_rds_rt_switching_period", lua_get_rds_rt_switching_period);
lua_register(L, "set_rds_rt_text_timeout", lua_set_rds_rt_text_timeout);
lua_register(L, "get_rds_rt_text_timeout", lua_get_rds_rt_text_timeout);
lua_register(L, "set_rds_level", lua_set_rds_level); lua_register(L, "set_rds_level", lua_set_rds_level);
lua_register(L, "get_rds_level", lua_get_rds_level); lua_register(L, "get_rds_level", lua_get_rds_level);
lua_register(L, "set_rds_ptyn", lua_set_rds_ptyn);
lua_register(L, "set_rds_ps", lua_set_rds_ps);
lua_register(L, "set_rds_tps", lua_set_rds_tps);
lua_register(L, "set_rds_rt1", lua_set_rds_rt1);
lua_register(L, "set_rds_rt2", lua_set_rds_rt2);
lua_register(L, "set_rds_default_rt", lua_set_rds_default_rt);
lua_register(L, "set_rds_lps", lua_set_rds_lps);
lua_register(L, "get_rds_lps", lua_get_rds_lps);
lua_register(L, "put_rds_custom_group", lua_put_rds_custom_group);
lua_register(L, "put_rds2_custom_group", lua_put_rds2_custom_group);
lua_register(L, "set_rds_af_group0", lua_set_rds_af_group0);
lua_register(L, "set_rds_eon", lua_set_rds_eon);
lua_register(L, "get_rds_eon", lua_get_rds_eon);
lua_register(L, "set_rds_udg", lua_set_rds_udg);
lua_register(L, "set_rds_udg2", lua_set_rds_udg2);
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);
lua_register(L, "crc16", lua_crc16);
if (luaL_loadfile(L, "/etc/rds95.lua") != LUA_OK) { if (luaL_loadfile(L, "/etc/rds95.lua") != LUA_OK) {
fprintf(stderr, "Lua error loading file: %s\n", lua_tostring(L, -1)); fprintf(stderr, "Lua error loading file: %s\n", lua_tostring(L, -1));
lua_pop(L, 1); lua_pop(L, 1);
@@ -562,6 +179,7 @@ void run_lua(char *str, char *cmd_output, size_t* out_len) {
lua_pop(L, 1); lua_pop(L, 1);
pthread_mutex_unlock(&lua_mutex); pthread_mutex_unlock(&lua_mutex);
} }
int lua_group(RDSGroup* group, const char grp) { int lua_group(RDSGroup* group, const char grp) {
pthread_mutex_lock(&lua_mutex); pthread_mutex_lock(&lua_mutex);
lua_getglobal(L, "group"); lua_getglobal(L, "group");
@@ -703,7 +321,58 @@ void lua_call_function(const char* function) {
pthread_mutex_unlock(&lua_mutex); pthread_mutex_unlock(&lua_mutex);
} }
void destroy_lua(void) { void lua_call_table_nolock(const char *table_name) {
lua_getglobal(L, table_name);
if (!lua_istable(L, -1)) {
lua_pop(L, 1);
return;
}
lua_Integer len = lua_rawlen(L, -1);
for (lua_Integer i = 1; i <= len; i++) {
lua_rawgeti(L, -1, i);
if (lua_isfunction(L, -1)) {
if (lua_pcall(L, 0, 0, 0) != LUA_OK) {
fprintf(stderr,
"Lua error: %s at '%s[%lld]'\n",
lua_tostring(L, -1),
table_name,
(long long)i);
lua_pop(L, 1);
}
} else lua_pop(L, 1);
}
lua_pop(L, 1); // pop table
}
void lua_call_table(const char* function) {
int need_lock = (pthread_mutex_trylock(&lua_mutex) == 0);
if (!need_lock) {
fprintf(stderr, "Warning: lua_mutex already locked when table calling %s\n", function);
return;
}
lua_call_table_nolock(function);
pthread_mutex_unlock(&lua_mutex);
}
void lua_call_tfunction_nolock(const char* name) {
char table_name[256];
lua_call_function_nolock(name);
snprintf(table_name, sizeof(table_name), "%ss", name);
lua_call_table_nolock(table_name);
}
void lua_call_tfunction(const char* name) {
int need_lock = (pthread_mutex_trylock(&lua_mutex) == 0);
if (!need_lock) {
fprintf(stderr, "Warning: lua_mutex already locked when table tcalling %s\n", name);
return;
}
lua_call_tfunction_nolock(name);
pthread_mutex_unlock(&lua_mutex);
}
void destroy_lua() {
if (L) { if (L) {
for (int i = 1; i < *unload_refs; i++) luaL_unref(L, LUA_REGISTRYINDEX, unload_refs[i]); for (int i = 1; i < *unload_refs; i++) luaL_unref(L, LUA_REGISTRYINDEX, unload_refs[i]);
*unload_refs = 1; *unload_refs = 1;

View File

@@ -1,10 +1,10 @@
#pragma once #pragma once
#include "common.h"
#include "rds.h"
#include "modulator.h"
#include <lua.h> #include <lua.h>
#include <lualib.h> #include <lualib.h>
#include <lauxlib.h> #include <lauxlib.h>
#include "rds.h"
#include "fs.h"
#include "modulator.h"
void init_lua(RDSModulator* rds_mod); void init_lua(RDSModulator* rds_mod);
void run_lua(char *str, char *cmd_output, size_t* out_len); void run_lua(char *str, char *cmd_output, size_t* out_len);
@@ -12,5 +12,9 @@ int lua_group(RDSGroup* group, const char grp);
int lua_rds2_group(RDSGroup* group, int stream); int lua_rds2_group(RDSGroup* group, int stream);
void lua_call_function_nolock(const char* function); void lua_call_function_nolock(const char* function);
void lua_call_function(const char* function); void lua_call_function(const char* function);
void lua_call_table_nolock(const char *table_name);
void lua_call_table(const char* function);
void lua_call_tfunction_nolock(const char* name);
void lua_call_tfunction(const char* name);
void lua_group_ref(RDSGroup* group, int ref); void lua_group_ref(RDSGroup* group, int ref);
void destroy_lua(); void destroy_lua();

View File

@@ -155,7 +155,7 @@ void get_rds_group(RDSEncoder* enc, RDSGroup *group, uint8_t stream) {
} }
} }
lua_call_function("tick"); lua_call_tfunction("tick");
} }
if (utc->tm_min != enc->state[enc->program].last_minute) { if (utc->tm_min != enc->state[enc->program].last_minute) {
@@ -378,10 +378,10 @@ void init_rds_encoder(RDSEncoder* enc) {
if (encoder_loadFromFile(enc)) { if (encoder_loadFromFile(enc)) {
printf("Encoder file will be reinitialized.\n"); printf("Encoder file will be reinitialized.\n");
lua_call_function("on_init"); lua_call_tfunction("on_init");
} }
for(int i = 0; i < PROGRAMS; i++) reset_rds_state(enc, i); for(int i = 0; i < PROGRAMS; i++) reset_rds_state(enc, i);
lua_call_function("on_start"); lua_call_tfunction("on_start");
lua_call_function("on_state"); lua_call_tfunction("on_state");
encoder_saveToFile(enc); encoder_saveToFile(enc);
} }

View File

@@ -101,12 +101,12 @@ int main(int argc, char **argv) {
const char *short_opt = "c:ah"; const char *short_opt = "c:ah";
struct option long_opt[] = struct option long_opt[] =
{ {
{"config", required_argument, NULL, 'c'}, {"config", required_argument, NULL, 'c'},
{"asciig", no_argument, NULL, 'a'}, {"asciig", no_argument, NULL, 'a'},
{"help", no_argument, NULL, 'h'}, {"help", no_argument, NULL, 'h'},
{ 0, 0, 0, 0 } {0, 0, 0, 0}
}; };
int opt; int opt;
@@ -144,7 +144,6 @@ int main(int argc, char **argv) {
pthread_attr_init(&attr); pthread_attr_init(&attr);
struct sigaction sa_stop; struct sigaction sa_stop;
sa_stop.sa_handler = stop; sa_stop.sa_handler = stop;
sigemptyset(&sa_stop.sa_mask); sigemptyset(&sa_stop.sa_mask);
sa_stop.sa_flags = 0; sa_stop.sa_flags = 0;
@@ -160,17 +159,7 @@ int main(int argc, char **argv) {
buffer.tlength = buffer.maxlength = NUM_MPX_FRAMES * config.num_streams; buffer.tlength = buffer.maxlength = NUM_MPX_FRAMES * config.num_streams;
if(config.asciig == 0) { if(config.asciig == 0) {
rds_device = pa_simple_new( rds_device = pa_simple_new(NULL, "rds95", PA_STREAM_PLAYBACK, config.rds_device_name, "RDS Generator", &format, NULL, &buffer, NULL);
NULL,
"rds95",
PA_STREAM_PLAYBACK,
config.rds_device_name,
"RDS Generator",
&format,
NULL,
&buffer,
NULL
);
if (rds_device == NULL) { if (rds_device == NULL) {
fprintf(stderr, "Error: cannot open sound device.\n"); fprintf(stderr, "Error: cannot open sound device.\n");
goto exit; goto exit;