USB: preliminary implementation

usb
Georg Lukas 2015-08-27 20:30:25 +02:00
rodzic 3f82e4a31e
commit 0b0f32d772
6 zmienionych plików z 204 dodań i 0 usunięć

Wyświetl plik

@ -13,6 +13,7 @@
<uses-feature android:name="android.hardware.location.gps" android:required="false" />
<uses-feature android:name="android.hardware.microphone" android:required="false" />
<uses-feature android:name="android.hardware.touchscreen" android:required="false" />
<uses-feature android:name="android.hardware.usb.host" android:required="false" />
<uses-library android:name="android.test.runner" android:required="false" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
@ -35,6 +36,12 @@
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<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" />
</activity>
<activity android:name=".LogActivity" android:label="@string/app_name"
android:launchMode="singleTop"

Wyświetl plik

@ -8,6 +8,7 @@
<item>@string/p_conn_bt</item>
<item>@string/p_conn_kwd</item>
<item>@string/p_conn_tcptnc</item>
<item>@string/p_conn_usb</item>
</string-array>
<string-array name="p_conntype_ev">
<item>tcp</item>
@ -17,6 +18,7 @@
<item>bluetooth</item>
<item>kenwood</item>
<item>tcptnc</item>
<item>usb</item>
</string-array>
<string-array name="p_afsk_out_ev">
<item>0</item>
@ -83,4 +85,11 @@
<item>1440</item>
<item>2880</item>
</string-array>
<string-array name="p_serial_baudrates">
<item>9600</item>
<item>19200</item>
<item>38400</item>
<item>57600</item>
<item>115200</item>
</string-array>
</resources>

Wyświetl plik

@ -181,6 +181,7 @@
<string name="p_conn_bt">Bluetooth TNC</string>
<string name="p_conn_kwd">Kenwood GPS Port</string>
<string name="p_conn_tcptnc">TCP/IP TNC</string>
<string name="p_conn_usb">USB Serial</string>
<!-- array of location sources -->
<string name="p_source_manual">Manual Position</string>
<string name="p_source_periodic">Periodic GPS/Network Position</string>
@ -359,4 +360,8 @@
<string name="ssl_import_error">Error importing certificate: %s!</string>
<string name="ssl_expired">Your certificate has expired!</string>
<string name="ssl_expire_in">Your certificate will expire in %d days!</string>
<!-- (USB) Serial TNC settings -->
<string name="p_serial_baudrate">Baud Rate</string>
<string name="p_serial_baudrate_summary">Data rate of the serial port</string>
</resources>

Wyświetl plik

@ -16,6 +16,13 @@ class APRSdroid extends Activity {
override def onCreate(savedInstanceState : Bundle) {
super.onCreate(savedInstanceState)
val prefs = PreferenceManager.getDefaultSharedPreferences(this)
// if this is a USB device, auto-launch the service
if (getIntent.getParcelableExtra("device") != null) {
prefs.edit().putString("backend", "usb").commit();
startService(AprsService.intent(this, AprsService.SERVICE))
}
prefs.getString("activity", "log") match {
case "hub" => replaceAct(classOf[HubActivity])
case "map" => replaceAct(classOf[MapAct])

Wyświetl plik

@ -57,6 +57,11 @@ object AprsBackend {
(s, p) => new TcpTnc(s, p),
R.xml.backend_tcptnc,
CAN_DUPLEX,
PASSCODE_NONE),
"usb" -> new BackendInfo(
(s, p) => new UsbTnc(s, p),
R.xml.backend_usb,
CAN_DUPLEX,
PASSCODE_NONE)
)

Wyświetl plik

@ -0,0 +1,171 @@
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.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._
class UsbTnc(service : AprsService, prefs : PrefsWrapper) extends AprsBackend(prefs) {
val TAG = "APRSdroid.Usb"
val USB_PERM_ACTION = "org.aprsdroid.app.UsbTnc.PERM"
val ACTION_USB_ATTACHED = "android.hardware.usb.action.USB_DEVICE_ATTACHED"
val ACTION_USB_DETACHED = "android.hardware.usb.action.USB_DEVICE_DETACHED"
var digipath = prefs.getString("digi_path", "WIDE1-1")
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("No permission for USB device!")
return
}
log("Obtained USB permissions.")
thread = new UsbThread()
thread.start()
}
}
var proto : TncProto = 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) {
Log.i(TAG, s)
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 (deviceVID != 0x1d6b || (devicePID != 0x0001 || devicePID != 0x0002 || devicePID != 0x0003)) {
// 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
}
}
service.postAbort("No USB device found!")
}
def update(packet : APRSPacket) : String = {
// the digipeater setting here is a duplicate just for log purpose
packet.setDigipeaters(Digipeater.parseList(digipath, true))
Log.d(TAG, "UsbTnc.update: " + packet)
//TODO
proto.writePacket(packet)
"USB OK"
}
def stop() {
if (alreadyRunning)
service.unregisterReceiver(receiver)
alreadyRunning = false
if (ser != null)
ser.close()
if (con != null)
con.close()
if (thread == null)
return
thread.synchronized {
thread.running = false
}
//thread.shutdown()
thread.interrupt()
thread.join(50)
}
class UsbThread()
extends Thread("APRSdroid USB connection") {
val TAG = "UsbThread"
var running = true
def log(s : String) {
Log.i(TAG, s)
service.postAddPost(StorageDatabase.Post.TYPE_INFO, R.string.post_info, s)
}
override def run() {
val con = usbManager.openDevice(dev)
val ser = UsbSerialDevice.createUsbSerialDevice(dev, con)
if (ser == null || !ser.open()) {
con.close()
service.postAbort("Unsupported serial port")
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)
log("Opened " + ser.getClass().getSimpleName() + " at " + baudrate + "bd")
val os = new SerialOutputStream(ser)
val initstring = prefs.getString("usb.init", null)
val initdelay = prefs.getStringInt("usb.delay", 300)
if (initstring != null && initstring != "") {
log("Sending init: " + initstring)
for (line <- initstring.split("\n")) {
os.write(line.getBytes())
os.write('\r')
os.write('\n')
Thread.sleep(initdelay)
}
}
proto = new KissProto(new SerialInputStream(ser), os, digipath)
service.postPosterStarted()
while (running) {
val line = proto.readPacket()
Log.d(TAG, "recv: " + line)
service.postSubmit(line)
}
Log.d(TAG, "terminate()")
}
}
}