mirror of
https://github.com/radio95-rnt/rds95.git
synced 2026-07-29 16:29:17 +02:00
proper uecp
This commit is contained in:
Vendored
+2
-1
@@ -32,6 +32,7 @@
|
|||||||
},
|
},
|
||||||
"C_Cpp.dimInactiveRegions": false,
|
"C_Cpp.dimInactiveRegions": false,
|
||||||
"Lua.diagnostics.disable": [
|
"Lua.diagnostics.disable": [
|
||||||
"duplicate-set-field"
|
"duplicate-set-field",
|
||||||
|
"lowercase-global"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
cmake_minimum_required(VERSION 3.10)
|
cmake_minimum_required(VERSION 3.10)
|
||||||
|
|
||||||
project(rds95 VERSION 1.7)
|
project(rds95 VERSION 1.8)
|
||||||
|
|
||||||
add_compile_options(-Wall -Werror -Wextra -pedantic -O2 -std=c18 -march=native -DVERSION=\"${PROJECT_VERSION}\")
|
add_compile_options(-Wall -Werror -Wextra -pedantic -O2 -std=c18 -march=native -DVERSION=\"${PROJECT_VERSION}\")
|
||||||
|
|
||||||
|
|||||||
+21
-42
@@ -40,29 +40,32 @@ function dp.set_writing_program(program_idx) end
|
|||||||
---@return integer
|
---@return integer
|
||||||
function dp.get_writing_program() end
|
function dp.get_writing_program() end
|
||||||
|
|
||||||
|
hooks = {}
|
||||||
|
|
||||||
---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
|
---This is a table of functions. Each will be called
|
||||||
function on_init() end
|
hooks.on_init = {}
|
||||||
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
|
---This is a table of functions. Each will be called
|
||||||
function on_start() end
|
hooks.on_start = {}
|
||||||
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
|
---This is a table of functions. Each will be called
|
||||||
function on_state() end
|
hooks.on_state = {}
|
||||||
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
|
---This is a table of functions. Each will be called
|
||||||
function tick() end
|
hooks.tick = {}
|
||||||
ticks = {}
|
|
||||||
|
---This function is calld every time a RT transmits start to end - Useful for UECP's RT buffer shenanigans
|
||||||
|
---It should be defined by the user in the script.
|
||||||
|
---This is a table of functions. Each will be called
|
||||||
|
hooks.rt_transmission = {}
|
||||||
|
|
||||||
-- 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
|
-- 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
|
||||||
|
|
||||||
@@ -140,25 +143,15 @@ function rds.get_ta() end
|
|||||||
|
|
||||||
-- Feature Flags
|
-- Feature Flags
|
||||||
---@param enabled boolean
|
---@param enabled boolean
|
||||||
function rds.set_rt1_enabled(enabled) end
|
function rds.set_rt_enabled(enabled) end
|
||||||
---@return boolean
|
---@return boolean
|
||||||
function rds.get_rt1_enabled() end
|
function rds.get_rt_enabled() end
|
||||||
|
|
||||||
---@param enabled boolean
|
|
||||||
function rds.set_rt2_enabled(enabled) end
|
|
||||||
---@return boolean
|
|
||||||
function rds.get_rt2_enabled() end
|
|
||||||
|
|
||||||
---@param enabled boolean
|
---@param enabled boolean
|
||||||
function rds.set_ptyn_enabled(enabled) end
|
function rds.set_ptyn_enabled(enabled) end
|
||||||
---@return boolean
|
---@return boolean
|
||||||
function rds.get_ptyn_enabled() end
|
function rds.get_ptyn_enabled() end
|
||||||
|
|
||||||
---@param rt_type integer
|
|
||||||
function rds.set_rt_type(rt_type) end
|
|
||||||
---@return integer
|
|
||||||
function rds.get_rt_type() end
|
|
||||||
|
|
||||||
-- Modulation & Generation
|
-- Modulation & Generation
|
||||||
---@param mode integer
|
---@param mode integer
|
||||||
function rds.set_rds2_mode(mode) end
|
function rds.set_rds2_mode(mode) end
|
||||||
@@ -176,18 +169,6 @@ function rds.set_link(linkage) end
|
|||||||
---@return boolean
|
---@return boolean
|
||||||
function rds.get_link() end
|
function rds.get_link() end
|
||||||
|
|
||||||
-- Timeouts and Periods
|
|
||||||
---@param period integer in seconds
|
|
||||||
function rds.set_rt_switching_period(period) end
|
|
||||||
---@return integer
|
|
||||||
function rds.get_rt_switching_period() end
|
|
||||||
|
|
||||||
---For a RT1, this sets the timeout period before setting RT1 into "Default RT" (not literally)
|
|
||||||
---@param timeout integer in seconds
|
|
||||||
function rds.set_rt_text_timeout(timeout) end
|
|
||||||
---@return integer
|
|
||||||
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 rds.set_ptyn(ptyn) end
|
function rds.set_ptyn(ptyn) end
|
||||||
@@ -195,12 +176,10 @@ function rds.set_ptyn(ptyn) end
|
|||||||
function rds.set_ps(ps) end
|
function rds.set_ps(ps) end
|
||||||
---@param tps string Traffic PS
|
---@param tps string Traffic PS
|
||||||
function rds.set_tps(tps) end
|
function rds.set_tps(tps) end
|
||||||
---@param rt1 string Radio Text 1 (max 64 chars)
|
---@param rt string Radio Text (max 64 chars)
|
||||||
function rds.set_rt1(rt1) end
|
function rds.set_rt(rt) end
|
||||||
---@param rt2 string Radio Text 2 (max 64 chars)
|
|
||||||
function rds.set_rt2(rt2) end
|
function rds.toggle_rt_ab() end
|
||||||
---@param rt string Default radio text - max 64 characters
|
|
||||||
function rds.set_default_rt(rt) end
|
|
||||||
|
|
||||||
---@param lps string
|
---@param lps string
|
||||||
function rds.set_lps(lps) end
|
function rds.set_lps(lps) end
|
||||||
|
|||||||
+1
-1
@@ -119,7 +119,7 @@ function group(group_type)
|
|||||||
return false, 0, 0, 0
|
return false, 0, 0, 0
|
||||||
end
|
end
|
||||||
|
|
||||||
table.insert(on_states, function ()
|
table.insert(hooks.on_state, function ()
|
||||||
_RDS_ODAs = {}
|
_RDS_ODAs = {}
|
||||||
_RDS_ODA_pointer = 1
|
_RDS_ODA_pointer = 1
|
||||||
end)
|
end)
|
||||||
@@ -125,7 +125,7 @@ function rds2_group(stream)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
table.insert(on_states, function ()
|
table.insert(hooks.on_state, function ()
|
||||||
_RDS2_ODAs = {}
|
_RDS2_ODAs = {}
|
||||||
_RDS2_ODA_aid = 0
|
_RDS2_ODA_aid = 0
|
||||||
_RDS2_ODA_pointer = 1
|
_RDS2_ODA_pointer = 1
|
||||||
|
|||||||
+1
-1
@@ -111,7 +111,7 @@ function rds.ext.set_af_oda(afs)
|
|||||||
save_af_to_userdata(afs)
|
save_af_to_userdata(afs)
|
||||||
end
|
end
|
||||||
|
|
||||||
table.insert(on_states, function ()
|
table.insert(hooks.on_state, function ()
|
||||||
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
|
||||||
end)
|
end)
|
||||||
+1
-1
@@ -80,6 +80,6 @@ function rds.ext.get_ert()
|
|||||||
return data:match("^(.-)[\r%z]*") or ""
|
return data:match("^(.-)[\r%z]*") or ""
|
||||||
end
|
end
|
||||||
|
|
||||||
table.insert(on_states, function ()
|
table.insert(hooks.on_state, function ()
|
||||||
if string.byte(userdata.get_offset(USERDATA_ERT_OFFSET+257, 1)) ~= 0 then init_ert() end
|
if string.byte(userdata.get_offset(USERDATA_ERT_OFFSET+257, 1)) ~= 0 then init_ert() end
|
||||||
end)
|
end)
|
||||||
+1
-1
@@ -89,7 +89,7 @@ function unregister_rtp(ertp)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
table.insert(on_states, function ()
|
table.insert(hooks.on_state, function ()
|
||||||
if rds.ext.get_rtp_meta(false) then init_rtp() end
|
if rds.ext.get_rtp_meta(false) then init_rtp() end
|
||||||
if rds.ext.get_rtp_meta(true) then init_ertp() end
|
if rds.ext.get_rtp_meta(true) then init_ertp() end
|
||||||
end)
|
end)
|
||||||
@@ -0,0 +1,281 @@
|
|||||||
|
uecp = {}
|
||||||
|
uecp.rt_buffer = {}
|
||||||
|
uecp.rt_buffer_index = 1
|
||||||
|
uecp.rt_tx_remaining = 0
|
||||||
|
|
||||||
|
hooks.rt_transmission[#hooks.rt_transmission + 1] = function ()
|
||||||
|
if #uecp.rt_buffer == 0 then return end
|
||||||
|
|
||||||
|
if #uecp.rt_buffer > 1 and uecp.rt_tx_remaining > 1 then
|
||||||
|
uecp.rt_tx_remaining = uecp.rt_tx_remaining - 1
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
uecp.rt_buffer_index = (uecp.rt_buffer_index % #uecp.rt_buffer) + 1
|
||||||
|
local entry = uecp.rt_buffer[uecp.rt_buffer_index]
|
||||||
|
uecp.rt_tx_remaining = entry.number_tx
|
||||||
|
|
||||||
|
rds.set_rt(entry.text)
|
||||||
|
if entry.toggle_ab then rds.toggle_rt_ab() end
|
||||||
|
end
|
||||||
|
|
||||||
|
local mec_handlers = {}
|
||||||
|
|
||||||
|
local function dsn_helper(dsn, write)
|
||||||
|
if dsn == 0 then write()
|
||||||
|
elseif dsn == 254 then
|
||||||
|
local start = dp.get_writing_program()
|
||||||
|
for i = 1, dp.max_programs do
|
||||||
|
local p = i - 1
|
||||||
|
if p ~= start then
|
||||||
|
dp.set_writing_program(p)
|
||||||
|
write()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
elseif dsn == 255 then
|
||||||
|
for i = 1, dp.max_programs do
|
||||||
|
dp.set_writing_program(i - 1)
|
||||||
|
write()
|
||||||
|
end
|
||||||
|
else
|
||||||
|
dp.set_writing_program(dsn - 1)
|
||||||
|
write()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
mec_handlers[1] = function (data)
|
||||||
|
-- PI
|
||||||
|
local dsn = string.byte(data, 2)
|
||||||
|
local psn = string.byte(data, 3)
|
||||||
|
local pi_msb = string.byte(data, 4)
|
||||||
|
local pi_lsb = string.byte(data, 5)
|
||||||
|
|
||||||
|
dsn_helper(dsn, function ()
|
||||||
|
rds.set_pi((pi_msb << 8) | pi_lsb)
|
||||||
|
end)
|
||||||
|
return 5
|
||||||
|
end
|
||||||
|
mec_handlers[2] = function (data)
|
||||||
|
-- PS
|
||||||
|
local dsn = string.byte(data, 2)
|
||||||
|
local psn = string.byte(data, 3)
|
||||||
|
local ps = string.sub(data, 4, 11) -- Static len
|
||||||
|
dsn_helper(dsn, function ()
|
||||||
|
rds.set_ps(ps)
|
||||||
|
end)
|
||||||
|
return 11
|
||||||
|
end
|
||||||
|
mec_handlers[0x21] = function (data)
|
||||||
|
-- LPS
|
||||||
|
local dsn = string.byte(data, 2)
|
||||||
|
local psn = string.byte(data, 3)
|
||||||
|
local mel = string.byte(data, 4)
|
||||||
|
local lps = string.sub(data, 5, 5+mel)
|
||||||
|
|
||||||
|
local cut = string.find(lps, "\r", 1, true)
|
||||||
|
if cut then lps = string.sub(lps, 1, cut - 1) end
|
||||||
|
|
||||||
|
dsn_helper(dsn, function ()
|
||||||
|
rds.set_lps(lps)
|
||||||
|
end)
|
||||||
|
return 4 + mel
|
||||||
|
end
|
||||||
|
mec_handlers[4] = function (data)
|
||||||
|
-- PTYI
|
||||||
|
local dsn = string.byte(data, 2)
|
||||||
|
local psn = string.byte(data, 3)
|
||||||
|
local data = string.byte(data, 4)
|
||||||
|
dsn_helper(dsn, function ()
|
||||||
|
rds.set_dpty((data & 8) ~= 0)
|
||||||
|
end)
|
||||||
|
return 4
|
||||||
|
end
|
||||||
|
mec_handlers[3] = function (data)
|
||||||
|
-- TP/TA
|
||||||
|
local dsn = string.byte(data, 2)
|
||||||
|
local psn = string.byte(data, 3)
|
||||||
|
local data = string.byte(data, 4)
|
||||||
|
dsn_helper(dsn, function ()
|
||||||
|
rds.set_ta((data & 1) ~= 0)
|
||||||
|
rds.set_ta((data & 2) ~= 0)
|
||||||
|
end)
|
||||||
|
return 4
|
||||||
|
end
|
||||||
|
mec_handlers[7] = function (data)
|
||||||
|
-- PTY
|
||||||
|
local dsn = string.byte(data, 2)
|
||||||
|
local psn = string.byte(data, 3)
|
||||||
|
local data = string.byte(data, 4)
|
||||||
|
dsn_helper(dsn, function ()
|
||||||
|
rds.set_pty(data)
|
||||||
|
end)
|
||||||
|
return 4
|
||||||
|
end
|
||||||
|
mec_handlers[0x3E] = function (data)
|
||||||
|
-- PTYN
|
||||||
|
local dsn = string.byte(data, 2)
|
||||||
|
local psn = string.byte(data, 3)
|
||||||
|
local ptyn = string.sub(data, 4, 11) -- Static
|
||||||
|
dsn_helper(dsn, function ()
|
||||||
|
rds.set_ptyn(ptyn)
|
||||||
|
end)
|
||||||
|
return 11
|
||||||
|
end
|
||||||
|
mec_handlers[0x0A] = function (data)
|
||||||
|
local dsn = string.byte(data, 2)
|
||||||
|
local psn = string.byte(data, 3)
|
||||||
|
local mel = string.byte(data, 4)
|
||||||
|
|
||||||
|
if mel == 0 then
|
||||||
|
uecp.rt_buffer = {}
|
||||||
|
uecp.rt_buffer_index = 1
|
||||||
|
uecp.rt_tx_remaining = 0
|
||||||
|
dsn_helper(dsn, function ()
|
||||||
|
rds.set_rt_enabled(false)
|
||||||
|
end)
|
||||||
|
return 4
|
||||||
|
end
|
||||||
|
|
||||||
|
local config = string.byte(data, 5)
|
||||||
|
local toggle_ab = (config & 1) ~= 0
|
||||||
|
local number_tx = (config >> 1) & 0xF
|
||||||
|
local buffer_config = (config >> 5) & 3
|
||||||
|
|
||||||
|
if mel == 1 and buffer_config == 0 then
|
||||||
|
uecp.rt_buffer = {}
|
||||||
|
uecp.rt_buffer_index = 1
|
||||||
|
uecp.rt_tx_remaining = 0
|
||||||
|
dsn_helper(dsn, function ()
|
||||||
|
rds.set_rt_enabled(false)
|
||||||
|
end)
|
||||||
|
return 5
|
||||||
|
end
|
||||||
|
|
||||||
|
local rt_text = string.sub(data, 6, 4 + mel)
|
||||||
|
local cr = string.find(rt_text, "\r", 1, true)
|
||||||
|
if cr then rt_text = string.sub(rt_text, 1, cr - 1) end
|
||||||
|
|
||||||
|
if buffer_config == 0 then
|
||||||
|
uecp.rt_buffer = {}
|
||||||
|
uecp.rt_buffer_index = 1
|
||||||
|
uecp.rt_buffer[1] = { text = rt_text, number_tx = number_tx, toggle_ab = toggle_ab }
|
||||||
|
uecp.rt_tx_remaining = number_tx
|
||||||
|
-- Seed the encoder immediately with the first entry
|
||||||
|
dsn_helper(dsn, function ()
|
||||||
|
rds.set_rt(rt_text)
|
||||||
|
if toggle_ab then rds.toggle_rt_ab() end
|
||||||
|
rds.set_rt_enabled(true)
|
||||||
|
end)
|
||||||
|
elseif buffer_config == 2 then
|
||||||
|
uecp.rt_buffer[#uecp.rt_buffer + 1] = { text = rt_text, number_tx = number_tx, toggle_ab = toggle_ab }
|
||||||
|
end
|
||||||
|
|
||||||
|
return 4 + mel
|
||||||
|
end
|
||||||
|
mec_handlers[0x13] = function (data)
|
||||||
|
-- AF
|
||||||
|
local dsn = string.byte(data, 2)
|
||||||
|
local psn = string.byte(data, 3)
|
||||||
|
local mel = string.sub(data, 4)
|
||||||
|
|
||||||
|
-- TODO: decode
|
||||||
|
|
||||||
|
return 4+mel
|
||||||
|
end
|
||||||
|
mec_handlers[0x1A] = function (data)
|
||||||
|
-- ECC / SLS
|
||||||
|
local dsn = string.byte(data, 2)
|
||||||
|
-- No PSN
|
||||||
|
local data = string.sub(data, 3)
|
||||||
|
local data_lsb = string.sub(data, 4)
|
||||||
|
|
||||||
|
local full_data = ((data & 15) << 8) | data_lsb
|
||||||
|
local variant = (data >> 4) & 3
|
||||||
|
if variant == 0 then
|
||||||
|
dsn_helper(dsn, function ()
|
||||||
|
rds.set_ecc(full_data)
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
return 4
|
||||||
|
end
|
||||||
|
mec_handlers[0x19] = function (data)
|
||||||
|
-- CT
|
||||||
|
local data = string.byte(data, 2)
|
||||||
|
rds.set_ct(data ~= 0)
|
||||||
|
return 2
|
||||||
|
end
|
||||||
|
mec_handlers[0x1C] = function (data)
|
||||||
|
-- DS select
|
||||||
|
local dsn = string.byte(data, 2)
|
||||||
|
dp.set_program(dsn)
|
||||||
|
dp.set_writing_program(dsn)
|
||||||
|
return 2
|
||||||
|
end
|
||||||
|
|
||||||
|
---@param data string
|
||||||
|
local function undo_byte_stuff(data)
|
||||||
|
local output = {}
|
||||||
|
local i = 1
|
||||||
|
while i <= #data do
|
||||||
|
local d0 = string.byte(data, i)
|
||||||
|
if d0 == 0xFD then
|
||||||
|
local d1 = string.byte(data, i + 1)
|
||||||
|
if not d1 then error("truncated escape sequence") end
|
||||||
|
output[#output + 1] = string.char(0xFD + d1)
|
||||||
|
i = i + 2
|
||||||
|
else
|
||||||
|
output[#output + 1] = string.char(d0)
|
||||||
|
i = i + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return table.concat(output)
|
||||||
|
end
|
||||||
|
|
||||||
|
---@param packet string
|
||||||
|
function uecp.parse_uecp(packet)
|
||||||
|
local end_i = string.find(packet, "\xff", 1, true)
|
||||||
|
if not end_i then
|
||||||
|
print("could not find 0xff")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local unstuffed = undo_byte_stuff(string.sub(packet, 2, end_i - 1))
|
||||||
|
|
||||||
|
local addr1 = string.byte(unstuffed, 1)
|
||||||
|
local addr2 = string.byte(unstuffed, 2)
|
||||||
|
local site_addr = (addr1 << 2) | (addr2 >> 6)
|
||||||
|
local encoder_addr = addr2 & 0x3F
|
||||||
|
local sequence_count = string.byte(unstuffed, 3)
|
||||||
|
local mfl = string.byte(unstuffed, 4)
|
||||||
|
|
||||||
|
local data = string.sub(unstuffed, 5, 4 + mfl)
|
||||||
|
|
||||||
|
if mfl ~= #data then
|
||||||
|
print("data len not right")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local crc_calculated = dp.crc16(string.sub(unstuffed, 1, 4 + mfl))
|
||||||
|
local crc_hi = string.byte(unstuffed, 4 + mfl + 1)
|
||||||
|
local crc_lo = string.byte(unstuffed, 4 + mfl + 2)
|
||||||
|
local crc_stored = (crc_hi << 8) | crc_lo
|
||||||
|
|
||||||
|
if crc_calculated ~= crc_stored then
|
||||||
|
print("bad crc")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local consumed = 1
|
||||||
|
while consumed <= #data do
|
||||||
|
local mec = string.byte(data, consumed)
|
||||||
|
local handler = mec_handlers[mec]
|
||||||
|
if not handler then
|
||||||
|
print(string.format("unknown MEC 0x%02X, cannot continue", mec))
|
||||||
|
break
|
||||||
|
end
|
||||||
|
local advance = handler(string.sub(data, consumed))
|
||||||
|
consumed = consumed + advance
|
||||||
|
dp.set_writing_program(dp.get_program())
|
||||||
|
end
|
||||||
|
end
|
||||||
+10
-144
@@ -1,121 +1,6 @@
|
|||||||
local mec_handlers = {}
|
|
||||||
|
|
||||||
local function dsn_helper(dsn, write)
|
|
||||||
if dsn == 0 then write()
|
|
||||||
elseif dsn == 254 then
|
|
||||||
local start = dp.get_writing_program()
|
|
||||||
for i = 1, dp.max_programs do
|
|
||||||
local p = i - 1
|
|
||||||
if p ~= start then
|
|
||||||
dp.set_writing_program(p)
|
|
||||||
write()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
elseif dsn == 255 then
|
|
||||||
for i = 1, dp.max_programs do
|
|
||||||
dp.set_writing_program(i - 1)
|
|
||||||
write()
|
|
||||||
end
|
|
||||||
else
|
|
||||||
dp.set_writing_program(dsn - 1)
|
|
||||||
write()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
mec_handlers[1] = function (data)
|
|
||||||
-- PI
|
|
||||||
local dsn = string.byte(data, 2)
|
|
||||||
local psn = string.byte(data, 3)
|
|
||||||
local pi_msb = string.byte(data, 4)
|
|
||||||
local pi_lsb = string.byte(data, 5)
|
|
||||||
|
|
||||||
dsn_helper(dsn, function ()
|
|
||||||
rds.set_pi((pi_msb << 8) | pi_lsb)
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
mec_handlers[2] = function (data)
|
|
||||||
-- PS
|
|
||||||
local dsn = string.byte(data, 2)
|
|
||||||
local psn = string.byte(data, 3)
|
|
||||||
local ps = string.sub(data, 4, 11)
|
|
||||||
dsn_helper(dsn, function ()
|
|
||||||
rds.set_ps(ps)
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
mec_handlers[3] = function (data)
|
|
||||||
-- TP/TA
|
|
||||||
local dsn = string.byte(data, 2)
|
|
||||||
local psn = string.byte(data, 3)
|
|
||||||
local data = string.byte(data, 4)
|
|
||||||
dsn_helper(dsn, function ()
|
|
||||||
rds.set_ta((data & 1) ~= 0)
|
|
||||||
rds.set_ta((data & 2) ~= 0)
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
|
|
||||||
---@param data string
|
|
||||||
local function undo_byte_stuff(data)
|
|
||||||
local output = {}
|
|
||||||
local i = 1
|
|
||||||
while i <= #data do
|
|
||||||
local d0 = string.byte(data, i)
|
|
||||||
if d0 == 0xFD then
|
|
||||||
local d1 = string.byte(data, i + 1)
|
|
||||||
output[#output + 1] = string.char(0xFD + d1)
|
|
||||||
i = i + 2
|
|
||||||
else
|
|
||||||
output[#output + 1] = string.char(d0)
|
|
||||||
i = i + 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return table.concat(output)
|
|
||||||
end
|
|
||||||
|
|
||||||
---@param packet string
|
|
||||||
local function parse_uecp(packet)
|
|
||||||
local end_i = string.find(packet, "\xff", 1, true)
|
|
||||||
if not end_i then
|
|
||||||
print("could not find 0xff")
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
local unstuffed = undo_byte_stuff(string.sub(packet, 2, end_i - 1))
|
|
||||||
|
|
||||||
local addr1 = string.byte(unstuffed, 1)
|
|
||||||
local addr2 = string.byte(unstuffed, 2)
|
|
||||||
local site_addr = (addr1 << 2) | (addr2 >> 6)
|
|
||||||
local encoder_addr = addr2 & 0x3F
|
|
||||||
local sequence_count = string.byte(unstuffed, 3)
|
|
||||||
local mfl = string.byte(unstuffed, 4)
|
|
||||||
|
|
||||||
local data = string.sub(unstuffed, 5, 4 + mfl)
|
|
||||||
|
|
||||||
if mfl ~= #data then
|
|
||||||
print("data len not right")
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
local crc_calculated = dp.crc16(string.sub(unstuffed, 1, 4 + mfl))
|
|
||||||
local crc_hi = string.byte(unstuffed, 4 + mfl + 1)
|
|
||||||
local crc_lo = string.byte(unstuffed, 4 + mfl + 2)
|
|
||||||
local crc_stored = (crc_hi << 8) | crc_lo
|
|
||||||
|
|
||||||
if crc_calculated ~= crc_stored then
|
|
||||||
print("bad crc")
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
local mec = string.byte(data, 1)
|
|
||||||
local handler = mec_handlers[mec]
|
|
||||||
if handler then
|
|
||||||
handler(data)
|
|
||||||
dp.set_writing_program(dp.get_program())
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function data_handle(data)
|
function data_handle(data)
|
||||||
-- UECP
|
-- UECP
|
||||||
if string.byte(data, 1) == 0xfe then return parse_uecp(data) end
|
if uecp.parse_uecp and string.byte(data, 1) == 0xfe then return uecp.parse_uecp(data) end
|
||||||
|
|
||||||
if string.sub(data, 1, 4):lower() == "lua=" then
|
if string.sub(data, 1, 4):lower() == "lua=" then
|
||||||
local chunk, err = load("return " .. string.sub(data, 5), "udp_chunk") -- skip "lua="
|
local chunk, err = load("return " .. string.sub(data, 5), "udp_chunk") -- skip "lua="
|
||||||
@@ -171,10 +56,8 @@ function data_handle(data)
|
|||||||
elseif data == "dpty" then return string.format("DPTY=%s\r\n", string.format("%d", (rds.get_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", (rds.get_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", (rds.get_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", (rds.get_rt1_enabled() and 1 or 0)))
|
elseif data == "rt1en" then return string.format("RT1EN=%s\r\n", string.format("%d", (rds.get_rt_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", (rds.get_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", rds.get_rt_type()))
|
|
||||||
elseif data == "rds2mod" then return string.format("RDS2MOD=%s\r\n", string.format("%d", rds.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", rds.get_streams()))
|
elseif data == "rdsgen" then return string.format("RDSGEN=%s\r\n", string.format("%d", rds.get_streams()))
|
||||||
elseif data == "link" then return string.format("LINK=%s\r\n", string.format("%d", (rds.get_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)))
|
||||||
@@ -353,23 +236,13 @@ function data_handle(data)
|
|||||||
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
|
||||||
rds.set_rt1_enabled(en ~= 0)
|
rds.set_rt_enabled(en ~= 0)
|
||||||
return "+\r\n"
|
|
||||||
elseif cmd == "rt2en" then
|
|
||||||
local en = tonumber(value)
|
|
||||||
if not en then return "-\r\n" end
|
|
||||||
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
|
||||||
rds.set_ptyn_enabled(en ~= 0)
|
rds.set_ptyn_enabled(en ~= 0)
|
||||||
return "+\r\n"
|
return "+\r\n"
|
||||||
elseif cmd == "rttype" then
|
|
||||||
local type = tonumber(value)
|
|
||||||
if not type then return "-\r\n" end
|
|
||||||
rds.set_rt_type(type)
|
|
||||||
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
|
||||||
@@ -390,10 +263,13 @@ function data_handle(data)
|
|||||||
rds.set_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
|
||||||
rds.set_rt1(value)
|
uecp.rt_buffer = {}
|
||||||
return "+\r\n"
|
uecp.rt_buffer_index = 1
|
||||||
elseif cmd == "rt2" then
|
uecp.rt_buffer[1] = { text = value, number_tx = 0, toggle_ab = true }
|
||||||
rds.set_rt2(value)
|
uecp.rt_tx_remaining = 0
|
||||||
|
rds.set_rt_enabled(true)
|
||||||
|
rds.set_rt(value)
|
||||||
|
rds.toggle_rt_ab()
|
||||||
return "+\r\n"
|
return "+\r\n"
|
||||||
elseif cmd == "lps" then
|
elseif cmd == "lps" then
|
||||||
rds.set_lps(value)
|
rds.set_lps(value)
|
||||||
@@ -406,11 +282,6 @@ function data_handle(data)
|
|||||||
if not link then return "-\r\n" end
|
if not link then return "-\r\n" end
|
||||||
rds.set_link(link ~= 0)
|
rds.set_link(link ~= 0)
|
||||||
return "+\r\n"
|
return "+\r\n"
|
||||||
elseif cmd == "rtper" then
|
|
||||||
local period = tonumber(value)
|
|
||||||
if not period then return "-\r\n" end
|
|
||||||
rds.set_rt_switching_period(period*60)
|
|
||||||
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
|
||||||
@@ -419,11 +290,6 @@ function data_handle(data)
|
|||||||
dp.set_writing_program(program-1)
|
dp.set_writing_program(program-1)
|
||||||
rds.set_ta(false)
|
rds.set_ta(false)
|
||||||
return "+\r\n"
|
return "+\r\n"
|
||||||
elseif cmd == "dttmout" then
|
|
||||||
local timeout = tonumber(value)
|
|
||||||
if not timeout then return "-\r\n" end
|
|
||||||
rds.set_rt_text_timeout(timeout*60)
|
|
||||||
return "+\r\n"
|
|
||||||
elseif cmd == "grpseq" then
|
elseif cmd == "grpseq" then
|
||||||
rds.set_grpseq(value)
|
rds.set_grpseq(value)
|
||||||
return "+\r\n"
|
return "+\r\n"
|
||||||
|
|||||||
+8
-25
@@ -162,18 +162,12 @@ BOOL_GETTER(tp)
|
|||||||
BOOL_SETTER(ta)
|
BOOL_SETTER(ta)
|
||||||
BOOL_GETTER(ta)
|
BOOL_GETTER(ta)
|
||||||
|
|
||||||
BOOL_SETTER(rt1_enabled)
|
BOOL_SETTER(rt_enabled)
|
||||||
BOOL_GETTER(rt1_enabled)
|
BOOL_GETTER(rt_enabled)
|
||||||
|
|
||||||
BOOL_SETTER(rt2_enabled)
|
|
||||||
BOOL_GETTER(rt2_enabled)
|
|
||||||
|
|
||||||
BOOL_SETTER(ptyn_enabled)
|
BOOL_SETTER(ptyn_enabled)
|
||||||
BOOL_GETTER(ptyn_enabled)
|
BOOL_GETTER(ptyn_enabled)
|
||||||
|
|
||||||
INT_SETTER(rt_type)
|
|
||||||
INT_GETTER(rt_type)
|
|
||||||
|
|
||||||
int lua_set_rds2_mode(lua_State *localL) {
|
int lua_set_rds2_mode(lua_State *localL) {
|
||||||
enc->encoder_data.rds2_mode = luaL_checkinteger(localL, 1);
|
enc->encoder_data.rds2_mode = luaL_checkinteger(localL, 1);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -238,20 +232,6 @@ int lua_get_rds_writing_program(lua_State *localL) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int lua_set_rds_rt_switching_period(lua_State *localL) {
|
|
||||||
enc->data[writing_program].rt_switching_period = luaL_checkinteger(localL, 1);
|
|
||||||
enc->state[writing_program].rt_switching_period_state = enc->data[writing_program].rt_switching_period;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
INT_GETTER(rt_switching_period)
|
|
||||||
|
|
||||||
int lua_set_rds_rt_text_timeout(lua_State *localL) {
|
|
||||||
enc->data[writing_program].rt_text_timeout = luaL_checkinteger(localL, 1);
|
|
||||||
enc->state[writing_program].rt_text_timeout_state = enc->data[writing_program].rt_text_timeout;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
INT_GETTER(rt_text_timeout)
|
|
||||||
|
|
||||||
int lua_put_rds_custom_group(lua_State *localL) {
|
int lua_put_rds_custom_group(lua_State *localL) {
|
||||||
enc->state[writing_program].custom_group[0] = 1;
|
enc->state[writing_program].custom_group[0] = 1;
|
||||||
enc->state[writing_program].custom_group[1] = luaL_checkinteger(localL, 1);
|
enc->state[writing_program].custom_group[1] = luaL_checkinteger(localL, 1);
|
||||||
@@ -272,9 +252,7 @@ int lua_put_rds2_custom_group(lua_State *localL) {
|
|||||||
STR_SETTER(ptyn, set_rds_ptyn)
|
STR_SETTER(ptyn, set_rds_ptyn)
|
||||||
STR_SETTER(ps, set_rds_ps)
|
STR_SETTER(ps, set_rds_ps)
|
||||||
STR_SETTER(tps, set_rds_tps)
|
STR_SETTER(tps, set_rds_tps)
|
||||||
STR_SETTER(rt1, set_rds_rt1)
|
STR_SETTER(rt, set_rds_rt)
|
||||||
STR_SETTER(rt2, set_rds_rt2)
|
|
||||||
STR_SETTER(default_rt, set_rds_default_rt)
|
|
||||||
|
|
||||||
STR_RAW_SETTER(lps, set_rds_lps)
|
STR_RAW_SETTER(lps, set_rds_lps)
|
||||||
STR_RAW_GETTER(lps, LPS_LENGTH)
|
STR_RAW_GETTER(lps, LPS_LENGTH)
|
||||||
@@ -293,6 +271,11 @@ STR_RAW_GETTER(grp_sqc, 32)
|
|||||||
|
|
||||||
AF_SETTER(af_group0, af, RDSAFs, add_rds_af)
|
AF_SETTER(af_group0, af, RDSAFs, add_rds_af)
|
||||||
|
|
||||||
|
int lua_toggle_rt_ab(lua_State *localL) {
|
||||||
|
TOGGLE(enc->state[writing_program].rt_ab);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int lua_set_rds_eon(lua_State *localL) {
|
int lua_set_rds_eon(lua_State *localL) {
|
||||||
int eon = luaL_checkinteger(localL, 1);
|
int eon = luaL_checkinteger(localL, 1);
|
||||||
if(eon >= EONs) return luaL_error(localL, "eon index exceeded");
|
if(eon >= EONs) return luaL_error(localL, "eon index exceeded");
|
||||||
|
|||||||
+5
-17
@@ -38,18 +38,12 @@ int lua_get_rds_tp(lua_State *localL);
|
|||||||
int lua_set_rds_ta(lua_State *localL);
|
int lua_set_rds_ta(lua_State *localL);
|
||||||
int lua_get_rds_ta(lua_State *localL);
|
int lua_get_rds_ta(lua_State *localL);
|
||||||
|
|
||||||
int lua_set_rds_rt1_enabled(lua_State *localL);
|
int lua_set_rds_rt_enabled(lua_State *localL);
|
||||||
int lua_get_rds_rt1_enabled(lua_State *localL);
|
int lua_get_rds_rt_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_set_rds_ptyn_enabled(lua_State *localL);
|
||||||
int lua_get_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_set_rds2_mode(lua_State *localL);
|
||||||
int lua_get_rds2_mode(lua_State *localL);
|
int lua_get_rds2_mode(lua_State *localL);
|
||||||
|
|
||||||
@@ -71,26 +65,20 @@ int lua_get_rds_program(lua_State *localL);
|
|||||||
int lua_set_rds_writing_program(lua_State *localL);
|
int lua_set_rds_writing_program(lua_State *localL);
|
||||||
int lua_get_rds_writing_program(lua_State *localL);
|
int lua_get_rds_writing_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_put_rds_custom_group(lua_State *localL);
|
int lua_put_rds_custom_group(lua_State *localL);
|
||||||
int lua_put_rds2_custom_group(lua_State *localL);
|
int lua_put_rds2_custom_group(lua_State *localL);
|
||||||
|
|
||||||
int lua_set_rds_lps(lua_State *localL);
|
int lua_set_rds_lps(lua_State *localL);
|
||||||
int lua_get_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_af_group0(lua_State *localL);
|
||||||
int lua_set_rds_default_rt(lua_State *localL);
|
int lua_set_rds_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_tps(lua_State *localL);
|
||||||
int lua_set_rds_ps(lua_State *localL);
|
int lua_set_rds_ps(lua_State *localL);
|
||||||
int lua_set_rds_ptyn(lua_State *localL);
|
int lua_set_rds_ptyn(lua_State *localL);
|
||||||
int lua_set_rds_grp_sqc(lua_State *localL);
|
int lua_set_rds_grp_sqc(lua_State *localL);
|
||||||
|
|
||||||
|
int lua_toggle_rt_ab(lua_State *localL);
|
||||||
|
|
||||||
int lua_set_rds_eon(lua_State *localL);
|
int lua_set_rds_eon(lua_State *localL);
|
||||||
int lua_get_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_udg(lua_State *localL);
|
||||||
|
|||||||
+27
-21
@@ -92,36 +92,23 @@ void init_lua(RDSEncoder* _enc) {
|
|||||||
lua_registertotable(L, "set_ta", lua_set_rds_ta);
|
lua_registertotable(L, "set_ta", lua_set_rds_ta);
|
||||||
lua_registertotable(L, "get_ta", lua_get_rds_ta);
|
lua_registertotable(L, "get_ta", lua_get_rds_ta);
|
||||||
|
|
||||||
lua_registertotable(L, "set_rt1_enabled", lua_set_rds_rt1_enabled);
|
lua_registertotable(L, "set_rt_enabled", lua_set_rds_rt_enabled);
|
||||||
lua_registertotable(L, "get_rt1_enabled", lua_get_rds_rt1_enabled);
|
lua_registertotable(L, "get_rt_enabled", lua_get_rds_rt_enabled);
|
||||||
|
|
||||||
lua_registertotable(L, "set_rt2_enabled", lua_set_rds_rt2_enabled);
|
|
||||||
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, "set_ptyn_enabled", lua_set_rds_ptyn_enabled);
|
||||||
lua_registertotable(L, "get_ptyn_enabled", lua_get_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, "set_rds2_mode", lua_set_rds2_mode);
|
||||||
lua_registertotable(L, "get_rds2_mode", lua_get_rds2_mode);
|
lua_registertotable(L, "get_rds2_mode", lua_get_rds2_mode);
|
||||||
|
|
||||||
lua_registertotable(L, "set_link", lua_set_rds_link);
|
lua_registertotable(L, "set_link", lua_set_rds_link);
|
||||||
lua_registertotable(L, "get_link", lua_get_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_ptyn", lua_set_rds_ptyn);
|
||||||
lua_registertotable(L, "set_ps", lua_set_rds_ps);
|
lua_registertotable(L, "set_ps", lua_set_rds_ps);
|
||||||
lua_registertotable(L, "set_tps", lua_set_rds_tps);
|
lua_registertotable(L, "set_tps", lua_set_rds_tps);
|
||||||
lua_registertotable(L, "set_rt1", lua_set_rds_rt1);
|
lua_registertotable(L, "set_rt", lua_set_rds_rt);
|
||||||
lua_registertotable(L, "set_rt2", lua_set_rds_rt2);
|
lua_registertotable(L, "toggle_rt_ab", lua_toggle_rt_ab);
|
||||||
lua_registertotable(L, "set_default_rt", lua_set_rds_default_rt);
|
|
||||||
|
|
||||||
lua_registertotable(L, "set_lps", lua_set_rds_lps);
|
lua_registertotable(L, "set_lps", lua_set_rds_lps);
|
||||||
lua_registertotable(L, "get_lps", lua_get_rds_lps);
|
lua_registertotable(L, "get_lps", lua_get_rds_lps);
|
||||||
@@ -362,10 +349,29 @@ void lua_call_table(const char* function) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void lua_call_tfunction_nolock(const char* name) {
|
void lua_call_tfunction_nolock(const char* name) {
|
||||||
char table_name[256];
|
lua_getglobal(L, "hooks");
|
||||||
lua_call_function_nolock(name);
|
lua_getfield(L, -1, name);
|
||||||
snprintf(table_name, sizeof(table_name), "%ss", name);
|
|
||||||
lua_call_table_nolock(table_name);
|
if (!lua_istable(L, -1)) {
|
||||||
|
lua_pop(L, 2);
|
||||||
|
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),
|
||||||
|
name,
|
||||||
|
(long long)i);
|
||||||
|
lua_pop(L, 1);
|
||||||
|
}
|
||||||
|
} else lua_pop(L, 1);
|
||||||
|
}
|
||||||
|
lua_pop(L, 2); // pop table
|
||||||
}
|
}
|
||||||
|
|
||||||
void lua_call_tfunction(const char* name) {
|
void lua_call_tfunction(const char* name) {
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ static uint8_t check_rds_good_group(RDSEncoder* enc, char* grp) {
|
|||||||
uint8_t good_group = 0;
|
uint8_t good_group = 0;
|
||||||
if(*grp == '0') good_group = 1;
|
if(*grp == '0') good_group = 1;
|
||||||
if(*grp == '1' && (enc->data[enc->program].ecc != 0 || enc->data[enc->program].slc_data != 0)) good_group = 1;
|
if(*grp == '1' && (enc->data[enc->program].ecc != 0 || enc->data[enc->program].slc_data != 0)) good_group = 1;
|
||||||
if(*grp == '2' && (enc->data[enc->program].rt1_enabled || enc->data[enc->program].rt2_enabled)) good_group = 1;
|
if(*grp == '2' && enc->data[enc->program].rt_enabled) good_group = 1;
|
||||||
if(*grp == 'A' && enc->data[enc->program].ptyn_enabled) good_group = 1;
|
if(*grp == 'A' && enc->data[enc->program].ptyn_enabled) good_group = 1;
|
||||||
if(*grp == 'E') {
|
if(*grp == 'E') {
|
||||||
for (int i = 0; i < EONs; i++) {
|
for (int i = 0; i < EONs; i++) {
|
||||||
@@ -133,28 +133,6 @@ void get_rds_group(RDSEncoder* enc, RDSGroup *group, uint8_t stream) {
|
|||||||
|
|
||||||
if(utc->tm_sec != enc->state[enc->program].last_second) {
|
if(utc->tm_sec != enc->state[enc->program].last_second) {
|
||||||
enc->state[enc->program].last_second = utc->tm_sec;
|
enc->state[enc->program].last_second = utc->tm_sec;
|
||||||
|
|
||||||
if(enc->data[enc->program].rt1_enabled && enc->data[enc->program].current_rt == 0 && enc->state[enc->program].rt_text_timeout_state != 0) {
|
|
||||||
enc->state[enc->program].rt_text_timeout_state--;
|
|
||||||
if(enc->state[enc->program].rt_text_timeout_state == 0) {
|
|
||||||
enc->state[enc->program].rt_update = 1;
|
|
||||||
memset(enc->state[enc->program].rt_text, 0, RT_LENGTH);
|
|
||||||
memcpy(enc->state[enc->program].rt_text, enc->data[enc->program].default_rt, RT_LENGTH);
|
|
||||||
enc->state[enc->program].rt_segments = enc->state[enc->program].default_rt_segments;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(enc->data[enc->program].rt1_enabled && enc->data[enc->program].rt2_enabled && enc->state[enc->program].rt_switching_period_state != 0) {
|
|
||||||
enc->state[enc->program].rt_switching_period_state--;
|
|
||||||
if(enc->state[enc->program].rt_switching_period_state == 0) {
|
|
||||||
TOGGLE(enc->data[enc->program].current_rt);
|
|
||||||
memset(enc->state[enc->program].rt_text, 0, RT_LENGTH);
|
|
||||||
if (enc->data[enc->program].current_rt == 1) memcpy(enc->state[enc->program].rt_text, enc->data[enc->program].rt2, RT_LENGTH);
|
|
||||||
else memcpy(enc->state[enc->program].rt_text, enc->data[enc->program].rt1, RT_LENGTH);
|
|
||||||
enc->state[enc->program].rt_state = 0;
|
|
||||||
enc->state[enc->program].rt_switching_period_state = enc->data[enc->program].rt_switching_period;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
lua_call_tfunction("tick");
|
lua_call_tfunction("tick");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -327,10 +305,8 @@ void reset_rds_state(RDSEncoder* enc, uint8_t program) {
|
|||||||
tempCoder.program = program;
|
tempCoder.program = program;
|
||||||
memset(&tempCoder.state[program], 0, sizeof(RDSState));
|
memset(&tempCoder.state[program], 0, sizeof(RDSState));
|
||||||
|
|
||||||
tempCoder.state[program].rt_ab = 1;
|
|
||||||
tempCoder.state[program].ptyn_ab = 1;
|
tempCoder.state[program].ptyn_ab = 1;
|
||||||
set_rds_rt1(&tempCoder, enc->data[program].rt1, program);
|
set_rds_rt(&tempCoder, enc->data[program].rt, program);
|
||||||
set_rds_rt2(&tempCoder, enc->data[program].rt2, program);
|
|
||||||
set_rds_ps(&tempCoder, enc->data[program].ps, program);
|
set_rds_ps(&tempCoder, enc->data[program].ps, program);
|
||||||
set_rds_tps(&tempCoder, enc->data[program].tps, program);
|
set_rds_tps(&tempCoder, enc->data[program].tps, program);
|
||||||
set_rds_lps(&tempCoder, enc->data[program].lps, program);
|
set_rds_lps(&tempCoder, enc->data[program].lps, program);
|
||||||
@@ -360,13 +336,9 @@ void set_rds_defaults(RDSEncoder* enc, uint8_t program) {
|
|||||||
enc->data[program].tp = 1;
|
enc->data[program].tp = 1;
|
||||||
enc->data[program].pi = 0xFFFF;
|
enc->data[program].pi = 0xFFFF;
|
||||||
strcpy((char *)enc->data[program].ps, "* RDS * ");
|
strcpy((char *)enc->data[program].ps, "* RDS * ");
|
||||||
enc->data[program].rt1_enabled = 1;
|
enc->data[program].rt_enabled = 1;
|
||||||
|
|
||||||
memset(enc->data[program].rt1, ' ', 64);
|
memset(enc->data[program].rt, ' ', 64);
|
||||||
memset(enc->data[program].rt2, ' ', 64);
|
|
||||||
memset(enc->data[program].default_rt, ' ', 64);
|
|
||||||
|
|
||||||
enc->data[program].rt_type = 2;
|
|
||||||
|
|
||||||
reset_rds_state(enc, program);
|
reset_rds_state(enc, program);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ typedef struct {
|
|||||||
uint16_t pi;
|
uint16_t pi;
|
||||||
|
|
||||||
char ps[PS_LENGTH];
|
char ps[PS_LENGTH];
|
||||||
char rt1[RT_LENGTH];
|
char rt[RT_LENGTH];
|
||||||
|
|
||||||
uint8_t ecc;
|
uint8_t ecc;
|
||||||
uint16_t slc_data : 12;
|
uint16_t slc_data : 12;
|
||||||
@@ -58,14 +58,7 @@ typedef struct {
|
|||||||
|
|
||||||
char tps[PS_LENGTH];
|
char tps[PS_LENGTH];
|
||||||
|
|
||||||
uint8_t rt1_enabled : 1;
|
uint8_t rt_enabled : 1;
|
||||||
uint8_t rt2_enabled : 1;
|
|
||||||
uint8_t rt_type : 2;
|
|
||||||
uint8_t rt_text_timeout;
|
|
||||||
uint8_t rt_switching_period;
|
|
||||||
uint8_t current_rt : 1;
|
|
||||||
char default_rt[RT_LENGTH];
|
|
||||||
char rt2[RT_LENGTH];
|
|
||||||
|
|
||||||
uint8_t ptyn_enabled : 1;
|
uint8_t ptyn_enabled : 1;
|
||||||
char ptyn[PTYN_LENGTH];
|
char ptyn[PTYN_LENGTH];
|
||||||
@@ -108,11 +101,8 @@ typedef struct {
|
|||||||
char rt_text[RT_LENGTH];
|
char rt_text[RT_LENGTH];
|
||||||
uint8_t rt_state : 5;
|
uint8_t rt_state : 5;
|
||||||
uint8_t rt_update : 1;
|
uint8_t rt_update : 1;
|
||||||
uint8_t rt2_update : 1;
|
|
||||||
uint8_t rt_ab : 1;
|
uint8_t rt_ab : 1;
|
||||||
uint8_t rt_segments : 5;
|
uint8_t rt_segments : 5;
|
||||||
uint8_t rt2_segments : 5;
|
|
||||||
uint8_t default_rt_segments : 5;
|
|
||||||
|
|
||||||
char ptyn_text[PTYN_LENGTH];
|
char ptyn_text[PTYN_LENGTH];
|
||||||
uint8_t ptyn_state : 1;
|
uint8_t ptyn_state : 1;
|
||||||
@@ -127,9 +117,6 @@ typedef struct {
|
|||||||
uint16_t custom_group[GROUP_LENGTH];
|
uint16_t custom_group[GROUP_LENGTH];
|
||||||
uint16_t custom_group2[GROUP_LENGTH + 1];
|
uint16_t custom_group2[GROUP_LENGTH + 1];
|
||||||
|
|
||||||
uint8_t rt_switching_period_state;
|
|
||||||
uint8_t rt_text_timeout_state;
|
|
||||||
|
|
||||||
uint8_t data_ecc : 1;
|
uint8_t data_ecc : 1;
|
||||||
uint8_t grp_seq_idx[4];
|
uint8_t grp_seq_idx[4];
|
||||||
uint8_t udg_idxs[2];
|
uint8_t udg_idxs[2];
|
||||||
@@ -195,9 +182,7 @@ void add_checkwords(RDSGroup *group, uint8_t *bits);
|
|||||||
void get_rds_group(RDSEncoder* enc, RDSGroup *group, uint8_t stream);
|
void get_rds_group(RDSEncoder* enc, RDSGroup *group, uint8_t stream);
|
||||||
void get_rds_bits(RDSEncoder* enc, uint8_t *bits, uint8_t stream);
|
void get_rds_bits(RDSEncoder* enc, uint8_t *bits, uint8_t stream);
|
||||||
|
|
||||||
void set_rds_rt1(RDSEncoder* enc, const char *rt1, uint8_t program);
|
void set_rds_rt(RDSEncoder* enc, const char *rt, uint8_t program);
|
||||||
void set_rds_rt2(RDSEncoder* enc, const char *rt2, uint8_t program);
|
|
||||||
void set_rds_default_rt(RDSEncoder* enc, const char *rt, uint8_t program);
|
|
||||||
void set_rds_ps(RDSEncoder* enc, const char *ps, uint8_t program);
|
void set_rds_ps(RDSEncoder* enc, const char *ps, uint8_t program);
|
||||||
void set_rds_tps(RDSEncoder* enc, const char *tps, uint8_t program);
|
void set_rds_tps(RDSEncoder* enc, const char *tps, uint8_t program);
|
||||||
void set_rds_lps(RDSEncoder* enc, const char *lps, uint8_t program);
|
void set_rds_lps(RDSEncoder* enc, const char *lps, uint8_t program);
|
||||||
|
|||||||
+8
-27
@@ -87,44 +87,25 @@ void get_rds_fasttuning_group(RDSEncoder* enc, RDSGroup *group) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void get_rds_rt_group(RDSEncoder* enc, RDSGroup *group) {
|
void get_rds_rt_group(RDSEncoder* enc, RDSGroup *group) {
|
||||||
if (enc->state[enc->program].rt_update && enc->data[enc->program].rt1_enabled && enc->data[enc->program].current_rt == 0) {
|
if (enc->state[enc->program].rt_update && enc->data[enc->program].rt_enabled) {
|
||||||
memcpy(enc->state[enc->program].rt_text, enc->data[enc->program].rt1, RT_LENGTH);
|
memcpy(enc->state[enc->program].rt_text, enc->data[enc->program].rt, RT_LENGTH);
|
||||||
TOGGLE(enc->state[enc->program].rt_ab);
|
|
||||||
enc->state[enc->program].rt_update = 0;
|
enc->state[enc->program].rt_update = 0;
|
||||||
enc->state[enc->program].rt_state = 0;
|
enc->state[enc->program].rt_state = 0;
|
||||||
enc->data[enc->program].current_rt = 0;
|
|
||||||
}
|
|
||||||
if(enc->state[enc->program].rt2_update && enc->data[enc->program].rt2_enabled && enc->data[enc->program].current_rt) {
|
|
||||||
memcpy(enc->state[enc->program].rt_text, enc->data[enc->program].rt2, RT_LENGTH);
|
|
||||||
TOGGLE(enc->state[enc->program].rt_ab);
|
|
||||||
enc->state[enc->program].rt2_update = 0;
|
|
||||||
enc->state[enc->program].rt_state = 0;
|
|
||||||
enc->data[enc->program].current_rt = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t ab = enc->state[enc->program].rt_ab;
|
|
||||||
switch (enc->data[enc->program].rt_type)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
ab = 0;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
ab = (enc->data[enc->program].current_rt == 0) ? 0 : 1;
|
|
||||||
break;
|
|
||||||
default: break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
group->b |= 2 << 12;
|
group->b |= 2 << 12;
|
||||||
group->b |= ab << 4;
|
group->b |= enc->state[enc->program].rt_ab << 4;
|
||||||
group->b |= enc->state[enc->program].rt_state;
|
group->b |= enc->state[enc->program].rt_state;
|
||||||
group->c = enc->state[enc->program].rt_text[enc->state[enc->program].rt_state * 4 ] << 8;
|
group->c = enc->state[enc->program].rt_text[enc->state[enc->program].rt_state * 4] << 8;
|
||||||
group->c |= enc->state[enc->program].rt_text[enc->state[enc->program].rt_state * 4 + 1];
|
group->c |= enc->state[enc->program].rt_text[enc->state[enc->program].rt_state * 4 + 1];
|
||||||
group->d = enc->state[enc->program].rt_text[enc->state[enc->program].rt_state * 4 + 2] << 8;
|
group->d = enc->state[enc->program].rt_text[enc->state[enc->program].rt_state * 4 + 2] << 8;
|
||||||
group->d |= enc->state[enc->program].rt_text[enc->state[enc->program].rt_state * 4 + 3];
|
group->d |= enc->state[enc->program].rt_text[enc->state[enc->program].rt_state * 4 + 3];
|
||||||
|
|
||||||
uint8_t segments = (enc->data[enc->program].current_rt == 1) ? enc->state[enc->program].rt2_segments : enc->state[enc->program].rt_segments;
|
|
||||||
enc->state[enc->program].rt_state++;
|
enc->state[enc->program].rt_state++;
|
||||||
if (enc->state[enc->program].rt_state >= segments || enc->state[enc->program].rt_state >= 16) enc->state[enc->program].rt_state = 0;
|
if (enc->state[enc->program].rt_state >= enc->state[enc->program].rt_segments || enc->state[enc->program].rt_state >= 16) {
|
||||||
|
lua_call_tfunction("rt_transmission");
|
||||||
|
enc->state[enc->program].rt_state = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void get_rdsp_ct_group(RDSGroup *group, time_t now) {
|
void get_rdsp_ct_group(RDSGroup *group, time_t now) {
|
||||||
|
|||||||
+6
-48
@@ -1,20 +1,18 @@
|
|||||||
#include "rds.h"
|
#include "rds.h"
|
||||||
|
|
||||||
void set_rds_rt1(RDSEncoder* enc, const char *rt1, uint8_t program) {
|
void set_rds_rt(RDSEncoder* enc, const char *rt, uint8_t program) {
|
||||||
uint8_t i = 0, len = 0;
|
uint8_t i = 0, len = 0;
|
||||||
|
|
||||||
enc->state[program].rt_text_timeout_state = enc->data[program].rt_text_timeout;
|
|
||||||
|
|
||||||
enc->state[program].rt_update = 1;
|
enc->state[program].rt_update = 1;
|
||||||
|
|
||||||
memset(enc->data[program].rt1, ' ', RT_LENGTH);
|
memset(enc->data[program].rt, ' ', RT_LENGTH);
|
||||||
while (*rt1 != 0 && len < RT_LENGTH) enc->data[program].rt1[len++] = *rt1++;
|
while (*rt != 0 && len < RT_LENGTH) enc->data[program].rt[len++] = *rt++;
|
||||||
|
|
||||||
while (len > 0 && enc->data[program].rt1[len - 1] == ' ') len--;
|
while (len > 0 && enc->data[program].rt[len - 1] == ' ') len--;
|
||||||
|
|
||||||
if (len < RT_LENGTH) {
|
if (len < RT_LENGTH) {
|
||||||
enc->state[program].rt_segments = 0;
|
enc->state[program].rt_segments = 0;
|
||||||
enc->data[program].rt1[len++] = '\r';
|
enc->data[program].rt[len++] = '\r';
|
||||||
while (i < len) {
|
while (i < len) {
|
||||||
i += 4;
|
i += 4;
|
||||||
enc->state[program].rt_segments++;
|
enc->state[program].rt_segments++;
|
||||||
@@ -23,46 +21,6 @@ void set_rds_rt1(RDSEncoder* enc, const char *rt1, uint8_t program) {
|
|||||||
if(enc->state[program].rt_segments > 16) enc->state[program].rt_segments = 16; //make sure
|
if(enc->state[program].rt_segments > 16) enc->state[program].rt_segments = 16; //make sure
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_rds_default_rt(RDSEncoder* enc, const char *rt, uint8_t program) {
|
|
||||||
uint8_t i = 0, len = 0;
|
|
||||||
|
|
||||||
memset(enc->data[program].default_rt, ' ', RT_LENGTH);
|
|
||||||
while (*rt != 0 && len < RT_LENGTH) enc->data[program].default_rt[len++] = *rt++;
|
|
||||||
|
|
||||||
while (len > 0 && enc->data[program].default_rt[len - 1] == ' ') len--;
|
|
||||||
|
|
||||||
if (len < RT_LENGTH) {
|
|
||||||
enc->state[program].default_rt_segments = 0;
|
|
||||||
enc->data[program].default_rt[len++] = '\r';
|
|
||||||
while (i < len) {
|
|
||||||
i += 4;
|
|
||||||
enc->state[program].default_rt_segments++;
|
|
||||||
}
|
|
||||||
} else enc->state[program].default_rt_segments = 16;
|
|
||||||
if(enc->state[program].default_rt_segments > 16) enc->state[program].default_rt_segments = 16; //make sure
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_rds_rt2(RDSEncoder* enc, const char *rt2, uint8_t program) {
|
|
||||||
uint8_t i = 0, len = 0;
|
|
||||||
|
|
||||||
enc->state[program].rt2_update = 1;
|
|
||||||
|
|
||||||
memset(enc->data[program].rt2, ' ', RT_LENGTH);
|
|
||||||
while (*rt2 != 0 && len < RT_LENGTH) enc->data[program].rt2[len++] = *rt2++;
|
|
||||||
|
|
||||||
while (len > 0 && enc->data[program].rt2[len - 1] == ' ') len--;
|
|
||||||
|
|
||||||
if (len < RT_LENGTH) {
|
|
||||||
enc->state[program].rt2_segments = 0;
|
|
||||||
enc->data[program].rt2[len++] = '\r';
|
|
||||||
while (i < len) {
|
|
||||||
i += 4;
|
|
||||||
enc->state[program].rt2_segments++;
|
|
||||||
}
|
|
||||||
} else enc->state[program].rt2_segments = 16;
|
|
||||||
if(enc->state[program].rt2_segments > 16) enc->state[program].rt2_segments = 16; //make sure
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_rds_ps(RDSEncoder* enc, const char *ps, uint8_t program) {
|
void set_rds_ps(RDSEncoder* enc, const char *ps, uint8_t program) {
|
||||||
uint8_t len = 0;
|
uint8_t len = 0;
|
||||||
|
|
||||||
@@ -93,7 +51,7 @@ void set_rds_lps(RDSEncoder* enc, const char *lps, uint8_t program) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
memset(enc->data[program].lps, ' ', LPS_LENGTH);
|
memset(enc->data[program].lps, ' ', LPS_LENGTH);
|
||||||
while (*lps != 0 && len < LPS_LENGTH) enc->data[program].lps[len++] = *lps++;
|
while (*lps != '\r' && *lps != 0 && len < LPS_LENGTH) enc->data[program].lps[len++] = *lps++;
|
||||||
|
|
||||||
if (len < LPS_LENGTH) {
|
if (len < LPS_LENGTH) {
|
||||||
enc->state[program].lps_segments = 0;
|
enc->state[program].lps_segments = 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user