Improve live S300 update responsiveness

This commit is contained in:
HVBT Dev 2026-07-27 00:25:39 +05:30
parent 0886bef200
commit 74476afc45
3 changed files with 20 additions and 20 deletions

View File

@ -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() {

View File

@ -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(),
);

View File

@ -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,
@ -102,8 +97,8 @@ class SettingsScreen extends ConsumerWidget {
_SectionHeader('THEME'),
...AppThemeVariant.values.map((v) {
final label = switch (v) {
AppThemeVariant.redDark => 'Red — Dark',
AppThemeVariant.redLight => 'Red — Light',
AppThemeVariant.redDark => 'Red — Dark',
AppThemeVariant.redLight => 'Red — Light',
AppThemeVariant.greenDark => 'Green — Dark',
AppThemeVariant.greenLight => 'Green — Light',
};