ESP32: добавить USB-диагностику регистрации Solana
This commit is contained in:
parent
21030b1d51
commit
436e1f0c53
@ -0,0 +1,45 @@
|
||||
# ESP32 USB-диагностика регистрации Solana
|
||||
|
||||
- статус: `pending`
|
||||
|
||||
## Что сделано
|
||||
|
||||
- В основной скетч `shine_homeserver_main` добавено сохранение последней диагностики регистрации Solana в `Preferences`.
|
||||
- Добавлены USB-команды через `Serial`:
|
||||
- `last_error`
|
||||
- `last_diag`
|
||||
- `reg_diag`
|
||||
- `clear_error`
|
||||
- `clear_diag`
|
||||
- `help`
|
||||
- Перед отправкой `create_user_pda` добавлена RPC-проверка `users_economy_config_pda`.
|
||||
- Стартовый `paid_limit_bytes` в подписываемой записи теперь берётся из on-chain `users_economy_config`, а не из хардкода.
|
||||
|
||||
## Что проверять
|
||||
|
||||
1. Подключить устройство по USB.
|
||||
2. Открыть последовательный порт `115200`.
|
||||
3. Отправить команду `last_error`.
|
||||
4. Убедиться, что устройство печатает сохранённую диагностику между маркерами:
|
||||
- `LAST_REGISTER_DIAG_BEGIN`
|
||||
- `LAST_REGISTER_DIAG_END`
|
||||
5. Запустить регистрацию с устройства и дождаться ошибки или успеха.
|
||||
6. Снова отправить `last_error`.
|
||||
7. Проверить, что в диагностике есть:
|
||||
- `status`
|
||||
- `summary`
|
||||
- `rpc`
|
||||
- `user_pda`
|
||||
- `users_economy_config_pda`
|
||||
- `inflow_vault_pda`
|
||||
- `root_pub`
|
||||
- `blockchain_pub`
|
||||
- `device_pub`
|
||||
8. При ошибке `0x3` проверить, что текст стал конкретнее и помогает понять, какая PDA или RPC-конфигурация не совпала.
|
||||
|
||||
## Ожидаемый результат
|
||||
|
||||
- Последняя ошибка регистрации читается по USB без просмотра экрана.
|
||||
- После неудачной регистрации на устройстве остаётся подробная диагностическая запись.
|
||||
- Если `users_economy_config_pda` отсутствует или принадлежит не той программе, это явно видно до отправки транзакции.
|
||||
|
||||
@ -256,6 +256,11 @@ static bool gRegisterConfirmCanSubmit = false;
|
||||
static String gRegisterResultMessage;
|
||||
static String gRegisterResultDetails;
|
||||
static bool gRegisterResultSuccess = false;
|
||||
static String gLastRegisterDiagStatus = "none";
|
||||
static String gLastRegisterDiagSummary;
|
||||
static String gLastRegisterDiagDetails;
|
||||
static String gLastRegisterDiagTime;
|
||||
static String gSerialCommandBuffer;
|
||||
static String gShineSessionId;
|
||||
static String gShineSessionKey;
|
||||
static String gShineStoragePwd;
|
||||
@ -362,6 +367,12 @@ static bool rpcCallSolana(const char *method, const String ¶msJson, String &
|
||||
static bool rpcResponseHasError(const String &payload);
|
||||
static bool getLatestBlockhashBytes(uint8_t out[32], String &blockhashB58, String &messageOut);
|
||||
static bool pdaAlreadyExists(const String &login, String &pdaAddress, String &messageOut);
|
||||
static bool loadUsersEconomyConfigState(const String &economyConfigAddress,
|
||||
uint64_t ®istrationFeeLamportsOut,
|
||||
uint64_t &lamportsPerLimitStepOut,
|
||||
uint64_t &startBonusLimitOut,
|
||||
String &messageOut);
|
||||
static bool loadAccountOwner(const String &address, String &ownerOut, bool &existsOut, String &messageOut);
|
||||
static bool extractRpcErrorSummary(const String &payload, String &messageOut);
|
||||
static String compactRpcLogs(const String &payload, int maxLines = 3);
|
||||
static bool simulateTransactionForError(const String &txBase64, String &messageOut);
|
||||
@ -374,6 +385,7 @@ static std::vector<uint8_t> buildUnsignedCreateRecord(
|
||||
const uint8_t devicePub[32],
|
||||
const uint8_t blockchainPub[32],
|
||||
const uint8_t lastBlockSignature[64],
|
||||
uint64_t paidLimitBytes,
|
||||
uint64_t createdAtMs);
|
||||
static std::vector<uint8_t> buildCreateInstructionData(
|
||||
const String &login,
|
||||
@ -399,6 +411,10 @@ static bool signMessageEd25519(const std::vector<uint8_t> &message, const uint8_
|
||||
static String encodeTransactionBase64(const uint8_t signature[64], const std::vector<uint8_t> &message);
|
||||
static bool awaitTransactionConfirmation(const String &signatureB58, String &messageOut);
|
||||
static bool registerHomeserverOnSolana(String &messageOut);
|
||||
static void saveRegisterDiag(const String &status, const String &summary, const String &details);
|
||||
static void printRegisterDiagToSerial();
|
||||
static void clearRegisterDiag();
|
||||
static void handleUsbSerialCommands();
|
||||
static void prepareRegisterAccountScreen();
|
||||
static String buildSessionKeyStringFromPublicBase64(const String &pubB64);
|
||||
static bool deriveKeypairFromSeed32(const uint8_t seed32[32], uint8_t pub32[32], uint8_t sec64[64]);
|
||||
@ -1140,6 +1156,7 @@ static std::vector<uint8_t> buildUnsignedCreateRecord(
|
||||
const uint8_t devicePub[32],
|
||||
const uint8_t blockchainPub[32],
|
||||
const uint8_t lastBlockSignature[64],
|
||||
uint64_t paidLimitBytes,
|
||||
uint64_t createdAtMs) {
|
||||
std::vector<uint8_t> out;
|
||||
out.reserve(512);
|
||||
@ -1169,7 +1186,7 @@ static std::vector<uint8_t> buildUnsignedCreateRecord(
|
||||
out.push_back(1);
|
||||
pushStrU8(out, blockchainName);
|
||||
pushFixed(out, blockchainPub, 32);
|
||||
pushU64LE(out, 100000);
|
||||
pushU64LE(out, paidLimitBytes);
|
||||
pushU64LE(out, 0);
|
||||
pushU32LE(out, 0);
|
||||
out.insert(out.end(), 32, 0);
|
||||
@ -1306,6 +1323,82 @@ static bool pdaAlreadyExists(const String &login, String &pdaAddress, String &me
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool loadAccountOwner(const String &address, String &ownerOut, bool &existsOut, String &messageOut) {
|
||||
ownerOut = "";
|
||||
existsOut = false;
|
||||
String payload;
|
||||
if (!rpcCallSolana("getAccountInfo", "[\"" + address + "\",{\"encoding\":\"base64\",\"commitment\":\"confirmed\"}]", payload)) {
|
||||
messageOut = "Failed to read account info";
|
||||
return false;
|
||||
}
|
||||
if (payload.indexOf("\"value\":null") >= 0) {
|
||||
existsOut = false;
|
||||
return true;
|
||||
}
|
||||
existsOut = true;
|
||||
if (!jsonStringField(payload, "owner", ownerOut) || ownerOut.isEmpty()) {
|
||||
messageOut = "Account owner missing in RPC response";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool loadUsersEconomyConfigState(const String &economyConfigAddress,
|
||||
uint64_t ®istrationFeeLamportsOut,
|
||||
uint64_t &lamportsPerLimitStepOut,
|
||||
uint64_t &startBonusLimitOut,
|
||||
String &messageOut) {
|
||||
registrationFeeLamportsOut = 0;
|
||||
lamportsPerLimitStepOut = 0;
|
||||
startBonusLimitOut = 0;
|
||||
|
||||
String payload;
|
||||
if (!rpcCallSolana("getAccountInfo", "[\"" + economyConfigAddress + "\",{\"encoding\":\"base64\",\"commitment\":\"confirmed\"}]", payload)) {
|
||||
messageOut = "Failed to read users economy config";
|
||||
return false;
|
||||
}
|
||||
if (payload.indexOf("\"value\":null") >= 0) {
|
||||
messageOut = "Users economy config is missing on this Solana RPC";
|
||||
return false;
|
||||
}
|
||||
|
||||
String owner;
|
||||
if (!jsonStringField(payload, "owner", owner) || owner.isEmpty()) {
|
||||
messageOut = "Users economy config owner is missing";
|
||||
return false;
|
||||
}
|
||||
if (owner != String(kShineUsersProgramId)) {
|
||||
messageOut = String("Users economy config owner mismatch: ") + owner;
|
||||
return false;
|
||||
}
|
||||
|
||||
String dataB64;
|
||||
if (!jsonStringField(payload, "data", dataB64) || dataB64.isEmpty()) {
|
||||
messageOut = "Users economy config base64 is missing";
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> raw;
|
||||
if (!base64DecodeStd(dataB64, raw)) {
|
||||
messageOut = "Users economy config base64 decode failed";
|
||||
return false;
|
||||
}
|
||||
if (raw.size() < 25) {
|
||||
messageOut = "Users economy config is too short";
|
||||
return false;
|
||||
}
|
||||
|
||||
registrationFeeLamportsOut = 0;
|
||||
lamportsPerLimitStepOut = 0;
|
||||
startBonusLimitOut = 0;
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
registrationFeeLamportsOut |= ((uint64_t)raw[1 + i]) << (8 * i);
|
||||
lamportsPerLimitStepOut |= ((uint64_t)raw[9 + i]) << (8 * i);
|
||||
startBonusLimitOut |= ((uint64_t)raw[17 + i]) << (8 * i);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static String compactRpcLogs(const String &payload, int maxLines) {
|
||||
String out;
|
||||
int pos = payload.indexOf("\"logs\"");
|
||||
@ -1490,22 +1583,33 @@ static bool awaitTransactionConfirmation(const String &signatureB58, String &mes
|
||||
|
||||
static bool registerHomeserverOnSolana(String &messageOut) {
|
||||
messageOut = "";
|
||||
String cleanLogin = normalizeLoginValue(gLoginValue);
|
||||
if (cleanLogin.isEmpty()) {
|
||||
messageOut = "Login is not set";
|
||||
String diagDetails;
|
||||
auto failWithDiag = [&](const String &summary) -> bool {
|
||||
messageOut = summary;
|
||||
saveRegisterDiag("error", summary, diagDetails);
|
||||
printRegisterDiagToSerial();
|
||||
return false;
|
||||
};
|
||||
|
||||
String cleanLogin = normalizeLoginValue(gLoginValue);
|
||||
diagDetails += String("login=") + cleanLogin + "\n";
|
||||
diagDetails += String("rpc=") + gSolanaRpcUrl + "\n";
|
||||
diagDetails += String("shine_server=") + gShineServerUrl + "\n";
|
||||
diagDetails += String("homeserver=") + gHomeserverValue + "\n";
|
||||
|
||||
if (cleanLogin.isEmpty()) {
|
||||
return failWithDiag("Login is not set");
|
||||
}
|
||||
if (!gSecretConfigured || gRootPrivB58.isEmpty() || gBlockchainPrivB58.isEmpty() || gDevicePrivB58.isEmpty()) {
|
||||
messageOut = "Secret is not ready";
|
||||
return false;
|
||||
return failWithDiag("Secret is not ready");
|
||||
}
|
||||
if (WiFi.status() != WL_CONNECTED) {
|
||||
messageOut = "Connect Wi-Fi first";
|
||||
return false;
|
||||
diagDetails += "wifi=disconnected\n";
|
||||
return failWithDiag("Connect Wi-Fi first");
|
||||
}
|
||||
diagDetails += String("wifi=connected:") + WiFi.localIP().toString() + "\n";
|
||||
if (gSolanaRpcUrl.isEmpty()) {
|
||||
messageOut = "Set Solana RPC first";
|
||||
return false;
|
||||
return failWithDiag("Set Solana RPC first");
|
||||
}
|
||||
|
||||
String existingPda;
|
||||
@ -1520,11 +1624,13 @@ static bool registerHomeserverOnSolana(String &messageOut) {
|
||||
gAccountStatusMessage = "User is already registered";
|
||||
gShineStatusLine = String("SHiNE: ") + (gShineServerUrl.isEmpty() ? "not set" : gShineServerUrl) + " registered";
|
||||
refreshAccountPdaStatus();
|
||||
diagDetails += String("user_pda=") + existingPda + "\n";
|
||||
saveRegisterDiag("ok", "User is already registered", diagDetails);
|
||||
return true;
|
||||
}
|
||||
if (pdaCheckMessage == "Failed to derive user PDA" || pdaCheckMessage == "Failed to check PDA" || pdaCheckMessage == "Unexpected getAccountInfo response") {
|
||||
messageOut = pdaCheckMessage;
|
||||
return false;
|
||||
diagDetails += String("user_pda_check=") + pdaCheckMessage + "\n";
|
||||
return failWithDiag(pdaCheckMessage);
|
||||
}
|
||||
|
||||
uint8_t userPda[32];
|
||||
@ -1540,10 +1646,44 @@ static bool registerHomeserverOnSolana(String &messageOut) {
|
||||
!findProgramAddress({
|
||||
std::vector<uint8_t>((const uint8_t *)kPaymentsInflowSeed, (const uint8_t *)kPaymentsInflowSeed + strlen(kPaymentsInflowSeed))
|
||||
}, kShinePaymentsProgramId, inflowVault)) {
|
||||
messageOut = "Failed to derive required PDAs";
|
||||
return false;
|
||||
return failWithDiag("Failed to derive required PDAs");
|
||||
}
|
||||
|
||||
String userPdaB58 = bytesToBase58(userPda, 32);
|
||||
String economyConfigB58 = bytesToBase58(economyConfig, 32);
|
||||
String inflowVaultB58 = bytesToBase58(inflowVault, 32);
|
||||
diagDetails += String("user_pda=") + userPdaB58 + "\n";
|
||||
diagDetails += String("users_economy_config_pda=") + economyConfigB58 + "\n";
|
||||
diagDetails += String("inflow_vault_pda=") + inflowVaultB58 + "\n";
|
||||
|
||||
String accountInfoMessage;
|
||||
String ownerValue;
|
||||
bool ownerExists = false;
|
||||
if (!loadAccountOwner(userPdaB58, ownerValue, ownerExists, accountInfoMessage)) {
|
||||
diagDetails += String("user_pda_rpc_error=") + accountInfoMessage + "\n";
|
||||
return failWithDiag(accountInfoMessage);
|
||||
}
|
||||
diagDetails += String("user_pda_exists=") + (ownerExists ? "true" : "false") + "\n";
|
||||
if (ownerExists) {
|
||||
diagDetails += String("user_pda_owner=") + ownerValue + "\n";
|
||||
return failWithDiag("User PDA already exists on RPC");
|
||||
}
|
||||
|
||||
uint64_t registrationFeeLamports = 0;
|
||||
uint64_t lamportsPerLimitStep = 0;
|
||||
uint64_t startBonusLimit = 0;
|
||||
if (!loadUsersEconomyConfigState(economyConfigB58,
|
||||
registrationFeeLamports,
|
||||
lamportsPerLimitStep,
|
||||
startBonusLimit,
|
||||
accountInfoMessage)) {
|
||||
diagDetails += String("users_economy_config_error=") + accountInfoMessage + "\n";
|
||||
return failWithDiag(accountInfoMessage);
|
||||
}
|
||||
diagDetails += String("registration_fee_lamports=") + String((unsigned long long)registrationFeeLamports) + "\n";
|
||||
diagDetails += String("lamports_per_limit_step=") + String((unsigned long long)lamportsPerLimitStep) + "\n";
|
||||
diagDetails += String("start_bonus_limit=") + String((unsigned long long)startBonusLimit) + "\n";
|
||||
|
||||
uint8_t rootSeed[32] = {};
|
||||
uint8_t rootPub[32] = {};
|
||||
uint8_t rootSec[64] = {};
|
||||
@ -1556,9 +1696,11 @@ static bool registerHomeserverOnSolana(String &messageOut) {
|
||||
if (!deriveSeedKeypairFromBase58(gRootPrivB58, rootSeed, rootPub, rootSec) ||
|
||||
!deriveSeedKeypairFromBase58(gBlockchainPrivB58, blockchainSeed, blockchainPub, blockchainSec) ||
|
||||
!deriveSeedKeypairFromBase58(gDevicePrivB58, deviceSeed, devicePub, deviceSec)) {
|
||||
messageOut = "Failed to restore keys";
|
||||
return false;
|
||||
return failWithDiag("Failed to restore keys");
|
||||
}
|
||||
diagDetails += String("root_pub=") + bytesToBase58(rootPub, 32) + "\n";
|
||||
diagDetails += String("blockchain_pub=") + bytesToBase58(blockchainPub, 32) + "\n";
|
||||
diagDetails += String("device_pub=") + bytesToBase58(devicePub, 32) + "\n";
|
||||
|
||||
String blockchainName = cleanLogin + "-001";
|
||||
std::vector<uint8_t> lastBlockState = buildLastBlockStateBytes(cleanLogin, blockchainName);
|
||||
@ -1566,21 +1708,19 @@ static bool registerHomeserverOnSolana(String &messageOut) {
|
||||
uint8_t lastBlockSignature[64];
|
||||
sha256calc(lastBlockState.data(), lastBlockState.size(), lastBlockHash);
|
||||
if (!signMessageEd25519(std::vector<uint8_t>(lastBlockHash, lastBlockHash + 32), blockchainSec, lastBlockSignature)) {
|
||||
messageOut = "Failed to sign LastBlockState";
|
||||
return false;
|
||||
return failWithDiag("Failed to sign LastBlockState");
|
||||
}
|
||||
|
||||
uint64_t createdAtMs = shineNowMs();
|
||||
std::vector<uint8_t> unsignedRecord = buildUnsignedCreateRecord(
|
||||
cleanLogin, blockchainName, gShineServerUrl,
|
||||
rootPub, devicePub, blockchainPub,
|
||||
lastBlockSignature, createdAtMs);
|
||||
lastBlockSignature, startBonusLimit, createdAtMs);
|
||||
uint8_t unsignedHash[32];
|
||||
uint8_t rootSignature[64];
|
||||
sha256calc(unsignedRecord.data(), unsignedRecord.size(), unsignedHash);
|
||||
if (!signMessageEd25519(std::vector<uint8_t>(unsignedHash, unsignedHash + 32), rootSec, rootSignature)) {
|
||||
messageOut = "Failed to sign PDA record";
|
||||
return false;
|
||||
return failWithDiag("Failed to sign PDA record");
|
||||
}
|
||||
|
||||
std::vector<uint8_t> createData = buildCreateInstructionData(
|
||||
@ -1593,8 +1733,10 @@ static bool registerHomeserverOnSolana(String &messageOut) {
|
||||
uint8_t recentBlockhash[32];
|
||||
String recentBlockhash58;
|
||||
if (!getLatestBlockhashBytes(recentBlockhash, recentBlockhash58, messageOut)) {
|
||||
return false;
|
||||
diagDetails += String("blockhash_error=") + messageOut + "\n";
|
||||
return failWithDiag(messageOut);
|
||||
}
|
||||
diagDetails += String("recent_blockhash=") + recentBlockhash58 + "\n";
|
||||
|
||||
std::vector<uint8_t> message = buildLegacyMessage(
|
||||
recentBlockhash,
|
||||
@ -1607,16 +1749,16 @@ static bool registerHomeserverOnSolana(String &messageOut) {
|
||||
createData);
|
||||
uint8_t txSignature[64];
|
||||
if (!signMessageEd25519(message, deviceSec, txSignature)) {
|
||||
messageOut = "Failed to sign Solana transaction";
|
||||
return false;
|
||||
return failWithDiag("Failed to sign Solana transaction");
|
||||
}
|
||||
String txBase64 = encodeTransactionBase64(txSignature, message);
|
||||
String signatureB58 = bytesToBase58(txSignature, 64);
|
||||
diagDetails += String("tx_signature=") + signatureB58 + "\n";
|
||||
|
||||
String payload;
|
||||
if (!rpcCallSolana("sendTransaction", "[\"" + txBase64 + "\",{\"encoding\":\"base64\",\"preflightCommitment\":\"confirmed\"}]", payload)) {
|
||||
messageOut = "RPC did not accept transaction";
|
||||
return false;
|
||||
diagDetails += "send_transaction_rpc_error=true\n";
|
||||
return failWithDiag("RPC did not accept transaction");
|
||||
}
|
||||
if (rpcResponseHasError(payload)) {
|
||||
if (!extractRpcErrorSummary(payload, messageOut)) {
|
||||
@ -1630,13 +1772,15 @@ static bool registerHomeserverOnSolana(String &messageOut) {
|
||||
messageOut += " | simulate: " + simulated;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
diagDetails += String("send_transaction_error=") + messageOut + "\n";
|
||||
return failWithDiag(messageOut);
|
||||
}
|
||||
if (!awaitTransactionConfirmation(signatureB58, messageOut)) {
|
||||
return false;
|
||||
diagDetails += String("confirmation_error=") + messageOut + "\n";
|
||||
return failWithDiag(messageOut);
|
||||
}
|
||||
|
||||
gUserPdaAddress = bytesToBase58(userPda, 32);
|
||||
gUserPdaAddress = userPdaB58;
|
||||
gRegistrationSignature = signatureB58;
|
||||
gAccountStatusMessage = "Solana registration complete";
|
||||
gAccountPdaStatus = ACCOUNT_PDA_OK;
|
||||
@ -1646,6 +1790,8 @@ static bool registerHomeserverOnSolana(String &messageOut) {
|
||||
saveAccountPrefs();
|
||||
refreshAccountPdaStatus();
|
||||
messageOut = "Solana registration confirmed";
|
||||
saveRegisterDiag("ok", messageOut, diagDetails);
|
||||
printRegisterDiagToSerial();
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -2573,6 +2719,10 @@ static void loadPrefs() {
|
||||
gShineStoragePwd = gPrefs.getString("shine_store_pwd", "");
|
||||
gUserPdaAddress = gPrefs.getString("user_pda", "");
|
||||
gRegistrationSignature = gPrefs.getString("registration_sig", "");
|
||||
gLastRegisterDiagStatus = gPrefs.getString("reg_diag_status", "none");
|
||||
gLastRegisterDiagSummary = gPrefs.getString("reg_diag_summary", "");
|
||||
gLastRegisterDiagDetails = gPrefs.getString("reg_diag_details", "");
|
||||
gLastRegisterDiagTime = gPrefs.getString("reg_diag_time", "");
|
||||
gBalanceStatusMessage = gDevicePubB58.isEmpty() ? "Balance: secret not set" : "Balance: tap to load";
|
||||
gAccountCheckPending = true;
|
||||
gLastAccountCheckMs = 0;
|
||||
@ -2687,6 +2837,71 @@ static String wifiHomeSummary() {
|
||||
return String("Wi-Fi (") + gWifiSavedSsid + ") disconnected";
|
||||
}
|
||||
|
||||
static void saveRegisterDiag(const String &status, const String &summary, const String &details) {
|
||||
gLastRegisterDiagStatus = status;
|
||||
gLastRegisterDiagSummary = summary.length() > 240 ? summary.substring(0, 240) : summary;
|
||||
gLastRegisterDiagDetails = details.length() > 1800 ? details.substring(0, 1800) : details;
|
||||
gLastRegisterDiagTime = String(shineNowMs());
|
||||
gPrefs.putString("reg_diag_status", gLastRegisterDiagStatus);
|
||||
gPrefs.putString("reg_diag_summary", gLastRegisterDiagSummary);
|
||||
gPrefs.putString("reg_diag_details", gLastRegisterDiagDetails);
|
||||
gPrefs.putString("reg_diag_time", gLastRegisterDiagTime);
|
||||
}
|
||||
|
||||
static void clearRegisterDiag() {
|
||||
gLastRegisterDiagStatus = "none";
|
||||
gLastRegisterDiagSummary = "";
|
||||
gLastRegisterDiagDetails = "";
|
||||
gLastRegisterDiagTime = "";
|
||||
gPrefs.remove("reg_diag_status");
|
||||
gPrefs.remove("reg_diag_summary");
|
||||
gPrefs.remove("reg_diag_details");
|
||||
gPrefs.remove("reg_diag_time");
|
||||
}
|
||||
|
||||
static void printRegisterDiagToSerial() {
|
||||
Serial.println("LAST_REGISTER_DIAG_BEGIN");
|
||||
Serial.println(String("status=") + gLastRegisterDiagStatus);
|
||||
Serial.println(String("time_ms=") + gLastRegisterDiagTime);
|
||||
Serial.println(String("summary=") + gLastRegisterDiagSummary);
|
||||
Serial.println("details<<");
|
||||
Serial.println(gLastRegisterDiagDetails);
|
||||
Serial.println(">>details");
|
||||
Serial.println("LAST_REGISTER_DIAG_END");
|
||||
}
|
||||
|
||||
static void handleUsbSerialCommands() {
|
||||
while (Serial.available() > 0) {
|
||||
char ch = (char)Serial.read();
|
||||
if (ch == '\r') {
|
||||
continue;
|
||||
}
|
||||
if (ch == '\n') {
|
||||
String cmd = gSerialCommandBuffer;
|
||||
gSerialCommandBuffer = "";
|
||||
cmd.trim();
|
||||
cmd.toLowerCase();
|
||||
if (cmd.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
if (cmd == "last_error" || cmd == "last_diag" || cmd == "reg_diag") {
|
||||
printRegisterDiagToSerial();
|
||||
} else if (cmd == "clear_error" || cmd == "clear_diag") {
|
||||
clearRegisterDiag();
|
||||
Serial.println("register diag cleared");
|
||||
} else if (cmd == "help") {
|
||||
Serial.println("commands: last_error, last_diag, reg_diag, clear_error, clear_diag, help");
|
||||
} else {
|
||||
Serial.println(String("unknown command: ") + cmd);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (gSerialCommandBuffer.length() < 120) {
|
||||
gSerialCommandBuffer += ch;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static String loginDisplayValue() {
|
||||
return gLoginValue.isEmpty() ? "login not set" : gLoginValue;
|
||||
}
|
||||
@ -4128,9 +4343,11 @@ void setup() {
|
||||
|
||||
rebuildScreen();
|
||||
Serial.println("Minimal nav test ready");
|
||||
Serial.println("USB diag commands: last_error, last_diag, reg_diag, clear_error, help");
|
||||
}
|
||||
|
||||
void loop() {
|
||||
handleUsbSerialCommands();
|
||||
lv_timer_handler();
|
||||
manageWifiReconnect();
|
||||
manageAccountPdaRefresh();
|
||||
|
||||
@ -1,2 +1,2 @@
|
||||
client.version=1.2.168
|
||||
server.version=1.2.157
|
||||
client.version=1.2.169
|
||||
server.version=1.2.158
|
||||
|
||||
Loading…
Reference in New Issue
Block a user