mirror of
https://github.com/meshtastic/Meshtastic-Android.git
synced 2026-04-20 22:23:37 +00:00
feat/decoupling (#4685)
Signed-off-by: James Rich <2199651+jamesarich@users.noreply.github.com>
This commit is contained in:
parent
40244f8337
commit
2c49db8041
254 changed files with 5132 additions and 2666 deletions
|
|
@ -37,19 +37,20 @@ import kotlinx.coroutines.launch
|
|||
import kotlinx.coroutines.withTimeoutOrNull
|
||||
import org.jetbrains.compose.resources.StringResource
|
||||
import org.jetbrains.compose.resources.getString
|
||||
import org.meshtastic.core.data.repository.DeviceHardwareRepository
|
||||
import org.meshtastic.core.data.repository.FirmwareReleaseRepository
|
||||
import org.meshtastic.core.data.repository.NodeRepository
|
||||
import org.meshtastic.core.database.entity.FirmwareRelease
|
||||
import org.meshtastic.core.database.entity.FirmwareReleaseType
|
||||
import org.meshtastic.core.database.entity.MyNodeEntity
|
||||
import org.meshtastic.core.datastore.BootloaderWarningDataSource
|
||||
import org.meshtastic.core.model.ConnectionState
|
||||
import org.meshtastic.core.model.DeviceHardware
|
||||
import org.meshtastic.core.model.MyNodeInfo
|
||||
import org.meshtastic.core.model.RadioController
|
||||
import org.meshtastic.core.prefs.radio.RadioPrefs
|
||||
import org.meshtastic.core.prefs.radio.isBle
|
||||
import org.meshtastic.core.prefs.radio.isSerial
|
||||
import org.meshtastic.core.prefs.radio.isTcp
|
||||
import org.meshtastic.core.repository.DeviceHardwareRepository
|
||||
import org.meshtastic.core.repository.NodeRepository
|
||||
import org.meshtastic.core.resources.Res
|
||||
import org.meshtastic.core.resources.firmware_update_battery_low
|
||||
import org.meshtastic.core.resources.firmware_update_copying
|
||||
|
|
@ -72,7 +73,6 @@ import org.meshtastic.core.resources.firmware_update_unknown_hardware
|
|||
import org.meshtastic.core.resources.firmware_update_updating
|
||||
import org.meshtastic.core.resources.firmware_update_validating
|
||||
import org.meshtastic.core.resources.unknown
|
||||
import org.meshtastic.core.service.ServiceRepository
|
||||
import java.io.File
|
||||
import javax.inject.Inject
|
||||
|
||||
|
|
@ -95,7 +95,7 @@ constructor(
|
|||
private val firmwareReleaseRepository: FirmwareReleaseRepository,
|
||||
private val deviceHardwareRepository: DeviceHardwareRepository,
|
||||
private val nodeRepository: NodeRepository,
|
||||
private val serviceRepository: ServiceRepository,
|
||||
private val radioController: RadioController,
|
||||
private val radioPrefs: RadioPrefs,
|
||||
private val bootloaderWarningDataSource: BootloaderWarningDataSource,
|
||||
private val firmwareUpdateManager: FirmwareUpdateManager,
|
||||
|
|
@ -106,6 +106,8 @@ constructor(
|
|||
private val _state = MutableStateFlow<FirmwareUpdateState>(FirmwareUpdateState.Idle)
|
||||
val state: StateFlow<FirmwareUpdateState> = _state.asStateFlow()
|
||||
|
||||
val connectionState = radioController.connectionState
|
||||
|
||||
private val _selectedReleaseType = MutableStateFlow(FirmwareReleaseType.STABLE)
|
||||
val selectedReleaseType: StateFlow<FirmwareReleaseType> = _selectedReleaseType.asStateFlow()
|
||||
|
||||
|
|
@ -429,14 +431,14 @@ constructor(
|
|||
// Trigger a fresh connection attempt by MeshService
|
||||
address?.let { currentAddr ->
|
||||
Logger.i { "Post-update: Requesting MeshService to reconnect to $currentAddr" }
|
||||
serviceRepository.meshService?.setDeviceAddress("$DFU_RECONNECT_PREFIX$currentAddr")
|
||||
radioController.setDeviceAddress("$DFU_RECONNECT_PREFIX$currentAddr")
|
||||
}
|
||||
|
||||
// Wait for device to reconnect and settle
|
||||
val result =
|
||||
withTimeoutOrNull(VERIFY_TIMEOUT) {
|
||||
// Wait for both Connected state and node info to be present
|
||||
serviceRepository.connectionState.first { it is ConnectionState.Connected }
|
||||
connectionState.first { it is ConnectionState.Connected }
|
||||
nodeRepository.ourNodeInfo.filterNotNull().first()
|
||||
delay(VERIFY_DELAY) // Extra buffer for initial config sync
|
||||
true
|
||||
|
|
@ -462,7 +464,7 @@ constructor(
|
|||
return !isBatteryLow
|
||||
}
|
||||
|
||||
private suspend fun getDeviceHardware(ourNode: MyNodeEntity): DeviceHardware? {
|
||||
private suspend fun getDeviceHardware(ourNode: MyNodeInfo): DeviceHardware? {
|
||||
val nodeInfo = nodeRepository.ourNodeInfo.value
|
||||
val hwModelInt = nodeInfo?.user?.hw_model?.value
|
||||
val target = ourNode.pioEnv
|
||||
|
|
|
|||
|
|
@ -33,12 +33,12 @@ import no.nordicsemi.android.dfu.DfuServiceListenerHelper
|
|||
import org.jetbrains.compose.resources.getString
|
||||
import org.meshtastic.core.database.entity.FirmwareRelease
|
||||
import org.meshtastic.core.model.DeviceHardware
|
||||
import org.meshtastic.core.model.RadioController
|
||||
import org.meshtastic.core.resources.Res
|
||||
import org.meshtastic.core.resources.firmware_update_downloading_percent
|
||||
import org.meshtastic.core.resources.firmware_update_nordic_failed
|
||||
import org.meshtastic.core.resources.firmware_update_not_found_in_release
|
||||
import org.meshtastic.core.resources.firmware_update_starting_service
|
||||
import org.meshtastic.core.service.ServiceRepository
|
||||
import java.io.File
|
||||
import javax.inject.Inject
|
||||
|
||||
|
|
@ -53,7 +53,7 @@ class NordicDfuHandler
|
|||
constructor(
|
||||
private val firmwareRetriever: FirmwareRetriever,
|
||||
@ApplicationContext private val context: Context,
|
||||
private val serviceRepository: ServiceRepository,
|
||||
private val radioController: RadioController,
|
||||
) : FirmwareUpdateHandler {
|
||||
|
||||
override suspend fun startUpdate(
|
||||
|
|
@ -113,7 +113,7 @@ constructor(
|
|||
updateState(FirmwareUpdateState.Processing(ProgressState(startingMsg)))
|
||||
|
||||
// n = Nordic (Legacy prefix handling in mesh service)
|
||||
serviceRepository.meshService?.setDeviceAddress("n")
|
||||
radioController.setDeviceAddress("n")
|
||||
|
||||
DfuServiceInitiator(address)
|
||||
.setDeviceName(deviceHardware.displayName)
|
||||
|
|
|
|||
|
|
@ -23,12 +23,13 @@ import kotlinx.coroutines.delay
|
|||
import org.jetbrains.compose.resources.getString
|
||||
import org.meshtastic.core.database.entity.FirmwareRelease
|
||||
import org.meshtastic.core.model.DeviceHardware
|
||||
import org.meshtastic.core.model.RadioController
|
||||
import org.meshtastic.core.repository.NodeRepository
|
||||
import org.meshtastic.core.resources.Res
|
||||
import org.meshtastic.core.resources.firmware_update_downloading_percent
|
||||
import org.meshtastic.core.resources.firmware_update_rebooting
|
||||
import org.meshtastic.core.resources.firmware_update_retrieval_failed
|
||||
import org.meshtastic.core.resources.firmware_update_usb_failed
|
||||
import org.meshtastic.core.service.ServiceRepository
|
||||
import java.io.File
|
||||
import javax.inject.Inject
|
||||
|
||||
|
|
@ -40,7 +41,8 @@ class UsbUpdateHandler
|
|||
@Inject
|
||||
constructor(
|
||||
private val firmwareRetriever: FirmwareRetriever,
|
||||
private val serviceRepository: ServiceRepository,
|
||||
private val radioController: RadioController,
|
||||
private val nodeRepository: NodeRepository,
|
||||
) : FirmwareUpdateHandler {
|
||||
|
||||
override suspend fun startUpdate(
|
||||
|
|
@ -62,8 +64,8 @@ constructor(
|
|||
|
||||
if (firmwareUri != null) {
|
||||
updateState(FirmwareUpdateState.Processing(ProgressState(rebootingMsg)))
|
||||
val myNodeNum = serviceRepository.meshService?.getMyNodeInfo()?.myNodeNum ?: 0
|
||||
serviceRepository.meshService?.rebootToDfu(myNodeNum)
|
||||
val myNodeNum = nodeRepository.myNodeInfo.value?.myNodeNum ?: 0
|
||||
radioController.rebootToDfu(myNodeNum)
|
||||
delay(REBOOT_DELAY)
|
||||
|
||||
updateState(FirmwareUpdateState.AwaitingFileSave(null, "firmware.uf2", firmwareUri))
|
||||
|
|
@ -85,8 +87,8 @@ constructor(
|
|||
null
|
||||
} else {
|
||||
updateState(FirmwareUpdateState.Processing(ProgressState(rebootingMsg)))
|
||||
val myNodeNum = serviceRepository.meshService?.getMyNodeInfo()?.myNodeNum ?: 0
|
||||
serviceRepository.meshService?.rebootToDfu(myNodeNum)
|
||||
val myNodeNum = nodeRepository.myNodeInfo.value?.myNodeNum ?: 0
|
||||
radioController.rebootToDfu(myNodeNum)
|
||||
delay(REBOOT_DELAY)
|
||||
|
||||
updateState(FirmwareUpdateState.AwaitingFileSave(firmwareFile, firmwareFile.name))
|
||||
|
|
|
|||
|
|
@ -21,14 +21,18 @@ import android.net.Uri
|
|||
import co.touchlab.kermit.Logger
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import kotlinx.coroutines.CancellationException
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import no.nordicsemi.kotlin.ble.client.android.CentralManager
|
||||
import org.jetbrains.compose.resources.getString
|
||||
import org.meshtastic.core.common.util.nowMillis
|
||||
import org.meshtastic.core.database.entity.FirmwareRelease
|
||||
import org.meshtastic.core.model.DeviceHardware
|
||||
import org.meshtastic.core.model.RadioController
|
||||
import org.meshtastic.core.repository.NodeRepository
|
||||
import org.meshtastic.core.resources.Res
|
||||
import org.meshtastic.core.resources.firmware_update_connecting_attempt
|
||||
import org.meshtastic.core.resources.firmware_update_downloading_percent
|
||||
|
|
@ -40,7 +44,6 @@ import org.meshtastic.core.resources.firmware_update_retrieval_failed
|
|||
import org.meshtastic.core.resources.firmware_update_starting_ota
|
||||
import org.meshtastic.core.resources.firmware_update_uploading
|
||||
import org.meshtastic.core.resources.firmware_update_waiting_reboot
|
||||
import org.meshtastic.core.service.ServiceRepository
|
||||
import org.meshtastic.feature.firmware.FirmwareRetriever
|
||||
import org.meshtastic.feature.firmware.FirmwareUpdateHandler
|
||||
import org.meshtastic.feature.firmware.FirmwareUpdateState
|
||||
|
|
@ -68,7 +71,8 @@ class Esp32OtaUpdateHandler
|
|||
@Inject
|
||||
constructor(
|
||||
private val firmwareRetriever: FirmwareRetriever,
|
||||
private val serviceRepository: ServiceRepository,
|
||||
private val radioController: RadioController,
|
||||
private val nodeRepository: NodeRepository,
|
||||
private val centralManager: CentralManager,
|
||||
@ApplicationContext private val context: Context,
|
||||
) : FirmwareUpdateHandler {
|
||||
|
|
@ -201,13 +205,11 @@ constructor(
|
|||
}
|
||||
|
||||
private fun triggerRebootOta(mode: Int, hash: ByteArray?) {
|
||||
val service = serviceRepository.meshService ?: return
|
||||
try {
|
||||
val myInfo = service.getMyNodeInfo() ?: return
|
||||
Logger.i { "ESP32 OTA: Triggering reboot OTA mode $mode with hash" }
|
||||
service.requestRebootOta(service.getPacketId(), myInfo.myNodeNum, mode, hash)
|
||||
} catch (@Suppress("TooGenericExceptionCaught") e: Exception) {
|
||||
Logger.e(e) { "ESP32 OTA: Failed to trigger reboot OTA" }
|
||||
val myInfo = nodeRepository.myNodeInfo.value ?: return
|
||||
val myNodeNum = myInfo.myNodeNum
|
||||
Logger.i { "ESP32 OTA: Triggering reboot OTA mode $mode with hash" }
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
radioController.requestRebootOta(radioController.getPacketId(), myNodeNum, mode, hash)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -216,12 +218,8 @@ constructor(
|
|||
* interface) cleanly disconnects without reconnection attempts.
|
||||
*/
|
||||
private fun disconnectMeshService() {
|
||||
try {
|
||||
Logger.i { "ESP32 OTA: Disconnecting mesh service for OTA" }
|
||||
serviceRepository.meshService?.setDeviceAddress("n")
|
||||
} catch (@Suppress("TooGenericExceptionCaught") e: Exception) {
|
||||
Logger.w(e) { "ESP32 OTA: Error disconnecting mesh service" }
|
||||
}
|
||||
Logger.i { "ESP32 OTA: Disconnecting mesh service for OTA" }
|
||||
radioController.setDeviceAddress("n")
|
||||
}
|
||||
|
||||
private suspend fun obtainFirmwareFile(
|
||||
|
|
|
|||
|
|
@ -33,7 +33,8 @@ import org.junit.Before
|
|||
import org.junit.Test
|
||||
import org.meshtastic.core.database.entity.FirmwareRelease
|
||||
import org.meshtastic.core.model.DeviceHardware
|
||||
import org.meshtastic.core.service.ServiceRepository
|
||||
import org.meshtastic.core.model.RadioController
|
||||
import org.meshtastic.core.repository.NodeRepository
|
||||
import org.meshtastic.feature.firmware.FirmwareRetriever
|
||||
import org.meshtastic.feature.firmware.FirmwareUpdateState
|
||||
import java.io.IOException
|
||||
|
|
@ -42,12 +43,14 @@ import java.io.IOException
|
|||
class Esp32OtaUpdateHandlerTest {
|
||||
|
||||
private val firmwareRetriever: FirmwareRetriever = mockk()
|
||||
private val serviceRepository: ServiceRepository = mockk()
|
||||
private val radioController: RadioController = mockk()
|
||||
private val nodeRepository: NodeRepository = mockk()
|
||||
private val centralManager: CentralManager = mockk()
|
||||
private val context: Context = mockk()
|
||||
private val contentResolver: ContentResolver = mockk()
|
||||
|
||||
private val handler = Esp32OtaUpdateHandler(firmwareRetriever, serviceRepository, centralManager, context)
|
||||
private val handler =
|
||||
Esp32OtaUpdateHandler(firmwareRetriever, radioController, nodeRepository, centralManager, context)
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue