flatudp: the signal-list codec, with a hand-computed decode check
This commit is contained in:
1 parent
dde2dad5b1
commit
6e8e71b32f
6 files changed
+311
No files matched your search
@@ -8,6 +8,7 @@
|
||||
|
||||
#include "source/probe_source.hpp"
|
||||
#include "source/e1608/e1608_source.hpp"
|
||||
#include "source/flatudp/flatudp_signals.hpp"
|
||||
#include "source/registry.hpp"
|
||||
#include "ui_app.hpp"
|
||||
|
||||
@@ -2037,6 +2038,70 @@ bool e1608_decode_check() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/// The `signals` codec and the datagram decode against values worked out by hand. The row set
|
||||
/// mixes every width and a vector: A:uint8, B:int16, C:float32, D:uint64[2], E:int8, 24 bytes.
|
||||
/// A = 254, B = -2, C = 1.5, D = {1, 4294967298}, E = -1.
|
||||
bool flatudp_codec_check() {
|
||||
using namespace flatudp;
|
||||
std::vector<Row> rows;
|
||||
if (!parse(" A:uint8, B:int16,C : float32 ,D:uint64[2],E:int8", rows).empty()) return false;
|
||||
const std::vector<Row> want = {{"A", Type::U8, 1}, {"B", Type::I16, 1}, {"C", Type::F32, 1},
|
||||
{"D", Type::U64, 2}, {"E", Type::I8, 1}};
|
||||
if (rows != want) return false;
|
||||
if (format(rows) != "A:uint8,B:int16,C:float32,D:uint64[2],E:int8") return false;
|
||||
if (datagram_size(rows) != 24 || all_scalar(rows) || !problem(rows).empty()) return false;
|
||||
// The enum value is the type code the model keeps.
|
||||
if (static_cast<int>(Type::F64) != 9 || static_cast<int>(Type::U64) != 6) return false;
|
||||
|
||||
const std::uint8_t le[24] = {0xFE, // A
|
||||
0xFE, 0xFF, // B
|
||||
0x00, 0x00, 0xC0, 0x3F, // C
|
||||
0x01, 0, 0, 0, 0, 0, 0, 0, // D[0]
|
||||
0x02, 0, 0, 0, 0x01, 0, 0, 0, // D[1]
|
||||
0xFF}; // E
|
||||
const std::uint8_t be[24] = {0xFE,
|
||||
0xFF, 0xFE,
|
||||
0x3F, 0xC0, 0x00, 0x00,
|
||||
0, 0, 0, 0, 0, 0, 0, 0x01,
|
||||
0, 0, 0, 0x01, 0, 0, 0, 0x02,
|
||||
0xFF};
|
||||
const double expect[5][2] = {{254, 0}, {-2, 0}, {1.5, 0}, {1, 4294967298.0}, {-1, 0}};
|
||||
const std::size_t counts[5] = {1, 1, 1, 2, 1};
|
||||
for (int pass = 0; pass < 2; ++pass) {
|
||||
std::vector<std::vector<double>> cols;
|
||||
decode_datagram(rows, pass == 0 ? le : be, pass == 1, cols);
|
||||
if (cols.size() != 5) return false;
|
||||
for (std::size_t s = 0; s < 5; ++s) {
|
||||
if (cols[s].size() != counts[s]) return false;
|
||||
for (std::size_t k = 0; k < counts[s]; ++k)
|
||||
if (cols[s][k] != expect[s][k]) return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Parse failures name the signal; a bad list never half-parses.
|
||||
std::vector<Row> bad;
|
||||
if (parse("A:uint8,B", bad).find("signal 2") == std::string::npos || !bad.empty()) return false;
|
||||
if (parse("A:uint7", bad).find("uint7") == std::string::npos) return false;
|
||||
if (parse("A:uint8[x]", bad).empty() || parse("A:uint8[3", bad).empty()) return false;
|
||||
if (!parse("", bad).empty() || !bad.empty() || problem(bad).empty()) return false;
|
||||
|
||||
// The validity rules.
|
||||
const auto prob = [](std::vector<Row> r) { return problem(r); };
|
||||
// One call per statement: GCC warns (-Wdangling-pointer) on two list temporaries joined by `||`.
|
||||
const auto valid = [](std::vector<Row> r) { return problem(r).empty(); };
|
||||
if (prob({{"A", Type::U8, 1}, {"A", Type::U8, 1}}).find("twice") == std::string::npos) return false;
|
||||
if (valid({{"", Type::U8, 1}})) return false;
|
||||
if (valid({{"a,b", Type::U8, 1}})) return false;
|
||||
if (valid({{"A", Type::U8, 0}})) return false;
|
||||
if (valid({{"A", Type::U8, 4097}})) return false;
|
||||
if (!valid({{"A", Type::U8, 4096}})) return false;
|
||||
// 2 x 32768 = 65536 bytes is over the datagram limit; 32768 + 16384 is not.
|
||||
if (prob({{"A", Type::F64, 4096}, {"B", Type::F64, 4096}}).find("65536") == std::string::npos)
|
||||
return false;
|
||||
if (!valid({{"A", Type::F64, 4096}, {"B", Type::F32, 4096}})) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
/// Phase 2, 1 s after the controls were driven: the stream, the calibration, the capture button,
|
||||
@@ -2182,6 +2247,15 @@ gboolean e1608_probe_reconnect(gpointer user) {
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
/// The flat UDP source's probe. For now only the pure codec check; it needs no flatudp source.
|
||||
gboolean flatudp_probe(gpointer user) {
|
||||
App* a = static_cast<App*>(user);
|
||||
if (a->window == nullptr) return G_SOURCE_REMOVE;
|
||||
std::fprintf(stderr, "[flatudp] codec: ok=%d\n", flatudp_codec_check() ? 1 : 0);
|
||||
std::fflush(stderr);
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
gboolean pan_probe(gpointer user) {
|
||||
App* a = static_cast<App*>(user);
|
||||
if (a->window == nullptr || a->rows->row_count() <= 0) return G_SOURCE_REMOVE;
|
||||
|
||||
Reference in new issue
Block a user