kopia lustrzana https://github.com/ge0rg/aprsdroid
136 wiersze
4.4 KiB
Scala
136 wiersze
4.4 KiB
Scala
package org.aprsdroid.app
|
|
|
|
import _root_.android.content.Context
|
|
import _root_.android.location._
|
|
import _root_.android.os.{Bundle, Handler}
|
|
import _root_.android.util.Log
|
|
import _root_.android.widget.Toast
|
|
|
|
class SmartBeaconing(service : AprsService, prefs : PrefsWrapper) extends LocationSource
|
|
with LocationListener {
|
|
val TAG = "APRSdroid.SmartBeaconing"
|
|
|
|
lazy val locMan = service.getSystemService(Context.LOCATION_SERVICE).asInstanceOf[LocationManager]
|
|
|
|
var lastLoc : Location = null
|
|
var started = false
|
|
|
|
def start(singleShot : Boolean) = {
|
|
lastLoc = null
|
|
if (!started) try {
|
|
locMan.requestLocationUpdates(LocationManager.GPS_PROVIDER,
|
|
0, 0, this)
|
|
started = true
|
|
} catch {
|
|
case e @ (_: IllegalArgumentException | _: SecurityException) =>
|
|
// we lack GPS or GPS permissions
|
|
service.postAbort(service.getString(R.string.service_sm_no_gps)
|
|
+ "\n" + e.getMessage())
|
|
}
|
|
service.getString(R.string.p_source_smart)
|
|
}
|
|
|
|
def stop() {
|
|
if (started)
|
|
locMan.removeUpdates(this)
|
|
started = false
|
|
}
|
|
|
|
def smartBeaconSpeedRate(speed : Float) : Int = {
|
|
val SB_FAST_SPEED = prefs.getStringInt("sb.fastspeed", 100)/3.6 // [m/s]
|
|
val SB_FAST_RATE = prefs.getStringInt("sb.fastrate", 60)
|
|
val SB_SLOW_SPEED = prefs.getStringInt("sb.slowspeed", 5)/3.6 // [m/s]
|
|
val SB_SLOW_RATE = prefs.getStringInt("sb.slowrate", 1200)
|
|
if (speed <= SB_SLOW_SPEED)
|
|
SB_SLOW_RATE
|
|
else if (speed >= SB_FAST_SPEED)
|
|
SB_FAST_RATE
|
|
else
|
|
(SB_FAST_RATE + (SB_SLOW_RATE - SB_FAST_RATE) * (SB_FAST_SPEED - speed) / (SB_FAST_SPEED-SB_SLOW_SPEED)).toInt
|
|
}
|
|
|
|
// returns the angle between two bearings
|
|
def getBearingAngle(alpha : Float, beta : Float) : Float = {
|
|
val delta = math.abs(alpha-beta)%360
|
|
if (delta <= 180) delta else (360-delta)
|
|
}
|
|
// obtain max speed in [m/s] from moved distance, last and current location
|
|
def getSpeed(location : Location) : Float = {
|
|
val dist = location.distanceTo(lastLoc)
|
|
val t_diff = location.getTime - lastLoc.getTime
|
|
math.max(math.max(dist*1000/t_diff, location.getSpeed), lastLoc.getSpeed)
|
|
}
|
|
|
|
def smartBeaconCornerPeg(location : Location) : Boolean = {
|
|
val SB_TURN_TIME = prefs.getStringInt("sb.turntime", 15)
|
|
val SB_TURN_MIN = prefs.getStringInt("sb.turnmin", 10)
|
|
val SB_TURN_SLOPE = prefs.getStringInt("sb.turnslope", 240)*1.0
|
|
|
|
val speed = location.getSpeed
|
|
val t_diff = location.getTime - lastLoc.getTime
|
|
val turn = getBearingAngle(location.getBearing, lastLoc.getBearing)
|
|
|
|
// no bearing / stillstand -> no corner pegging
|
|
if (!location.hasBearing || speed == 0)
|
|
return false
|
|
|
|
// if last bearing unknown, deploy turn_time
|
|
if (!lastLoc.hasBearing)
|
|
return (t_diff/1000 >= SB_TURN_TIME)
|
|
|
|
// threshold depends on slope/speed [mph]
|
|
val threshold = SB_TURN_MIN + SB_TURN_SLOPE/(speed*2.23693629)
|
|
|
|
Log.d(TAG, "smartBeaconCornerPeg: %1.0f < %1.0f %d/%d".format(turn, threshold,
|
|
t_diff/1000, SB_TURN_TIME))
|
|
// need to corner peg if turn time reached and turn > threshold
|
|
(t_diff/1000 >= SB_TURN_TIME && turn > threshold)
|
|
}
|
|
|
|
// return true if current position is "new enough" vs. lastLoc
|
|
def smartBeaconCheck(location : Location) : Boolean = {
|
|
if (lastLoc == null)
|
|
return true
|
|
if (smartBeaconCornerPeg(location))
|
|
return true
|
|
val dist = location.distanceTo(lastLoc)
|
|
val t_diff = location.getTime - lastLoc.getTime
|
|
val speed = getSpeed(location)
|
|
//if (location.hasSpeed && location.hasBearing)
|
|
val speed_rate = smartBeaconSpeedRate(speed)
|
|
Log.d(TAG, "smartBeaconCheck: %1.0fm, %1.2fm/s -> %d/%ds - %s".format(dist, speed,
|
|
t_diff/1000, speed_rate, (t_diff/1000 >= speed_rate).toString))
|
|
if (t_diff/1000 >= speed_rate)
|
|
true
|
|
else
|
|
false
|
|
}
|
|
|
|
// LocationListener interface
|
|
override def onLocationChanged(location : Location) {
|
|
if (smartBeaconCheck(location))
|
|
postLocation(location)
|
|
}
|
|
|
|
override def onProviderDisabled(provider : String) {
|
|
Log.d(TAG, "onProviderDisabled: " + provider)
|
|
if (provider == LocationManager.GPS_PROVIDER) {
|
|
// GPS was our last data source, we have to complain!
|
|
Toast.makeText(service, R.string.service_sm_no_gps, Toast.LENGTH_LONG).show()
|
|
}
|
|
}
|
|
override def onProviderEnabled(provider : String) {
|
|
Log.d(TAG, "onProviderEnabled: " + provider)
|
|
}
|
|
override def onStatusChanged(provider : String, st: Int, extras : Bundle) {
|
|
Log.d(TAG, "onStatusChanged: " + provider)
|
|
}
|
|
|
|
|
|
def postLocation(location : Location) {
|
|
lastLoc = location
|
|
|
|
service.postLocation(location)
|
|
}
|
|
}
|