Improve live S300 update responsiveness
This commit is contained in:
parent
0886bef200
commit
74476afc45
@ -8,7 +8,7 @@ enum EcuType { s300, kpro }
|
||||
|
||||
/// Sends the ECU request byte every [pollingInterval] ms,
|
||||
/// accumulates raw bytes into 128-byte frames, validates NEG8,
|
||||
/// and emits valid frames on [frameStream].
|
||||
/// and emits the newest usable frame on [frameStream].
|
||||
class BtPoller {
|
||||
final BtService _service;
|
||||
EcuType ecuType;
|
||||
@ -34,7 +34,7 @@ class BtPoller {
|
||||
BtPoller(
|
||||
this._service, {
|
||||
this.ecuType = EcuType.s300,
|
||||
this.pollingInterval = const Duration(milliseconds: 100),
|
||||
this.pollingInterval = const Duration(milliseconds: 50),
|
||||
});
|
||||
|
||||
void start() {
|
||||
@ -66,6 +66,8 @@ class BtPoller {
|
||||
// Extract as many 128-byte frames as possible.
|
||||
// Frame start sync: first byte should be 0x1B (header marker).
|
||||
// If we have a misaligned buffer, scan forward.
|
||||
Uint8List? latestUsableFrame;
|
||||
|
||||
while (_rxBuf.length >= 128) {
|
||||
// Scan for 0x1B frame header
|
||||
int startIdx = 0;
|
||||
@ -91,7 +93,7 @@ class BtPoller {
|
||||
if (canUseFrame) {
|
||||
if (!checksumOk) droppedFrames++;
|
||||
validFrames++;
|
||||
_frameController.add(frame);
|
||||
latestUsableFrame = frame;
|
||||
_rxBuf.removeRange(0, startIdx + 128);
|
||||
} else {
|
||||
// Bad checksum — skip this byte and try again
|
||||
@ -99,6 +101,10 @@ class BtPoller {
|
||||
_rxBuf.removeRange(0, startIdx + 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (latestUsableFrame != null) {
|
||||
_frameController.add(latestUsableFrame);
|
||||
}
|
||||
}
|
||||
|
||||
void stop() {
|
||||
|
||||
@ -7,7 +7,7 @@ class AppSettings {
|
||||
|
||||
const AppSettings({
|
||||
this.ecuType = EcuType.s300,
|
||||
this.pollingInterval = const Duration(milliseconds: 100),
|
||||
this.pollingInterval = const Duration(milliseconds: 50),
|
||||
});
|
||||
|
||||
AppSettings copyWith({EcuType? ecuType, Duration? pollingInterval}) =>
|
||||
@ -25,7 +25,6 @@ class SettingsNotifier extends StateNotifier<AppSettings> {
|
||||
state = state.copyWith(pollingInterval: d);
|
||||
}
|
||||
|
||||
final settingsProvider =
|
||||
StateNotifierProvider<SettingsNotifier, AppSettings>(
|
||||
final settingsProvider = StateNotifierProvider<SettingsNotifier, AppSettings>(
|
||||
(ref) => SettingsNotifier(),
|
||||
);
|
||||
|
||||
@ -27,11 +27,9 @@ class SettingsScreen extends ConsumerWidget {
|
||||
leading: Icon(Icons.bluetooth, color: colors.accent),
|
||||
title: const Text('Bluetooth Device'),
|
||||
subtitle: Text(
|
||||
bt.isConnected
|
||||
? 'Connected: ${bt.deviceName}'
|
||||
: 'Not connected',
|
||||
style: TextStyle(
|
||||
color: bt.isConnected ? Colors.green : Colors.grey),
|
||||
bt.isConnected ? 'Connected: ${bt.deviceName}' : 'Not connected',
|
||||
style:
|
||||
TextStyle(color: bt.isConnected ? Colors.green : Colors.grey),
|
||||
),
|
||||
trailing: bt.isConnected
|
||||
? TextButton(
|
||||
@ -47,8 +45,7 @@ class SettingsScreen extends ConsumerWidget {
|
||||
? null
|
||||
: () => Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (_) => const BtPickerScreen()),
|
||||
MaterialPageRoute(builder: (_) => const BtPickerScreen()),
|
||||
),
|
||||
),
|
||||
const Divider(height: 1, color: Colors.white10),
|
||||
@ -63,8 +60,7 @@ class SettingsScreen extends ConsumerWidget {
|
||||
groupValue: settings.ecuType,
|
||||
activeColor: colors.accent,
|
||||
onChanged: (v) {
|
||||
if (v != null)
|
||||
ref.read(settingsProvider.notifier).setEcuType(v);
|
||||
if (v != null) ref.read(settingsProvider.notifier).setEcuType(v);
|
||||
},
|
||||
),
|
||||
RadioListTile<EcuType>(
|
||||
@ -75,15 +71,14 @@ class SettingsScreen extends ConsumerWidget {
|
||||
groupValue: settings.ecuType,
|
||||
activeColor: colors.accent,
|
||||
onChanged: (v) {
|
||||
if (v != null)
|
||||
ref.read(settingsProvider.notifier).setEcuType(v);
|
||||
if (v != null) ref.read(settingsProvider.notifier).setEcuType(v);
|
||||
},
|
||||
),
|
||||
const Divider(height: 1, color: Colors.white10),
|
||||
|
||||
// ── Polling Interval ─────────────────────────────────────
|
||||
_SectionHeader('POLLING INTERVAL'),
|
||||
...[50, 100, 200].map((ms) => RadioListTile<int>(
|
||||
...[20, 50, 100, 200].map((ms) => RadioListTile<int>(
|
||||
title: Text('${ms}ms (~${(1000 / ms).round()} Hz)'),
|
||||
value: ms,
|
||||
groupValue: settings.pollingInterval.inMilliseconds,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user