generated from Grigo/AndroidTemplate
added more fields
This commit is contained in:
@@ -19,7 +19,7 @@ public final class RadioSnapshot {
|
||||
public final String frame;
|
||||
public final Double frequencyMhz;
|
||||
public final Integer sf;
|
||||
public final Integer bwKhz;
|
||||
public final Double bwKhz;
|
||||
public final Double powerDbm;
|
||||
public final Double rssiDbm;
|
||||
public final Double snrDb;
|
||||
@@ -30,6 +30,18 @@ public final class RadioSnapshot {
|
||||
public final Double rxPktPerS;
|
||||
public final Double perPercent;
|
||||
public final Double rxQualityPercent;
|
||||
public final String codeRate;
|
||||
public final Integer preambleLength;
|
||||
public final String lowDataRateOpt;
|
||||
public final Boolean crcEnabled;
|
||||
public final Integer payloadLengthBytes;
|
||||
public final Double txTimeoutMs;
|
||||
public final Integer packetReceive;
|
||||
public final Integer packetTotal;
|
||||
public final Integer packetError;
|
||||
public final Integer crcError;
|
||||
public final Integer preambleDetected;
|
||||
public final Integer headerValid;
|
||||
public final Map<String, String> extraFields;
|
||||
|
||||
public RadioSnapshot(
|
||||
@@ -37,7 +49,7 @@ public final class RadioSnapshot {
|
||||
String frame,
|
||||
Double frequencyMhz,
|
||||
Integer sf,
|
||||
Integer bwKhz,
|
||||
Double bwKhz,
|
||||
Double powerDbm,
|
||||
Double rssiDbm,
|
||||
Double snrDb,
|
||||
@@ -48,6 +60,18 @@ public final class RadioSnapshot {
|
||||
Double rxPktPerS,
|
||||
Double perPercent,
|
||||
Double rxQualityPercent,
|
||||
String codeRate,
|
||||
Integer preambleLength,
|
||||
String lowDataRateOpt,
|
||||
Boolean crcEnabled,
|
||||
Integer payloadLengthBytes,
|
||||
Double txTimeoutMs,
|
||||
Integer packetReceive,
|
||||
Integer packetTotal,
|
||||
Integer packetError,
|
||||
Integer crcError,
|
||||
Integer preambleDetected,
|
||||
Integer headerValid,
|
||||
Map<String, String> extraFields
|
||||
) {
|
||||
this.role = role;
|
||||
@@ -65,12 +89,26 @@ public final class RadioSnapshot {
|
||||
this.rxPktPerS = rxPktPerS;
|
||||
this.perPercent = perPercent;
|
||||
this.rxQualityPercent = rxQualityPercent;
|
||||
this.codeRate = codeRate;
|
||||
this.preambleLength = preambleLength;
|
||||
this.lowDataRateOpt = lowDataRateOpt;
|
||||
this.crcEnabled = crcEnabled;
|
||||
this.payloadLengthBytes = payloadLengthBytes;
|
||||
this.txTimeoutMs = txTimeoutMs;
|
||||
this.packetReceive = packetReceive;
|
||||
this.packetTotal = packetTotal;
|
||||
this.packetError = packetError;
|
||||
this.crcError = crcError;
|
||||
this.preambleDetected = preambleDetected;
|
||||
this.headerValid = headerValid;
|
||||
this.extraFields = extraFields != null ? extraFields : Map.of();
|
||||
}
|
||||
|
||||
public static RadioSnapshot empty() {
|
||||
return new RadioSnapshot(null, null, null, null, null, null, null, null,
|
||||
null, null, null, null, null, null, null, Map.of());
|
||||
null, null, null, null, null, null, null,
|
||||
null, null, null, null, null, null, null, null, null, null, null, null,
|
||||
Map.of());
|
||||
}
|
||||
|
||||
public static RadioSnapshot fromMeta(String metaJson, String roleFallback, Double rssiFallback) {
|
||||
@@ -78,7 +116,9 @@ public final class RadioSnapshot {
|
||||
RadioSnapshot snap = empty();
|
||||
if (roleFallback != null || rssiFallback != null) {
|
||||
return new RadioSnapshot(roleFallback, null, null, null, null, null,
|
||||
rssiFallback, null, null, null, null, null, null, null, null, Map.of());
|
||||
rssiFallback, null, null, null, null, null, null, null, null,
|
||||
null, null, null, null, null, null, null, null, null, null, null, null,
|
||||
Map.of());
|
||||
}
|
||||
return snap;
|
||||
}
|
||||
@@ -108,7 +148,7 @@ public final class RadioSnapshot {
|
||||
text(o, "frame"),
|
||||
hzToMhz(lng(o, "frequency_hz")),
|
||||
integer(o, "spreading_factor"),
|
||||
integer(o, "bandwidth_khz"),
|
||||
dbl(o, "bandwidth_khz"),
|
||||
dbl(o, "power_dbm"),
|
||||
rssi,
|
||||
dbl(o, "snr_db"),
|
||||
@@ -119,11 +159,25 @@ public final class RadioSnapshot {
|
||||
dbl(o, "rx_pkt_per_s"),
|
||||
dbl(o, "per_percent"),
|
||||
dbl(o, "rx_quality_percent"),
|
||||
text(o, "code_rate"),
|
||||
integer(o, "preamble_length"),
|
||||
text(o, "low_data_rate_opt"),
|
||||
bool(o, "crc_enabled"),
|
||||
integer(o, "payload_length_bytes"),
|
||||
dbl(o, "tx_timeout_ms"),
|
||||
integer(o, "packet_receive"),
|
||||
integer(o, "packet_total"),
|
||||
integer(o, "packet_error"),
|
||||
integer(o, "crc_error"),
|
||||
integer(o, "preamble_detected"),
|
||||
integer(o, "header_valid"),
|
||||
extra
|
||||
);
|
||||
} catch (Exception ignored) {
|
||||
return new RadioSnapshot(roleFallback, null, null, null, null, null,
|
||||
rssiFallback, null, null, null, null, null, null, null, null, Map.of());
|
||||
rssiFallback, null, null, null, null, null, null, null, null,
|
||||
null, null, null, null, null, null, null, null, null, null, null, null,
|
||||
Map.of());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -152,6 +206,14 @@ public final class RadioSnapshot {
|
||||
cmp(changed, "sf", sf, prev.sf);
|
||||
cmp(changed, "bw", bwKhz, prev.bwKhz);
|
||||
cmp(changed, "power", powerDbm, prev.powerDbm);
|
||||
cmp(changed, "packetReceive", packetReceive, prev.packetReceive);
|
||||
cmp(changed, "packetTotal", packetTotal, prev.packetTotal);
|
||||
cmp(changed, "packetError", packetError, prev.packetError);
|
||||
cmp(changed, "crcError", crcError, prev.crcError);
|
||||
cmp(changed, "preambleDetected", preambleDetected, prev.preambleDetected);
|
||||
cmp(changed, "headerValid", headerValid, prev.headerValid);
|
||||
cmp(changed, "codeRate", codeRate, prev.codeRate);
|
||||
cmp(changed, "crc", crcEnabled, prev.crcEnabled);
|
||||
return changed;
|
||||
}
|
||||
|
||||
@@ -167,8 +229,12 @@ public final class RadioSnapshot {
|
||||
|| n.contains("frequency") || n.equals("power") || n.equals("rssi")
|
||||
|| n.equals("snr") || n.contains("spreading") || n.contains("bandwidth")
|
||||
|| n.equals("packet") || n.contains("packet number") || n.equals("payload")
|
||||
|| n.contains("packet receive") || n.contains("packet total") || n.contains("packet error")
|
||||
|| n.contains("crc error") || n.contains("preamble detected") || n.contains("header valid")
|
||||
|| n.contains("on air") || n.contains("tx speed") || n.contains("rx speed")
|
||||
|| n.equals("per") || n.contains("rx quality");
|
||||
|| n.equals("per") || n.contains("rx quality") || n.contains("tx timeout")
|
||||
|| n.contains("code rate") || n.contains("preamble length")
|
||||
|| n.contains("low data rate") || n.equals("crc") || n.contains("payload length");
|
||||
}
|
||||
|
||||
private static String text(JsonObject o, String key) {
|
||||
@@ -186,6 +252,11 @@ public final class RadioSnapshot {
|
||||
return e != null && e.isJsonPrimitive() ? e.getAsDouble() : null;
|
||||
}
|
||||
|
||||
private static Boolean bool(JsonObject o, String key) {
|
||||
JsonElement e = o.get(key);
|
||||
return e != null && e.isJsonPrimitive() ? e.getAsBoolean() : null;
|
||||
}
|
||||
|
||||
private static Long lng(JsonObject o, String key) {
|
||||
JsonElement e = o.get(key);
|
||||
return e != null && e.isJsonPrimitive() ? e.getAsLong() : null;
|
||||
|
||||
@@ -40,6 +40,12 @@ public final class LoraStatsFormatter {
|
||||
appendLine(sb, "Пакет", fmtInt(s.packet), "packet", changed);
|
||||
appendLine(sb, "Payload", s.payload, "payload", changed);
|
||||
appendLine(sb, "PER", fmtSuffix(s.perPercent, " %"), "per", changed);
|
||||
appendLine(sb, "Принято", fmtInt(s.packetReceive), "packetReceive", changed);
|
||||
appendLine(sb, "Всего пакетов", fmtInt(s.packetTotal), "packetTotal", changed);
|
||||
appendLine(sb, "Ошибки пакетов", fmtInt(s.packetError), "packetError", changed);
|
||||
appendLine(sb, "CRC Error", fmtInt(s.crcError), "crcError", changed);
|
||||
appendLine(sb, "Preamble Det.", fmtInt(s.preambleDetected), "preambleDetected", changed);
|
||||
appendLine(sb, "Header Valid", fmtInt(s.headerValid), "headerValid", changed);
|
||||
appendLine(sb, "TX Speed", fmtSuffix(s.txPktPerS, " pkt/s"), "txSpeed", changed);
|
||||
appendLine(sb, "RX Speed", fmtSuffix(s.rxPktPerS, " pkt/s"), "rxSpeed", changed);
|
||||
for (Map.Entry<String, String> e : s.extraFields.entrySet()) {
|
||||
@@ -58,8 +64,14 @@ public final class LoraStatsFormatter {
|
||||
}
|
||||
appendLine(sb, "Частота", fmtSuffix(s.frequencyMhz, " MHz"), "frequency", changed);
|
||||
appendLine(sb, "SF", fmtInt(s.sf), "sf", changed);
|
||||
appendLine(sb, "BW", fmtSuffix(s.bwKhz, " kHz"), "bw", changed);
|
||||
appendLine(sb, "BW", fmtBw(s.bwKhz), "bw", changed);
|
||||
appendLine(sb, "Мощность TX", fmtDbm(s.powerDbm), "power", changed);
|
||||
appendLine(sb, "Code Rate", s.codeRate, "codeRate", changed);
|
||||
appendLine(sb, "Preamble Len", fmtInt(s.preambleLength), "preambleLength", changed);
|
||||
appendLine(sb, "Low DR Opt", s.lowDataRateOpt, "lowDataRateOpt", changed);
|
||||
appendLine(sb, "CRC", fmtCrc(s.crcEnabled), "crc", changed);
|
||||
appendLine(sb, "Payload len", fmtSuffix(s.payloadLengthBytes, " byte"), "payloadLength", changed);
|
||||
appendLine(sb, "TX Timeout", fmtSuffix(s.txTimeoutMs, " ms"), "txTimeout", changed);
|
||||
appendLine(sb, "On Air", fmtSuffix(s.onAirMs, " ms"), "onAir", changed);
|
||||
return sb.toString().trim();
|
||||
}
|
||||
@@ -111,11 +123,22 @@ public final class LoraStatsFormatter {
|
||||
return v != null ? String.valueOf(v) : null;
|
||||
}
|
||||
|
||||
private static String fmtSuffix(Double v, String suffix) {
|
||||
return v != null ? String.format(Locale.US, "%s%s", v, suffix) : null;
|
||||
private static String fmtBw(Double v) {
|
||||
return v != null ? String.format(Locale.US, "%.2f kHz", v) : null;
|
||||
}
|
||||
|
||||
private static String fmtCrc(Boolean enabled) {
|
||||
if (enabled == null) {
|
||||
return null;
|
||||
}
|
||||
return enabled ? "On" : "Off";
|
||||
}
|
||||
|
||||
private static String fmtSuffix(Integer v, String suffix) {
|
||||
return v != null ? v + suffix : null;
|
||||
}
|
||||
|
||||
private static String fmtSuffix(Double v, String suffix) {
|
||||
return v != null ? String.format(Locale.US, "%s%s", v, suffix) : null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,9 +25,26 @@ public class StatsExtractor {
|
||||
private static final Pattern SNR = Pattern.compile("SNR\\s*:\\s*(-?\\d+(?:\\.\\d+)?)", Pattern.CASE_INSENSITIVE);
|
||||
private static final Pattern FREQUENCY = Pattern.compile("Frequency\\s*:\\s*(\\d+)", Pattern.CASE_INSENSITIVE);
|
||||
private static final Pattern SPREADING = Pattern.compile("Spreading Factor\\s*:\\s*(\\d+)", Pattern.CASE_INSENSITIVE);
|
||||
private static final Pattern BANDWIDTH = Pattern.compile("Bandwidth\\s*:\\s*(\\d+)", Pattern.CASE_INSENSITIVE);
|
||||
private static final Pattern PACKET = Pattern.compile("Packet\\s*:\\s*(\\d+)", Pattern.CASE_INSENSITIVE);
|
||||
private static final Pattern BANDWIDTH = Pattern.compile("Bandwidth\\s*:\\s*([\\d.]+)", Pattern.CASE_INSENSITIVE);
|
||||
private static final Pattern PACKET_TX = Pattern.compile("(?m)^\\s*Packet\\s*:\\s*(\\d+)", Pattern.CASE_INSENSITIVE);
|
||||
private static final Pattern PACKET_NUMBER = Pattern.compile("Packet Number\\s*:\\s*(\\d+)", Pattern.CASE_INSENSITIVE);
|
||||
private static final Pattern PACKET_RECEIVE = Pattern.compile("Packet Receive\\s*:\\s*(\\d+)", Pattern.CASE_INSENSITIVE);
|
||||
private static final Pattern PACKET_TOTAL = Pattern.compile("Packet Total\\s*:\\s*(\\d+)", Pattern.CASE_INSENSITIVE);
|
||||
private static final Pattern PACKET_ERROR = Pattern.compile("Packet Error\\s*:\\s*(\\d+)", Pattern.CASE_INSENSITIVE);
|
||||
private static final Pattern CRC_ERROR = Pattern.compile("CRC Error\\s*:\\s*(\\d+)", Pattern.CASE_INSENSITIVE);
|
||||
private static final Pattern PREAMBLE_DETECTED = Pattern.compile(
|
||||
"Preamble Detected\\s*:\\s*(\\d+)", Pattern.CASE_INSENSITIVE);
|
||||
private static final Pattern HEADER_VALID = Pattern.compile("Header Valid\\s*:\\s*(\\d+)", Pattern.CASE_INSENSITIVE);
|
||||
private static final Pattern CODE_RATE = Pattern.compile("Code Rate\\s*:\\s*(\\S+)", Pattern.CASE_INSENSITIVE);
|
||||
private static final Pattern PREAMBLE_LENGTH = Pattern.compile(
|
||||
"Preamble Length\\s*:\\s*(\\d+)", Pattern.CASE_INSENSITIVE);
|
||||
private static final Pattern LOW_DATA_RATE = Pattern.compile(
|
||||
"Low Data Rate Opt\\s*:\\s*(\\S+)", Pattern.CASE_INSENSITIVE);
|
||||
private static final Pattern CRC = Pattern.compile("CRC\\s*:\\s*(On|Off)", Pattern.CASE_INSENSITIVE);
|
||||
private static final Pattern PAYLOAD_LENGTH = Pattern.compile(
|
||||
"Payload length\\s*:\\s*(\\d+)", Pattern.CASE_INSENSITIVE);
|
||||
private static final Pattern TX_TIMEOUT = Pattern.compile(
|
||||
"TX Timeout\\s*:\\s*([\\d.]+)", Pattern.CASE_INSENSITIVE);
|
||||
private static final Pattern PAYLOAD = Pattern.compile("Payload\\s*:\\s*(.+)", Pattern.CASE_INSENSITIVE);
|
||||
private static final Pattern ON_AIR = Pattern.compile("On Air\\s*:\\s*([\\d.]+)", Pattern.CASE_INSENSITIVE);
|
||||
private static final Pattern TX_SPEED = Pattern.compile("TX Speed\\s*:\\s*([\\d.]+)", Pattern.CASE_INSENSITIVE);
|
||||
@@ -89,10 +106,10 @@ public class StatsExtractor {
|
||||
|
||||
putLong(meta, "frequency_hz", matchLong(FREQUENCY, normalized));
|
||||
putInt(meta, "spreading_factor", matchInt(SPREADING, normalized));
|
||||
putInt(meta, "bandwidth_khz", matchInt(BANDWIDTH, normalized));
|
||||
putDouble(meta, "bandwidth_khz", matchDouble(BANDWIDTH, normalized));
|
||||
Integer packet = matchInt(PACKET_NUMBER, normalized);
|
||||
if (packet == null) {
|
||||
packet = matchInt(PACKET, normalized);
|
||||
packet = matchInt(PACKET_TX, normalized);
|
||||
}
|
||||
putInt(meta, "packet", packet);
|
||||
putString(meta, "payload", matchString(PAYLOAD, normalized));
|
||||
@@ -101,6 +118,18 @@ public class StatsExtractor {
|
||||
putDouble(meta, "rx_pkt_per_s", matchDouble(RX_SPEED, normalized));
|
||||
putDouble(meta, "per_percent", matchDouble(PER, normalized));
|
||||
putDouble(meta, "rx_quality_percent", matchDouble(RX_QUALITY, normalized));
|
||||
putString(meta, "code_rate", matchString(CODE_RATE, normalized));
|
||||
putInt(meta, "preamble_length", matchInt(PREAMBLE_LENGTH, normalized));
|
||||
putString(meta, "low_data_rate_opt", matchString(LOW_DATA_RATE, normalized));
|
||||
putBool(meta, "crc_enabled", matchBool(CRC, normalized));
|
||||
putInt(meta, "payload_length_bytes", matchInt(PAYLOAD_LENGTH, normalized));
|
||||
putDouble(meta, "tx_timeout_ms", matchDouble(TX_TIMEOUT, normalized));
|
||||
putInt(meta, "packet_receive", matchInt(PACKET_RECEIVE, normalized));
|
||||
putInt(meta, "packet_total", matchInt(PACKET_TOTAL, normalized));
|
||||
putInt(meta, "packet_error", matchInt(PACKET_ERROR, normalized));
|
||||
putInt(meta, "crc_error", matchInt(CRC_ERROR, normalized));
|
||||
putInt(meta, "preamble_detected", matchInt(PREAMBLE_DETECTED, normalized));
|
||||
putInt(meta, "header_valid", matchInt(HEADER_VALID, normalized));
|
||||
|
||||
if (!fields.isEmpty()) {
|
||||
meta.put("fields", fields);
|
||||
@@ -144,8 +173,12 @@ public class StatsExtractor {
|
||||
return n.equals("frequency") || n.equals("power") || n.equals("rssi")
|
||||
|| n.equals("snr") || n.contains("spreading factor") || n.equals("bandwidth")
|
||||
|| n.equals("packet") || n.contains("packet number") || n.equals("payload")
|
||||
|| n.contains("packet receive") || n.contains("packet total") || n.contains("packet error")
|
||||
|| n.contains("crc error") || n.contains("preamble detected") || n.contains("header valid")
|
||||
|| n.contains("on air") || n.contains("tx speed") || n.contains("rx speed")
|
||||
|| n.equals("per") || n.contains("rx quality") || n.equals("timeout");
|
||||
|| n.equals("per") || n.contains("rx quality") || n.contains("tx timeout")
|
||||
|| n.contains("code rate") || n.contains("preamble length")
|
||||
|| n.contains("low data rate") || n.equals("crc") || n.contains("payload length");
|
||||
}
|
||||
|
||||
private static ExtractedStats empty(String frame) {
|
||||
@@ -208,6 +241,20 @@ public class StatsExtractor {
|
||||
}
|
||||
}
|
||||
|
||||
private static void putBool(Map<String, Object> meta, String key, Boolean value) {
|
||||
if (value != null) {
|
||||
meta.put(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
private static Boolean matchBool(Pattern pattern, String text) {
|
||||
Matcher m = pattern.matcher(text);
|
||||
if (!m.find()) {
|
||||
return null;
|
||||
}
|
||||
return "on".equalsIgnoreCase(m.group(1).trim());
|
||||
}
|
||||
|
||||
private static Double matchDouble(Pattern pattern, String text) {
|
||||
Matcher m = pattern.matcher(text);
|
||||
if (m.find()) {
|
||||
|
||||
@@ -92,14 +92,30 @@ public class RadioComparePanel extends LinearLayout {
|
||||
addRow(table, "Пакет", fmtInt(tx.packet), fmtInt(rx.packet), "packet", changedTx, changedRx);
|
||||
addRow(table, "Payload", str(tx.payload), str(rx.payload), "payload", changedTx, changedRx);
|
||||
addRow(table, "PER", fmtSuffix(tx.perPercent, " %"), fmtSuffix(rx.perPercent, " %"), "per", changedTx, changedRx);
|
||||
addRow(table, "Принято", fmtInt(tx.packetReceive), fmtInt(rx.packetReceive), "packetReceive", changedTx, changedRx);
|
||||
addRow(table, "Всего", fmtInt(tx.packetTotal), fmtInt(rx.packetTotal), "packetTotal", changedTx, changedRx);
|
||||
addRow(table, "Ошибки", fmtInt(tx.packetError), fmtInt(rx.packetError), "packetError", changedTx, changedRx);
|
||||
addRow(table, "CRC err", fmtInt(tx.crcError), fmtInt(rx.crcError), "crcError", changedTx, changedRx);
|
||||
addRow(table, "Preamble", fmtInt(tx.preambleDetected), fmtInt(rx.preambleDetected),
|
||||
"preambleDetected", changedTx, changedRx);
|
||||
addRow(table, "Header OK", fmtInt(tx.headerValid), fmtInt(rx.headerValid), "headerValid", changedTx, changedRx);
|
||||
addRow(table, "TX spd", fmtSuffix(tx.txPktPerS, " p/s"), fmtSuffix(rx.txPktPerS, " p/s"), "txSpeed", changedTx, changedRx);
|
||||
addRow(table, "RX spd", fmtSuffix(tx.rxPktPerS, " p/s"), fmtSuffix(rx.rxPktPerS, " p/s"), "rxSpeed", changedTx, changedRx);
|
||||
} else {
|
||||
addRow(table, "Роль", LoraStatsFormatter.roleLabel(tx.role), LoraStatsFormatter.roleLabel(rx.role), "role", changedTx, changedRx);
|
||||
addRow(table, "Частота", fmtMhz(tx.frequencyMhz), fmtMhz(rx.frequencyMhz), "frequency", changedTx, changedRx);
|
||||
addRow(table, "SF", fmtInt(tx.sf), fmtInt(rx.sf), "sf", changedTx, changedRx);
|
||||
addRow(table, "BW", fmtSuffixInt(tx.bwKhz, " kHz"), fmtSuffixInt(rx.bwKhz, " kHz"), "bw", changedTx, changedRx);
|
||||
addRow(table, "BW", fmtBw(tx.bwKhz), fmtBw(rx.bwKhz), "bw", changedTx, changedRx);
|
||||
addRow(table, "Мощн.", fmtDbm(tx.powerDbm), fmtDbm(rx.powerDbm), "power", changedTx, changedRx);
|
||||
addRow(table, "Code Rate", str(tx.codeRate), str(rx.codeRate), "codeRate", changedTx, changedRx);
|
||||
addRow(table, "Preamble", fmtInt(tx.preambleLength), fmtInt(rx.preambleLength), "preambleLength", changedTx, changedRx);
|
||||
addRow(table, "LDR", str(tx.lowDataRateOpt), str(rx.lowDataRateOpt), "lowDataRateOpt", changedTx, changedRx);
|
||||
addRow(table, "CRC", fmtCrc(tx.crcEnabled), fmtCrc(rx.crcEnabled), "crc", changedTx, changedRx);
|
||||
addRow(table, "Payl.len", fmtSuffixInt(tx.payloadLengthBytes, " B"), fmtSuffixInt(rx.payloadLengthBytes, " B"),
|
||||
"payloadLength", changedTx, changedRx);
|
||||
addRow(table, "TX Timeout", fmtSuffix(tx.txTimeoutMs, " ms"), fmtSuffix(rx.txTimeoutMs, " ms"),
|
||||
"txTimeout", changedTx, changedRx);
|
||||
addRow(table, "On Air", fmtSuffix(tx.onAirMs, " ms"), fmtSuffix(rx.onAirMs, " ms"), "onAir", changedTx, changedRx);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -183,6 +199,17 @@ public class RadioComparePanel extends LinearLayout {
|
||||
return v != null ? v + suffix : "—";
|
||||
}
|
||||
|
||||
private static String fmtBw(Double v) {
|
||||
return v != null ? String.format(Locale.US, "%.2f kHz", v) : "—";
|
||||
}
|
||||
|
||||
private static String fmtCrc(Boolean enabled) {
|
||||
if (enabled == null) {
|
||||
return "—";
|
||||
}
|
||||
return enabled ? "On" : "Off";
|
||||
}
|
||||
|
||||
private static String fmtSuffixInt(Integer v, String suffix) {
|
||||
return v != null ? v + suffix : "—";
|
||||
}
|
||||
|
||||
@@ -54,11 +54,10 @@ public class LoraFrameExtractTest {
|
||||
public void parsesAllLabeledLinesFromSendScreen() {
|
||||
StatsExtractor extractor = StatsExtractor.withDefaults();
|
||||
StatsExtractor.ExtractedStats stats = extractor.extract(FULL_SEND);
|
||||
assertTrue(stats.metaJson.contains("\"fields\""));
|
||||
assertTrue(stats.metaJson.contains("Frequency"));
|
||||
assertTrue(stats.metaJson.contains("Spreading Factor"));
|
||||
assertTrue(stats.metaJson.contains("Packet"));
|
||||
assertTrue(stats.metaJson.contains("Payload"));
|
||||
assertTrue(stats.metaJson.contains("\"code_rate\":\"4/5\""));
|
||||
assertTrue(stats.metaJson.contains("\"spreading_factor\":12"));
|
||||
assertTrue(stats.metaJson.contains("\"packet\":304"));
|
||||
assertTrue(stats.metaJson.contains("Test TX!"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -83,7 +82,8 @@ public class LoraFrameExtractTest {
|
||||
assertEquals(StatsExtractor.ROLE_RX, stats.role);
|
||||
assertEquals(-78.0, stats.rssi, 0.01);
|
||||
assertEquals(10.5, stats.snrDb, 0.01);
|
||||
assertTrue(stats.metaJson.contains("\"fields\""));
|
||||
assertTrue(stats.metaJson.contains("\"packet\":0"));
|
||||
assertTrue(stats.metaJson.contains("\"rx_pkt_per_s\":0.45"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -96,6 +96,73 @@ public class LoraFrameExtractTest {
|
||||
assertTrue(!stats.metaJson.contains("RX Quality"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parsesRxCountersAndCrcErrors() {
|
||||
StatsExtractor extractor = StatsExtractor.withDefaults();
|
||||
String frame = """
|
||||
RECEIVE
|
||||
Frequency: 433500000 Hz
|
||||
Power: 0 dBm
|
||||
Spreading Factor: 5
|
||||
Bandwidth: 7.81 kHz
|
||||
Code Rate: 4/6
|
||||
Preamble Length: 8
|
||||
Low Data Rate Opt: Off
|
||||
CRC: Off
|
||||
Payload length: 32 byte
|
||||
On Air: 427.14 ms, 2.34 pkt/c
|
||||
Packet Number: 0
|
||||
Payload: test
|
||||
RSSI: -78
|
||||
SNR: 10.5
|
||||
RX Speed: 0.45 pkt/s, 120 bit/s
|
||||
Packet Receive: 12
|
||||
Packet Total: 100
|
||||
Packet Error: 3
|
||||
CRC Error: 2
|
||||
PER: 3.00 %
|
||||
Preamble Detected: 2
|
||||
Header Valid: 1
|
||||
RX Quality: 87 %
|
||||
""";
|
||||
StatsExtractor.ExtractedStats stats = extractor.extract(frame);
|
||||
assertTrue(stats.metaJson.contains("\"crc_error\":2"));
|
||||
assertTrue(stats.metaJson.contains("\"packet_error\":3"));
|
||||
assertTrue(stats.metaJson.contains("\"packet_total\":100"));
|
||||
assertTrue(stats.metaJson.contains("\"packet_receive\":12"));
|
||||
assertTrue(stats.metaJson.contains("\"bandwidth_khz\":7.81"));
|
||||
assertTrue(stats.metaJson.contains("\"crc_enabled\":false"));
|
||||
assertTrue(stats.metaJson.contains("\"code_rate\":\"4/6\""));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parsesSendCrcAndConfig() {
|
||||
StatsExtractor extractor = StatsExtractor.withDefaults();
|
||||
String frame = """
|
||||
SEND
|
||||
Frequency: 433500000 Hz
|
||||
Power: 0 dBm
|
||||
Spreading Factor: 5
|
||||
Bandwidth: 125 kHz
|
||||
Code Rate: 4/5
|
||||
Preamble Length: 8
|
||||
Low Data Rate Opt: Off
|
||||
CRC: On
|
||||
Payload length: 32 byte
|
||||
On Air: 23.10 ms, 43.28 pkt/c
|
||||
Packet: 3816
|
||||
Payload: Test TX!
|
||||
TX Timeout: 0 ms
|
||||
TX Speed: 32.06 pkt/s, 8206 bit/s
|
||||
""";
|
||||
StatsExtractor.ExtractedStats stats = extractor.extract(frame);
|
||||
assertTrue(stats.metaJson.contains("\"packet\":3816"));
|
||||
assertTrue(stats.metaJson.contains("\"crc_enabled\":true"));
|
||||
assertTrue(stats.metaJson.contains("\"payload_length_bytes\":32"));
|
||||
assertTrue(stats.metaJson.contains("\"tx_timeout_ms\":0"));
|
||||
assertTrue(stats.metaJson.contains("\"preamble_length\":8"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void splitsTwoFramesByReceiveHeaderWithoutEsc() {
|
||||
List<String> frames = new ArrayList<>();
|
||||
|
||||
Reference in New Issue
Block a user