fix: OTA wait for 0xFF confirm before reboot, version bump to 15, improved logging
This commit is contained in:
parent
f74a4a5420
commit
516a938c7b
6 changed files with 87 additions and 28 deletions
Binary file not shown.
|
|
@ -373,7 +373,8 @@ class BleRelayManager(
|
||||||
((value[3].toInt() and 0xFF) shl 8) or
|
((value[3].toInt() and 0xFF) shl 8) or
|
||||||
(value[4].toInt() and 0xFF)
|
(value[4].toInt() and 0xFF)
|
||||||
} else 0
|
} else 0
|
||||||
Log.d(TAG, "OTA notify: status=$status seq=$seq")
|
val statusName = when (status) { 0x00 -> "ACK"; 0x01 -> "NAK"; 0x10 -> "COMPLETE"; 0x11 -> "ERROR"; else -> "UNKNOWN(0x${status.toString(16)})" }
|
||||||
|
Log.d(TAG, "OTA notify: status=$statusName seq=$seq raw=${value.joinToString("") { "%02X".format(it) }}")
|
||||||
handler.post { otaNotifyCallback?.onOtaNotify(status, seq) }
|
handler.post { otaNotifyCallback?.onOtaNotify(status, seq) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,7 @@ class OtaManager(
|
||||||
|
|
||||||
val notifyCallback = object : BleRelayManager.OtaNotifyCallback {
|
val notifyCallback = object : BleRelayManager.OtaNotifyCallback {
|
||||||
override fun onOtaNotify(status: Int, seq: Int) {
|
override fun onOtaNotify(status: Int, seq: Int) {
|
||||||
|
Log.d(TAG, "OTA notify received: status=0x${status.toString(16)} seq=$seq (0x00=ACK, 0x01=NAK, 0x10=COMPLETE, 0x11=ERROR)")
|
||||||
when (status) {
|
when (status) {
|
||||||
0x00 -> chunkAckReceived = true
|
0x00 -> chunkAckReceived = true
|
||||||
0x01 -> chunkNakReceived = true
|
0x01 -> chunkNakReceived = true
|
||||||
|
|
@ -163,7 +164,9 @@ class OtaManager(
|
||||||
withContext(Dispatchers.Main) { callback.onProgress(99, "Hash verifiëren...") }
|
withContext(Dispatchers.Main) { callback.onProgress(99, "Hash verifiëren...") }
|
||||||
|
|
||||||
finalStatusReceived = false
|
finalStatusReceived = false
|
||||||
relayManager.sendOtaData(sha256)
|
Log.d(TAG, "Sending SHA256 hash (${sha256.size} bytes) to ESP")
|
||||||
|
val shaSent = relayManager.sendOtaData(sha256)
|
||||||
|
Log.d(TAG, "SHA256 write result: $shaSent")
|
||||||
|
|
||||||
try {
|
try {
|
||||||
withTimeout(OTA_FINAL_TIMEOUT_MS) {
|
withTimeout(OTA_FINAL_TIMEOUT_MS) {
|
||||||
|
|
@ -173,14 +176,17 @@ class OtaManager(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (_: kotlinx.coroutines.TimeoutCancellationException) {
|
} catch (_: kotlinx.coroutines.TimeoutCancellationException) {
|
||||||
Log.w(TAG, "Timeout waiting for final OTA status")
|
Log.w(TAG, "Timeout waiting for final OTA status after SHA256")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Log.d(TAG, "Final status: received=$finalStatusReceived status=$finalStatus (0x10=COMPLETE, 0x11=ERROR)")
|
||||||
|
|
||||||
relayManager.setOtaNotifyCallback(null)
|
relayManager.setOtaNotifyCallback(null)
|
||||||
|
|
||||||
if (finalStatus == 0x10) {
|
if (finalStatus == 0x10) {
|
||||||
relayManager.sendOtaData(byteArrayOf(0xFF.toByte()))
|
Log.d(TAG, "ESP confirmed SHA256 OK, sending 0xFF reboot confirmation")
|
||||||
Log.d(TAG, "Sent 0xFF reboot confirmation to ESP")
|
val confirmSent = relayManager.sendOtaData(byteArrayOf(0xFF.toByte()))
|
||||||
|
Log.d(TAG, "0xFF write result: $confirmSent")
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
callback.onProgress(100, "Herstart...")
|
callback.onProgress(100, "Herstart...")
|
||||||
callback.onComplete()
|
callback.onComplete()
|
||||||
|
|
|
||||||
|
|
@ -424,7 +424,7 @@ void loop() {
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t heartbeat = 0;
|
static uint32_t heartbeat = 0;
|
||||||
if (millis() - heartbeat > 5000) {
|
if (millis() - heartbeat > 60000) {
|
||||||
Serial.printf("[heartbeat] t1=%s t2=%s btn=%s r1=%s r2=%s connected=%s\n",
|
Serial.printf("[heartbeat] t1=%s t2=%s btn=%s r1=%s r2=%s connected=%s\n",
|
||||||
t1Active ? "YES" : "no",
|
t1Active ? "YES" : "no",
|
||||||
t2Active ? "YES" : "no",
|
t2Active ? "YES" : "no",
|
||||||
|
|
|
||||||
100
src/main.cpp
100
src/main.cpp
|
|
@ -63,6 +63,11 @@ uint32_t otaWritten = 0;
|
||||||
uint8_t otaExpectedSha[32];
|
uint8_t otaExpectedSha[32];
|
||||||
mbedtls_sha256_context otaShaCtx;
|
mbedtls_sha256_context otaShaCtx;
|
||||||
bool otaShaStarted = false;
|
bool otaShaStarted = false;
|
||||||
|
bool otaReady = false;
|
||||||
|
bool otaEnded = false;
|
||||||
|
bool otaConfirmed = false;
|
||||||
|
uint32_t otaEndedAt = 0;
|
||||||
|
#define OTA_CONFIRM_TIMEOUT_MS 10000
|
||||||
|
|
||||||
uint8_t hmacKey[HMAC_KEY_LEN];
|
uint8_t hmacKey[HMAC_KEY_LEN];
|
||||||
uint8_t deviceUuid[ESP_UUID_LEN];
|
uint8_t deviceUuid[ESP_UUID_LEN];
|
||||||
|
|
@ -183,6 +188,9 @@ static void otaReset() {
|
||||||
otaPartition = nullptr;
|
otaPartition = nullptr;
|
||||||
otaExpectedSize = 0;
|
otaExpectedSize = 0;
|
||||||
otaWritten = 0;
|
otaWritten = 0;
|
||||||
|
otaReady = false;
|
||||||
|
otaEnded = false;
|
||||||
|
otaConfirmed = false;
|
||||||
if (otaShaStarted) {
|
if (otaShaStarted) {
|
||||||
mbedtls_sha256_free(&otaShaCtx);
|
mbedtls_sha256_free(&otaShaCtx);
|
||||||
otaShaStarted = false;
|
otaShaStarted = false;
|
||||||
|
|
@ -258,36 +266,40 @@ class OtaCharacteristicCallbacks : public NimBLECharacteristicCallbacks {
|
||||||
mbedtls_sha256_finish_ret(&otaShaCtx, computedSha);
|
mbedtls_sha256_finish_ret(&otaShaCtx, computedSha);
|
||||||
mbedtls_sha256_free(&otaShaCtx);
|
mbedtls_sha256_free(&otaShaCtx);
|
||||||
otaShaStarted = false;
|
otaShaStarted = false;
|
||||||
esp_err_t err = esp_ota_end(otaHandle);
|
|
||||||
if (err != ESP_OK) {
|
Serial.printf("OTA: SHA256 verify — written=%lu expected=%lu\n", otaWritten, otaExpectedSize);
|
||||||
Serial.printf("OTA: end failed (%d)\n", err);
|
|
||||||
otaReset();
|
|
||||||
sendOtaNotify(pChar, OTA_STATUS_ERROR, 0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (memcmp(computedSha, otaExpectedSha, 32) != 0) {
|
if (memcmp(computedSha, otaExpectedSha, 32) != 0) {
|
||||||
Serial.println("OTA: SHA256 mismatch — aborting");
|
Serial.println("OTA: SHA256 mismatch — aborting");
|
||||||
|
esp_ota_abort(otaHandle);
|
||||||
otaReset();
|
otaReset();
|
||||||
sendOtaNotify(pChar, OTA_STATUS_ERROR, 0);
|
sendOtaNotify(pChar, OTA_STATUS_ERROR, 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
err = esp_ota_set_boot_partition(otaPartition);
|
|
||||||
if (err != ESP_OK) {
|
|
||||||
Serial.printf("OTA: set boot partition failed (%d)\n", err);
|
|
||||||
otaReset();
|
|
||||||
sendOtaNotify(pChar, OTA_STATUS_ERROR, 0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
leds[0] = CRGB::Green;
|
|
||||||
FastLED.show();
|
|
||||||
sendOtaNotify(pChar, OTA_STATUS_COMPLETE, 0);
|
|
||||||
Serial.println("OTA: SHA256 OK, rebooting...");
|
|
||||||
delay(500);
|
|
||||||
esp_restart();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!otaInProgress) return;
|
Serial.println("OTA: SHA256 OK, setting otaReady=true, sending COMPLETE notify");
|
||||||
|
otaReady = true;
|
||||||
|
sendOtaNotify(pChar, OTA_STATUS_COMPLETE, 0);
|
||||||
|
Serial.printf("OTA: COMPLETE notify sent, otaReady=%d, otaConfirmed=%d, otaInProgress=%d\n",
|
||||||
|
otaReady, otaConfirmed, otaInProgress);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!otaInProgress) {
|
||||||
|
Serial.printf("OTA: write ignored — otaInProgress=false (len=%d, data0=0x%02X)\n", len, data[0]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len == 1 && data[0] == 0xFF) {
|
||||||
|
Serial.printf("OTA: 0xFF received — otaReady=%d, otaEnded=%d, otaConfirmed=%d, otaInProgress=%d\n",
|
||||||
|
otaReady, otaEnded, otaConfirmed, otaInProgress);
|
||||||
|
if (!otaEnded) {
|
||||||
|
Serial.println("OTA: 0xFF IGNORED — otaEnded is false (esp_ota_end not yet called or failed)");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Serial.println("OTA: 0xFF confirm accepted, setting otaConfirmed=true");
|
||||||
|
otaConfirmed = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (data[0] < 0x10) {
|
if (data[0] < 0x10) {
|
||||||
uint32_t seq = ((uint32_t)data[0] << 24) | ((uint32_t)data[1] << 16) |
|
uint32_t seq = ((uint32_t)data[0] << 24) | ((uint32_t)data[1] << 16) |
|
||||||
|
|
@ -521,6 +533,46 @@ void loop() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (otaReady) {
|
||||||
|
Serial.printf("OTA: loop() processing otaReady — otaWritten=%lu, otaExpectedSize=%lu\n",
|
||||||
|
otaWritten, otaExpectedSize);
|
||||||
|
esp_err_t err = esp_ota_end(otaHandle);
|
||||||
|
if (err != ESP_OK) {
|
||||||
|
Serial.printf("OTA: esp_ota_end failed (%d) — aborting\n", err);
|
||||||
|
otaReset();
|
||||||
|
} else {
|
||||||
|
Serial.println("OTA: esp_ota_end OK, setting otaEnded=true, waiting for 0xFF confirm");
|
||||||
|
otaEnded = true;
|
||||||
|
otaEndedAt = millis();
|
||||||
|
leds[0] = CRGB::Yellow;
|
||||||
|
FastLED.show();
|
||||||
|
}
|
||||||
|
otaReady = false;
|
||||||
|
Serial.printf("OTA: otaReady cleared — otaReady=%d, otaEnded=%d, otaConfirmed=%d, otaInProgress=%d\n",
|
||||||
|
otaReady, otaEnded, otaConfirmed, otaInProgress);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (otaEnded && !otaConfirmed && (millis() - otaEndedAt > OTA_CONFIRM_TIMEOUT_MS)) {
|
||||||
|
Serial.printf("OTA: 0xFF confirm timeout (%lu ms) — discarding update, resuming normal operation\n",
|
||||||
|
millis() - otaEndedAt);
|
||||||
|
otaReset();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (otaConfirmed) {
|
||||||
|
Serial.println("OTA: otaConfirmed=true, setting boot partition");
|
||||||
|
esp_err_t err = esp_ota_set_boot_partition(otaPartition);
|
||||||
|
if (err != ESP_OK) {
|
||||||
|
Serial.printf("OTA: set boot partition failed (%d)\n", err);
|
||||||
|
} else {
|
||||||
|
leds[0] = CRGB::Green;
|
||||||
|
FastLED.show();
|
||||||
|
Serial.println("OTA: done, rebooting...");
|
||||||
|
delay(500);
|
||||||
|
esp_restart();
|
||||||
|
}
|
||||||
|
otaReset();
|
||||||
|
}
|
||||||
|
|
||||||
static bool t1Stable = false;
|
static bool t1Stable = false;
|
||||||
static bool t2Stable = false;
|
static bool t2Stable = false;
|
||||||
static bool btnStable = false;
|
static bool btnStable = false;
|
||||||
|
|
@ -574,7 +626,7 @@ void loop() {
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t heartbeat = 0;
|
static uint32_t heartbeat = 0;
|
||||||
if (!otaInProgress && millis() - heartbeat > 5000) {
|
if (!otaInProgress && millis() - heartbeat > 60000) {
|
||||||
bool anyBle1 = (connActive[0] && bleRelay1[0]) || (connActive[1] && bleRelay1[1]);
|
bool anyBle1 = (connActive[0] && bleRelay1[0]) || (connActive[1] && bleRelay1[1]);
|
||||||
bool anyBle2 = (connActive[0] && bleRelay2[0]) || (connActive[1] && bleRelay2[1]);
|
bool anyBle2 = (connActive[0] && bleRelay2[0]) || (connActive[1] && bleRelay2[1]);
|
||||||
Serial.printf("[heartbeat] R1=%s R2=%s t1=%s t2=%s btn=%s ble1=%s ble2=%s clients=%d\n",
|
Serial.printf("[heartbeat] R1=%s R2=%s t1=%s t2=%s btn=%s ble1=%s ble2=%s clients=%d\n",
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,2 @@
|
||||||
server=8
|
server=15
|
||||||
client=1
|
client=1
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue