| 1072 | // ═════════════════════════════════════════════════════════════════════════════ |
| 1073 | |
| 1074 | void section6Ptt(RigctlClient& c, Runner& r) |
| 1075 | { |
| 1076 | r.section(QStringLiteral("Section 6 — PTT ⚠ TX ACTIVE")); |
| 1077 | |
| 1078 | // Power safety: read current power, drop to 0.01 (≈ 1 W) and confirm before keying |
| 1079 | QStringList lines = c.send(QStringLiteral("\\get_level RFPOWER")); |
| 1080 | const QString origRfpower = c.field(lines, QStringLiteral("RFPOWER")); |
| 1081 | r.check(QStringLiteral("6.0 read RFPOWER before PTT tests"), |
| 1082 | c.ok(lines) && isFloat(origRfpower), origRfpower); |
| 1083 | |
| 1084 | lines = c.send(QStringLiteral("\\set_level RFPOWER 0.01")); |
| 1085 | r.check(QStringLiteral("6.0b set RFPOWER 0.01 (≈ 1 W) returns RPRT 0"), c.ok(lines)); |
| 1086 | QString safePwr; |
| 1087 | { |
| 1088 | QElapsedTimer t; t.start(); |
| 1089 | do { |
| 1090 | lines = c.send(QStringLiteral("\\get_level RFPOWER")); |
| 1091 | safePwr = c.field(lines, QStringLiteral("RFPOWER")); |
| 1092 | if ((isFloat(safePwr) && safePwr.toDouble() <= 0.03) || t.elapsed() >= 1000) break; |
| 1093 | QThread::msleep(100); |
| 1094 | } while (true); |
| 1095 | } |
| 1096 | r.check(QStringLiteral("6.0c confirm RFPOWER ≤ 0.03 before keying"), |
| 1097 | c.ok(lines) && isFloat(safePwr) && safePwr.toDouble() <= 0.03, safePwr); |
| 1098 | |
| 1099 | lines = c.send(QStringLiteral("\\get_ptt")); |
| 1100 | const QString ptt = c.field(lines, QStringLiteral("PTT")); |
| 1101 | r.check(QStringLiteral("6.1 get_ptt returns 0 (RX) before keying"), |
| 1102 | c.ok(lines) && ptt == QLatin1String("0"), ptt); |
| 1103 | |
| 1104 | lines = c.send(QStringLiteral("\\set_ptt 1")); |
| 1105 | r.check(QStringLiteral("6.2 set_ptt 1 returns RPRT 0"), c.ok(lines)); |
| 1106 | QThread::msleep(1000); // hold TX 1 s so carrier is audible on dummy load |
| 1107 | |
| 1108 | lines = c.send(QStringLiteral("\\get_ptt")); |
| 1109 | const QString pttTx = c.field(lines, QStringLiteral("PTT")); |
| 1110 | r.check(QStringLiteral("6.3 get_ptt returns 1 while transmitting"), |
| 1111 | c.ok(lines) && pttTx == QLatin1String("1"), pttTx); |
| 1112 | |
| 1113 | lines = c.send(QStringLiteral("\\set_ptt 0")); |
| 1114 | r.check(QStringLiteral("6.4 set_ptt 0 returns RPRT 0"), c.ok(lines)); |
| 1115 | QThread::msleep(250); |
| 1116 | |
| 1117 | lines = c.send(QStringLiteral("\\get_ptt")); |
| 1118 | const QString pttRx = c.field(lines, QStringLiteral("PTT")); |
| 1119 | r.check(QStringLiteral("6.4b get_ptt returns 0 after releasing PTT"), |
| 1120 | c.ok(lines) && pttRx == QLatin1String("0"), pttRx); |
| 1121 | |
| 1122 | // VFO-prefixed short forms — sent by WSJT-X when chk_vfo=1. |
| 1123 | // Session is in extended mode (m_extended=true), so get_ptt returns 3 lines; |
| 1124 | // read all 3 to avoid poisoning subsequent sendRaw calls with leftover bytes. |
| 1125 | lines = c.sendRaw(QStringLiteral("t VFOA"), 3); |
| 1126 | r.check(QStringLiteral("6.4c t VFOA (get_ptt, VFO-prefixed) returns 0 in RX"), |
| 1127 | c.ok(lines) && c.field(lines, QStringLiteral("PTT")) == QLatin1String("0"), |
| 1128 | c.field(lines, QStringLiteral("PTT"))); |
| 1129 | |
| 1130 | lines = c.sendRaw(QStringLiteral("T VFOA 0"), 1); |
| 1131 | r.check(QStringLiteral("6.4d T VFOA 0 (set_ptt, VFO-prefixed) returns RPRT 0"), |