kopia lustrzana https://github.com/meshtastic/Meshtastic-Android
WIP add concept of interface factories
rodzic
2ec15bf7b1
commit
2c75d0dee7
|
@ -78,7 +78,15 @@ A variable keepAllPackets, if set to true will suppress this behavior and instea
|
|||
class BluetoothInterface(val service: RadioInterfaceService, val address: String) : IRadioInterface,
|
||||
Logging {
|
||||
|
||||
companion object : Logging {
|
||||
companion object : Logging, InterfaceFactory('x') {
|
||||
override fun createInterface(
|
||||
service: RadioInterfaceService,
|
||||
rest: String
|
||||
): IRadioInterface = BluetoothInterface(service, rest)
|
||||
|
||||
init {
|
||||
registerFactory()
|
||||
}
|
||||
|
||||
/// this service UUID is publically visible for scanning
|
||||
val BTM_SERVICE_UUID = UUID.fromString("6ba1b218-15a8-461f-9fa8-5dcae273eafd")
|
||||
|
@ -100,12 +108,12 @@ class BluetoothInterface(val service: RadioInterfaceService, val address: String
|
|||
fun toInterfaceName(deviceName: String) = "x$deviceName"
|
||||
|
||||
/** Return true if this address is still acceptable. For BLE that means, still bonded */
|
||||
fun addressValid(context: Context, address: String): Boolean {
|
||||
override fun addressValid(context: Context, rest: String): Boolean {
|
||||
val allPaired =
|
||||
getBluetoothAdapter(context)?.bondedDevices.orEmpty().map { it.address }.toSet()
|
||||
|
||||
return if (!allPaired.contains(address)) {
|
||||
warn("Ignoring stale bond to ${address.anonymize}")
|
||||
return if (!allPaired.contains(rest)) {
|
||||
warn("Ignoring stale bond to ${rest.anonymize}")
|
||||
false
|
||||
} else
|
||||
true
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
package com.geeksville.mesh.service
|
||||
|
||||
import android.content.Context
|
||||
|
||||
/**
|
||||
* A base class for the singleton factories that make interfaces. One instance per interface type
|
||||
*/
|
||||
abstract class InterfaceFactory(val prefix: Char) {
|
||||
companion object {
|
||||
private val factories = mutableMapOf<Char, InterfaceFactory>()
|
||||
|
||||
fun getFactory(l: Char) = factories.get(l)
|
||||
}
|
||||
|
||||
protected fun registerFactory() {
|
||||
factories[prefix] = this
|
||||
}
|
||||
|
||||
abstract fun createInterface(service: RadioInterfaceService, rest: String): IRadioInterface
|
||||
|
||||
/** Return true if this address is still acceptable. For BLE that means, still bonded */
|
||||
open fun addressValid(context: Context, rest: String): Boolean = true
|
||||
}
|
|
@ -8,9 +8,15 @@ import okhttp3.internal.toHexString
|
|||
|
||||
/** A simulated interface that is used for testing in the simulator */
|
||||
class MockInterface(private val service: RadioInterfaceService) : Logging, IRadioInterface {
|
||||
companion object : Logging {
|
||||
companion object : Logging, InterfaceFactory('m') {
|
||||
override fun createInterface(
|
||||
service: RadioInterfaceService,
|
||||
rest: String
|
||||
): IRadioInterface = MockInterface(service)
|
||||
|
||||
const val interfaceName = "m"
|
||||
init {
|
||||
registerFactory()
|
||||
}
|
||||
}
|
||||
|
||||
private var messageCount = 50
|
||||
|
|
|
@ -1,7 +1,20 @@
|
|||
package com.geeksville.mesh.service
|
||||
|
||||
import com.geeksville.android.Logging
|
||||
|
||||
class NopInterface : IRadioInterface {
|
||||
override fun handleSendToRadio(p: ByteArray) {
|
||||
companion object : Logging, InterfaceFactory('n') {
|
||||
override fun createInterface(
|
||||
service: RadioInterfaceService,
|
||||
rest: String
|
||||
): IRadioInterface = NopInterface()
|
||||
|
||||
init {
|
||||
registerFactory()
|
||||
}
|
||||
}
|
||||
|
||||
override fun handleSendToRadio(p: ByteArray) {
|
||||
}
|
||||
|
||||
override fun close() {
|
||||
|
|
|
@ -78,7 +78,7 @@ class RadioInterfaceService : Service(), Logging {
|
|||
|
||||
// If we are running on the emulator we default to the mock interface, so we can have some data to show to the user
|
||||
if(address == null && isMockInterfaceAvailable(context))
|
||||
address = MockInterface.interfaceName
|
||||
address = MockInterface.prefix.toString()
|
||||
|
||||
return address
|
||||
}
|
||||
|
@ -104,13 +104,7 @@ class RadioInterfaceService : Service(), Logging {
|
|||
if (address != null) {
|
||||
val c = address[0]
|
||||
val rest = address.substring(1)
|
||||
val isValid = when (c) {
|
||||
'x' -> BluetoothInterface.addressValid(context, rest)
|
||||
's' -> SerialInterface.addressValid(context, rest)
|
||||
'n' -> true
|
||||
'm' -> true
|
||||
else -> TODO("Unexpected interface type $c")
|
||||
}
|
||||
val isValid = InterfaceFactory.getFactory(c)?.addressValid(context, rest) ?: false
|
||||
if (!isValid)
|
||||
return null
|
||||
}
|
||||
|
@ -131,8 +125,7 @@ class RadioInterfaceService : Service(), Logging {
|
|||
*/
|
||||
var serviceScope = CoroutineScope(Dispatchers.IO + Job())
|
||||
|
||||
private val nopIf = NopInterface()
|
||||
private var radioIf: IRadioInterface = nopIf
|
||||
private var radioIf: IRadioInterface = NopInterface()
|
||||
|
||||
/** true if we have started our interface
|
||||
*
|
||||
|
@ -217,7 +210,7 @@ class RadioInterfaceService : Service(), Logging {
|
|||
|
||||
/** Start our configured interface (if it isn't already running) */
|
||||
private fun startInterface() {
|
||||
if (radioIf != nopIf)
|
||||
if (radioIf !is NopInterface)
|
||||
warn("Can't start interface - $radioIf is already running")
|
||||
else {
|
||||
val address = getBondedDeviceAddress(this)
|
||||
|
@ -234,26 +227,17 @@ class RadioInterfaceService : Service(), Logging {
|
|||
|
||||
val c = address[0]
|
||||
val rest = address.substring(1)
|
||||
radioIf = when (c) {
|
||||
'x' -> BluetoothInterface(this, rest)
|
||||
's' -> SerialInterface(this, rest)
|
||||
'm' -> MockInterface(this)
|
||||
'n' -> nopIf
|
||||
else -> {
|
||||
errormsg("Unexpected radio interface type")
|
||||
nopIf
|
||||
}
|
||||
}
|
||||
radioIf = InterfaceFactory.getFactory(c)?.createInterface(this, rest) ?:
|
||||
NopInterface()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun stopInterface() {
|
||||
val r = radioIf
|
||||
info("stopping interface $r")
|
||||
isStarted = false
|
||||
radioIf = nopIf
|
||||
radioIf = NopInterface()
|
||||
r.close()
|
||||
|
||||
// cancel any old jobs and get ready for the new ones
|
||||
|
@ -266,7 +250,7 @@ class RadioInterfaceService : Service(), Logging {
|
|||
receivedPacketsLog.close()
|
||||
|
||||
// Don't broadcast disconnects if we were just using the nop device
|
||||
if (r != nopIf)
|
||||
if (r !is NopInterface)
|
||||
onDisconnect(isPermanent = true) // Tell any clients we are now offline
|
||||
}
|
||||
|
||||
|
|
|
@ -21,7 +21,15 @@ import com.hoho.android.usbserial.util.SerialInputOutputManager
|
|||
*/
|
||||
class SerialInterface(service: RadioInterfaceService, private val address: String) :
|
||||
StreamInterface(service), Logging, SerialInputOutputManager.Listener {
|
||||
companion object : Logging {
|
||||
companion object : Logging, InterfaceFactory('s') {
|
||||
override fun createInterface(
|
||||
service: RadioInterfaceService,
|
||||
rest: String
|
||||
): IRadioInterface = SerialInterface(service, rest)
|
||||
|
||||
init {
|
||||
registerFactory()
|
||||
}
|
||||
|
||||
/**
|
||||
* according to https://stackoverflow.com/questions/12388914/usb-device-access-pop-up-suppression/15151075#15151075
|
||||
|
@ -41,14 +49,14 @@ class SerialInterface(service: RadioInterfaceService, private val address: Strin
|
|||
return drivers
|
||||
}
|
||||
|
||||
fun addressValid(context: Context, rest: String): Boolean {
|
||||
override fun addressValid(context: Context, rest: String): Boolean {
|
||||
findSerial(context, rest)?.let { d ->
|
||||
return assumePermission || context.usbManager.hasPermission(d.device)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
fun findSerial(context: Context, rest: String): UsbSerialDriver? {
|
||||
private fun findSerial(context: Context, rest: String): UsbSerialDriver? {
|
||||
val drivers = findDrivers(context)
|
||||
|
||||
return if (drivers.isEmpty())
|
||||
|
@ -61,7 +69,7 @@ class SerialInterface(service: RadioInterfaceService, private val address: Strin
|
|||
private var uart: UsbSerialDriver? = null
|
||||
private var ioManager: SerialInputOutputManager? = null
|
||||
|
||||
var usbReceiver = object : BroadcastReceiver() {
|
||||
private var usbReceiver = object : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context, intent: Intent) = exceptionReporter {
|
||||
|
||||
if (UsbManager.ACTION_USB_DEVICE_DETACHED == intent.action) {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package com.geeksville.mesh.service
|
||||
|
||||
import com.geeksville.android.Logging
|
||||
import java.io.*
|
||||
import java.net.InetAddress
|
||||
import java.net.Socket
|
||||
|
@ -9,7 +10,18 @@ import kotlin.concurrent.thread
|
|||
class TCPInterface(service: RadioInterfaceService, private val address: String) :
|
||||
StreamInterface(service) {
|
||||
|
||||
var socket: Socket? = null
|
||||
companion object : Logging, InterfaceFactory('t') {
|
||||
override fun createInterface(
|
||||
service: RadioInterfaceService,
|
||||
rest: String
|
||||
): IRadioInterface = TCPInterface(service, rest)
|
||||
|
||||
init {
|
||||
registerFactory()
|
||||
}
|
||||
}
|
||||
|
||||
var socket: Socket? = null
|
||||
lateinit var outStream: OutputStream
|
||||
lateinit var inStream: InputStream
|
||||
|
||||
|
|
Ładowanie…
Reference in New Issue