diff --git a/plugin.lua b/plugin.lua index d8f20ab..9719555 100644 --- a/plugin.lua +++ b/plugin.lua @@ -28,11 +28,18 @@ function dp.reset_rds() end ---@return nil function dp.force_save() end +---Set the program which is actually being modulated. Setting this does not affect the writing program ---@param program_idx integer 0 to (max_programs - 1) function dp.set_program(program_idx) end ---@return integer function dp.get_program() end +---Sets the program all of the set/get functions affect +---@param program_idx integer 0 to (max_programs - 1) +function dp.set_writing_program(program_idx) end +---@return integer +function dp.get_writing_program() end + ---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. ---@return nil diff --git a/scripts/99-data.lua b/scripts/99-data.lua index fd89666..7e9cdae 100644 --- a/scripts/99-data.lua +++ b/scripts/99-data.lua @@ -1,4 +1,113 @@ +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 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 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 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) + -- UECP + if string.byte(data, 1) == 0xfe then return parse_uecp(data) end + if string.sub(data, 1, 4):lower() == "lua=" then local chunk, err = load("return " .. string.sub(data, 5), "udp_chunk") -- skip "lua=" if not chunk then return string.format("-\r\n%s\r\n", err) end @@ -212,11 +321,6 @@ function data_handle(data) if not pty then return "-\r\n" end rds.set_pty(pty) return "+\r\n" - elseif cmd == "slcd" then - local slc_data = tonumber(value, 16) - if not slc_data then return "-\r\n" end - rds.set_slc_data(slc_data) - return "+\r\n" elseif cmd == "ct" then local ct = tonumber(value) if not ct then return "-\r\n" end @@ -303,6 +407,7 @@ function data_handle(data) if not program then return "-\r\n" end if program < 1 or program > dp.max_programs then return "-\r\n" end dp.set_program(program-1) + dp.set_writing_program(program-1) rds.set_ta(false) return "+\r\n" elseif cmd == "dttmout" then diff --git a/src/lua_api.c b/src/lua_api.c index 3c6498f..d713790 100644 --- a/src/lua_api.c +++ b/src/lua_api.c @@ -6,24 +6,25 @@ static int in_set_defaults = 0; extern lua_State *L; extern RDSEncoder* enc; extern uint8_t unload_refs[33]; +static int writing_program = 0; int lua_get_userdata(lua_State *localL) { - lua_pushlstring(localL, (const char*)&enc->data[enc->program].lua_data, LUA_USER_DATA); + lua_pushlstring(localL, (const char*)&enc->data[writing_program].lua_data, LUA_USER_DATA); return 1; } int lua_get_userdata_offset(lua_State *localL) { uint16_t offset = luaL_checkinteger(localL, 1); uint16_t size = luaL_checkinteger(localL, 2); if((offset+size) > LUA_USER_DATA) return luaL_error(localL, "data exceeds limit"); - lua_pushlstring(localL, (const char*)&enc->data[enc->program].lua_data[offset], size); + lua_pushlstring(localL, (const char*)&enc->data[writing_program].lua_data[offset], size); return 1; } int lua_set_userdata(lua_State *localL) { size_t len; const char *data = luaL_checklstring(localL, 1, &len); if(len > LUA_USER_DATA) return luaL_error(localL, "data exceeds limit"); - memset(enc->data[enc->program].lua_data, 0, LUA_USER_DATA); - memcpy(enc->data[enc->program].lua_data, data, len); + memset(enc->data[writing_program].lua_data, 0, LUA_USER_DATA); + memcpy(enc->data[writing_program].lua_data, data, len); return 0; } @@ -34,8 +35,8 @@ int lua_set_userdata_offset(lua_State *localL) { size_t len; const char *data = luaL_checklstring(localL, 3, &len); if(len > size || (offset + size) > LUA_USER_DATA) return luaL_error(localL, "data exceeds limit"); - memset(enc->data[enc->program].lua_data + offset, 0, size); - memcpy(enc->data[enc->program].lua_data + offset, data, len); + memset(enc->data[writing_program].lua_data + offset, 0, size); + memcpy(enc->data[writing_program].lua_data + offset, data, len); return 0; } @@ -55,7 +56,7 @@ int lua_set_rds_program_defaults(lua_State *localL) { in_set_defaults = 1; for (int i = 1; i < *unload_refs; i++) luaL_unref(L, LUA_REGISTRYINDEX, unload_refs[i]); unload_refs[0] = 1; - set_rds_defaults(enc, enc->program); + set_rds_defaults(enc, writing_program); lua_call_tfunction_nolock("on_init"); lua_call_tfunction_nolock("on_state"); in_set_defaults = 0; @@ -77,24 +78,24 @@ int lua_reset_rds(lua_State *localL) { #define BOOL_SETTER(name) \ int lua_set_rds_##name(lua_State *localL) { \ if (!lua_isboolean(localL, 1)) return luaL_error(localL, "boolean expected, got %s", luaL_typename(localL, 1)); \ - enc->data[enc->program].name = lua_toboolean(localL, 1); \ + enc->data[writing_program].name = lua_toboolean(localL, 1); \ return 0; \ } #define INT_SETTER(name) \ int lua_set_rds_##name(lua_State *localL) { \ - enc->data[enc->program].name = luaL_checkinteger(localL, 1); \ + enc->data[writing_program].name = luaL_checkinteger(localL, 1); \ return 0; \ } #define STR_SETTER(name, function) \ int lua_set_rds_##name(lua_State *localL) { \ const char* str = luaL_checklstring(localL, 1, NULL); \ - function(enc, convert_to_rdscharset(str)); \ + function(enc, convert_to_rdscharset(str), writing_program); \ return 0; \ } #define STR_RAW_SETTER(name, function) \ int lua_set_rds_##name(lua_State *localL) { \ const char* str = luaL_checklstring(localL, 1, NULL); \ - function(enc, str); \ + function(enc, str, writing_program); \ return 0; \ } #define AF_SETTER(name, af_field, af_struct, add_func) \ @@ -103,7 +104,7 @@ int lua_set_rds_##name(lua_State *localL) { \ \ int n = lua_rawlen(localL, 1); \ if (n == 0) { \ - memset(&(enc->data[enc->program].af_field), 0, sizeof(af_struct)); \ + memset(&(enc->data[writing_program].af_field), 0, sizeof(af_struct)); \ return 0; \ } \ if(n > 25) return luaL_error(localL, "table length over 25"); \ @@ -117,24 +118,24 @@ int lua_set_rds_##name(lua_State *localL) { \ else return luaL_error(localL, "number expected, got %s", luaL_typename(localL, -1)); \ lua_pop(localL, 1); \ } \ - memcpy(&(enc->data[enc->program].af_field), &new_af, sizeof(new_af)); \ + memcpy(&(enc->data[writing_program].af_field), &new_af, sizeof(new_af)); \ \ return 0; \ } #define INT_GETTER(name) \ int lua_get_rds_##name(lua_State *localL) { \ - lua_pushinteger(localL, enc->data[enc->program].name); \ + lua_pushinteger(localL, enc->data[writing_program].name); \ return 1; \ } #define BOOL_GETTER(name) \ int lua_get_rds_##name(lua_State *localL) { \ - lua_pushboolean(localL, enc->data[enc->program].name); \ + lua_pushboolean(localL, enc->data[writing_program].name); \ return 1; \ } #define STR_RAW_GETTER(name, length) \ int lua_get_rds_##name(lua_State *localL) { \ - lua_pushlstring(localL, enc->data[enc->program].name, length); \ + lua_pushlstring(localL, enc->data[writing_program].name, length); \ return 1; \ } INT_SETTER(pi) @@ -195,12 +196,12 @@ int lua_get_rds_streams(lua_State *localL) { int lua_set_rds_link(lua_State *localL) { if (!lua_isboolean(localL, 1)) return luaL_error(localL, "boolean expected, got %s", luaL_typename(localL, 1)); - enc->state[enc->program].eon_linkage = lua_toboolean(localL, 1); + enc->state[writing_program].eon_linkage = lua_toboolean(localL, 1); return 0; } int lua_get_rds_link(lua_State *localL) { - lua_pushboolean(localL, enc->state[enc->program].eon_linkage); + lua_pushboolean(localL, enc->state[writing_program].eon_linkage); return 1; } @@ -214,6 +215,7 @@ int lua_set_rds_program(lua_State *localL) { enc->data[enc->program].ta = 0; enc->data[(uint8_t)program].ta = 0; enc->program = (uint8_t)program; + writing_program = program; return 0; } @@ -222,34 +224,48 @@ int lua_get_rds_program(lua_State *localL) { return 1; } +int lua_set_rds_writing_program(lua_State *localL) { + int program = luaL_checkinteger(localL, 1); + if(program >= PROGRAMS) program = (PROGRAMS-1); + if(program < 0) program = 0; + + writing_program = program; + return 0; +} + +int lua_get_rds_writing_program(lua_State *localL) { + lua_pushinteger(localL, writing_program); + return 1; +} + int lua_set_rds_rt_switching_period(lua_State *localL) { - enc->data[enc->program].rt_switching_period = luaL_checkinteger(localL, 1); - enc->state[enc->program].rt_switching_period_state = enc->data[enc->program].rt_switching_period; + 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[enc->program].rt_text_timeout = luaL_checkinteger(localL, 1); - enc->state[enc->program].rt_text_timeout_state = enc->data[enc->program].rt_text_timeout; + 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) { - enc->state[enc->program].custom_group[0] = 1; - enc->state[enc->program].custom_group[1] = luaL_checkinteger(localL, 1); - enc->state[enc->program].custom_group[2] = luaL_checkinteger(localL, 2); - enc->state[enc->program].custom_group[3] = luaL_checkinteger(localL, 3); + 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[2] = luaL_checkinteger(localL, 2); + enc->state[writing_program].custom_group[3] = luaL_checkinteger(localL, 3); return 0; } int lua_put_rds2_custom_group(lua_State *localL) { - enc->state[enc->program].custom_group2[0] = 1; - enc->state[enc->program].custom_group2[1] = luaL_checkinteger(localL, 1); - enc->state[enc->program].custom_group2[2] = luaL_checkinteger(localL, 2); - enc->state[enc->program].custom_group2[3] = luaL_checkinteger(localL, 3); - enc->state[enc->program].custom_group2[4] = luaL_checkinteger(localL, 4); + enc->state[writing_program].custom_group2[0] = 1; + enc->state[writing_program].custom_group2[1] = luaL_checkinteger(localL, 1); + enc->state[writing_program].custom_group2[2] = luaL_checkinteger(localL, 2); + enc->state[writing_program].custom_group2[3] = luaL_checkinteger(localL, 3); + enc->state[writing_program].custom_group2[4] = luaL_checkinteger(localL, 4); return 0; } @@ -268,8 +284,8 @@ STR_RAW_GETTER(grp_sqc_rds2, 32) int lua_set_rds_grp_sqc(lua_State *localL) { const char* str = luaL_checklstring(localL, 1, NULL); - if(_strnlen(str, 2) < 1) set_rds_grpseq(enc, DEFAULT_GRPSQC); - else set_rds_grpseq(enc, str); + if(_strnlen(str, 2) < 1) set_rds_grpseq(enc, DEFAULT_GRPSQC, writing_program); + else set_rds_grpseq(enc, str, writing_program); return 0; } @@ -284,16 +300,16 @@ int lua_set_rds_eon(lua_State *localL) { if (!lua_isboolean(localL, 4)) return luaL_error(localL, "boolean expected, got %s", luaL_typename(localL, 4)); if (!lua_isboolean(localL, 5)) return luaL_error(localL, "boolean expected, got %s", luaL_typename(localL, 5)); luaL_checktype(localL, 8, LUA_TTABLE); - enc->data[enc->program].eon[eon].enabled = lua_toboolean(localL, 2); - enc->data[enc->program].eon[eon].pi = luaL_checkinteger(localL, 3); - enc->data[enc->program].eon[eon].tp = lua_toboolean(localL, 4); - enc->data[enc->program].eon[eon].ta = lua_toboolean(localL, 5); - enc->data[enc->program].eon[eon].pty = luaL_checkinteger(localL, 6); - _strncpy(enc->data[enc->program].eon[eon].ps, luaL_checklstring(localL, 7, NULL), 8); + enc->data[writing_program].eon[eon].enabled = lua_toboolean(localL, 2); + enc->data[writing_program].eon[eon].pi = luaL_checkinteger(localL, 3); + enc->data[writing_program].eon[eon].tp = lua_toboolean(localL, 4); + enc->data[writing_program].eon[eon].ta = lua_toboolean(localL, 5); + enc->data[writing_program].eon[eon].pty = luaL_checkinteger(localL, 6); + _strncpy(enc->data[writing_program].eon[eon].ps, luaL_checklstring(localL, 7, NULL), 8); int n = lua_rawlen(localL, 8); if (n == 0) { - memset(&(enc->data[enc->program].eon[eon].af), 0, sizeof(RDSAFs)); + memset(&(enc->data[writing_program].eon[eon].af), 0, sizeof(RDSAFs)); return 0; } if(n > 25) return luaL_error(localL, "table length over 25"); @@ -307,23 +323,23 @@ int lua_set_rds_eon(lua_State *localL) { else return luaL_error(localL, "number expected, got %s", luaL_typename(localL, -1)); lua_pop(localL, 1); } - memcpy(&(enc->data[enc->program].eon[eon].af), &new_af, sizeof(new_af)); + memcpy(&(enc->data[writing_program].eon[eon].af), &new_af, sizeof(new_af)); - enc->data[enc->program].eon[eon].data = luaL_checkinteger(localL, 9); + enc->data[writing_program].eon[eon].data = luaL_checkinteger(localL, 9); return 0; } int lua_get_rds_eon(lua_State *localL) { int eon = luaL_checkinteger(localL, 1); if(eon >= EONs) return luaL_error(localL, "eon index exceeded"); - lua_pushboolean(localL, enc->data[enc->program].eon[eon].enabled); - lua_pushinteger(localL, enc->data[enc->program].eon[eon].pi); - lua_pushboolean(localL, enc->data[enc->program].eon[eon].tp); - lua_pushboolean(localL, enc->data[enc->program].eon[eon].ta); - lua_pushinteger(localL, enc->data[enc->program].eon[eon].pty); - lua_pushlstring(localL, enc->data[enc->program].eon[eon].ps, 8); + lua_pushboolean(localL, enc->data[writing_program].eon[eon].enabled); + lua_pushinteger(localL, enc->data[writing_program].eon[eon].pi); + lua_pushboolean(localL, enc->data[writing_program].eon[eon].tp); + lua_pushboolean(localL, enc->data[writing_program].eon[eon].ta); + lua_pushinteger(localL, enc->data[writing_program].eon[eon].pty); + lua_pushlstring(localL, enc->data[writing_program].eon[eon].ps, 8); lua_createtable(localL, 0, 0); // don't have decoding for AF, so just return empty table - lua_pushinteger(localL, enc->data[enc->program].eon[eon].data); + lua_pushinteger(localL, enc->data[writing_program].eon[eon].data); return 8; } @@ -353,11 +369,11 @@ int lua_set_rds_udg(lua_State *localL) { } if(xy) { - memcpy(&(enc->data[enc->program].udg2), blocks, n * sizeof(uint16_t[3])); - enc->data[enc->program].udg2_len = n; + memcpy(&(enc->data[writing_program].udg2), blocks, n * sizeof(uint16_t[3])); + enc->data[writing_program].udg2_len = n; } else { - memcpy(&(enc->data[enc->program].udg1), blocks, n * sizeof(uint16_t[3])); - enc->data[enc->program].udg1_len = n; + memcpy(&(enc->data[writing_program].udg1), blocks, n * sizeof(uint16_t[3])); + enc->data[writing_program].udg1_len = n; } return 0; @@ -389,11 +405,11 @@ int lua_set_rds_udg2(lua_State *localL) { } if(xy) { - memcpy(&(enc->data[enc->program].udg2_rds2), blocks, n * sizeof(uint16_t[4])); - enc->data[enc->program].udg2_len_rds2 = n; + memcpy(&(enc->data[writing_program].udg2_rds2), blocks, n * sizeof(uint16_t[4])); + enc->data[writing_program].udg2_len_rds2 = n; } else { - memcpy(&(enc->data[enc->program].udg1_rds2), blocks, n * sizeof(uint16_t[4])); - enc->data[enc->program].udg1_len_rds2 = n; + memcpy(&(enc->data[writing_program].udg1_rds2), blocks, n * sizeof(uint16_t[4])); + enc->data[writing_program].udg1_len_rds2 = n; } return 0; diff --git a/src/lua_api.h b/src/lua_api.h index f9039b5..28f00e9 100644 --- a/src/lua_api.h +++ b/src/lua_api.h @@ -68,6 +68,9 @@ int lua_get_rds_link(lua_State *localL); int lua_set_rds_program(lua_State *localL); int lua_get_rds_program(lua_State *localL); +int lua_set_rds_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); diff --git a/src/lua_rds.c b/src/lua_rds.c index 61b3bdd..f670a64 100644 --- a/src/lua_rds.c +++ b/src/lua_rds.c @@ -56,6 +56,8 @@ void init_lua(RDSEncoder* _enc) { lua_setfield(L, -2, "max_programs"); lua_registertotable(L, "set_program", lua_set_rds_program); lua_registertotable(L, "get_program", lua_get_rds_program); + lua_registertotable(L, "set_writing_program", lua_set_rds_writing_program); + lua_registertotable(L, "get_writing_program", lua_get_rds_writing_program); lua_setglobal(L, "dp"); lua_newtable(L); @@ -163,16 +165,23 @@ void init_lua(RDSEncoder* _enc) { } } -void run_lua(char *str, char *cmd_output, size_t* out_len) { +void run_lua(char *str, size_t str_len, char *cmd_output, size_t *out_len) { pthread_mutex_lock(&lua_mutex); + lua_getglobal(L, "data_handle"); if (lua_isfunction(L, -1)) { - lua_pushstring(L, str); + lua_pushlstring(L, str, str_len); + if (lua_pcall(L, 1, 1, 0) == LUA_OK) { - if (lua_isstring(L, -1) && cmd_output) _strncpy(cmd_output, lua_tolstring(L, -1, out_len), 254); + if (lua_isstring(L, -1) && cmd_output) { + const char *lua_str = lua_tolstring(L, -1, out_len); + if (*out_len > 254) *out_len = 254; + memcpy(cmd_output, lua_str, *out_len); + } } else fprintf(stderr, "Lua error: %s at 'data_handle'\n", lua_tostring(L, -1)); - } else if (lua_isstring(L, -1) && cmd_output) _strncpy(cmd_output, lua_tolstring(L, -1, out_len), 254); + } else fprintf(stderr, "'data_handle' is not a function\n"); + lua_pop(L, 1); pthread_mutex_unlock(&lua_mutex); } diff --git a/src/lua_rds.h b/src/lua_rds.h index e271a3b..0ce1006 100644 --- a/src/lua_rds.h +++ b/src/lua_rds.h @@ -6,7 +6,7 @@ #include void init_lua(RDSEncoder* _enc); -void run_lua(char *str, char *cmd_output, size_t* out_len); +void run_lua(char *str, size_t str_len, char *cmd_output, size_t* out_len); int lua_group(RDSGroup* group, const char grp); int lua_rds2_group(RDSGroup* group, int stream); void lua_call_function_nolock(const char* function); diff --git a/src/rds.c b/src/rds.c index c824fac..de8fb2a 100644 --- a/src/rds.c +++ b/src/rds.c @@ -329,14 +329,14 @@ void reset_rds_state(RDSEncoder* enc, uint8_t program) { tempCoder.state[program].rt_ab = 1; tempCoder.state[program].ptyn_ab = 1; - set_rds_rt1(&tempCoder, enc->data[program].rt1); - set_rds_rt2(&tempCoder, enc->data[program].rt2); - set_rds_ps(&tempCoder, enc->data[program].ps); - set_rds_tps(&tempCoder, enc->data[program].tps); - set_rds_ptyn(&tempCoder, enc->data[program].ptyn); - set_rds_lps(&tempCoder, enc->data[program].lps); - set_rds_grpseq(&tempCoder, enc->data[program].grp_sqc); - set_rds_grpseq2(&tempCoder, enc->data[program].grp_sqc_rds2); + set_rds_rt1(&tempCoder, enc->data[program].rt1, program); + set_rds_rt2(&tempCoder, enc->data[program].rt2, program); + set_rds_ps(&tempCoder, enc->data[program].ps), program; + set_rds_tps(&tempCoder, enc->data[program].tps, program); + set_rds_lps(&tempCoder, enc->data[program].lps, program); + set_rds_ptyn(&tempCoder, enc->data[program].ptyn, program); + set_rds_grpseq(&tempCoder, enc->data[program].grp_sqc, program); + set_rds_grpseq2(&tempCoder, enc->data[program].grp_sqc_rds2, program); struct tm *utc; time_t now; diff --git a/src/rds.h b/src/rds.h index bab4681..baa759c 100644 --- a/src/rds.h +++ b/src/rds.h @@ -195,12 +195,12 @@ void add_checkwords(RDSGroup *group, uint8_t *bits); void get_rds_group(RDSEncoder* enc, RDSGroup *group, uint8_t stream); void get_rds_bits(RDSEncoder* enc, uint8_t *bits, uint8_t stream); -void set_rds_rt1(RDSEncoder* enc, const char *rt1); -void set_rds_rt2(RDSEncoder* enc, const char *rt2); -void set_rds_default_rt(RDSEncoder* enc, const char *rt); -void set_rds_ps(RDSEncoder* enc, const char *ps); -void set_rds_tps(RDSEncoder* enc, const char *tps); -void set_rds_lps(RDSEncoder* enc, const char *lps); -void set_rds_ptyn(RDSEncoder *enc, const char *ptyn); -void set_rds_grpseq(RDSEncoder* enc, const char *grpseq); -void set_rds_grpseq2(RDSEncoder* enc, const char *grpseq2); \ No newline at end of file +void set_rds_rt1(RDSEncoder* enc, const char *rt1, 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_tps(RDSEncoder* enc, const char *tps, uint8_t program); +void set_rds_lps(RDSEncoder* enc, const char *lps, uint8_t program); +void set_rds_ptyn(RDSEncoder *enc, const char *ptyn, uint8_t program); +void set_rds_grpseq(RDSEncoder* enc, const char *grpseq, uint8_t program); +void set_rds_grpseq2(RDSEncoder* enc, const char *grpseq2, uint8_t program); \ No newline at end of file diff --git a/src/rds_setters.c b/src/rds_setters.c index 23cb26f..17a3308 100644 --- a/src/rds_setters.c +++ b/src/rds_setters.c @@ -1,148 +1,148 @@ #include "rds.h" -void set_rds_rt1(RDSEncoder* enc, const char *rt1) { +void set_rds_rt1(RDSEncoder* enc, const char *rt1, uint8_t program) { uint8_t i = 0, len = 0; - enc->state[enc->program].rt_text_timeout_state = enc->data[enc->program].rt_text_timeout; + enc->state[program].rt_text_timeout_state = enc->data[program].rt_text_timeout; - enc->state[enc->program].rt_update = 1; + enc->state[program].rt_update = 1; - memset(enc->data[enc->program].rt1, ' ', RT_LENGTH); - while (*rt1 != 0 && len < RT_LENGTH) enc->data[enc->program].rt1[len++] = *rt1++; + memset(enc->data[program].rt1, ' ', RT_LENGTH); + while (*rt1 != 0 && len < RT_LENGTH) enc->data[program].rt1[len++] = *rt1++; - while (len > 0 && enc->data[enc->program].rt1[len - 1] == ' ') len--; + while (len > 0 && enc->data[program].rt1[len - 1] == ' ') len--; if (len < RT_LENGTH) { - enc->state[enc->program].rt_segments = 0; - enc->data[enc->program].rt1[len++] = '\r'; + enc->state[program].rt_segments = 0; + enc->data[program].rt1[len++] = '\r'; while (i < len) { i += 4; - enc->state[enc->program].rt_segments++; + enc->state[program].rt_segments++; } - } else enc->state[enc->program].rt_segments = 16; - if(enc->state[enc->program].rt_segments > 16) enc->state[enc->program].rt_segments = 16; //make sure + } else enc->state[program].rt_segments = 16; + 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) { +void set_rds_default_rt(RDSEncoder* enc, const char *rt, uint8_t program) { uint8_t i = 0, len = 0; - memset(enc->data[enc->program].default_rt, ' ', RT_LENGTH); - while (*rt != 0 && len < RT_LENGTH) enc->data[enc->program].default_rt[len++] = *rt++; + 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[enc->program].default_rt[len - 1] == ' ') len--; + while (len > 0 && enc->data[program].default_rt[len - 1] == ' ') len--; if (len < RT_LENGTH) { - enc->state[enc->program].default_rt_segments = 0; - enc->data[enc->program].default_rt[len++] = '\r'; + enc->state[program].default_rt_segments = 0; + enc->data[program].default_rt[len++] = '\r'; while (i < len) { i += 4; - enc->state[enc->program].default_rt_segments++; + enc->state[program].default_rt_segments++; } - } else enc->state[enc->program].default_rt_segments = 16; - if(enc->state[enc->program].default_rt_segments > 16) enc->state[enc->program].default_rt_segments = 16; //make sure + } 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) { +void set_rds_rt2(RDSEncoder* enc, const char *rt2, uint8_t program) { uint8_t i = 0, len = 0; - enc->state[enc->program].rt2_update = 1; + enc->state[program].rt2_update = 1; - memset(enc->data[enc->program].rt2, ' ', RT_LENGTH); - while (*rt2 != 0 && len < RT_LENGTH) enc->data[enc->program].rt2[len++] = *rt2++; + memset(enc->data[program].rt2, ' ', RT_LENGTH); + while (*rt2 != 0 && len < RT_LENGTH) enc->data[program].rt2[len++] = *rt2++; - while (len > 0 && enc->data[enc->program].rt2[len - 1] == ' ') len--; + while (len > 0 && enc->data[program].rt2[len - 1] == ' ') len--; if (len < RT_LENGTH) { - enc->state[enc->program].rt2_segments = 0; - enc->data[enc->program].rt2[len++] = '\r'; + enc->state[program].rt2_segments = 0; + enc->data[program].rt2[len++] = '\r'; while (i < len) { i += 4; - enc->state[enc->program].rt2_segments++; + enc->state[program].rt2_segments++; } - } else enc->state[enc->program].rt2_segments = 16; - if(enc->state[enc->program].rt2_segments > 16) enc->state[enc->program].rt2_segments = 16; //make sure + } 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) { +void set_rds_ps(RDSEncoder* enc, const char *ps, uint8_t program) { uint8_t len = 0; - enc->state[enc->program].ps_update = 1; - memset(enc->data[enc->program].ps, ' ', PS_LENGTH); - while (*ps != 0 && len < PS_LENGTH) enc->data[enc->program].ps[len++] = *ps++; + enc->state[program].ps_update = 1; + memset(enc->data[program].ps, ' ', PS_LENGTH); + while (*ps != 0 && len < PS_LENGTH) enc->data[program].ps[len++] = *ps++; } -void set_rds_tps(RDSEncoder* enc, const char *tps) { +void set_rds_tps(RDSEncoder* enc, const char *tps, uint8_t program) { uint8_t len = 0; - enc->state[enc->program].tps_update = 1; + enc->state[program].tps_update = 1; if(tps[0] == '\0') { - memset(enc->data[enc->program].tps, 0, PS_LENGTH); + memset(enc->data[program].tps, 0, PS_LENGTH); return; } - memset(enc->data[enc->program].tps, ' ', PS_LENGTH); - while (*tps != 0 && len < PS_LENGTH) enc->data[enc->program].tps[len++] = *tps++; + memset(enc->data[program].tps, ' ', PS_LENGTH); + while (*tps != 0 && len < PS_LENGTH) enc->data[program].tps[len++] = *tps++; } -void set_rds_lps(RDSEncoder* enc, const char *lps) { +void set_rds_lps(RDSEncoder* enc, const char *lps, uint8_t program) { uint8_t i = 0, len = 0; - enc->state[enc->program].lps_update = 1; + enc->state[program].lps_update = 1; if(lps[0] == '\0') { - memset(enc->data[enc->program].lps, 0, LPS_LENGTH); + memset(enc->data[program].lps, 0, LPS_LENGTH); return; } - memset(enc->data[enc->program].lps, ' ', LPS_LENGTH); - while (*lps != 0 && len < LPS_LENGTH) enc->data[enc->program].lps[len++] = *lps++; + memset(enc->data[program].lps, ' ', LPS_LENGTH); + while (*lps != 0 && len < LPS_LENGTH) enc->data[program].lps[len++] = *lps++; if (len < LPS_LENGTH) { - enc->state[enc->program].lps_segments = 0; - enc->data[enc->program].lps[len++] = '\r'; + enc->state[program].lps_segments = 0; + enc->data[program].lps[len++] = '\r'; while (i < len) { i += 4; - enc->state[enc->program].lps_segments++; + enc->state[program].lps_segments++; } - } else enc->state[enc->program].lps_segments = 8; - if(enc->state[enc->program].lps_segments > 8) enc->state[enc->program].lps_segments = 8; //make sure + } else enc->state[program].lps_segments = 8; + if(enc->state[program].lps_segments > 8) enc->state[program].lps_segments = 8; //make sure } -void set_rds_ptyn(RDSEncoder* enc, const char *ptyn) { +void set_rds_ptyn(RDSEncoder* enc, const char *ptyn, uint8_t program) { uint8_t len = 0; - enc->state[enc->program].ptyn_update = 1; + enc->state[program].ptyn_update = 1; if(ptyn[0] == '\0') { - memset(enc->data[enc->program].ptyn, 0, PTYN_LENGTH); + memset(enc->data[program].ptyn, 0, PTYN_LENGTH); return; } - memset(enc->data[enc->program].ptyn, ' ', PTYN_LENGTH); - while (*ptyn != 0 && len < PTYN_LENGTH) enc->data[enc->program].ptyn[len++] = *ptyn++; + memset(enc->data[program].ptyn, ' ', PTYN_LENGTH); + while (*ptyn != 0 && len < PTYN_LENGTH) enc->data[program].ptyn[len++] = *ptyn++; } -void set_rds_grpseq(RDSEncoder* enc, const char *grpseq) { +void set_rds_grpseq(RDSEncoder* enc, const char *grpseq, uint8_t program) { uint8_t len = 0; if(grpseq[0] == '\0') { while (DEFAULT_GRPSQC[len] != 0 && len < 32) { - enc->data[enc->program].grp_sqc[len] = DEFAULT_GRPSQC[len]; + enc->data[program].grp_sqc[len] = DEFAULT_GRPSQC[len]; len++; } return; } - memset(enc->data[enc->program].grp_sqc, 0, 32); - while (*grpseq != 0 && len < 32) enc->data[enc->program].grp_sqc[len++] = *grpseq++; + memset(enc->data[program].grp_sqc, 0, 32); + while (*grpseq != 0 && len < 32) enc->data[program].grp_sqc[len++] = *grpseq++; } -void set_rds_grpseq2(RDSEncoder* enc, const char *grpseq2) { +void set_rds_grpseq2(RDSEncoder* enc, const char *grpseq2, uint8_t program) { uint8_t len = 0; if(grpseq2[0] == '\0') { - memset(enc->data[enc->program].grp_sqc_rds2, 0, 32); - memcpy(enc->data[enc->program].grp_sqc_rds2, enc->data[enc->program].grp_sqc, 32); + memset(enc->data[program].grp_sqc_rds2, 0, 32); + memcpy(enc->data[program].grp_sqc_rds2, enc->data[program].grp_sqc, 32); return; } - memset(enc->data[enc->program].grp_sqc_rds2, 0, 32); - while (*grpseq2 != 0 && len < 32) enc->data[enc->program].grp_sqc_rds2[len++] = *grpseq2++; + memset(enc->data[program].grp_sqc_rds2, 0, 32); + while (*grpseq2 != 0 && len < 32) enc->data[program].grp_sqc_rds2[len++] = *grpseq2++; } \ No newline at end of file diff --git a/src/udp_server.c b/src/udp_server.c index dfda0d5..2c81e10 100644 --- a/src/udp_server.c +++ b/src/udp_server.c @@ -44,22 +44,46 @@ void poll_udp_server() { ssize_t bytes_read = recvfrom(sockfd, buf, BUF_SIZE - 1, 0, (struct sockaddr *)&client_addr, &client_len); if (bytes_read <= 0) return; - buf[bytes_read] = '\0'; + size_t start = 0; + + for (ssize_t i = 0; i < bytes_read; i++) { + if (buf[i] == '\n' || (unsigned char)buf[i] == 0xFF) { + size_t len = i - start; + + if (len > 0 && len < BUF_SIZE) { + memset(cmd_buf, 0, BUF_SIZE); + memcpy(cmd_buf, buf + start, len); + memset(cmd_output, 0, BUF_SIZE); + + size_t out_len = 0; + run_lua(cmd_buf, len, cmd_output, &out_len); + + if (out_len > 0 && + sendto(sockfd, cmd_output, out_len, 0, + (struct sockaddr *)&client_addr, client_len) == -1) { + perror("sendto"); + } + } + + start = i + 1; + } + } + + if (start < bytes_read) { + size_t len = bytes_read - start; - char *token = strtok(buf, "\r\n"); - while (token != NULL) { - size_t len = strlen(token); if (len > 0 && len < BUF_SIZE) { - memset(cmd_buf, 0, BUF_SIZE); - strncpy(cmd_buf, token, BUF_SIZE - 1); - - memset(cmd_output, 0, BUF_SIZE); + memcpy(cmd_buf, buf + start, len); size_t out_len = 0; - run_lua(cmd_buf, cmd_output, &out_len); - if (out_len > 0 && sendto(sockfd, cmd_output, out_len, 0, (struct sockaddr *)&client_addr, client_len) == -1) perror("sendto"); // no walrus + run_lua(cmd_buf, len, cmd_output, &out_len); + + if (out_len > 0 && + sendto(sockfd, cmd_output, out_len, 0, + (struct sockaddr *)&client_addr, client_len) == -1) { + perror("sendto"); + } } - token = strtok(NULL, "\r\n"); } } diff --git a/standards/R22_039_1_part10.pdf b/standards/R22_039_1_part10.pdf new file mode 100644 index 0000000..7b7f602 Binary files /dev/null and b/standards/R22_039_1_part10.pdf differ