From d8e656284ad14d31c488a2f484846ab72cac25e8 Mon Sep 17 00:00:00 2001 From: Gandalf Date: Fri, 12 Jun 2026 12:29:02 +0100 Subject: [PATCH] feat: add MockK dependency and update README documentation for diagnostic features --- README.md | 93 +++++++++++++------ app/build.gradle.kts | 1 + .../ui/charts/ChartsScreen.kt | 2 + gradle/libs.versions.toml | 2 + 4 files changed, 70 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index d8f99f5..da20fa9 100644 --- a/README.md +++ b/README.md @@ -1,39 +1,76 @@ # ESP32 ALDL Dashboard Android Application -This Android app connects via Bluetooth SPP to an ESP32 microcontroller that interfaces with a 1986 Pontiac Fiero 1227170 ECM using the 160-baud ALDL (Assembly Line Diagnostic Link) datastream. It decodes the telemetry stream in real-time and displays it on a modern Jetpack Compose dashboard. +A modern, high-performance Android application designed to interface with GM OBD1 systems—specifically the **1986 Pontiac Fiero 1227170 ECM**—using a custom ESP32 Bluetooth SPP bridge. The app decodes the low-speed 160-baud ALDL (Assembly Line Diagnostic Link) datastream in real-time, displaying live telemetry, logging diagnostic parameters, and generating tuning heatmaps. -## Features +--- -* **Real-time Dashboard:** View essential engine metrics including Engine Speed (RPM), Vehicle Speed (MPH), Coolant Temperature, Manifold Air Temperature (MAT), Manifold Absolute Pressure (MAP), Throttle Position (TPS), O2 Sensor Voltage, and Battery Voltage. -* **Custom UI Components:** Beautiful animated Canvas-based radial RPM gauge and TPS bar graph. -* **Trouble Code Alerts:** Automatically decodes ECM active fault codes into human-readable alerts (e.g., Code 14 - Coolant Temperature Sensor High). -* **Status Flags:** Real-time visibility into Closed Loop, Rich Mixture, TCC Lockup, A/C Clutch requests, and more. -* **Derived Metrics:** Calculates estimated Engine Load and Fuel Flow Hint based on core telemetry data. -* **Real-Time Line Charts:** Built-in rolling graphs of RPM vs. Time, perfect for diagnostic troubleshooting. -* **Background Telemetry Logging:** Uses an Android Foreground Service to maintain the Bluetooth connection and record data seamlessly even when the app is minimized. -* **Local Persistence:** Uses Jetpack Room database to save full sessions with timestamped raw payloads. -* **CSV Data Export:** Automatically generates TunerPro RT compatible `.csv` log files in the `Downloads/ALDLLogs` folder using Android MediaStore APIs. -* **Settings & Configuration:** Persistent DataStore preferences for Unit Toggle (°C/°F), Auto-Logging toggles, and Coolant Alert Thresholds. +## 🌟 Key Features -## Architecture Highlights +* **Real-Time Instrumentation Dashboard:** + * Vibrant, animated Canvas-based components including a radial RPM gauge and a Throttle Position Sensor (TPS) bar graph. + * Instantaneous readouts for Engine Speed (RPM), Vehicle Speed (MPH), Coolant Temperature, Manifold Air Temp (MAT), Manifold Absolute Pressure (MAP), TPS voltage, O2 Sensor voltage, and Battery voltage. + * **Status Flags:** Instant visibility into critical operating states like Closed Loop Mode, Rich/Lean Mixture, Torque Converter Clutch (TCC) Lockup, and A/C Clutch requests. + * **Derived Metrics:** Real-time calculated estimates of Engine Load and Fuel Flow Hints. +* **BLM & INT Fuel Trim Heatmap Grid (New):** + * A real-time diagnostic table indexing fuel trim metrics across **14 RPM bands** (600 to 4800 RPM) and **17 MAP bands** (20 to 100 kPa). + * Color-coded cell visualisations using dynamic RGB interpolation: Green for lean fuel trims ($\le 120$), Blue for stoichiometric neutral ($128$), and Red for rich fuel trims ($\ge 150$). +* **Multi-Parameter Line Charting (New):** + * A dynamic telemetry visualizer toggling between a **Single Chart Mode** (large-scale view of any metric) and a **Multi Chart Mode** displaying up to 4 selected metrics in a 2x2 grid. + * Supports charting for **12 distinct parameters**: RPM, Coolant Temp, MAP, TPS, O2 Sensor, Battery Voltage, Spark Advance, Base Pulse Width (BPW), MAT, BLM, Integrator, and Idle Air Control (IAC) Position. +* **Trouble Code Diagnostic Engine:** + * Decodes active ECM trouble codes into human-readable alerts (e.g., *Code 14 - Coolant Temperature Sensor High*) dynamically displayed at the bottom of the dashboard screen. +* **Dual-Logging Framework:** + * **Room Database Sessions:** Saves all active telemetry packets to a local SQLite database using Jetpack Room. + * **TunerPro RT CSV Export:** Automatically compiles sessions into `.csv` log files fully compatible with TunerPro RT, exported to `Downloads/ALDLLogs` using Android MediaStore. + * **Raw Binary Stream Logging (New):** Optional raw capture recording direct 27-byte diagnostic datastream packets (incorporating `AA 55` headers and 25-byte payloads) to `.bin` files for advanced playback and diagnostic troubleshooting. +* **Logged Files Manager (New):** + * An in-app browser inside the Settings panel that scans `Downloads/ALDLLogs` for CSV and BIN logs, enabling users to view details, open logs with default viewers, or share files via the Android Sharesheet. +* **Persistent Preferences & Guardrails:** + * DataStore-backed settings for Temperature Unit toggle (°C/°F), Auto-Logging toggles, Coolant alert thresholds, Low Battery alert thresholds, and Raw Binary Stream recording toggles. -* **MVVM & StateFlow:** Strict MVVM separation of concerns. The UI reactivity is entirely driven by `StateFlow` streams. -* **Circular Ring Buffer Packet Parsing:** The Bluetooth ingest layer uses `ArrayDeque` circular buffering. It constantly seeks the `AA 55` header, preventing misalignment desyncs over noisy lines. -* **Robust Parsers:** The `ALDLParser` encapsulates all scaling constants and interpolation arrays (for MAT) required by the TunerPro `24-INT10.ads` definition. +--- -## Requirements +## 🛠️ Architecture & Technical Highlights -* Android Device running Android 8.0+ (Tested extensively against Android 13+) -* Bluetooth Permissions (Nearby Devices on Android 12+) -* ESP32 hardware module programmed with the accompanying ALDL datastream code. +* **Jetpack Compose & MVVM:** Developed with a clean Model-View-ViewModel architecture. State emission is managed via reactive `StateFlow` and `SharedFlow` streams to guarantee lag-free rendering. +* **Circular Buffering & Packet Validation (New):** + * Ingests raw Bluetooth stream buffers using an `ArrayDeque` circular buffer. + * Employs a **27-byte lookahead validation algorithm** to search for authentic `AA 55` frame headers, preventing sync misalignment or telemetry corruption from noisy serial lines. +* **TunerPro ADS Translation:** Uses an advanced [ALDLParser](file:///home/gordon/esp32-aldl-android/app/src/test/java/com/example/esp32aldldashboard/ALDLParserTest.kt) mapping raw 25-byte payloads into physical metrics using exact scale conversions, offsets, and non-linear lookup interpolations (derived from the `24-INT10.ads` definition file). +* **Foreground Service Operations (New):** + * Runs a persistent `BluetoothForegroundService` to keep the Bluetooth socket open and stream telemetry continuously in the background, even when the phone screen is locked or the app is minimized. +* **Firebase Integration:** Incorporates Firebase Crashlytics to monitor application stability and track runtime exceptions. -## Setup Instructions +--- -1. Pair the ESP32 (named `ESP32-ALDL`) in your Android Bluetooth settings. -2. Grant the requested Bluetooth permissions inside the app. -3. Tap "Connect BT" to begin the telemetry stream. -4. Navigate to the **Settings** tab to toggle Auto-Logging or customize unit formats. -5. View historical `.csv` logs in your device's `Downloads/ALDLLogs` folder. +## 📱 Requirements -## Build Information -Developed using Android Studio and Gradle. Built with Jetpack Compose, Room (with KSP Annotation Processor), and DataStore. \ No newline at end of file +* **Android Device:** Android 8.0 (API Level 26) or higher. +* **Bluetooth Permissions:** Requires Nearby Devices (Android 12+) and Legacy Bluetooth Admin access. +* **ESP32 Transceiver:** Bridge hardware programmed to output 160-baud serial data from the ALDL pin and stream it over Classic Bluetooth SPP (named `ESP32-ALDL`). + +--- + +## 🚀 Setup & Usage + +1. Pair the `ESP32-ALDL` Bluetooth module in your Android system settings. +2. Launch the application and grant all requested permissions. +3. Tap **Connect BT** on the main dashboard to establish connection and start telemetry. +4. Navigate between screens (Dashboard, Charts, BLM Table, Settings) using the bottom navigation bar. +5. Configure logging preferences or browse logged CSV/BIN files in the **Settings** menu. + +--- + +## 🧪 Testing & Verification + +The parsing logic, scaling calculations, and boundary conditions are validated by a unit test suite located in [ALDLParserTest.kt](file:///home/gordon/esp32-aldl-android/app/src/test/java/com/example/esp32aldldashboard/ALDLParserTest.kt). + +To run the unit tests, execute the following Gradle command in the root project directory: +```bash +./gradlew test +``` + +### Coverage Areas +* **Sample Frame Decoding:** Parses a real-world telemetry payload and verifies the output of IAC position, coolant/manifold temperatures, MAP, TPS, battery voltage, BLM, integrator, spark advance, base pulse width, closed-loop flags, and active trouble codes. +* **Boundary Guards:** Ensures outlier protection for engine speeds, battery voltages, TPS, and coolant temperatures, rejecting out-of-range sensor values as invalid data packets. +* **Lookahead Stability:** Validates parser behavior against truncated or incomplete frame fragments. \ No newline at end of file diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 591773d..aab8ae8 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -73,6 +73,7 @@ dependencies { // Local tests: jUnit, coroutines, Android runner testImplementation(libs.junit) testImplementation(libs.kotlinx.coroutines.test) + testImplementation(libs.mockk) // Instrumented tests: jUnit rules and runners androidTestImplementation(libs.androidx.test.core) diff --git a/app/src/main/java/com/example/esp32aldldashboard/ui/charts/ChartsScreen.kt b/app/src/main/java/com/example/esp32aldldashboard/ui/charts/ChartsScreen.kt index 4026314..871e6ba 100644 --- a/app/src/main/java/com/example/esp32aldldashboard/ui/charts/ChartsScreen.kt +++ b/app/src/main/java/com/example/esp32aldldashboard/ui/charts/ChartsScreen.kt @@ -1,5 +1,7 @@ +@file:OptIn(androidx.compose.material3.ExperimentalMaterial3Api::class) package com.example.esp32aldldashboard.ui.charts +import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.foundation.Canvas import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyRow diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 904dcbd..fa69ce7 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -16,6 +16,7 @@ lifecycleViewmodelNav3 = "2.10.0" room = "2.6.1" datastore = "1.1.1" ksp = "2.1.0-1.0.29" +mockk = "1.13.10" [libraries] androidx-core-ktx = { module = "androidx.core:core-ktx", version.ref = "androidxCore" } @@ -45,6 +46,7 @@ androidx-room-runtime = { module = "androidx.room:room-runtime", version.ref = " androidx-room-ktx = { module = "androidx.room:room-ktx", version.ref = "room" } androidx-room-compiler = { module = "androidx.room:room-compiler", version.ref = "room" } androidx-datastore-preferences = { module = "androidx.datastore:datastore-preferences", version.ref = "datastore" } +mockk = { module = "io.mockk:mockk", version.ref = "mockk" } [plugins] android-application = { id = "com.android.application", version.ref = "androidGradlePlugin" }