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

improvements (no way)

This commit is contained in:
2025-12-29 09:51:00 +01:00
parent 8aefcf08d5
commit 26e151a6b6
4 changed files with 142 additions and 66 deletions

View File

@@ -304,6 +304,10 @@ function set_rds_af_oda(afs) end
---@return integer oda_id ---@return integer oda_id
function register_oda(group, group_version, aid, data) end 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 ---Sets the data for a existing ODA group
---@param oda_id integer ---@param oda_id integer
---@param data integer ---@param data integer
@@ -340,7 +344,7 @@ function get_userdata() end
function get_userdata_offset(offset, size) end function get_userdata_offset(offset, size) end
---The callback function for an ODA handler ---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 ---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)) ---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 ---@return integer oda_id
function register_oda_rds2(aid, data, file_related) end 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 ---This function is defined externally
---Loads the file into RFT and initializes it if needed, note that this needs RDR2 mode 2 ---Loads the file into RFT and initializes it if needed, note that this needs RDR2 mode 2
---@param path string ---@param path string

View File

@@ -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 == 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)
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) table.insert(_RDS_ODAs, oda)
return #_RDS_ODAs return #_RDS_ODAs
end 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 ---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 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 _RDS_ODAs[oda_id].data = data
end end
@@ -41,29 +58,40 @@ end
---@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 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 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
end end
local function get_aid() local function get_aid()
local oda = _RDS_ODAs[_RDS_ODA_pointer] local checked = 0
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 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 end
local function get_data() local function get_data()
local checked_count = 0 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] 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() local generated, b, c, d = oda.handler()
_RDS_ODA_pointer = (_RDS_ODA_pointer % #_RDS_ODAs) + 1 _RDS_ODA_pointer = (_RDS_ODA_pointer % #_RDS_ODAs) + 1
b = b | oda.group << 12 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 _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
local b, c, d = get_aid() return get_aid()
return true, b, c, d
elseif group_type == "K" then elseif group_type == "K" then
return get_data() return get_data()
end end

View File

@@ -17,15 +17,32 @@ _RDS2_ODA_pointer = 1
---@return integer oda_id ---@return integer oda_id
function register_oda_rds2(aid, data, file_related) function 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
if _RDS2_ODAs[i] == false then
_RDS2_ODAs[i] = oda
return i
end
end
table.insert(_RDS2_ODAs, oda) table.insert(_RDS2_ODAs, oda)
return #_RDS2_ODAs return #_RDS2_ODAs
end 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 ---This function is defined externally
---@param oda_id integer ---@param oda_id integer
---@param data integer ---@param data integer
function set_oda_id_data_rds2(oda_id, data) 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 _RDS2_ODAs[oda_id].data = data
end end
@@ -33,12 +50,22 @@ 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 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 _RDS2_ODAs[oda_id].handler = func
end end
function rds2_group(stream) function rds2_group(stream)
if #_RDS2_ODAs == 0 then return false, 0, 0, 0, 0 end 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 if _RDS2_ODA_pointer > #_RDS2_ODAs then _RDS2_ODA_pointer = 1 end
local oda = _RDS2_ODAs[_RDS2_ODA_pointer] local oda = _RDS2_ODAs[_RDS2_ODA_pointer]

View File

@@ -10,19 +10,19 @@ _Rft_crc = false
_Rft_crc_full_file = 0 _Rft_crc_full_file = 0
_Rft_crc_mode = 0 _Rft_crc_mode = 0
_Rft_crc_sent = false _Rft_crc_sent = false
_Rft_aid = 0xFF7F _Rft_aid = 0
local function start_rft() 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) _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 if #_Rft_file == 0 then return false, 0, 0, 0, 0 end
local total_segments = math.ceil(#_Rft_file / 5) local total_segments = math.ceil(#_Rft_file / 5)
local seg = _Rft_file_segment local seg = _Rft_file_segment
local base = seg * 5 + 1 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 _Rft_crc_sent = true
local chunk_address = math.floor((_Rft_crc_segment - 1) / 2) local chunk_address = math.floor((_Rft_crc_segment - 1) / 2)
local c = (1 << 12) | (_Rft_crc_mode & 7) << 9 | (chunk_address & 0x1ff) 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 _Rft_crc_segment = _Rft_crc_segment + 2
if _Rft_crc_segment > #_Rft_crc_data then _Rft_crc_segment = 1 end 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 return true, (2 << 14), _Rft_aid, c, (high_byte << 8) | low_byte
else else
_Rft_crc_sent = false _Rft_crc_sent = false
@@ -60,12 +60,35 @@ local function start_rft()
end end
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 ---This function is defined externally
---Loads the file into RFT and initializes it if needed, note that this needs RDR2 mode 2 ---Loads the file into RFT and initializes it if needed, note that this needs RDR2 mode 2
---@param path string ---@param path string filesystem path on the os
---@param id integer ---@param id integer mostly use 0 here
---@param crc integer|boolean ---@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) function load_station_logo(path, id, crc)
if _Rft_aid ~= 0xFF7F then stop_rft() end
_Rft_aid = 0xFF7F
local file = io.open(path, "rb") local file = io.open(path, "rb")
if not file then error("Could not open file") end if not file then error("Could not open file") end
_Rft_file = file:read("*a") _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 if _Rft_version > 7 then _Rft_version = 0 end
end end
_Rft_crc_data = "" -- Clear previous CRC data _Rft_crc_data = ""
_Rft_crc = (crc ~= false) _Rft_crc = (crc ~= false)
local chunk_size = 0
if crc and crc == 0 then if crc and crc == 0 then
_Rft_crc_mode = 0 _Rft_crc_mode = 0
_Rft_crc_full_file = crc16(_Rft_file) _Rft_crc_full_file = crc16(_Rft_file)
elseif crc and crc == 1 and #_Rft_file <= 40960 then elseif crc and crc == 1 and #_Rft_file <= 40960 then
_Rft_crc_mode = 1 _Rft_crc_mode = 1
local chunk_size = 5 * 16 -- 80 bytes chunk_size = 5 * 16
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
elseif crc and crc == 2 and #_Rft_file < 40960 and #_Rft_file >= 81920 then elseif crc and crc == 2 and #_Rft_file < 40960 and #_Rft_file >= 81920 then
_Rft_crc_mode = 2 _Rft_crc_mode = 2
local chunk_size = 5 * 32 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
elseif crc and crc == 3 and #_Rft_file > 81960 then elseif crc and crc == 3 and #_Rft_file > 81960 then
_Rft_crc_mode = 3 _Rft_crc_mode = 3
local chunk_size = 5 * 64 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
elseif crc and crc == 4 and #_Rft_file > 81960 then elseif crc and crc == 4 and #_Rft_file > 81960 then
_Rft_crc_mode = 4 _Rft_crc_mode = 4
local chunk_size = 5 * 128 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
elseif crc and crc == 5 and #_Rft_file > 81960 then elseif crc and crc == 5 and #_Rft_file > 81960 then
_Rft_crc_mode = 5 _Rft_crc_mode = 5
local chunk_size = 5 * 256 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
elseif crc and (crc == 7 or crc == true) then elseif crc and (crc == 7 or crc == true) then
_Rft_crc_mode = 7 if #_Rft_file <= 40960 then
local chunk_size = 0 _Rft_crc_mode = 1
if #_Rft_file <= 40960 then chunk_size = 5*16 chunk_size = 5*16
elseif #_Rft_file > 40960 and #_Rft_file <= 81920 then chunk_size = 5*32 elseif #_Rft_file > 40960 and #_Rft_file <= 81920 then
elseif #_Rft_file > 81960 then chunk_size = 5*64 end _Rft_crc_mode = 2
if chunk_size ~= 0 then chunk_size = 5*32
for i = 1, #_Rft_file, chunk_size do elseif #_Rft_file > 81960 then
local chunk = string.sub(_Rft_file, i, i + chunk_size - 1) _Rft_crc_mode = 3
local crc_val = crc16(chunk) chunk_size = 5*64
_Rft_crc_data = _Rft_crc_data .. string.char(math.floor(crc_val / 256), crc_val % 256)
end
end end
else else
_Rft_crc = false _Rft_crc = false
end 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_file > 262143 then error("The file is too large", 2) end
if _Rft_oda_id == nil then start_rft() end if _Rft_oda_id == nil then start_rft() end
---@diagnostic disable-next-line: param-type-mismatch ---@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) 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 _Rft_last_id = id
end 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