0
1
mirror of https://github.com/radio95-rnt/rds95.git synced 2026-02-26 12:32:05 +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
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

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 == 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

View File

@@ -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]

View File

@@ -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
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