App 2.27.3: read the cruise control target speed, log it raw
The head unit names a vendor float AAD_EPTCCTRGTSPD (0x2160A15B), the cruise control target speed by its name. EVHardware reads it raw; the Logs tab lists each change with time, speed and gear, to establish the unit and the off value on the car. Emulator only (absent there). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LhzAVaUyqcw5PkGjz4mWW6
This commit is contained in:
+2
-2
@@ -34,8 +34,8 @@ android {
|
||||
applicationId "com.stinnesbeck.nilsmg4"
|
||||
minSdk 27
|
||||
targetSdk 36
|
||||
versionCode 123
|
||||
versionName "2.27.2"
|
||||
versionCode 124
|
||||
versionName "2.27.3"
|
||||
|
||||
// Nothing about the server ships in the APK: its URL and ingest token are entered in
|
||||
// the app's Server tab (ServerConfig), and the database is only reachable by the server.
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
package com.evsuite.abrp;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* Every change of the cruise control target speed the car reports (`0x2160A15B`, raw, unit not
|
||||
* established) with the time, speed and gear, the last {@link #MAX_LINES}, shown on the Logs
|
||||
* tab. It is how the value gets matched to what the cluster shows: set the cruise control, change
|
||||
* the speed, switch it off, and read what the car reported. Kept in preferences; a line is
|
||||
* written only when the value (to 0.1) changes.
|
||||
*/
|
||||
final class CruiseLog {
|
||||
|
||||
static final int MAX_LINES = 12;
|
||||
private static final String PREFS = "cruise_log";
|
||||
private static final String KEY = "lines";
|
||||
|
||||
/** The last value seen in this process, as text ("unread" when null); null before the first. */
|
||||
private static String last;
|
||||
|
||||
private CruiseLog() {}
|
||||
|
||||
/** The value as the log writes it: one decimal, or "unread". */
|
||||
static String format(Float raw) {
|
||||
return raw == null || !Float.isFinite(raw) ? "unread" : String.format(Locale.US, "%.1f", raw);
|
||||
}
|
||||
|
||||
/** Called with every reading; records a line when the value differs from the last one. */
|
||||
static void note(Context context, Float raw, Float speedKmh, Integer gear) {
|
||||
String value = format(raw);
|
||||
synchronized (CruiseLog.class) {
|
||||
if (context == null || value.equals(last)) return;
|
||||
last = value;
|
||||
String line = new SimpleDateFormat("dd.MM. HH:mm:ss", Locale.US).format(new Date())
|
||||
+ " target " + value
|
||||
+ " at " + (speedKmh == null ? "—" : String.format(Locale.US, "%.0f km/h", speedKmh))
|
||||
+ " gear " + (Gear.label(gear).isEmpty() ? "?" : Gear.label(gear));
|
||||
SharedPreferences prefs = context.getApplicationContext()
|
||||
.getSharedPreferences(PREFS, Context.MODE_PRIVATE);
|
||||
List<String> lines = UpdateLog.append(split(prefs.getString(KEY, null)), line, MAX_LINES);
|
||||
prefs.edit().putString(KEY, String.join("\n", lines)).apply();
|
||||
}
|
||||
}
|
||||
|
||||
/** The value now as text, "—" before the first reading. */
|
||||
static synchronized String current() {
|
||||
return last == null ? "—" : last;
|
||||
}
|
||||
|
||||
/** Newest first. */
|
||||
static List<String> lines(Context context) {
|
||||
SharedPreferences prefs = context.getApplicationContext()
|
||||
.getSharedPreferences(PREFS, Context.MODE_PRIVATE);
|
||||
return split(prefs.getString(KEY, null));
|
||||
}
|
||||
|
||||
private static List<String> split(String stored) {
|
||||
if (stored == null || stored.isEmpty()) return new ArrayList<>();
|
||||
return new ArrayList<>(Arrays.asList(stored.split("\n")));
|
||||
}
|
||||
}
|
||||
@@ -1731,6 +1731,7 @@ public class MainActivity extends AppCompatActivity {
|
||||
vehTireFr.setText(unit.format(s.getTirePressures().getFrontRightKpa()));
|
||||
vehTireRl.setText(unit.format(s.getTirePressures().getRearLeftKpa()));
|
||||
vehTireRr.setText(unit.format(s.getTirePressures().getRearRightKpa()));
|
||||
CruiseLog.note(this, s.getCruiseTargetSpeedRaw(), s.getSpeedKmh(), s.getGearRaw());
|
||||
showGauges(s);
|
||||
showCockpit(s);
|
||||
showDrawnStyles(s);
|
||||
@@ -2056,6 +2057,13 @@ public class MainActivity extends AppCompatActivity {
|
||||
// Update steps first: after a failed install, they are what the driver came here for.
|
||||
java.util.List<String> updates = UpdateLog.lines(this);
|
||||
StringBuilder sb = new StringBuilder();
|
||||
// The cruise control target speed as the car reports it, to match it on the car.
|
||||
java.util.List<String> cruise = CruiseLog.lines(this);
|
||||
if (!cruise.isEmpty()) {
|
||||
sb.append(getString(R.string.cruise_log_title, CruiseLog.current()));
|
||||
for (String line : cruise) sb.append('\n').append(line);
|
||||
sb.append("\n\n");
|
||||
}
|
||||
if (!updates.isEmpty()) {
|
||||
sb.append(getString(R.string.update_log_title));
|
||||
for (String line : updates) sb.append('\n').append(line);
|
||||
|
||||
@@ -198,6 +198,7 @@
|
||||
<string name="label_call_log">Recent uploads</string>
|
||||
<string name="call_log_empty">No upload attempted yet.</string>
|
||||
<string name="update_log_title">Updates, newest first:</string>
|
||||
<string name="cruise_log_title">Cruise control target speed, newest first (now: %1$s; raw, unit not known yet):</string>
|
||||
<string name="btn_flush_now">Upload now</string>
|
||||
<string name="status_starting">Starting…</string>
|
||||
<string name="status_running_no_upload">Running — waiting for first upload</string>
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.evsuite.abrp;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/** The cruise control log's value format — pure JVM. */
|
||||
public class CruiseLogTest {
|
||||
|
||||
@Test
|
||||
public void oneDecimalOrUnread() {
|
||||
assertEquals("120.0", CruiseLog.format(120f));
|
||||
assertEquals("33.3", CruiseLog.format(33.33f));
|
||||
assertEquals("0.0", CruiseLog.format(0f));
|
||||
assertEquals("unread", CruiseLog.format(null));
|
||||
assertEquals("unread", CruiseLog.format(Float.NaN));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user