Files
esp32-aldl-android/app/src/main/java/com/example/esp32aldldashboard/logging/CsvLogger.kt
T

101 lines
3.5 KiB
Kotlin

package com.example.esp32aldldashboard.logging
import android.content.ContentValues
import android.content.Context
import android.os.Build
import android.os.Environment
import android.provider.MediaStore
import com.example.esp32aldldashboard.parser.ALDLFrame
import java.io.OutputStream
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
class CsvLogger(private val context: Context) {
private var currentOutputStream: OutputStream? = null
fun startNewSession(isSimulation: Boolean): Boolean {
val timeStamp: String = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US).format(Date())
val fileName = "ALDL_Log_${if(isSimulation) "SIM_" else ""}$timeStamp.csv"
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
val resolver = context.contentResolver
val contentValues = ContentValues().apply {
put(MediaStore.MediaColumns.DISPLAY_NAME, fileName)
put(MediaStore.MediaColumns.MIME_TYPE, "text/csv")
put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DOWNLOADS + "/ALDLLogs")
}
val uri = resolver.insert(MediaStore.Downloads.EXTERNAL_CONTENT_URI, contentValues)
if (uri != null) {
currentOutputStream = resolver.openOutputStream(uri)
}
} else {
// For older Android versions, we'd need WRITE_EXTERNAL_STORAGE and write to Environment.getExternalStoragePublicDirectory.
// We'll skip legacy support for this specific snippet to keep it concise, assuming target is modern Android.
return false
}
// Write CSV Header
val header = "Timestamp,Raw_Hex,RPM,Coolant_C,Coolant_F,MAP_kPa,MAP_Volts,TPS_Volts,O2_mV,Battery_V,Spark_Adv,IAC,BPW_ms,Speed_MPH,MAT_C,MAT_F,BLM,INT,EGR_Duty,Rich_Crosses,Closed_Loop,Rich\n"
currentOutputStream?.write(header.toByteArray())
return true
} catch (e: Exception) {
e.printStackTrace()
return false
}
}
fun logFrame(frame: ALDLFrame) {
val out = currentOutputStream ?: return
val hexString = frame.rawBytes.joinToString(" ") { String.format("%02X", it) }
val dateString = SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS", Locale.US).format(Date(frame.timestamp))
val row = String.format(
Locale.US,
"%s,%s,%d,%.1f,%.1f,%.1f,%.3f,%.3f,%.1f,%.1f,%.1f,%d,%.2f,%d,%.1f,%.1f,%d,%d,%.1f,%d,%b,%b\n",
dateString,
hexString,
frame.engineSpeedRpm,
frame.coolantTempC,
frame.coolantTempF,
frame.mapKpa,
frame.mapVolts,
frame.tpsVolts,
frame.o2SensorMv,
frame.batteryVolts,
frame.sparkAdvance,
frame.iacPosition,
frame.bpwMs,
frame.vehicleSpeedMPH,
frame.matC,
frame.matF,
frame.blm,
frame.integrator,
frame.egrDutyCycle,
frame.richLeanCrosses,
frame.isClosedLoop,
frame.isRich
)
try {
out.write(row.toByteArray())
} catch (e: Exception) {
e.printStackTrace()
}
}
fun endSession() {
try {
currentOutputStream?.close()
} catch (e: Exception) {
e.printStackTrace()
} finally {
currentOutputStream = null
}
}
}