Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ class TripViewAdapter internal constructor(
init {
if (showDeleteButton) {
loadTrip.setOnClickListener {
tripManager.loadTripAsync(data.elementAt(adapterPosition).source.fileName)
tripManager.loadTrip(data.elementAt(adapterPosition).source.fileName)
}

deleteTrip.setOnClickListener {
Expand Down
2 changes: 0 additions & 2 deletions app/src/main/java/org/obd/graphs/ui/graph/GraphFragment.kt
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,6 @@ import org.obd.metrics.pid.PidDefinitionRegistry
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
import java.util.concurrent.ConcurrentLinkedDeque

private const val LOG_TAG = "Graph"

Expand Down Expand Up @@ -261,7 +260,6 @@ class GraphFragment : Fragment() {
val sensorData =
SensorData(
id = it.command.pid.id,
metrics = ConcurrentLinkedDeque(),
min = hist.min,
max = hist.max,
mean = hist.mean
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ internal class WorkflowOrchestrator internal constructor() {
"Collecting process is completed."
)
sendBroadcastEvent(DATA_LOGGER_STOPPED_EVENT)
tripManager.saveCurrentTripAsync()
tripManager.saveCurrentTrip()
}
}

Expand Down
175 changes: 105 additions & 70 deletions datalogger/src/main/java/org/obd/graphs/bl/trip/DefaultTripManager.kt
Original file line number Diff line number Diff line change
Expand Up @@ -18,29 +18,33 @@ package org.obd.graphs.bl.trip

import android.content.Context
import android.util.Log
import org.obd.graphs.bl.datalogger.MetricsProcessor
import org.obd.graphs.SCREEN_LOCK_PROGRESS_EVENT
import org.obd.graphs.SCREEN_UNLOCK_PROGRESS_EVENT
import org.obd.graphs.ScreenLock
import org.obd.graphs.bl.datalogger.DataLoggerRepository
import org.obd.graphs.bl.datalogger.scaleToRange
import org.obd.graphs.commons.R
import org.obd.graphs.getContext
import org.obd.graphs.isNumber
import org.obd.graphs.preferences.Prefs
import org.obd.graphs.preferences.isEnabled
import org.obd.graphs.profile.profile
import org.obd.graphs.runAsync
import org.obd.graphs.sendBroadcastEvent
import org.obd.metrics.api.model.ObdMetric
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale

val tripManager: TripManager by lazy { DefaultTripManager() }

private const val LOGGER_TAG = "TripManager"
private const val LOG_TAG = "TripManager"
private const val MIN_TRIP_LENGTH = 5
private const val TRIP_FILE_PREFIX = "trip"

private const val MAX_CACHED_METRICS_PER_SENSOR = 18000

internal class DefaultTripManager :
TripManager,
MetricsProcessor {
internal class DefaultTripManager : TripManager {

private val dateFormat: SimpleDateFormat = SimpleDateFormat("MM.dd HH:mm:ss", Locale.getDefault())
private val tripCache = TripCache()
Expand All @@ -56,8 +60,8 @@ internal class DefaultTripManager :
try {
tripCache.getTrip { trip ->
val ts = (System.currentTimeMillis() - trip.startTs).toFloat()
val key = obdMetric.command.pid.id
val newRecord = if (obdMetric.isNumber()) Entry(ts, obdMetric.scaleToRange(), key) else Entry(ts, obdMetric.value, key)
val id = obdMetric.command.pid.id
val newRecord = if (obdMetric.isNumber()) Entry(ts, obdMetric.scaleToRange(), id) else Entry(ts, obdMetric.value, id)

val metric = Metric(
entry = newRecord,
Expand All @@ -67,18 +71,20 @@ internal class DefaultTripManager :

repository.saveMetric(metric)

val tripEntry = trip.entries.getOrPut(key) {
SensorData(id = key)
val tripEntry = trip.entries.getOrPut(id) {
SensorData(id = id)
}

tripEntry.metrics.add(metric)
synchronized(tripEntry.metrics) {
tripEntry.metrics.add(metric)

while (tripEntry.metrics.size > MAX_CACHED_METRICS_PER_SENSOR) {
tripEntry.metrics.removeFirst()
while (tripEntry.metrics.size > MAX_CACHED_METRICS_PER_SENSOR) {
tripEntry.metrics.removeFirst()
}
}
}
} catch (e: Throwable) {
Log.e(LOGGER_TAG, "Failed to process metric for ${obdMetric.command.pid.pid}", e)
Log.e(LOG_TAG, "Failed to process metric for ${obdMetric.command.pid.pid}", e)
}
}

Expand All @@ -89,36 +95,104 @@ internal class DefaultTripManager :
tripCache.getTrip() ?: Trip(startTs = newTs)
}

Log.i(LOGGER_TAG, "Get current trip ts: '${formatTimestamp(trip.startTs)}'")
Log.i(LOG_TAG, "Get current trip ts: '${formatTimestamp(trip.startTs)}'")
return trip
}

override fun startNewTrip(newTs: Long) {
Log.i(LOGGER_TAG, "Starting new trip, timestamp: '${formatTimestamp(newTs)}'")
Log.i(LOG_TAG, "Starting new trip, timestamp: '${formatTimestamp(newTs)}'")
updateCache(newTs)

activeTripId = "$TRIP_FILE_PREFIX-${profile.getCurrentProfile()}-$newTs.jsonl"
repository.initStorage(activeTripId!!)
}

override fun saveCurrentTrip() {
tripCache.getTrip { trip ->
val recordShortTrip = Prefs.isEnabled("pref.trips.recordings.save.short.trip")
val tripLength = getTripLength(trip)
val currentTripId = activeTripId ?: return@getTrip

Log.i(LOGGER_TAG, "Stopping trip, length: ${tripLength}s")

repository.releaseStorage(currentTripId)

if (recordShortTrip || tripLength > MIN_TRIP_LENGTH) {
repository.updateTripMetadata(currentTripId, trip.startTs, tripLength, profile.getCurrentProfile())
} else {
Log.w(LOGGER_TAG, "Trip time is less than ${MIN_TRIP_LENGTH}s. Discarding.")
repository.deleteTrip(currentTripId)
override fun loadTrip(tripName: String) {
if (!DataLoggerRepository.isRunning()) {
runAsync(wait = false) {
try {
Log.i(LOG_TAG, "Loading trip: '$tripName' ...................")

if (tripName.isEmpty()) {
updateCache(System.currentTimeMillis())
} else {
sendBroadcastEvent(
SCREEN_LOCK_PROGRESS_EVENT,
ScreenLock(message = R.string.dialog_screen_lock_trip_load_message)
)

try {
val parts = tripDescParser.decodeTripName(tripName)
val startTs = parts.getOrNull(2)?.toLongOrNull() ?: System.currentTimeMillis()
val trip = Trip(startTs = startTs)

repository.loadTrip(tripName) { metric ->
val key = metric.entry.data
if (!trip.entries.containsKey(key)) {
trip.entries[key] = SensorData(id = key)
}
trip.entries[key]!!.metrics.add(metric)
}

trip.entries.values.forEach { sensorData ->
val values = sensorData.metrics.mapNotNull { it.entry.y.toString().toFloatOrNull() }
if (values.isNotEmpty()) {
sensorData.min = values.minOrNull() ?: 0f
sensorData.max = values.maxOrNull() ?: 0f
sensorData.mean = values.average()
}
}

Log.i(LOG_TAG, "Trip loaded successfully. PIDs: ${trip.entries.keys}")

tripCache.updateTrip(trip)
tripVirtualScreenManager.updateReservedVirtualScreen(trip.entries.keys.map { it.toString() })

Log.i(LOG_TAG, "Trip: '$tripName' is loaded")
} catch (e: Throwable) {
Log.e(LOG_TAG, "Failed to load trip '$tripName'.", e)
updateCache(System.currentTimeMillis())
}
}
} finally {
sendBroadcastEvent(SCREEN_UNLOCK_PROGRESS_EVENT)
}
}
}
}

activeTripId = null
override fun saveCurrentTrip() {
sendBroadcastEvent(
SCREEN_LOCK_PROGRESS_EVENT,
ScreenLock(message = R.string.dialog_screen_lock_trip_save_message)
)

runAsync(wait = false) {
try {
tripCache.getTrip { trip ->
var ts = System.currentTimeMillis()
val recordShortTrip = Prefs.isEnabled("pref.trips.recordings.save.short.trip")
val tripLength = getTripLength(trip)
val currentTripId = activeTripId ?: return@getTrip

Log.i(LOG_TAG, "Stopping current trip: $currentTripId, length: ${tripLength}s")

repository.releaseStorage(currentTripId)

if (recordShortTrip || tripLength > MIN_TRIP_LENGTH) {
repository.updateTripMetadata(currentTripId, trip.startTs, tripLength, profile.getCurrentProfile())
} else {
Log.w(LOG_TAG, "Trip time is less than ${MIN_TRIP_LENGTH}s. Discarding.")
repository.deleteTrip(currentTripId)
}

activeTripId = null
ts = System.currentTimeMillis() - ts
Log.i(LOG_TAG, "Trip: $currentTripId is saved. It took $ts ms")
}
} finally {
sendBroadcastEvent(SCREEN_UNLOCK_PROGRESS_EVENT)
}
}
}

Expand All @@ -130,45 +204,6 @@ internal class DefaultTripManager :
repository.deleteTrip(trip.fileName)
}

override fun loadTrip(tripId: String) {
Log.i(LOGGER_TAG, "Loading trip ID: '$tripId'")

if (tripId.isEmpty()) {
updateCache(System.currentTimeMillis())
return
}

try {
val parts = tripDescParser.decodeTripName(tripId)
val startTs = parts.getOrNull(2)?.toLongOrNull() ?: System.currentTimeMillis()
val trip = Trip(startTs = startTs)

repository.loadTrip(tripId) { metric ->
val key = metric.entry.data
if (!trip.entries.containsKey(key)) {
trip.entries[key] = SensorData(id = key)
}
trip.entries[key]!!.metrics.add(metric)
}

trip.entries.values.forEach { sensorData ->
val values = sensorData.metrics.mapNotNull { it.entry.y.toString().toFloatOrNull() }
if (values.isNotEmpty()) {
sensorData.min = values.minOrNull() ?: 0f
sensorData.max = values.maxOrNull() ?: 0f
sensorData.mean = values.average()
}
}

Log.i(LOGGER_TAG, "Trip loaded successfully. PIDs: ${trip.entries.keys}")
tripCache.updateTrip(trip)
tripVirtualScreenManager.updateReservedVirtualScreen(trip.entries.keys.map { it.toString() })
} catch (e: Throwable) {
Log.e(LOGGER_TAG, "Failed to load trip '$tripId'.", e)
updateCache(System.currentTimeMillis())
}
}

private fun updateCache(newTs: Long) {
val trip = Trip(startTs = newTs)
tripCache.updateTrip(trip)
Expand Down
37 changes: 1 addition & 36 deletions datalogger/src/main/java/org/obd/graphs/bl/trip/TripManager.kt
Original file line number Diff line number Diff line change
Expand Up @@ -17,51 +17,16 @@
package org.obd.graphs.bl.trip

import android.content.Context
import android.util.Log
import org.obd.graphs.*
import org.obd.graphs.bl.datalogger.DataLoggerRepository
import org.obd.graphs.bl.datalogger.MetricsProcessor
import org.obd.graphs.commons.R

private const val LOG_TAG = "TripManager"

interface TripManager : MetricsProcessor {
fun getCurrentTrip(): Trip
fun startNewTrip(newTs: Long)
fun saveCurrentTrip()
fun getTripsDirectory(context: Context): String

fun saveCurrentTripAsync(){
sendBroadcastEvent(SCREEN_LOCK_PROGRESS_EVENT,
ScreenLock(message = R.string.dialog_screen_lock_trip_save_message))

runAsync (wait = false) {
try {
tripManager.saveCurrentTrip()
} finally {
sendBroadcastEvent(SCREEN_UNLOCK_PROGRESS_EVENT)
}
}
}
fun saveCurrentTrip()

fun findAllTripsBy(filter: String = ""): MutableCollection<TripFileDesc>
fun deleteTrip(trip: TripFileDesc)
fun loadTrip(tripName: String)
fun loadTripAsync(tripName: String){
if (!DataLoggerRepository.isRunning()) {
sendBroadcastEvent(SCREEN_LOCK_PROGRESS_EVENT,
ScreenLock(message = R.string.dialog_screen_lock_trip_load_message))


runAsync (wait = false) {
try {
Log.i(LOG_TAG, "Loading trip: '$tripName' ...................")
tripManager.loadTrip(tripName)
Log.i(LOG_TAG, "Trip: '$tripName' is loaded")
} finally {
sendBroadcastEvent(SCREEN_UNLOCK_PROGRESS_EVENT)
}
}
}
}
}
3 changes: 1 addition & 2 deletions datalogger/src/main/java/org/obd/graphs/bl/trip/TripModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ package org.obd.graphs.bl.trip
import com.fasterxml.jackson.annotation.JsonIgnoreProperties
import org.obd.metrics.transport.message.ConnectorResponse
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.ConcurrentLinkedDeque

data class TripFileDesc(
val fileName: String,
Expand All @@ -46,7 +45,7 @@ data class Metric(
@JsonIgnoreProperties(ignoreUnknown = true)
data class SensorData(
val id: Long,
val metrics: ConcurrentLinkedDeque<Metric> = ConcurrentLinkedDeque(),
val metrics: ArrayDeque<Metric> = ArrayDeque(),
var min: Number = 0,
var max: Number = 0,
var mean: Number = 0
Expand Down
Loading
Loading