fix: Threading & optimizations
This commit is contained in:
parent
6d71245d9f
commit
f5ec500343
4 changed files with 142 additions and 142 deletions
|
@ -7,12 +7,11 @@ import android.bluetooth.BluetoothSocket
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import com.mapbox.navigation.tripdata.maneuver.model.Maneuver
|
import com.mapbox.navigation.tripdata.maneuver.model.Maneuver
|
||||||
import eu.ztsh.garmin.data.DataCache
|
import eu.ztsh.garmin.data.DataCache
|
||||||
import eu.ztsh.garmin.data.GarminManeuver
|
|
||||||
import eu.ztsh.garmin.data.GarminMapper
|
import eu.ztsh.garmin.data.GarminMapper
|
||||||
import eu.ztsh.garmin.data.GarminModelItem
|
|
||||||
import eu.ztsh.garmin.data.MapboxMapper
|
import eu.ztsh.garmin.data.MapboxMapper
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
import java.util.concurrent.Executors
|
||||||
import java.util.concurrent.SynchronousQueue
|
import java.util.concurrent.SynchronousQueue
|
||||||
|
|
||||||
@SuppressLint("MissingPermission")
|
@SuppressLint("MissingPermission")
|
||||||
|
@ -23,88 +22,98 @@ class Garmin(
|
||||||
) {
|
) {
|
||||||
|
|
||||||
private lateinit var connection: ConnectThread
|
private lateinit var connection: ConnectThread
|
||||||
private val observer = ProcessingThreadObserver()
|
private lateinit var maneuvers: ManeuverProcessingThread
|
||||||
private val cache = DataCache()
|
private val cache = DataCache()
|
||||||
|
|
||||||
|
private val maneuversPool = Executors.newFixedThreadPool(4)
|
||||||
|
|
||||||
fun start() {
|
fun start() {
|
||||||
connection = ConnectThread()
|
connection = ConnectThread()
|
||||||
connection.start()
|
connection.start()
|
||||||
|
|
||||||
|
maneuvers = ManeuverProcessingThread()
|
||||||
|
maneuvers.start()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun close() {
|
fun close() {
|
||||||
connection.close()
|
connection.close()
|
||||||
|
|
||||||
|
maneuvers.interrupt()
|
||||||
|
maneuvers.join(0)
|
||||||
|
|
||||||
|
maneuversPool.shutdown()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun process(maneuver: Maneuver) {
|
fun process(maneuver: Maneuver) {
|
||||||
ManeuverProcessingThread(maneuver).start()
|
maneuversPool.submit{maneuvers.enqueue(maneuver)}
|
||||||
}
|
}
|
||||||
|
|
||||||
// fun process(location: LocationMatcherResult) {
|
private inner class ManeuverProcessingThread : ProcessingThread<Maneuver>() {
|
||||||
// LocationProcessingThread(location).start()
|
|
||||||
// }
|
|
||||||
|
|
||||||
// fun process(navigationSessionState: NavigationSessionState) {
|
override fun mapAndSend(maybeItem: Maneuver?): Maneuver? {
|
||||||
// cache.update(navigationSessionState)
|
if (maybeItem != null) {
|
||||||
// }
|
Log.d(TAG, "mapAndSend (${currentThread().name}): got new")
|
||||||
|
var changed = false
|
||||||
private inner class ManeuverProcessingThread(val maneuver: Maneuver) : ProcessingThread<GarminManeuver>() {
|
if (cache.hasChanged(maybeItem.laneGuidance)) {
|
||||||
|
changed = true
|
||||||
override fun process(): GarminManeuver? {
|
Log.d(TAG, "mapAndSend: lanes")
|
||||||
if (cache.hasChanged(maneuver)) {
|
send(GarminMapper.map(MapboxMapper.asLanes(maybeItem)))
|
||||||
cache.update(maneuver)
|
}
|
||||||
return MapboxMapper.map(maneuver)
|
if (cache.hasChanged(maybeItem.stepDistance)) {
|
||||||
|
changed = true
|
||||||
|
Log.d(TAG, "mapAndSend: stepDistance")
|
||||||
|
send(GarminMapper.map(MapboxMapper.asDistance(maybeItem)))
|
||||||
|
}
|
||||||
|
if (cache.hasChanged(maybeItem.primary)) {
|
||||||
|
changed = true
|
||||||
|
Log.d(TAG, "mapAndSend: primary")
|
||||||
|
send(GarminMapper.map(MapboxMapper.asDirection(maybeItem)))
|
||||||
|
}
|
||||||
|
if (changed) {
|
||||||
|
return maybeItem
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun enqueue(item: GarminManeuver) {
|
override fun updateCache(item: Maneuver) {
|
||||||
if (cache.hasChanged(item.lanes)) {
|
cache.update(item)
|
||||||
connection.enqueue(GarminMapper.map(item.lanes))
|
|
||||||
}
|
|
||||||
if (cache.hasChanged(item.direction)) {
|
|
||||||
connection.enqueue(GarminMapper.map(item.direction))
|
|
||||||
}
|
|
||||||
if (cache.hasChanged(item.distance)) {
|
|
||||||
connection.enqueue(GarminMapper.map(item.distance))
|
|
||||||
}
|
|
||||||
// flag?
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// private inner class LocationProcessingThread(val location: LocationMatcherResult) : ProcessingThread() {
|
private abstract inner class ProcessingThread<T> : Thread() {
|
||||||
//
|
|
||||||
// override fun process() {
|
|
||||||
// if (cache.hasChanged(location)) {
|
|
||||||
// cache.update(location)
|
|
||||||
// send(MapboxMapper.apply(location))
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
private abstract inner class ProcessingThread<T : GarminModelItem> : Thread() {
|
private val queue: SynchronousQueue<T> = SynchronousQueue()
|
||||||
|
private var stop: Boolean = false
|
||||||
|
|
||||||
abstract fun process(): T?
|
abstract fun mapAndSend(maybeItem: T?): T?
|
||||||
|
|
||||||
abstract fun enqueue(item: T)
|
abstract fun updateCache(item: T)
|
||||||
|
|
||||||
|
fun send(data: IntArray) {
|
||||||
|
connection.enqueue(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun enqueue(item: T) {
|
||||||
|
queue.put(item)
|
||||||
|
}
|
||||||
|
|
||||||
override fun run() {
|
override fun run() {
|
||||||
val processing = process()
|
while (!stop) {
|
||||||
if (processing != null) {
|
val maybeItem = queue.poll()
|
||||||
enqueue(processing)
|
val item = mapAndSend(maybeItem)
|
||||||
cache.update(processing)
|
if (item != null) {
|
||||||
|
Log.d(TAG, "run: Cache updated")
|
||||||
|
updateCache(item)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
observer.join(this)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
override fun interrupt() {
|
||||||
|
stop = true
|
||||||
private inner class ProcessingThreadObserver {
|
super.interrupt()
|
||||||
|
|
||||||
fun <T : GarminModelItem> join(thread: ProcessingThread<T>) {
|
|
||||||
thread.join()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private inner class ConnectThread : Thread() {
|
private inner class ConnectThread : Thread() {
|
||||||
|
@ -126,9 +135,11 @@ class Garmin(
|
||||||
context.setConnectionStatus(true)
|
context.setConnectionStatus(true)
|
||||||
sleep(3000)
|
sleep(3000)
|
||||||
readAll()
|
readAll()
|
||||||
|
send(intArrayOf(0x07, 0x01)) // Set GPS to true
|
||||||
while (true) {
|
while (true) {
|
||||||
val newCurrent = queue.poll()
|
val newCurrent = queue.poll()
|
||||||
if (newCurrent == null) {
|
if (newCurrent == null) {
|
||||||
|
Log.d(TAG, "run (${currentThread().name}): Sleep...")
|
||||||
sleep(500)
|
sleep(500)
|
||||||
} else {
|
} else {
|
||||||
current = newCurrent
|
current = newCurrent
|
||||||
|
@ -177,7 +188,6 @@ class Garmin(
|
||||||
private fun sendRaw(buff: IntArray) {
|
private fun sendRaw(buff: IntArray) {
|
||||||
buff.forEach { socket!!.outputStream.write(it) }
|
buff.forEach { socket!!.outputStream.write(it) }
|
||||||
socket!!.outputStream.flush()
|
socket!!.outputStream.flush()
|
||||||
sleep(2000)
|
|
||||||
readAll()
|
readAll()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,10 @@ package eu.ztsh.garmin.data
|
||||||
|
|
||||||
import com.mapbox.navigation.core.trip.session.LocationMatcherResult
|
import com.mapbox.navigation.core.trip.session.LocationMatcherResult
|
||||||
import com.mapbox.navigation.core.trip.session.NavigationSessionState
|
import com.mapbox.navigation.core.trip.session.NavigationSessionState
|
||||||
|
import com.mapbox.navigation.tripdata.maneuver.model.Lane
|
||||||
import com.mapbox.navigation.tripdata.maneuver.model.Maneuver
|
import com.mapbox.navigation.tripdata.maneuver.model.Maneuver
|
||||||
|
import com.mapbox.navigation.tripdata.maneuver.model.PrimaryManeuver
|
||||||
|
import com.mapbox.navigation.tripdata.maneuver.model.StepDistance
|
||||||
|
|
||||||
class DataCache {
|
class DataCache {
|
||||||
|
|
||||||
|
@ -11,38 +14,17 @@ class DataCache {
|
||||||
private var locationCache: LocationMatcherResult? = null
|
private var locationCache: LocationMatcherResult? = null
|
||||||
private var session: NavigationSessionState? = null
|
private var session: NavigationSessionState? = null
|
||||||
|
|
||||||
// state
|
|
||||||
fun hasChanged(lanes: Lanes): Boolean {
|
|
||||||
return garminManeuver.lanes != lanes
|
|
||||||
}
|
|
||||||
|
|
||||||
fun hasChanged(distance: Distance): Boolean {
|
|
||||||
return garminManeuver.distance != distance
|
|
||||||
}
|
|
||||||
|
|
||||||
fun hasChanged(direction: Direction): Boolean {
|
|
||||||
return garminManeuver.direction != direction
|
|
||||||
}
|
|
||||||
//
|
|
||||||
// fun hasChanged(speed: Speed?): Boolean {
|
|
||||||
// return stateCache.speed == null || stateCache.speed != speed
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// fun hasChanged(arrival: Arrival?): Boolean {
|
|
||||||
// return stateCache.arrival == null || stateCache.arrival != arrival
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Merge states
|
|
||||||
fun update(item: GarminModelItem) {
|
|
||||||
when(item) {
|
|
||||||
is GarminManeuver -> garminManeuver.merge(item)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// maneuver
|
// maneuver
|
||||||
fun hasChanged(maneuver: Maneuver): Boolean {
|
fun hasChanged(guidance: Lane?): Boolean {
|
||||||
return maneuverCache == null || maneuverCache!! != maneuver
|
return guidance != null && maneuverCache.let { it == null || it.laneGuidance != guidance }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun hasChanged(distance: StepDistance): Boolean {
|
||||||
|
return maneuverCache.let { it == null || it.stepDistance != distance }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun hasChanged(primaryManeuver: PrimaryManeuver): Boolean {
|
||||||
|
return maneuverCache.let { it == null || it.primary != primaryManeuver }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun update(maneuver: Maneuver) {
|
fun update(maneuver: Maneuver) {
|
||||||
|
|
|
@ -6,74 +6,78 @@ import com.mapbox.navigation.core.trip.session.LocationMatcherResult
|
||||||
class MapboxMapper {
|
class MapboxMapper {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
fun map(maneuver: Maneuver): GarminManeuver {
|
fun asDirection(maneuver: Maneuver): Direction {
|
||||||
val state = GarminManeuver()
|
val direction = Direction()
|
||||||
maneuver.apply {
|
maneuver.primary.apply {
|
||||||
this.primary.apply {
|
when (this.type) {
|
||||||
state.direction = Direction()
|
"roundabout" -> {
|
||||||
when (this.type) {
|
direction.out = OutType.RightRoundabout
|
||||||
"roundabout" -> {
|
|
||||||
state.direction.out = OutType.RightRoundabout
|
|
||||||
}
|
|
||||||
"fork" -> state.direction.out = OutType.LongerLane
|
|
||||||
"arrive" -> {
|
|
||||||
state.flag = true
|
|
||||||
}
|
|
||||||
"turn" -> {
|
|
||||||
when (this.type) {
|
|
||||||
"straight" -> state.direction.angle = OutAngle.Straight
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
when (this.modifier) {
|
"fork" -> direction.out = OutType.LongerLane
|
||||||
"right" -> {
|
"arrive" -> {
|
||||||
when (this.type) {
|
// flag = true
|
||||||
"turn" -> state.direction.angle = OutAngle.Right
|
}
|
||||||
"roundabout" -> {
|
"turn" -> {
|
||||||
when (this.degrees) {
|
when (this.type) {
|
||||||
137.0 -> state.direction.angle = OutAngle.EasyRight
|
"straight" -> direction.angle = OutAngle.Straight
|
||||||
180.0 -> state.direction.angle = OutAngle.Straight
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"off ramp" -> {
|
|
||||||
state.direction.angle = OutAngle.EasyRight
|
|
||||||
state.direction.out = OutType.LongerLane
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
"left" -> {
|
|
||||||
when (this.type) {
|
|
||||||
"turn" -> state.direction.angle = OutAngle.Left
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.stepDistance.apply {
|
when (this.modifier) {
|
||||||
this.distanceRemaining?.apply {
|
"right" -> {
|
||||||
distanceFormatter.formatDistance(this).split(" ").apply {
|
when (this.type) {
|
||||||
state.distance = Distance(
|
"turn" -> direction.angle = OutAngle.Right
|
||||||
this[0].replace(',', '.').toDouble(),
|
"roundabout" -> {
|
||||||
when (this[1]) {
|
when (this.degrees) {
|
||||||
"m" -> Unit.Metres
|
137.0 -> direction.angle = OutAngle.EasyRight
|
||||||
"km" -> Unit.Kilometres
|
180.0 -> direction.angle = OutAngle.Straight
|
||||||
else -> Unit.Any
|
|
||||||
}
|
}
|
||||||
)
|
}
|
||||||
|
"off ramp" -> {
|
||||||
|
direction.angle = OutAngle.EasyRight
|
||||||
|
direction.out = OutType.LongerLane
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
// TODO: implement
|
"left" -> {
|
||||||
state.lanes = Lanes(Arrows(listOf()), Arrows(listOf()))
|
when (this.type) {
|
||||||
this.laneGuidance?.apply {
|
"turn" -> direction.angle = OutAngle.Left
|
||||||
this.allLanes.apply {
|
"off ramp" -> {
|
||||||
println()
|
direction.angle = OutAngle.EasyLeft
|
||||||
|
direction.out = OutType.LongerLane
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return state
|
return direction
|
||||||
|
}
|
||||||
|
|
||||||
|
fun asDistance(maneuver: Maneuver): Distance {
|
||||||
|
return maneuver.stepDistance.let { step ->
|
||||||
|
step.distanceFormatter.formatDistance(step.distanceRemaining!!).split(" ").let {
|
||||||
|
Distance(
|
||||||
|
it[0].replace(',', '.').toDouble(),
|
||||||
|
when (it[1]) {
|
||||||
|
"m" -> Unit.Metres
|
||||||
|
"km" -> Unit.Kilometres
|
||||||
|
else -> Unit.Any
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun asLanes(maneuver: Maneuver): Lanes {
|
||||||
|
// TODO: implement
|
||||||
|
maneuver.laneGuidance?.apply {
|
||||||
|
this.allLanes.apply {
|
||||||
|
println()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Lanes(Arrows(listOf()), Arrows(listOf()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun map(locationMatcherResult: LocationMatcherResult): GarminLocation {
|
fun map(locationMatcherResult: LocationMatcherResult): GarminLocation {
|
||||||
|
|
|
@ -89,6 +89,10 @@ class Distance(val distance: Double, val unit: Unit) {
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return "Distance($distance$unit)"
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class Speed(val speed: Int, val limit: Int)
|
class Speed(val speed: Int, val limit: Int)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue