From 26e151a6b6daa6da1099150fa3b99f25cec4393a Mon Sep 17 00:00:00 2001 From: KubaPro010 Date: Mon, 29 Dec 2025 09:51:00 +0100 Subject: [PATCH] improvements (no way) --- plugin.lua | 10 +++- scripts/0-oda.lua | 51 +++++++++++++----- scripts/0-rds2_oda.lua | 31 ++++++++++- scripts/1-rft.lua | 116 +++++++++++++++++++++++------------------ 4 files changed, 142 insertions(+), 66 deletions(-) diff --git a/plugin.lua b/plugin.lua index c251a77..94415bf 100644 --- a/plugin.lua +++ b/plugin.lua @@ -304,6 +304,10 @@ function set_rds_af_oda(afs) end ---@return integer oda_id function register_oda(group, group_version, aid, data) end +---Unregisters an ODA, this stops the handler or AID being called/sent +---@param oda_id integer +function unregister_oda(oda_id) end + ---Sets the data for a existing ODA group ---@param oda_id integer ---@param data integer @@ -340,7 +344,7 @@ function get_userdata() end function get_userdata_offset(offset, size) end ---The callback function for an ODA handler ----@alias RDS2_ODAHandler fun(): (boolean, integer, integer, integer, integer) +---@alias RDS2_ODAHandler fun(integer): (boolean, integer, integer, integer, integer) ---This function is defined externally ---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)) @@ -360,6 +364,10 @@ function set_oda_id_data_rds2(oda_id, data) end ---@return integer oda_id function register_oda_rds2(aid, data, file_related) end +---Unregisters an RDS 2 ODA, this stops the handler or AID being called/sent +---@param oda_id integer +function unregister_oda_rds2(oda_id) end + ---This function is defined externally ---Loads the file into RFT and initializes it if needed, note that this needs RDR2 mode 2 ---@param path string diff --git a/scripts/0-oda.lua b/scripts/0-oda.lua index 81700bd..56998ad 100644 --- a/scripts/0-oda.lua +++ b/scripts/0-oda.lua @@ -21,15 +21,32 @@ function 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 == 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) + for i = 1, #_RDS_ODAs do + if _RDS_ODAs[i] == false then + _RDS_ODAs[i] = oda + return i + end + end table.insert(_RDS_ODAs, oda) return #_RDS_ODAs end +---Unregisters an ODA, this stops the handler or AID being called/sent +---@param oda_id integer +function 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 + + _RDS_ODAs[oda_id] = false + + if _RDS_ODA_pointer == oda_id then _RDS_ODA_pointer = (_RDS_ODA_pointer % #_RDS_ODAs) + 1 end +end + + ---Sets the id_data for a existing ODA group ---@param oda_id integer ---@param data integer function set_oda_id_data(oda_id, data) - if oda_id < 1 or oda_id > #_RDS_ODAs 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 end @@ -41,29 +58,40 @@ end ---@param oda_id integer The ID returned by register_oda ---@param fun ODAHandler function set_oda_handler(oda_id, fun) - if oda_id < 1 or oda_id > #_RDS_ODAs 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 _RDS_ODAs[oda_id].handler = fun end local function get_aid() - local oda = _RDS_ODAs[_RDS_ODA_pointer] - local b = 3 << 12 | oda.group << 1 | (oda.group_version and 1 or 0) - local data, aid = oda.data, oda.aid + local checked = 0 - _RDS_ODA_pointer = (_RDS_ODA_pointer % #_RDS_ODAs) + 1 + while checked < #_RDS_ODAs do + local oda = _RDS_ODAs[_RDS_ODA_pointer] - return b, data, aid + if oda ~= false then + local b = 3 << 12 | oda.group << 1 | (oda.group_version and 1 or 0) + local data, aid = oda.data, oda.aid + + _RDS_ODA_pointer = (_RDS_ODA_pointer % #_RDS_ODAs) + 1 + return b, data, aid + end + + _RDS_ODA_pointer = (_RDS_ODA_pointer % #_RDS_ODAs) + 1 + checked = checked + 1 + end + + return false, 0, 0, 0 end + local function get_data() local checked_count = 0 - local total_odas = #_RDS_ODAs - while checked_count < total_odas do + while checked_count < #_RDS_ODAs do local oda = _RDS_ODAs[_RDS_ODA_pointer] - if type(oda.handler) == "function" then + if oda ~= false and type(oda.handler) == "function" then local generated, b, c, d = oda.handler() _RDS_ODA_pointer = (_RDS_ODA_pointer % #_RDS_ODAs) + 1 b = b | oda.group << 12 @@ -84,8 +112,7 @@ function group(group_type) if _RDS_ODA_pointer > #_RDS_ODAs or _RDS_ODA_pointer < 1 then _RDS_ODA_pointer = 1 end if group_type == "O" then - local b, c, d = get_aid() - return true, b, c, d + return get_aid() elseif group_type == "K" then return get_data() end diff --git a/scripts/0-rds2_oda.lua b/scripts/0-rds2_oda.lua index fb8d48b..9a0e8e0 100644 --- a/scripts/0-rds2_oda.lua +++ b/scripts/0-rds2_oda.lua @@ -17,15 +17,32 @@ _RDS2_ODA_pointer = 1 ---@return integer oda_id function register_oda_rds2(aid, data, file_related) local oda = _RDS2_ODA.new(aid, data, false, file_related) + for i = 1, #_RDS2_ODAs do + if _RDS2_ODAs[i] == false then + _RDS2_ODAs[i] = oda + return i + end + end table.insert(_RDS2_ODAs, oda) return #_RDS2_ODAs end +---Unregisters an RDS 2 ODA, this stops the handler or AID being called/sent +---@param oda_id integer +function 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 + + _RDS2_ODAs[oda_id] = false + + if _RDS2_ODA_pointer == oda_id then _RDS2_ODA_pointer = _RDS2_ODA_pointer + 1 end +end + + ---This function is defined externally ---@param oda_id integer ---@param data integer function set_oda_id_data_rds2(oda_id, data) - if oda_id < 1 or oda_id > #_RDS2_ODAs 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 end @@ -33,12 +50,22 @@ end ---@param oda_id integer ---@param func RDS2_ODAHandler function set_oda_handler_rds2(oda_id, func) - if oda_id < 1 or oda_id > #_RDS2_ODAs 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 end function rds2_group(stream) if #_RDS2_ODAs == 0 then return false, 0, 0, 0, 0 end + + local checked = 0 + while checked < #_RDS2_ODAs and _RDS2_ODAs[_RDS2_ODA_pointer] == false do + _RDS2_ODA_pointer = _RDS2_ODA_pointer + 1 + if _RDS2_ODA_pointer > #_RDS2_ODAs then _RDS2_ODA_pointer = 1 end + checked = checked + 1 + end + + if checked == #_RDS2_ODAs then return false, 0, 0, 0, 0 end + if _RDS2_ODA_pointer > #_RDS2_ODAs then _RDS2_ODA_pointer = 1 end local oda = _RDS2_ODAs[_RDS2_ODA_pointer] diff --git a/scripts/1-rft.lua b/scripts/1-rft.lua index 9d4116c..5e9aa35 100644 --- a/scripts/1-rft.lua +++ b/scripts/1-rft.lua @@ -10,19 +10,19 @@ _Rft_crc = false _Rft_crc_full_file = 0 _Rft_crc_mode = 0 _Rft_crc_sent = false -_Rft_aid = 0xFF7F +_Rft_aid = 0 local function start_rft() - if _Rft_oda_id == nil then + if _Rft_oda_id == nil and _Rft_aid ~= 0 then _Rft_oda_id = register_oda_rds2(_Rft_aid, 0, true) - set_oda_handler_rds2(_Rft_oda_id, function () + set_oda_handler_rds2(_Rft_oda_id, function (stream) if #_Rft_file == 0 then return false, 0, 0, 0, 0 end local total_segments = math.ceil(#_Rft_file / 5) local seg = _Rft_file_segment local base = seg * 5 + 1 - if not _Rft_crc_sent and _Rft_crc and (seg % 16 == 0) then + if not _Rft_crc_sent and _Rft_crc and (seg % 16 == 0) and stream == 1 then _Rft_crc_sent = true local chunk_address = math.floor((_Rft_crc_segment - 1) / 2) local c = (1 << 12) | (_Rft_crc_mode & 7) << 9 | (chunk_address & 0x1ff) @@ -39,7 +39,7 @@ local function start_rft() _Rft_crc_segment = _Rft_crc_segment + 2 if _Rft_crc_segment > #_Rft_crc_data then _Rft_crc_segment = 1 end - + return true, (2 << 14), _Rft_aid, c, (high_byte << 8) | low_byte else _Rft_crc_sent = false @@ -60,12 +60,35 @@ local function start_rft() end end +local function stop_rft() + if _Rft_oda_id ~= nil and _Rft_aid ~= 0 then + unregister_oda_rds2(_Rft_oda_id) + _Rft_oda_id = nil + _Rft_aid = 0 + end + + _Rft_file = "" + _Rft_crc_data = "" + _Rft_file_segment = 0 + _Rft_crc_segment = 0 + _Rft_toggle = false + _Rft_last_id = -1 + _Rft_version = 0 + _Rft_crc = false + _Rft_crc_full_file = 0 + _Rft_crc_mode = 0 + _Rft_crc_sent = false +end + ---This function is defined externally ---Loads the file into RFT and initializes it if needed, note that this needs RDR2 mode 2 ----@param path string ----@param id integer ----@param crc integer|boolean +---@param path string filesystem path on the os +---@param id integer mostly use 0 here +---@param crc integer|boolean false for disabled, true for mode 7, and an integer for any of the modes function load_station_logo(path, id, crc) + if _Rft_aid ~= 0xFF7F then stop_rft() end + _Rft_aid = 0xFF7F + local file = io.open(path, "rb") if not file then error("Could not open file") end _Rft_file = file:read("*a") @@ -78,72 +101,63 @@ function load_station_logo(path, id, crc) if _Rft_version > 7 then _Rft_version = 0 end end - _Rft_crc_data = "" -- Clear previous CRC data + _Rft_crc_data = "" _Rft_crc = (crc ~= false) + local chunk_size = 0 if crc and crc == 0 then _Rft_crc_mode = 0 _Rft_crc_full_file = crc16(_Rft_file) elseif crc and crc == 1 and #_Rft_file <= 40960 then _Rft_crc_mode = 1 - local chunk_size = 5 * 16 -- 80 bytes - for i = 1, #_Rft_file, chunk_size do - local chunk = string.sub(_Rft_file, i, i + chunk_size - 1) - local crc_val = crc16(chunk) - _Rft_crc_data = _Rft_crc_data .. string.char(math.floor(crc_val / 256), crc_val % 256) - end + chunk_size = 5 * 16 elseif crc and crc == 2 and #_Rft_file < 40960 and #_Rft_file >= 81920 then _Rft_crc_mode = 2 - local chunk_size = 5 * 32 - for i = 1, #_Rft_file, chunk_size do - local chunk = string.sub(_Rft_file, i, i + chunk_size - 1) - local crc_val = crc16(chunk) - _Rft_crc_data = _Rft_crc_data .. string.char(math.floor(crc_val / 256), crc_val % 256) - end + chunk_size = 5 * 32 elseif crc and crc == 3 and #_Rft_file > 81960 then _Rft_crc_mode = 3 - local chunk_size = 5 * 64 - for i = 1, #_Rft_file, chunk_size do - local chunk = string.sub(_Rft_file, i, i + chunk_size - 1) - local crc_val = crc16(chunk) - _Rft_crc_data = _Rft_crc_data .. string.char(math.floor(crc_val / 256), crc_val % 256) - end + chunk_size = 5 * 64 elseif crc and crc == 4 and #_Rft_file > 81960 then _Rft_crc_mode = 4 - local chunk_size = 5 * 128 - for i = 1, #_Rft_file, chunk_size do - local chunk = string.sub(_Rft_file, i, i + chunk_size - 1) - local crc_val = crc16(chunk) - _Rft_crc_data = _Rft_crc_data .. string.char(math.floor(crc_val / 256), crc_val % 256) - end + chunk_size = 5 * 128 elseif crc and crc == 5 and #_Rft_file > 81960 then _Rft_crc_mode = 5 - local chunk_size = 5 * 256 - for i = 1, #_Rft_file, chunk_size do - local chunk = string.sub(_Rft_file, i, i + chunk_size - 1) - local crc_val = crc16(chunk) - _Rft_crc_data = _Rft_crc_data .. string.char(math.floor(crc_val / 256), crc_val % 256) - end + chunk_size = 5 * 256 elseif crc and (crc == 7 or crc == true) then - _Rft_crc_mode = 7 - local chunk_size = 0 - if #_Rft_file <= 40960 then chunk_size = 5*16 - elseif #_Rft_file > 40960 and #_Rft_file <= 81920 then chunk_size = 5*32 - elseif #_Rft_file > 81960 then chunk_size = 5*64 end - if chunk_size ~= 0 then - for i = 1, #_Rft_file, chunk_size do - local chunk = string.sub(_Rft_file, i, i + chunk_size - 1) - local crc_val = crc16(chunk) - _Rft_crc_data = _Rft_crc_data .. string.char(math.floor(crc_val / 256), crc_val % 256) - end + if #_Rft_file <= 40960 then + _Rft_crc_mode = 1 + chunk_size = 5*16 + elseif #_Rft_file > 40960 and #_Rft_file <= 81920 then + _Rft_crc_mode = 2 + chunk_size = 5*32 + elseif #_Rft_file > 81960 then + _Rft_crc_mode = 3 + chunk_size = 5*64 end else _Rft_crc = false end + if _Rft_crc and chunk_size ~= 0 then + for i = 1, #_Rft_file, chunk_size do + local chunk = string.sub(_Rft_file, i, i + chunk_size - 1) + local crc_val = crc16(chunk) + _Rft_crc_data = _Rft_crc_data .. string.char(math.floor(crc_val / 256), crc_val % 256) + end + end + if #_Rft_file > 262143 then error("The file is too large", 2) end if _Rft_oda_id == nil then start_rft() end ---@diagnostic disable-next-line: param-type-mismatch set_oda_id_data_rds2(_Rft_oda_id, #_Rft_file | (id & 63) << 18 | (_Rft_version & 7) << 24 | (_Rft_crc and 1 or 0) << 27) _Rft_last_id = id -end \ No newline at end of file +end + +local _old_on_state_oda_rds2 = on_state +function on_state() + stop_rft() + _RDS2_ODAs = {} + _RDS2_ODA_aid = 0 + _RDS2_ODA_pointer = 1 + if type(_old_on_state_oda_rds2) == "function" then _old_on_state_oda_rds2() end +end