diff --git a/app/build.gradle b/app/build.gradle
index 7f7983f5..22efa53b 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -215,7 +215,7 @@ dependencies {
implementation 'com.fasterxml.jackson.core:jackson-databind:2.11.0'
implementation 'com.fasterxml.jackson.module:jackson-module-kotlin:2.11.0'
implementation 'io.reactivex:rxjava:1.3.8'
- implementation 'io.apisense:rhino-android:1.1.1'
+ implementation 'io.apisense:rhino-android:1.3.0'
implementation 'com.github.PhilJay:MPAndroidChart:v3.1.0'
implementation 'io.dropwizard.metrics:metrics-core:4.1.17'
implementation 'com.dynatrace.dynahist:dynahist:1.1'
diff --git a/app/src/main/java/org/obd/graphs/preferences/PreferencesFragment.kt b/app/src/main/java/org/obd/graphs/preferences/PreferencesFragment.kt
index 37d6621c..f0487197 100644
--- a/app/src/main/java/org/obd/graphs/preferences/PreferencesFragment.kt
+++ b/app/src/main/java/org/obd/graphs/preferences/PreferencesFragment.kt
@@ -228,6 +228,12 @@ class PreferencesFragment : PreferenceFragmentCompat() {
p3?.isVisible = true
}
+ "mock" -> {
+ p1?.isVisible = false
+ p2?.isVisible = false
+ p3?.isVisible = false
+ }
+
else -> {
}
}
@@ -254,6 +260,12 @@ class PreferencesFragment : PreferenceFragmentCompat() {
p3?.isVisible = true
}
+ "mock" -> {
+ p1?.isVisible = false
+ p2?.isVisible = false
+ p3?.isVisible = false
+ }
+
else -> {
p1?.isVisible = false
p2?.isVisible = true
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 5baf925a..86a4766b 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -101,7 +101,8 @@
OBD2 Adapter Connection
This section contains settings related to your adapter type. Here, you can configure the Wi-Fi or Bluetooth parameters of your adapter.
- Type of connection
+ Select OBD adapter connection type
+ OBD adapter connection type
Connection timeout
Available bluetooth devices
@@ -431,9 +432,10 @@
Theme
- - wifi
- bluetooth
+ - wifi
- usb
+ - mock
Settings
diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml
index 0b0d9daa..f0db77fb 100644
--- a/app/src/main/res/xml/preferences.xml
+++ b/app/src/main/res/xml/preferences.xml
@@ -133,7 +133,7 @@
-
-
runAsync(wait: Boolean = true, handler: () -> T) : T {
- val asyncJob: AsyncTask = object : AsyncTask() {
- @Deprecated("Deprecated in Java", ReplaceWith("handler()"))
- override fun doInBackground(vararg params: Void?): T {
- return handler()
- }
- }
- return if (wait) {
- asyncJob.execute().get()
- } else {
- asyncJob.execute()
- null as T
- }
-}
+ fun runAsync(wait: Boolean = false, handler: () -> T): T? {
+ return if (wait) {
+ runBlocking(Dispatchers.Default) {
+ handler()
+ }
+ } else {
+ backgroundScope.launch {
+ handler()
+ }
+ null
+ }
+ }
diff --git a/datalogger/src/main/java/org/obd/graphs/bl/datalogger/AdjustmentsStrategy.kt b/datalogger/src/main/java/org/obd/graphs/bl/datalogger/AdjustmentsStrategy.kt
index 93d76bb7..0711ee6e 100644
--- a/datalogger/src/main/java/org/obd/graphs/bl/datalogger/AdjustmentsStrategy.kt
+++ b/datalogger/src/main/java/org/obd/graphs/bl/datalogger/AdjustmentsStrategy.kt
@@ -28,7 +28,6 @@ import org.obd.metrics.api.model.PidDefinitionCustomization
import org.obd.metrics.api.model.ProducerPolicy
import org.obd.metrics.api.model.STNxxExtensions
import org.obd.metrics.api.model.SniffingPolicy
-import org.obd.metrics.codec.GeneratorPolicy
import java.io.File
internal class AdjustmentsStrategy {
@@ -86,12 +85,6 @@ internal class AdjustmentsStrategy {
.pidPriority(4, 4) // atm pressure, ambient temp
.conditionalSleepEnabled(false)
.build(),
- ).generatorPolicy(
- GeneratorPolicy
- .builder()
- .enabled(preferences.generatorEnabled)
- .increment(0.5)
- .build(),
).adaptiveTimeoutPolicy(
AdaptiveTimeoutPolicy
.builder()
@@ -103,13 +96,17 @@ internal class AdjustmentsStrategy {
)
if (dataLoggerSettings.instance().adapter.stnExtensionsEnabled) {
- val highPriorityOverridePolicy = PidDefinitionCustomization.builder().priority(0).build()
+ val highPriorityOverridePolicy =
+ PidDefinitionCustomization.builder().priority(0).build()
builder =
builder
.override(Pid.ATM_PRESSURE_PID_ID.id, highPriorityOverridePolicy)
.override(Pid.AMBIENT_TEMP_PID_ID.id, highPriorityOverridePolicy)
.override(Pid.DYNAMIC_SELECTOR_PID_ID.id, highPriorityOverridePolicy)
- .override(Pid.ENGINE_TORQUE_PID_ID.id, PidDefinitionCustomization.builder().priority(4).build())
+ .override(
+ Pid.ENGINE_TORQUE_PID_ID.id,
+ PidDefinitionCustomization.builder().priority(4).build(),
+ )
}
return builder.build()
@@ -120,9 +117,15 @@ internal class AdjustmentsStrategy {
.builder()
.sniffing(SniffingPolicy.builder().enabled(false).build())
.debugEnabled(preferences.debugLogging)
- .override(Pid.DISTANCE_PID_ID.id, PidDefinitionCustomization.builder().lastInTheQuery(true).build())
- .formulaExternalParams(FormulaExternalParams.builder().param("unit_tank_size", preferences.fuelTankSize).build())
- .errorsPolicy(
+ .override(
+ Pid.DISTANCE_PID_ID.id,
+ PidDefinitionCustomization.builder().lastInTheQuery(true).build(),
+ ).formulaExternalParams(
+ FormulaExternalParams
+ .builder()
+ .param("unit_tank_size", preferences.fuelTankSize)
+ .build(),
+ ).errorsPolicy(
ErrorsPolicy
.builder()
.numberOfRetries(preferences.adapter.maxReconnectNum)
@@ -142,7 +145,7 @@ internal class AdjustmentsStrategy {
STNxxExtensions
.builder()
.promoteSlowGroupsEnabled(false)
- .stripWhitespaces(true)
+ .stripWhitespaces(dataLoggerSettings.instance().adapter.connectionType != "mock")
.promoteAllGroupsEnabled(preferences.adapter.stnIgnorePIDsPriorities)
.enabled(preferences.adapter.stnExtensionsEnabled)
.build(),
@@ -153,7 +156,12 @@ internal class AdjustmentsStrategy {
.cachePolicy(
CachePolicy
.builder()
- .resultCacheFilePath(File(getContext()?.cacheDir, "formula_cache.json").absolutePath)
+ .resultCacheFilePath(
+ File(
+ getContext()?.cacheDir,
+ "formula_cache.json",
+ ).absolutePath,
+ ).storeResultCacheOnDisk(false)
.resultCacheEnabled(preferences.adapter.resultsCacheEnabled)
.build(),
).producerPolicy(
@@ -162,12 +170,6 @@ internal class AdjustmentsStrategy {
.conditionalSleepEnabled(preferences.adapter.adaptiveConnectionEnabled)
.conditionalSleepSliceSize(10)
.build(),
- ).generatorPolicy(
- GeneratorPolicy
- .builder()
- .enabled(preferences.generatorEnabled)
- .increment(0.5)
- .build(),
).adaptiveTimeoutPolicy(
AdaptiveTimeoutPolicy
.builder()
diff --git a/datalogger/src/main/java/org/obd/graphs/bl/datalogger/DataLoggerSettings.kt b/datalogger/src/main/java/org/obd/graphs/bl/datalogger/DataLoggerSettings.kt
index 4ccfa1a9..03c70162 100644
--- a/datalogger/src/main/java/org/obd/graphs/bl/datalogger/DataLoggerSettings.kt
+++ b/datalogger/src/main/java/org/obd/graphs/bl/datalogger/DataLoggerSettings.kt
@@ -117,8 +117,6 @@ data class DataLoggerSettings(
var dragRacingCommandFrequency: Long = 10,
@XmlPreference("pref.mode", "Generic mode", String::class)
var mode: String = "Generic mode",
- @XmlPreference("pref.debug.generator.enabled", "false", Boolean::class)
- var generatorEnabled: Boolean = false,
@XmlPreference("pref.pids.registry.list", "", Set::class)
var resources: Set = modules.getDefaultModules().keys,
@XmlPreference("pref.debug.trip.save.connector_response", "false", Boolean::class)
diff --git a/datalogger/src/main/java/org/obd/graphs/bl/datalogger/WorkflowOrchestrator.kt b/datalogger/src/main/java/org/obd/graphs/bl/datalogger/WorkflowOrchestrator.kt
index f820f01e..2b3d03cf 100644
--- a/datalogger/src/main/java/org/obd/graphs/bl/datalogger/WorkflowOrchestrator.kt
+++ b/datalogger/src/main/java/org/obd/graphs/bl/datalogger/WorkflowOrchestrator.kt
@@ -21,6 +21,9 @@ import android.content.Context
import android.content.Intent
import android.util.Log
import androidx.lifecycle.LifecycleOwner
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.SupervisorJob
import org.obd.graphs.*
import org.obd.graphs.bl.datalogger.connectors.ConnectionManager
import org.obd.graphs.bl.query.Query
@@ -44,7 +47,7 @@ import org.obd.metrics.pid.Urls
import org.obd.metrics.pid.ValueType
import java.util.*
-private const val JS_ENGINE_NAME = "rhino"
+const val JS_ENGINE_NAME = "rhino"
/**
* That's the wrapper interface on Workflow API.
@@ -75,9 +78,12 @@ internal class WorkflowOrchestrator internal constructor() {
sendBroadcastEvent(DATA_LOGGER_CONNECTING_EVENT)
}
- override fun onRoutineCompleted(routineCommand: RoutineCommand, status: RoutineExecutionStatus) {
- Log.e(LOG_TAG, "Routine: ${routineCommand.pid.description} execution status: $status")
- val event = when (status){
+ override fun onRoutineCompleted(
+ routineCommand: RoutineCommand,
+ status: RoutineExecutionStatus
+ ) {
+ Log.i(LOG_TAG, "Routine: ${routineCommand.pid.description} execution status: $status")
+ val event = when (status) {
RoutineExecutionStatus.ERROR -> ROUTINE_EXECUTION_FAILED_EVENT
RoutineExecutionStatus.NO_DATA -> ROUTINE_EXECUTION_NO_DATA_RECEIVED_EVENT
RoutineExecutionStatus.SUCCESS -> ROUTINE_EXECUTED_SUCCESSFULLY_EVENT
@@ -138,10 +144,10 @@ internal class WorkflowOrchestrator internal constructor() {
private val adjustmentsStrategy = AdjustmentsStrategy()
fun observe(metricsProcessor: MetricsProcessor) {
- if (metricsProcessorsRegistry.contains(metricsProcessor)){
- Log.i(LOG_TAG,"Metrics processor is already registered: $metricsProcessor")
- }else {
- Log.i(LOG_TAG,"Registering: $metricsProcessor metrics processor")
+ if (metricsProcessorsRegistry.contains(metricsProcessor)) {
+ Log.i(LOG_TAG, "Metrics processor is already registered: $metricsProcessor")
+ } else {
+ Log.i(LOG_TAG, "Registering: $metricsProcessor metrics processor")
metricsProcessorsRegistry.add(metricsProcessor)
metricsObserver.observe(metricsProcessor)
}
@@ -160,9 +166,11 @@ internal class WorkflowOrchestrator internal constructor() {
fun diagnostics(): Diagnostics = workflow.diagnostics
- fun findHistogramFor(metric: ObdMetric): Histogram = workflow.diagnostics.histogram().findBy(metric.command.pid)
+ fun findHistogramFor(metric: ObdMetric): Histogram =
+ workflow.diagnostics.histogram().findBy(metric.command.pid)
- fun findRateFor(metric: ObdMetric): Optional = workflow.diagnostics.rate().findBy(RateType.MEAN, metric.command.pid)
+ fun findRateFor(metric: ObdMetric): Optional =
+ workflow.diagnostics.rate().findBy(RateType.MEAN, metric.command.pid)
fun pidDefinitionRegistry(): PidDefinitionRegistry = workflow.pidRegistry
@@ -179,34 +187,54 @@ internal class WorkflowOrchestrator internal constructor() {
Log.e(LOG_TAG, "Failed to stop the workflow", e)
}
}
-
fun start(query: Query) {
- currentQuery = query
+ runAsync (wait=false) {
+ android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_BACKGROUND)
+ currentQuery = query
- val dataLoggerQuery = org.obd.metrics.api.model.Query.builder().pids(query.getIDs()).build()
- Log.i(LOG_TAG, "Stating collecting process. Strategy: ${query.getStrategy()}. Selected PIDs: ${dataLoggerQuery.pids}")
- ConnectionManager.obtain()?.run {
- val status = workflow.start(
- this, dataLoggerQuery, init(),
- adjustmentsStrategy.findAdjustmentFor(query.getStrategy())
+ val dataLoggerQuery =
+ org.obd.metrics.api.model.Query.builder().pids(query.getIDs()).build()
+ Log.i(
+ LOG_TAG,
+ "Stating collecting process. Strategy: ${query.getStrategy()}. Selected PIDs: ${dataLoggerQuery.pids}"
)
- Log.i(LOG_TAG, "Collecting process started. Strategy: ${query.getStrategy()}. Status=$status")
+ val adjustments = adjustmentsStrategy.findAdjustmentFor(query.getStrategy())
+ val init = init()
+
+ ConnectionManager.obtain(pidDefinitionRegistry(), dataLoggerQuery, adjustments, init)
+ ?.run {
+ val status = workflow.start(this, dataLoggerQuery, init, adjustments)
+ Log.i(
+ LOG_TAG,
+ "Collecting process started. Strategy: ${query.getStrategy()}. Status=$status"
+ )
+ }
}
}
fun executeRoutine(query: Query) {
currentQuery = query
+ val init = init()
+ val dataLoggerQuery = org.obd.metrics.api.model.Query.builder().pids(query.getIDs()).build()
+ val adjustments = adjustmentsStrategy.findAdjustmentFor(query.getStrategy())
+ ConnectionManager.obtain(pidDefinitionRegistry(), dataLoggerQuery, adjustments, init)?.run {
+ Log.i(
+ LOG_TAG,
+ "Executing routine. Strategy: ${query.getStrategy()}. Selected PIDs: ${dataLoggerQuery.pids}"
+ )
- ConnectionManager.obtain()?.run {
- val dataLoggerQuery = org.obd.metrics.api.model.Query.builder().pids(query.getIDs()).build()
- Log.i(LOG_TAG, "Executing routine. Strategy: ${query.getStrategy()}. Selected PIDs: ${dataLoggerQuery.pids}")
-
- val status = workflow.executeRoutine(dataLoggerQuery.pids.first(), init())
- Log.i(LOG_TAG, "Routines has been completed. Strategy: ${query.getStrategy()}. Status=$status")
+ val status = workflow.executeRoutine(dataLoggerQuery.pids.first(), init)
+ Log.i(
+ LOG_TAG,
+ "Routines has been completed. Strategy: ${query.getStrategy()}. Status=$status"
+ )
when (status) {
WorkflowExecutionStatus.REJECTED -> sendBroadcastEvent(ROUTINE_REJECTED_EVENT)
- WorkflowExecutionStatus.NOT_RUNNING -> sendBroadcastEvent(ROUTINE_WORKFLOW_NOT_RUNNING_EVENT)
+ WorkflowExecutionStatus.NOT_RUNNING -> sendBroadcastEvent(
+ ROUTINE_WORKFLOW_NOT_RUNNING_EVENT
+ )
+
else -> sendBroadcastEvent(ROUTINE_UNKNOWN_STATUS_EVENT)
}
}
@@ -215,41 +243,50 @@ internal class WorkflowOrchestrator internal constructor() {
private lateinit var currentQuery: Query
- fun getCurrentQuery (): Query? = if (::currentQuery.isInitialized) currentQuery else null
+ fun getCurrentQuery(): Query? = if (::currentQuery.isInitialized) currentQuery else null
fun updateQuery(query: Query) {
if (isSameQuery(query)) {
Log.w(LOG_TAG, "Received same query=${query.getIDs()}. Do not update.")
} else {
- val dataLoggerQuery = org.obd.metrics.api.model.Query.builder().pids(query.getIDs()).build()
+ val dataLoggerQuery =
+ org.obd.metrics.api.model.Query.builder().pids(query.getIDs()).build()
val adjustments = adjustmentsStrategy.findAdjustmentFor(query.getStrategy())
+
val status = workflow.updateQuery(
dataLoggerQuery,
init(), adjustments
)
- Log.i(LOG_TAG, "Query update finished, strategy: ${query.getStrategy()}. Status=$status")
+ Log.i(
+ LOG_TAG,
+ "Query update finished, strategy: ${query.getStrategy()}. Status=$status"
+ )
}
currentQuery = query
}
- fun isSameQuery(query: Query) = ::currentQuery.isInitialized && query.getIDs() == currentQuery.getIDs()
+ fun isSameQuery(query: Query) =
+ ::currentQuery.isInitialized && query.getIDs() == currentQuery.getIDs()
fun isDTCEnabled(): Boolean = workflow.pidRegistry.findBy(PIDsGroup.DTC_READ).isNotEmpty()
- private fun init(preferences: DataLoggerSettings = dataLoggerSettings.instance()) = Init.builder()
- .delayAfterInit(preferences.adapter.initDelay)
- .delayAfterReset(preferences.adapter.delayAfterReset)
- .headers(diagnosticRequestIDMapper.getMapping().map { entry ->
- Init.Header.builder().mode(entry.key).header(entry.value).build()
- }.toMutableList())
- .protocol(Init.Protocol.valueOf(preferences.adapter.initProtocol))
- .sequence(DefaultCommandGroup.INIT).build()
+ private fun init(preferences: DataLoggerSettings = dataLoggerSettings.instance()) =
+ Init.builder()
+ .delayAfterInit(preferences.adapter.initDelay)
+ .delayAfterReset(preferences.adapter.delayAfterReset)
+ .headers(diagnosticRequestIDMapper.getMapping().map { entry ->
+ Init.Header.builder().mode(entry.key).header(entry.value).build()
+ }.toMutableList())
+ .protocol(Init.Protocol.valueOf(preferences.adapter.initProtocol))
+ .sequence(DefaultCommandGroup.INIT).build()
private fun workflow() = Workflow.instance()
- .formulaEvaluatorConfig(FormulaEvaluatorConfig.builder().scriptEngine(JS_ENGINE_NAME).build())
+ .formulaEvaluatorConfig(
+ FormulaEvaluatorConfig.builder().scriptEngine(JS_ENGINE_NAME).build()
+ )
.pids(
pids()
)
@@ -271,19 +308,33 @@ internal class WorkflowOrchestrator internal constructor() {
}
}
- registerGPSPids(workflow.pidRegistry)
+ registerGPSPids(workflow.pidRegistry)
}
private fun registerGPSPids(pidRegistry: PidDefinitionRegistry) {
- Log.d(LOG_TAG,"Registering GPS PIDs")
- pidRegistry.register(PidDefinition(Pid.GPS_LOCATION_PID_ID.id, 2, "", "22", "Alt", "m", "GPS", -180, 10000, ValueType.DOUBLE))
+ Log.d(LOG_TAG, "Registering GPS PIDs")
+ pidRegistry.register(
+ PidDefinition(
+ Pid.GPS_LOCATION_PID_ID.id,
+ 2,
+ "",
+ "22",
+ "Alt",
+ "m",
+ "GPS",
+ -180,
+ 10000,
+ ValueType.DOUBLE
+ )
+ )
}
- private fun pids(): Pids? = Pids.builder().resources(dataLoggerSettings.instance().resources.map {
- if (modules.isExternalStorageModule(it)) {
- modules.externalModuleToURL(it)
- } else {
- Urls.resourceToUrl(it)
- }
- }.toMutableList()).build()
+ private fun pids(): Pids? =
+ Pids.builder().resources(dataLoggerSettings.instance().resources.map {
+ if (modules.isExternalStorageModule(it)) {
+ modules.externalModuleToURL(it)
+ } else {
+ Urls.resourceToUrl(it)
+ }
+ }.toMutableList()).build()
}
diff --git a/datalogger/src/main/java/org/obd/graphs/bl/datalogger/connectors/ConnectionManager.kt b/datalogger/src/main/java/org/obd/graphs/bl/datalogger/connectors/ConnectionManager.kt
index 4e41b400..3106bb57 100644
--- a/datalogger/src/main/java/org/obd/graphs/bl/datalogger/connectors/ConnectionManager.kt
+++ b/datalogger/src/main/java/org/obd/graphs/bl/datalogger/connectors/ConnectionManager.kt
@@ -23,16 +23,24 @@ import org.obd.graphs.bl.datalogger.DATA_LOGGER_ERROR_CONNECT_EVENT
import org.obd.graphs.bl.datalogger.DATA_LOGGER_WIFI_INCORRECT
import org.obd.graphs.bl.datalogger.DATA_LOGGER_WIFI_NOT_CONNECTED
import org.obd.graphs.bl.datalogger.DataLoggerSettings
+import org.obd.graphs.bl.datalogger.JS_ENGINE_NAME
import org.obd.graphs.bl.datalogger.LOG_TAG
import org.obd.graphs.bl.datalogger.dataLoggerSettings
import org.obd.graphs.getContext
import org.obd.graphs.sendBroadcastEvent
+import org.obd.metrics.api.model.Adjustments
+import org.obd.metrics.api.model.Init
+import org.obd.metrics.api.model.Query
+import org.obd.metrics.pid.PidDefinitionRegistry
import org.obd.metrics.transport.AdapterConnection
+import org.obd.metrics.transport.mock.SmartMockConnectionFactory
+import org.obd.metrics.transport.mock.strategy.Strategy
-internal object ConnectionManager {
+ internal object ConnectionManager {
- fun obtain(): AdapterConnection? =
+ fun obtain(registry: PidDefinitionRegistry, query: Query, adjustments: Adjustments, init: Init): AdapterConnection? =
when (dataLoggerSettings.instance().adapter.connectionType) {
+ "mock" -> mockConnection(registry,query,adjustments,init)
"wifi" -> wifiConnection()
"bluetooth" -> bluetoothConnection()
"usb" -> getContext()?.let { UsbConnection.of(context = it) }
@@ -40,7 +48,17 @@ internal object ConnectionManager {
null
}
}
-
+ private fun mockConnection(registry: PidDefinitionRegistry, query: Query, adjustments: Adjustments, init: Init): AdapterConnection? =
+ SmartMockConnectionFactory
+ .smartBuilder()
+ .init(init)
+ .registry(registry)
+ .query(query)
+ .jsEngineName(JS_ENGINE_NAME)
+ .optional(adjustments)
+ .strategy(Strategy.SmartSawtooth)
+ .responseCount(500)
+ .build();
private fun bluetoothConnection(): AdapterConnection? =
try {
val deviceAddress = dataLoggerSettings.instance().adapter.deviceAddress
diff --git a/gradle.properties b/gradle.properties
index 4308c5f4..0f73a498 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -19,4 +19,4 @@ android.useAndroidX=true
android.enableJetifier=true
# Kotlin code style for this project: "official" or "obsolete":
kotlin.code.style=official
-obdMetricVersion=11.12.0-SNAPSHOT
+obdMetricVersion=11.14.0-SNAPSHOT