From f5ec5003431d14aac988a0283808da53ad15a4fe Mon Sep 17 00:00:00 2001 From: Piotr Dec Date: Thu, 1 Aug 2024 22:52:26 +0200 Subject: [PATCH] fix: Threading & optimizations --- app/src/main/java/eu/ztsh/garmin/Garmin.kt | 116 +++++++++-------- .../java/eu/ztsh/garmin/data/DataCache.kt | 44 ++----- .../java/eu/ztsh/garmin/data/MapboxMapper.kt | 120 +++++++++--------- .../main/java/eu/ztsh/garmin/data/Model.kt | 4 + 4 files changed, 142 insertions(+), 142 deletions(-) diff --git a/app/src/main/java/eu/ztsh/garmin/Garmin.kt b/app/src/main/java/eu/ztsh/garmin/Garmin.kt index e9731cc..587e68f 100644 --- a/app/src/main/java/eu/ztsh/garmin/Garmin.kt +++ b/app/src/main/java/eu/ztsh/garmin/Garmin.kt @@ -7,12 +7,11 @@ import android.bluetooth.BluetoothSocket import android.util.Log import com.mapbox.navigation.tripdata.maneuver.model.Maneuver import eu.ztsh.garmin.data.DataCache -import eu.ztsh.garmin.data.GarminManeuver import eu.ztsh.garmin.data.GarminMapper -import eu.ztsh.garmin.data.GarminModelItem import eu.ztsh.garmin.data.MapboxMapper import java.io.IOException import java.util.* +import java.util.concurrent.Executors import java.util.concurrent.SynchronousQueue @SuppressLint("MissingPermission") @@ -23,88 +22,98 @@ class Garmin( ) { private lateinit var connection: ConnectThread - private val observer = ProcessingThreadObserver() + private lateinit var maneuvers: ManeuverProcessingThread private val cache = DataCache() + private val maneuversPool = Executors.newFixedThreadPool(4) + fun start() { connection = ConnectThread() connection.start() + + maneuvers = ManeuverProcessingThread() + maneuvers.start() } fun close() { connection.close() + + maneuvers.interrupt() + maneuvers.join(0) + + maneuversPool.shutdown() } fun process(maneuver: Maneuver) { - ManeuverProcessingThread(maneuver).start() + maneuversPool.submit{maneuvers.enqueue(maneuver)} } -// fun process(location: LocationMatcherResult) { -// LocationProcessingThread(location).start() -// } + private inner class ManeuverProcessingThread : ProcessingThread() { -// fun process(navigationSessionState: NavigationSessionState) { -// cache.update(navigationSessionState) -// } - - private inner class ManeuverProcessingThread(val maneuver: Maneuver) : ProcessingThread() { - - override fun process(): GarminManeuver? { - if (cache.hasChanged(maneuver)) { - cache.update(maneuver) - return MapboxMapper.map(maneuver) + override fun mapAndSend(maybeItem: Maneuver?): Maneuver? { + if (maybeItem != null) { + Log.d(TAG, "mapAndSend (${currentThread().name}): got new") + var changed = false + if (cache.hasChanged(maybeItem.laneGuidance)) { + changed = true + Log.d(TAG, "mapAndSend: lanes") + send(GarminMapper.map(MapboxMapper.asLanes(maybeItem))) + } + 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 } - override fun enqueue(item: GarminManeuver) { - if (cache.hasChanged(item.lanes)) { - 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? + override fun updateCache(item: Maneuver) { + cache.update(item) } } -// private inner class LocationProcessingThread(val location: LocationMatcherResult) : ProcessingThread() { -// -// override fun process() { -// if (cache.hasChanged(location)) { -// cache.update(location) -// send(MapboxMapper.apply(location)) -// } -// } -// } + private abstract inner class ProcessingThread : Thread() { - private abstract inner class ProcessingThread : Thread() { + private val queue: SynchronousQueue = 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() { - val processing = process() - if (processing != null) { - enqueue(processing) - cache.update(processing) + while (!stop) { + val maybeItem = queue.poll() + val item = mapAndSend(maybeItem) + if (item != null) { + Log.d(TAG, "run: Cache updated") + updateCache(item) + } } - observer.join(this) } - } - - private inner class ProcessingThreadObserver { - - fun join(thread: ProcessingThread) { - thread.join() + override fun interrupt() { + stop = true + super.interrupt() } - } private inner class ConnectThread : Thread() { @@ -126,9 +135,11 @@ class Garmin( context.setConnectionStatus(true) sleep(3000) readAll() + send(intArrayOf(0x07, 0x01)) // Set GPS to true while (true) { val newCurrent = queue.poll() if (newCurrent == null) { + Log.d(TAG, "run (${currentThread().name}): Sleep...") sleep(500) } else { current = newCurrent @@ -177,7 +188,6 @@ class Garmin( private fun sendRaw(buff: IntArray) { buff.forEach { socket!!.outputStream.write(it) } socket!!.outputStream.flush() - sleep(2000) readAll() } diff --git a/app/src/main/java/eu/ztsh/garmin/data/DataCache.kt b/app/src/main/java/eu/ztsh/garmin/data/DataCache.kt index 2abeaa8..51fb02e 100644 --- a/app/src/main/java/eu/ztsh/garmin/data/DataCache.kt +++ b/app/src/main/java/eu/ztsh/garmin/data/DataCache.kt @@ -2,7 +2,10 @@ package eu.ztsh.garmin.data import com.mapbox.navigation.core.trip.session.LocationMatcherResult 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.PrimaryManeuver +import com.mapbox.navigation.tripdata.maneuver.model.StepDistance class DataCache { @@ -11,38 +14,17 @@ class DataCache { private var locationCache: LocationMatcherResult? = 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 - fun hasChanged(maneuver: Maneuver): Boolean { - return maneuverCache == null || maneuverCache!! != maneuver + fun hasChanged(guidance: Lane?): Boolean { + 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) { diff --git a/app/src/main/java/eu/ztsh/garmin/data/MapboxMapper.kt b/app/src/main/java/eu/ztsh/garmin/data/MapboxMapper.kt index f771068..d9161c5 100644 --- a/app/src/main/java/eu/ztsh/garmin/data/MapboxMapper.kt +++ b/app/src/main/java/eu/ztsh/garmin/data/MapboxMapper.kt @@ -6,74 +6,78 @@ import com.mapbox.navigation.core.trip.session.LocationMatcherResult class MapboxMapper { companion object { - - fun map(maneuver: Maneuver): GarminManeuver { - val state = GarminManeuver() - maneuver.apply { - this.primary.apply { - state.direction = Direction() - when (this.type) { - "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 - } - } + + fun asDirection(maneuver: Maneuver): Direction { + val direction = Direction() + maneuver.primary.apply { + when (this.type) { + "roundabout" -> { + direction.out = OutType.RightRoundabout } - when (this.modifier) { - "right" -> { - when (this.type) { - "turn" -> state.direction.angle = OutAngle.Right - "roundabout" -> { - when (this.degrees) { - 137.0 -> state.direction.angle = OutAngle.EasyRight - 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 - } + "fork" -> direction.out = OutType.LongerLane + "arrive" -> { +// flag = true + } + "turn" -> { + when (this.type) { + "straight" -> direction.angle = OutAngle.Straight } } } - this.stepDistance.apply { - this.distanceRemaining?.apply { - distanceFormatter.formatDistance(this).split(" ").apply { - state.distance = Distance( - this[0].replace(',', '.').toDouble(), - when (this[1]) { - "m" -> Unit.Metres - "km" -> Unit.Kilometres - else -> Unit.Any + when (this.modifier) { + "right" -> { + when (this.type) { + "turn" -> direction.angle = OutAngle.Right + "roundabout" -> { + when (this.degrees) { + 137.0 -> direction.angle = OutAngle.EasyRight + 180.0 -> direction.angle = OutAngle.Straight } - ) - + } + "off ramp" -> { + direction.angle = OutAngle.EasyRight + direction.out = OutType.LongerLane + } } } - } - // TODO: implement - state.lanes = Lanes(Arrows(listOf()), Arrows(listOf())) - this.laneGuidance?.apply { - this.allLanes.apply { - println() + + "left" -> { + when (this.type) { + "turn" -> direction.angle = OutAngle.Left + "off ramp" -> { + 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 { diff --git a/app/src/main/java/eu/ztsh/garmin/data/Model.kt b/app/src/main/java/eu/ztsh/garmin/data/Model.kt index ef30ede..ad6b205 100644 --- a/app/src/main/java/eu/ztsh/garmin/data/Model.kt +++ b/app/src/main/java/eu/ztsh/garmin/data/Model.kt @@ -89,6 +89,10 @@ class Distance(val distance: Double, val unit: Unit) { return result } + override fun toString(): String { + return "Distance($distance$unit)" + } + } class Speed(val speed: Int, val limit: Int)