1.2-legacy
geeksville 2020-06-08 14:04:56 -07:00
rodzic 303fb86aa6
commit 420b718b11
4 zmienionych plików z 125 dodań i 45 usunięć

Wyświetl plik

@ -104,19 +104,6 @@
android:enabled="true"
android:exported="false" />
<!-- This is a private service which just does direct communication to the radio -->
<!-- <service
android:name="com.geeksville.mesh.service.SerialInterfaceService"
android:enabled="true"
android:exported="false">
<intent-filter>
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
</intent-filter>
<meta-data
android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
android:resource="@xml/device_filter" />
</service> -->
<activity
android:name="com.geeksville.mesh.MainActivity"
android:label="@string/app_name"
@ -137,6 +124,8 @@
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
@ -145,6 +134,11 @@
android:host="www.meshtastic.org"
android:pathPrefix="/c/" />
</intent-filter>
<!-- The USB devices we want to be informed about -->
<meta-data
android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
android:resource="@xml/device_filter" />
</activity>
<receiver android:name="com.geeksville.mesh.service.BootCompleteReceiver">

Wyświetl plik

@ -13,6 +13,8 @@ import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.pm.PackageManager
import android.hardware.usb.UsbDevice
import android.hardware.usb.UsbManager
import android.net.Uri
import android.os.Build
import android.os.Bundle
@ -427,6 +429,11 @@ class MainActivity : AppCompatActivity(), Logging,
// We now wait for the device to connect, once connected, we ask the user if they want to switch to the new channel
}
if (appLinkAction == UsbManager.ACTION_USB_ACCESSORY_ATTACHED) {
val device: UsbDevice = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE)!!
errormsg("Handle USB device attached! $device")
}
}
override fun onDestroy() {

Wyświetl plik

@ -6,44 +6,58 @@ import com.geeksville.android.Logging
import com.hoho.android.usbserial.driver.UsbSerialDriver
import com.hoho.android.usbserial.driver.UsbSerialPort
import com.hoho.android.usbserial.driver.UsbSerialProber
import kotlin.concurrent.thread
class SerialInterface(private val service: RadioInterfaceService, val address: String) : Logging,
IRadioInterface {
companion object {
companion object : Logging {
private const val START1 = 0x94.toByte()
private const val START2 = 0xc3.toByte()
private const val MAX_TO_FROM_RADIO_SIZE = 512
fun findDrivers(context: Context): List<UsbSerialDriver> {
val manager = context.getSystemService(Context.USB_SERVICE) as UsbManager
val drivers = UsbSerialProber.getDefaultProber().findAllDrivers(manager)
val devices = drivers.map { it.device }
devices.forEach { d ->
debug("Found serial port $d")
}
return drivers
}
}
private var uart: UsbSerialPort? = null
private val manager: UsbManager by lazy {
service.getSystemService(Context.USB_SERVICE) as UsbManager
}
private var uart: UsbSerialPort?
private lateinit var reader: Thread
init {
val drivers = UsbSerialProber.getDefaultProber().findAllDrivers(manager)
val manager = service.getSystemService(Context.USB_SERVICE) as UsbManager
val drivers = findDrivers(this)
// Open a connection to the first available driver.
// Open a connection to the first available driver.
val driver: UsbSerialDriver = drivers[0]
val connection = manager.openDevice(driver.device)
val device = drivers[0].device
info("Opening $device")
val connection = manager.openDevice(device)
if (connection == null) {
// FIXME add UsbManager.requestPermission(driver.getDevice(), ..) handling to activity
TODO()
// FIXME add UsbManager.requestPermission(device, ..) handling to activity
TODO("Need permissions for port")
} else {
val port = driver.ports[0] // Most devices have just one port (port 0)
val port = drivers[0].ports[0] // Most devices have just one port (port 0)
port.open(connection)
port.setParameters(921600, 8, UsbSerialPort.STOPBITS_1, UsbSerialPort.PARITY_NONE)
uart = port
debug("Starting serial reader thread")
// FIXME, start reading thread
reader =
thread(start = true, isDaemon = true, name = "serial reader", block = ::readerLoop)
}
}
override fun handleSendToRadio(p: ByteArray) {
// This method is called from a continuation and it might show up late, so check for uart being null
uart?.apply {
val header = ByteArray(4)
header[0] = START1
@ -57,7 +71,7 @@ class SerialInterface(private val service: RadioInterfaceService, val address: S
/** Print device serial debug output somewhere */
private fun debugOut(c: Byte) {
debug("Got c: ${c.toChar()}")
}
private fun readerLoop() {
@ -71,7 +85,7 @@ class SerialInterface(private val service: RadioInterfaceService, val address: S
var msb = 0
var lsb = 0
while (true) { // FIXME wait for someone to ask us to exit, and catch continuation exception
while (uart != null) { // we run until our port gets closed
uart?.apply {
read(scratch, 0)
val c = scratch[0]
@ -113,7 +127,8 @@ class SerialInterface(private val service: RadioInterfaceService, val address: S
}
override fun close() {
uart?.close()
debug("Closing serial port")
uart?.close() // This will cause the reader thread to exit
uart = null
}
}

Wyświetl plik

@ -2,6 +2,7 @@ package com.geeksville.mesh.ui
import android.annotation.SuppressLint
import android.app.Application
import android.app.PendingIntent
import android.bluetooth.BluetoothDevice
import android.bluetooth.BluetoothDevice.BOND_BONDED
import android.bluetooth.BluetoothDevice.BOND_BONDING
@ -11,6 +12,8 @@ import android.companion.AssociationRequest
import android.companion.BluetoothDeviceFilter
import android.companion.CompanionDeviceManager
import android.content.*
import android.hardware.usb.UsbDevice
import android.hardware.usb.UsbManager
import android.os.Bundle
import android.os.ParcelUuid
import android.view.LayoutInflater
@ -32,6 +35,7 @@ import com.geeksville.mesh.model.UIViewModel
import com.geeksville.mesh.service.BluetoothInterface
import com.geeksville.mesh.service.MeshService
import com.geeksville.mesh.service.RadioInterfaceService
import com.geeksville.mesh.service.SerialInterface
import com.geeksville.util.anonymize
import com.geeksville.util.exceptionReporter
import com.google.android.material.dialog.MaterialAlertDialogBuilder
@ -105,6 +109,9 @@ class BTScanModel(app: Application) : AndroidViewModel(app), Logging {
override fun toString(): String {
return "DeviceListEntry(name=${name.anonymize}, addr=${address.anonymize})"
}
val isBluetooth: Boolean get() = name[0] == 'x'
val isSerial: Boolean get() = name[0] == 's'
}
override fun onCleared() {
@ -116,10 +123,11 @@ class BTScanModel(app: Application) : AndroidViewModel(app), Logging {
val bluetoothAdapter =
(context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager?)?.adapter
private val usbManager = context.getSystemService(Context.USB_SERVICE) as UsbManager
var selectedAddress: String? = null
val errorText = object : MutableLiveData<String?>(null) {}
private var scanner: BluetoothLeScanner? = null
/// If this address is for a bluetooth device, return the macaddr portion, else null
@ -231,6 +239,17 @@ class BTScanModel(app: Application) : AndroidViewModel(app), Logging {
// Include a placeholder for "None"
addDevice(DeviceListEntry(context.getString(R.string.none), "n", true))
SerialInterface.findDrivers(context).forEach { d ->
val hasPerms = usbManager.hasPermission(d.device)
addDevice(
DeviceListEntry(
d.device.deviceName,
"s${d.device.deviceName}",
hasPerms
)
)
}
// filter and only accept devices that have a sw update service
val filter =
ScanFilter.Builder()
@ -279,25 +298,70 @@ class BTScanModel(app: Application) : AndroidViewModel(app), Logging {
changeScanSelection(activity, it.address)
return true
} else {
// We ignore missing BT adapters, because it lets us run on the emulator
bluetoothAdapter
?.getRemoteDevice(it.address)?.let { device ->
requestBonding(activity, device) { state ->
if (state == BOND_BONDED) {
errorText.value = activity.getString(R.string.pairing_completed)
changeScanSelection(
activity,
it.address
)
} else {
errorText.value = activity.getString(R.string.pairing_failed_try_again)
}
// Handle requestng USB or bluetooth permissions for the device
// Force the GUI to redraw
devices.value = devices.value
if (it.isBluetooth) {
// Request bonding for bluetooth
// We ignore missing BT adapters, because it lets us run on the emulator
bluetoothAdapter
?.getRemoteDevice(it.address)?.let { device ->
requestBonding(activity, device) { state ->
if (state == BOND_BONDED) {
errorText.value = activity.getString(R.string.pairing_completed)
changeScanSelection(
activity,
it.address
)
} else {
errorText.value =
activity.getString(R.string.pairing_failed_try_again)
}
// Force the GUI to redraw
devices.value = devices.value
}
}
}
if (it.isSerial) {
val ACTION_USB_PERMISSION = "com.geeksville.mesh.USB_PERMISSION"
val usbReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
if (ACTION_USB_PERMISSION == intent.action) {
val device: UsbDevice? =
intent.getParcelableExtra(UsbManager.EXTRA_DEVICE)
if (intent.getBooleanExtra(
UsbManager.EXTRA_PERMISSION_GRANTED,
false
)
) {
device?.apply {
info("User approved USB access")
changeScanSelection(activity, it.address)
// Force the GUI to redraw
devices.value = devices.value
}
} else {
errormsg("USB permission denied for device $device")
}
}
// We don't need to stay registered
activity.unregisterReceiver(this)
}
}
val permissionIntent =
PendingIntent.getBroadcast(activity, 0, Intent(ACTION_USB_PERMISSION), 0)
val filter = IntentFilter(ACTION_USB_PERMISSION)
activity.registerReceiver(usbReceiver, filter)
usbManager.requestPermission(device, permissionIntent)
}
return false
}
}