mirror of
https://github.com/meshtastic/Meshtastic-Android.git
synced 2026-04-20 22:23:37 +00:00
feat: Add ESP32 Unified OTA update support (#4095)
Signed-off-by: James Rich <2199651+jamesarich@users.noreply.github.com> Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
This commit is contained in:
parent
6b5dd24249
commit
2a60480bd9
40 changed files with 3410 additions and 717 deletions
|
|
@ -151,69 +151,76 @@ constructor(
|
|||
val attemptStart = System.currentTimeMillis()
|
||||
Logger.i { "[$address] TCP connection attempt starting..." }
|
||||
|
||||
val (host, port) =
|
||||
address.split(":", limit = 2).let { it[0] to (it.getOrNull(1)?.toIntOrNull() ?: SERVICE_PORT) }
|
||||
val parts = address.split(":", limit = 2)
|
||||
val host = parts[0]
|
||||
val port = parts.getOrNull(1)?.toIntOrNull() ?: SERVICE_PORT
|
||||
Logger.i { "[$address] Parsed address. Host: $host, Port: $port" }
|
||||
|
||||
Logger.d { "[$address] Resolving host '$host' and connecting to port $port..." }
|
||||
|
||||
Socket(InetAddress.getByName(host), port).use { socket ->
|
||||
socket.tcpNoDelay = true
|
||||
socket.soTimeout = SOCKET_TIMEOUT
|
||||
this@TCPInterface.socket = socket
|
||||
try {
|
||||
Socket(InetAddress.getByName(host), port).use { socket ->
|
||||
socket.tcpNoDelay = true
|
||||
socket.soTimeout = SOCKET_TIMEOUT
|
||||
this@TCPInterface.socket = socket
|
||||
|
||||
val connectTime = System.currentTimeMillis() - attemptStart
|
||||
connectionStartTime = System.currentTimeMillis()
|
||||
Logger.i {
|
||||
"[$address] TCP socket connected in ${connectTime}ms - " +
|
||||
"Local: ${socket.localSocketAddress}, Remote: ${socket.remoteSocketAddress}"
|
||||
}
|
||||
val connectTime = System.currentTimeMillis() - attemptStart
|
||||
connectionStartTime = System.currentTimeMillis()
|
||||
Logger.i {
|
||||
"[$address] TCP socket connected in ${connectTime}ms - " +
|
||||
"Local: ${socket.localSocketAddress}, Remote: ${socket.remoteSocketAddress}"
|
||||
}
|
||||
|
||||
BufferedOutputStream(socket.getOutputStream()).use { outputStream ->
|
||||
outStream = outputStream
|
||||
BufferedOutputStream(socket.getOutputStream()).use { outputStream ->
|
||||
outStream = outputStream
|
||||
|
||||
BufferedInputStream(socket.getInputStream()).use { inputStream ->
|
||||
super.connect()
|
||||
BufferedInputStream(socket.getInputStream()).use { inputStream ->
|
||||
super.connect()
|
||||
|
||||
retryCount = 1
|
||||
backoffDelay = MIN_BACKOFF_MILLIS
|
||||
retryCount = 1
|
||||
backoffDelay = MIN_BACKOFF_MILLIS
|
||||
|
||||
var timeoutCount = 0
|
||||
while (timeoutCount < SOCKET_RETRIES) {
|
||||
try { // close after 90s of inactivity
|
||||
val c = inputStream.read()
|
||||
if (c == -1) {
|
||||
Logger.w {
|
||||
"[$address] TCP got EOF on stream after $packetsReceived packets received"
|
||||
var timeoutCount = 0
|
||||
while (timeoutCount < SOCKET_RETRIES) {
|
||||
try { // close after 90s of inactivity
|
||||
val c = inputStream.read()
|
||||
if (c == -1) {
|
||||
Logger.w {
|
||||
"[$address] TCP got EOF on stream after $packetsReceived packets received"
|
||||
}
|
||||
break
|
||||
} else {
|
||||
timeoutCount = 0
|
||||
packetsReceived++
|
||||
bytesReceived++
|
||||
readChar(c.toByte())
|
||||
}
|
||||
break
|
||||
} else {
|
||||
timeoutCount = 0
|
||||
packetsReceived++
|
||||
bytesReceived++
|
||||
readChar(c.toByte())
|
||||
}
|
||||
} catch (ex: SocketTimeoutException) {
|
||||
timeoutCount++
|
||||
timeoutEvents++
|
||||
if (timeoutCount % TIMEOUT_LOG_INTERVAL == 0) {
|
||||
Logger.d {
|
||||
"[$address] TCP socket timeout count: $timeoutCount/$SOCKET_RETRIES " +
|
||||
"(total timeouts: $timeoutEvents)"
|
||||
} catch (ex: SocketTimeoutException) {
|
||||
timeoutCount++
|
||||
timeoutEvents++
|
||||
if (timeoutCount % TIMEOUT_LOG_INTERVAL == 0) {
|
||||
Logger.d {
|
||||
"[$address] TCP socket timeout count: $timeoutCount/$SOCKET_RETRIES " +
|
||||
"(total timeouts: $timeoutEvents)"
|
||||
}
|
||||
}
|
||||
// Ignore and start another read
|
||||
}
|
||||
// Ignore and start another read
|
||||
}
|
||||
}
|
||||
if (timeoutCount >= SOCKET_RETRIES) {
|
||||
val inactivityMs = SOCKET_RETRIES * SOCKET_TIMEOUT
|
||||
Logger.w {
|
||||
"[$address] TCP closing connection due to $SOCKET_RETRIES consecutive timeouts " +
|
||||
"(${inactivityMs}ms of inactivity)"
|
||||
if (timeoutCount >= SOCKET_RETRIES) {
|
||||
val inactivityMs = SOCKET_RETRIES * SOCKET_TIMEOUT
|
||||
Logger.w {
|
||||
"[$address] TCP closing connection due to $SOCKET_RETRIES consecutive timeouts " +
|
||||
"(${inactivityMs}ms of inactivity)"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
onDeviceDisconnect(false)
|
||||
}
|
||||
onDeviceDisconnect(false)
|
||||
} catch (e: IOException) {
|
||||
Logger.e(e) { "[$address] Error connecting to $host:$port" }
|
||||
throw e
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ package com.geeksville.mesh.service
|
|||
|
||||
import com.geeksville.mesh.concurrent.handledLaunch
|
||||
import com.geeksville.mesh.util.ignoreException
|
||||
import com.google.protobuf.ByteString
|
||||
import dagger.Lazy
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
|
|
@ -302,6 +303,16 @@ constructor(
|
|||
commandSender.sendAdmin(destNum, requestId) { rebootSeconds = DEFAULT_REBOOT_DELAY }
|
||||
}
|
||||
|
||||
fun handleRequestRebootOta(requestId: Int, destNum: Int, mode: Int, hash: ByteArray?) {
|
||||
val otaMode = AdminProtos.OTAMode.forNumber(mode) ?: AdminProtos.OTAMode.NO_REBOOT_OTA
|
||||
val otaEventBuilder = AdminProtos.AdminMessage.OTAEvent.newBuilder()
|
||||
otaEventBuilder.rebootOtaMode = otaMode
|
||||
if (hash != null) {
|
||||
otaEventBuilder.otaHash = ByteString.copyFrom(hash)
|
||||
}
|
||||
commandSender.sendAdmin(destNum, requestId) { otaRequest = otaEventBuilder.build() }
|
||||
}
|
||||
|
||||
fun handleRequestFactoryReset(requestId: Int, destNum: Int) {
|
||||
commandSender.sendAdmin(destNum, requestId) { factoryResetDevice = 1 }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ import org.meshtastic.core.service.ServiceRepository
|
|||
import javax.inject.Inject
|
||||
|
||||
@AndroidEntryPoint
|
||||
@Suppress("TooManyFunctions", "LargeClass")
|
||||
class MeshService : Service() {
|
||||
|
||||
@Inject lateinit var radioInterfaceService: RadioInterfaceService
|
||||
|
|
@ -342,5 +343,10 @@ class MeshService : Service() {
|
|||
override fun requestTelemetry(requestId: Int, destNum: Int, type: Int) = toRemoteExceptions {
|
||||
router.actionHandler.handleRequestTelemetry(requestId, destNum, type)
|
||||
}
|
||||
|
||||
override fun requestRebootOta(requestId: Int, destNum: Int, mode: Int, hash: ByteArray?) =
|
||||
toRemoteExceptions {
|
||||
router.actionHandler.handleRequestRebootOta(requestId, destNum, mode, hash)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue