From 23b063dfec181f82119cf7159714337e0ea7dec8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oona=20R=C3=A4is=C3=A4nen?= Date: Fri, 20 Sep 2024 06:44:05 +0300 Subject: [PATCH] Workaround buggy encoders that show 1 extra character in RT+ fields --- CHANGES.md | 3 +- README.md | 3 +- src/groups.cc | 6 ++-- test/unit.cc | 86 ++++++++++++++++++++++++++++++++------------------- 4 files changed, 62 insertions(+), 36 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 558ef6a..59a0dbb 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -5,6 +5,7 @@ * New features: * Decode 'broadcaster use' data in Slow labeling codes (variant 6) * Decode 'decoder identification' bits in Group 15B + * Workaround buggy encoders that show 1 extra character in RT+ fields * Bug fixes: * Fix the CSVReader (used in the TMC decoder) ignoring the last line of any file * Remove extra trailing space in transparent data channels hexdump @@ -13,7 +14,7 @@ * macOS: ask Homebrew about liquid-dsp location instead of hardcoding it * Set default installation prefix to /usr/local (all platforms) -## 1.0.1 +## 1.0.1 (2024-07-19) * Fixes: * Fix a crash (uncaught json exception) when attempting to serialize a string that's diff --git a/README.md b/README.md index 1d9fe1e..b43de2c 100644 --- a/README.md +++ b/README.md @@ -227,7 +227,8 @@ Try running this in the terminal: ## Contributing -We welcome bug reports and documentation contributions. See +We welcome bug reports and documentation contributions. Or take a peek at our +[open issues](https://github.com/windytan/redsea/issues) to see where we could use a hand. See [CONTRIBUTING](CONTRIBUTING.md) for more information. Also, if a station in your area is transmitting an interesting RDS feature diff --git a/src/groups.cc b/src/groups.cc index dffb552..3331796 100644 --- a/src/groups.cc +++ b/src/groups.cc @@ -322,11 +322,11 @@ void Station::updateAndPrint(const Group& group, std::ostream& stream) { // incomplete JSON objects could get printed. std::stringstream output_proxy_stream; output_proxy_stream << json_; - stream << output_proxy_stream.str() << std::endl << std::flush; + stream << output_proxy_stream.str() << std::endl; } catch (const std::exception& e) { nlohmann::ordered_json json_from_exception; json_from_exception["debug"] = std::string(e.what()); - stream << json_from_exception << std::endl << std::flush; + stream << json_from_exception << std::endl; } } @@ -1022,7 +1022,7 @@ void parseRadioTextPlus(const Group& group, RadioText& rt, nlohmann::ordered_jso if (text.length() > 0 && tag.content_type != 0) { nlohmann::ordered_json tag_json; tag_json["content-type"] = getRTPlusContentTypeString(tag.content_type); - tag_json["data"] = text; + tag_json["data"] = rtrim(text); json_el["tags"].push_back(tag_json); } } diff --git a/test/unit.cc b/test/unit.cc index 0a857a0..0c87340 100644 --- a/test/unit.cc +++ b/test/unit.cc @@ -327,26 +327,59 @@ TEST_CASE("Enhanced RadioText") { TEST_CASE("RadioText Plus") { redsea::Options options; - SECTION("Containing non-ascii characters") { + // Some encoders forget that RT+ length field means _additional_ length, so we need to rtrim + SECTION("Off-by-one encoder bug workaround") { + // clang-format off + const auto json_lines{hex2json({ + // RT+ ODA identifier + 0x53C5'3558'0000'4BD7, + // RT+ + 0x53C5'C548'8020'0A6A, + // RT message + 0x53C5'2550'4649'4F52, + 0x53C5'2551'454C'4C41, + 0x53C5'2552'204D'414E, + 0x53C5'2553'4E4F'4941, + 0x53C5'2554'202D'2047, + 0x53C5'2555'4C49'2041, + 0x53C5'2556'4D41'4E54, + 0x53C5'2557'4920'2020, + 0x53C5'2558'2020'2020, 0x53C5'2559'2020'2020, 0x53C5'255A'2020'2020, + 0x53C5'255B'2020'2020, 0x53C5'255C'2020'2020, 0x53C5'255D'2020'2020, + 0x53C5'255E'2020'2020, 0x53C5'255F'2020'2020, + // RT+ (second one) + 0x53C5'C548'8020'0A6A, + }, options, 0x53C5)}; + // clang-format on + + REQUIRE(json_lines.back()["radiotext_plus"]["tags"].size() == 2); + CHECK(json_lines.back()["radiotext_plus"]["tags"][0]["content-type"] == "item.artist"); + CHECK(json_lines.back()["radiotext_plus"]["tags"][0]["data"] == "FIORELLA MANNOIA"); + CHECK(json_lines.back()["radiotext_plus"]["tags"][1]["content-type"] == "item.title"); + CHECK(json_lines.back()["radiotext_plus"]["tags"][1]["data"] == "GLI AMANTI"); + } + + // Should count the number of letters and not UTF8-converted bytes + SECTION("Containing non-ASCII characters") { // Antenne 2016-09-17 // clang-format off - const auto json_lines{hex2json({ - // RT+ ODA identifier - 0xD318'3558'0000'4BD7, - // RT+ (we need two of these to confirm) - 0xD318'C558'8D20'0DCF, - // RT message - 0xD318'2540'6A65'747A, 0xD318'2541'7420'6175, - 0xD318'2542'6620'414E, 0xD318'2543'5445'4E4E, - 0xD318'2544'4520'4241, 0xD318'2545'5945'524E, - 0xD318'2546'3A20'4368, 0xD318'2547'7269'7374, - 0xD318'2548'696E'6120, 0xD318'2549'5374'9972, - 0xD318'254A'6D65'7220, 0xD318'254B'2D20'4569, - 0xD318'254C'6E20'5465, 0xD318'254D'696C'2076, - 0xD318'254E'6F6E'206D, 0xD318'254F'6972'2020, - // RT+ (second one) - 0xD318'C558'8D20'0DCF - }, options, 0xD318)}; + const auto json_lines{hex2json({ + // RT+ ODA identifier + 0xD318'3558'0000'4BD7, + // RT+ (we need two of these to confirm) + 0xD318'C558'8D20'0DCF, + // RT message + 0xD318'2540'6A65'747A, 0xD318'2541'7420'6175, + 0xD318'2542'6620'414E, 0xD318'2543'5445'4E4E, + 0xD318'2544'4520'4241, 0xD318'2545'5945'524E, + 0xD318'2546'3A20'4368, 0xD318'2547'7269'7374, + 0xD318'2548'696E'6120, 0xD318'2549'5374'9972, + 0xD318'254A'6D65'7220, 0xD318'254B'2D20'4569, + 0xD318'254C'6E20'5465, 0xD318'254D'696C'2076, + 0xD318'254E'6F6E'206D, 0xD318'254F'6972'2020, + // RT+ (second one) + 0xD318'C558'8D20'0DCF + }, options, 0xD318)}; // clang-format on REQUIRE(json_lines.back()["radiotext_plus"]["tags"].size() == 2); @@ -418,18 +451,9 @@ TEST_CASE("Alternative frequencies") { // YLE Helsinki (fi) 2016-09-15 // clang-format off const auto json_lines{hex2json({ - 0x6403'0447'F741'4920, - 0x6403'0440'415F'594C, - 0x6403'0441'4441'4520, - 0x6403'0442'5541'484B, - 0x6403'0447'1C41'4920, - 0x6403'0440'6841'594C, - 0x6403'0441'5E41'4520, - 0x6403'0442'414B'484B, - 0x6403'0447'4156'4920, - 0x6403'0440'CB41'594C, - 0x6403'0441'B741'4520, - 0x6403'0442'4174'484B + 0x6403'0447'F741'4920, 0x6403'0440'415F'594C, 0x6403'0441'4441'4520, 0x6403'0442'5541'484B, + 0x6403'0447'1C41'4920, 0x6403'0440'6841'594C, 0x6403'0441'5E41'4520, 0x6403'0442'414B'484B, + 0x6403'0447'4156'4920, 0x6403'0440'CB41'594C, 0x6403'0441'B741'4520, 0x6403'0442'4174'484B }, options, 0x6403)}; // clang-format on @@ -520,7 +544,7 @@ TEST_CASE("Clock-time and date") { } } -// TDS is a rarely seen feature. The TRDS4001 encoder is known to fill the fields +// TDC is a rarely seen feature. The TRDS4001 encoder is known to fill the fields // with its version string and some unknown binary data. We can at least test that this // version string is found somewhere in the data. TEST_CASE("Transparent data channels") {