Added DigiRig backend and some UI elements in the AFSK config screen.

pull/383/head
Charlie Burrows 2023-03-14 00:51:10 -04:00 zatwierdzone przez Alex Thorlton
rodzic d38a0dae39
commit f2a3cbdda1
6 zmienionych plików z 239 dodań i 3 usunięć

Wyświetl plik

@ -325,6 +325,8 @@
<string name="p_afsk_btsco">Bluetooth Headset</string>
<string name="p_afsk_btsco_summary">Use Bluetooth (SCO) headset for AFSK</string>
<string name="p_afsk_output">Audio Output</string>
<string name="p_afsk_ptt">Use Push-to-Talk</string>
<string name="p_afsk_pttport">Push-to-Talk Port</string>
<string-array name="p_afsk_out_e">
<item>Voice Call</item>
<item>Ringtone</item>

Wyświetl plik

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceCategory
android:title="@string/p_link_usb">
<de.duenndns.ListPreferenceWithValue
android:key="baudrate"
android:title="@string/p_serial_baudrate"
android:summary="@string/p_serial_baudrate_summary"
android:entries="@array/p_serial_baudrates"
android:entryValues="@array/p_serial_baudrates"
android:defaultValue="115200"
android:dialogTitle="@string/p_serial_baudrate" />
</PreferenceCategory>
</PreferenceScreen>

Wyświetl plik

@ -37,8 +37,20 @@
android:title="@string/p_afsk_prefix"
android:summary="@string/p_afsk_prefix_summary"
android:dialogTitle="@string/p_afsk_prefix_entry" />
<CheckBoxPreference
android:defaultValue="false"
android:key="afsk.ptt"
android:title="@string/p_afsk_ptt"
android:visibility="visible" />
<EditTextPreference
android:defaultValue="Default value"
android:key="afsk.pttport"
android:selectAllOnFocus="true"
android:singleLine="true"
android:title="@string/p_afsk_pttport"
android:visibility="visible" />
</PreferenceCategory>
</PreferenceCategory>
</PreferenceScreen>

Wyświetl plik

@ -102,6 +102,8 @@ class PrefsWrapper(val context : Context) {
def getProto() = getString("proto", "aprsis")
def getAfskHQ() = getBoolean("afsk.hqdemod", true)
def getAfskRTS() = getBoolean("afsk.ptt", false)
def getPTTPort() = getString("afsk.pttport", "")
def getAfskBluetooth() = getBoolean("afsk.btsco", false) && getAfskHQ()
def getAfskOutput() = if (getAfskBluetooth()) AudioManager.STREAM_VOICE_CALL else getStringInt("afsk.output", 0)
}

Wyświetl plik

@ -3,6 +3,7 @@ package org.aprsdroid.app
import android.Manifest
import android.os.Build
import _root_.net.ab0oo.aprs.parser.APRSPacket
import _root_.java.io.{InputStream, OutputStream}
object AprsBackend {
@ -94,7 +95,14 @@ object AprsBackend {
R.xml.backend_usb,
Set(),
CAN_DUPLEX,
PASSCODE_NONE)
PASSCODE_NONE),
"digirig" -> new BackendInfo(
(s, p) => new DigiRig(s, p),
R.xml.backend_digirig,
Set(),
CAN_DUPLEX,
PASSCODE_NONE
)
)
class ProtoInfo(
@ -119,7 +127,7 @@ object AprsBackend {
"kenwood" -> new ProtoInfo(
(s, is, os) => new KenwoodProto(s, is, os),
R.xml.proto_kenwood, "link")
);
)
def defaultProtoInfo(p : String) : ProtoInfo = {
proto_collection.get(p) match {
case Some(pi) => pi

Wyświetl plik

@ -0,0 +1,193 @@
package org.aprsdroid.app
import android.app.PendingIntent
import android.app.Service
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.SharedPreferences
import android.hardware.usb.UsbManager
import android.hardware.usb.UsbDevice
import android.hardware.usb.UsbDeviceConnection
import android.util.Log
import java.io.{InputStream, OutputStream}
import net.ab0oo.aprs.parser._
import com.felhr.usbserial._
object DigiRig {
def deviceHandle(dev : UsbDevice) = {
"usb_%04x_%04x_%s".format(dev.getVendorId(), dev.getProductId(), dev.getDeviceName())
}
def checkDeviceHandle(prefs : SharedPreferences, dev_p : android.os.Parcelable) : Boolean = {
if (dev_p == null)
return false
val dev = dev_p.asInstanceOf[UsbDevice]
val last_use = prefs.getString(deviceHandle(dev), null)
if (last_use == null)
return false
prefs.edit().putString("proto", last_use)
.putString("link", "usb").commit()
true
}
}
class DigiRig(service : AprsService, prefs : PrefsWrapper) extends AprsBackend(prefs) {
val TAG = "APRSdroid.Usb"
val USB_PERM_ACTION = "org.aprsdroid.app.DigiRig.PERM"
val ACTION_USB_ATTACHED = "android.hardware.usb.action.USB_DEVICE_ATTACHED"
val ACTION_USB_DETACHED = "android.hardware.usb.action.USB_DEVICE_DETACHED"
val usbManager = service.getSystemService(Context.USB_SERVICE).asInstanceOf[UsbManager];
var thread : UsbThread = null
var dev : UsbDevice = null
var con : UsbDeviceConnection = null
var ser : UsbSerialInterface = null
var alreadyRunning = false
val intent = new Intent(USB_PERM_ACTION)
val pendingIntent = PendingIntent.getBroadcast(service, 0, intent, 0)
val receiver = new BroadcastReceiver() {
override def onReceive(ctx : Context, i : Intent) {
Log.d(TAG, "onReceive: " + i)
if (i.getAction() == ACTION_USB_DETACHED) {
log("USB device detached.")
ctx.stopService(AprsService.intent(ctx, AprsService.SERVICE))
return
}
val granted = i.getExtras().getBoolean(UsbManager.EXTRA_PERMISSION_GRANTED)
if (!granted) {
service.postAbort(service.getString(R.string.p_serial_noperm))
return
}
log("Obtained USB permissions.")
thread = new UsbThread()
thread.start()
}
}
var proto : TncProto = null
var sis : SerialInputStream = null
def start() = {
val filter = new IntentFilter(USB_PERM_ACTION)
filter.addAction(ACTION_USB_DETACHED)
service.registerReceiver(receiver, filter)
alreadyRunning = true
if (ser == null)
requestPermissions()
false
}
def log(s : String) {
service.postAddPost(StorageDatabase.Post.TYPE_INFO, R.string.post_info, s)
}
def requestPermissions() {
Log.d(TAG, "UsbTnc.requestPermissions");
val dl = usbManager.getDeviceList();
var requested = false
import scala.collection.JavaConversions._
for ((name, dev) <- dl) {
val deviceVID = dev.getVendorId()
val devicePID = dev.getProductId()
if (UsbSerialDevice.isSupported(dev)) {
// this is not a USB Hub
log("Found USB device %04x:%04x, requesting permissions.".format(deviceVID, devicePID))
this.dev = dev
usbManager.requestPermission(dev, pendingIntent)
return
} else
log("Unsupported USB device %04x:%04x.".format(deviceVID, devicePID))
}
service.postAbort(service.getString(R.string.p_serial_notfound))
}
def update(packet : APRSPacket) : String = {
proto.writePacket(packet)
"USB OK"
}
def stop() {
if (alreadyRunning)
service.unregisterReceiver(receiver)
alreadyRunning = false
if (ser != null)
ser.close()
if (sis != null)
sis.close()
if (con != null)
con.close()
if (thread == null)
return
thread.synchronized {
thread.running = false
}
//thread.shutdown()
thread.interrupt()
thread.join(50)
if (proto != null)
proto.stop()
}
class UsbThread()
extends Thread("APRSdroid USB connection") {
val TAG = "UsbThread"
var running = true
def log(s : String) {
service.postAddPost(StorageDatabase.Post.TYPE_INFO, R.string.post_info, s)
}
override def run() {
val con = usbManager.openDevice(dev)
ser = UsbSerialDevice.createUsbSerialDevice(dev, con)
if (ser == null || !ser.syncOpen()) {
con.close()
service.postAbort(service.getString(R.string.p_serial_unsupported))
return
}
val baudrate = prefs.getStringInt("baudrate", 115200)
ser.setBaudRate(baudrate)
ser.setDataBits(UsbSerialInterface.DATA_BITS_8)
ser.setStopBits(UsbSerialInterface.STOP_BITS_1)
ser.setParity(UsbSerialInterface.PARITY_NONE)
ser.setFlowControl(UsbSerialInterface.FLOW_CONTROL_OFF)
// success: remember this for usb-attach launch
prefs.prefs.edit().putString(UsbTnc.deviceHandle(dev), prefs.getString("proto", "kiss")).commit()
log("Opened " + ser.getClass().getSimpleName() + " at " + baudrate + "bd")
sis = new SerialInputStream(ser)
try {
proto = AprsBackend.instanciateProto(service, sis, new SerialOutputStream(ser))
} catch {
case e : IllegalArgumentException =>
service.postAbort(e.getMessage()); running = false
return
}
service.postPosterStarted()
while (running) {
try {
val line = proto.readPacket()
Log.d(TAG, "recv: " + line)
service.postSubmit(line)
} catch {
case e : Exception =>
Log.d(TAG, "readPacket exception: " + e.toString())
if (running) {
service.postAbort(e.toString()); running = false
}
}
}
Log.d(TAG, "terminate()")
}
}
}