- Phase 1 core protocol: temp_table, neg8, sensor_state, s300_parser, kpro_parser, dtc_map, sensor_defs (50/50 tests passing) - BT layer: bt_service.dart, bt_poller.dart (100ms poll, NEG8 validation) - Connection test UI: device picker, protocol selector, live sensor screen with LIVE DATA + DEBUG LOG tabs - Runtime BT permission request (Android 12+) + auto-enable Bluetooth - Android: minSdk=26, all BT+location permissions in manifest - Fixed flutter_bluetooth_serial namespace for AGP compatibility
185 lines
4.0 KiB
Dart
185 lines
4.0 KiB
Dart
/// Fully decoded ECU sensor state. Immutable. Produced by S300 or KPro parser.
|
||
class SensorState {
|
||
final double rpm;
|
||
final double vss;
|
||
final double map;
|
||
final double tps;
|
||
final double inj;
|
||
final double ign;
|
||
final double ect;
|
||
final double iat;
|
||
final double bat;
|
||
final double o2;
|
||
final int gear;
|
||
final double eth;
|
||
final double pa;
|
||
final double afr;
|
||
final double strim;
|
||
final double ltrim;
|
||
// Analog inputs (AIN0–AIN7)
|
||
final double ain0;
|
||
final double ain1;
|
||
final double ain2;
|
||
final double ain3;
|
||
final double ain4;
|
||
final double ain5;
|
||
final double ain6;
|
||
final double ain7;
|
||
// Boolean flags
|
||
final bool mil;
|
||
final bool fuelCut;
|
||
final bool fanOut;
|
||
final bool vtec;
|
||
final bool knock;
|
||
final bool revLimit;
|
||
final bool launch;
|
||
// Raw DTC bytes (ERR00..ERR17 for KPro, ERR00..ERR03 for S300)
|
||
final List<int> errBytes;
|
||
// Frame timestamp
|
||
final DateTime timestamp;
|
||
|
||
const SensorState({
|
||
required this.rpm,
|
||
required this.vss,
|
||
required this.map,
|
||
required this.tps,
|
||
required this.inj,
|
||
required this.ign,
|
||
required this.ect,
|
||
required this.iat,
|
||
required this.bat,
|
||
required this.o2,
|
||
required this.gear,
|
||
required this.eth,
|
||
required this.pa,
|
||
required this.afr,
|
||
required this.strim,
|
||
required this.ltrim,
|
||
required this.ain0,
|
||
required this.ain1,
|
||
required this.ain2,
|
||
required this.ain3,
|
||
required this.ain4,
|
||
required this.ain5,
|
||
required this.ain6,
|
||
required this.ain7,
|
||
required this.mil,
|
||
required this.fuelCut,
|
||
required this.fanOut,
|
||
required this.vtec,
|
||
required this.knock,
|
||
required this.revLimit,
|
||
required this.launch,
|
||
required this.errBytes,
|
||
required this.timestamp,
|
||
});
|
||
|
||
factory SensorState.zero() => SensorState(
|
||
rpm: 0,
|
||
vss: 0,
|
||
map: 0,
|
||
tps: 0,
|
||
inj: 0,
|
||
ign: 0,
|
||
ect: 0,
|
||
iat: 0,
|
||
bat: 0,
|
||
o2: 0,
|
||
gear: 0,
|
||
eth: 0,
|
||
pa: 0,
|
||
afr: 0,
|
||
strim: 0,
|
||
ltrim: 0,
|
||
ain0: 0,
|
||
ain1: 0,
|
||
ain2: 0,
|
||
ain3: 0,
|
||
ain4: 0,
|
||
ain5: 0,
|
||
ain6: 0,
|
||
ain7: 0,
|
||
mil: false,
|
||
fuelCut: false,
|
||
fanOut: false,
|
||
vtec: false,
|
||
knock: false,
|
||
revLimit: false,
|
||
launch: false,
|
||
errBytes: const [],
|
||
timestamp: DateTime(0),
|
||
);
|
||
|
||
SensorState copyWith({
|
||
double? rpm,
|
||
double? vss,
|
||
double? map,
|
||
double? tps,
|
||
double? inj,
|
||
double? ign,
|
||
double? ect,
|
||
double? iat,
|
||
double? bat,
|
||
double? o2,
|
||
int? gear,
|
||
double? eth,
|
||
double? pa,
|
||
double? afr,
|
||
double? strim,
|
||
double? ltrim,
|
||
double? ain0,
|
||
double? ain1,
|
||
double? ain2,
|
||
double? ain3,
|
||
double? ain4,
|
||
double? ain5,
|
||
double? ain6,
|
||
double? ain7,
|
||
bool? mil,
|
||
bool? fuelCut,
|
||
bool? fanOut,
|
||
bool? vtec,
|
||
bool? knock,
|
||
bool? revLimit,
|
||
bool? launch,
|
||
List<int>? errBytes,
|
||
DateTime? timestamp,
|
||
}) {
|
||
return SensorState(
|
||
rpm: rpm ?? this.rpm,
|
||
vss: vss ?? this.vss,
|
||
map: map ?? this.map,
|
||
tps: tps ?? this.tps,
|
||
inj: inj ?? this.inj,
|
||
ign: ign ?? this.ign,
|
||
ect: ect ?? this.ect,
|
||
iat: iat ?? this.iat,
|
||
bat: bat ?? this.bat,
|
||
o2: o2 ?? this.o2,
|
||
gear: gear ?? this.gear,
|
||
eth: eth ?? this.eth,
|
||
pa: pa ?? this.pa,
|
||
afr: afr ?? this.afr,
|
||
strim: strim ?? this.strim,
|
||
ltrim: ltrim ?? this.ltrim,
|
||
ain0: ain0 ?? this.ain0,
|
||
ain1: ain1 ?? this.ain1,
|
||
ain2: ain2 ?? this.ain2,
|
||
ain3: ain3 ?? this.ain3,
|
||
ain4: ain4 ?? this.ain4,
|
||
ain5: ain5 ?? this.ain5,
|
||
ain6: ain6 ?? this.ain6,
|
||
ain7: ain7 ?? this.ain7,
|
||
mil: mil ?? this.mil,
|
||
fuelCut: fuelCut ?? this.fuelCut,
|
||
fanOut: fanOut ?? this.fanOut,
|
||
vtec: vtec ?? this.vtec,
|
||
knock: knock ?? this.knock,
|
||
revLimit: revLimit ?? this.revLimit,
|
||
launch: launch ?? this.launch,
|
||
errBytes: errBytes ?? this.errBytes,
|
||
timestamp: timestamp ?? this.timestamp,
|
||
);
|
||
}
|
||
}
|