Skip to content
Open
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
6a9d363
feat: next-gen protocol commands (streaming function) - #1808
ctrlVnt Aug 15, 2026
dccd4ce
dart format .
ctrlVnt Aug 15, 2026
d7af22f
workflow issues
ctrlVnt Aug 15, 2026
70977b3
restore pubspec.lock
ctrlVnt Aug 15, 2026
7cfdb79
pubspeck.lock reset
ctrlVnt Aug 15, 2026
43a6eb1
dart format .
ctrlVnt Aug 15, 2026
16f8473
workflow issues
ctrlVnt Aug 15, 2026
a050bc8
Fixed a bug variable
ctrlVnt Aug 16, 2026
57a34d6
Fixed, it works now
ctrlVnt Aug 16, 2026
d5a8bbd
Merge branch 'development' into next-gen-protocol-commands
ctrlVnt Aug 27, 2026
da538a8
Merge branch 'development' into next-gen-protocol-commands
ctrlVnt Aug 31, 2026
16ef9d0
resolved conflicts
ctrlVnt Aug 31, 2026
78fdee6
Merge branch 'development' into next-gen-protocol-commands
ctrlVnt Sep 21, 2026
4452b58
dart format .
ctrlVnt Sep 21, 2026
4faa761
dart format .
ctrlVnt Sep 21, 2026
a83ff11
UI corrections
ctrlVnt Sep 21, 2026
8a47245
Some corrections
ctrlVnt Sep 21, 2026
457f812
Some corrections
ctrlVnt Sep 21, 2026
49c7a7d
restore logic
ctrlVnt Sep 21, 2026
7908ce9
Moved _safeDisconnect when is not nextGeneration
ctrlVnt Sep 21, 2026
952e01e
Merge branch 'development' into next-gen-protocol-commands
ctrlVnt Sep 21, 2026
1f0a078
Added exception for unexpected disconnection
ctrlVnt Sep 21, 2026
ab2ebf3
Merge remote-tracking branch 'origin/next-gen-protocol-commands' into…
ctrlVnt Sep 21, 2026
af14fb1
Added exception for unexpected disconnection
ctrlVnt Sep 21, 2026
40dea18
Changed commands order
ctrlVnt Sep 21, 2026
d07b0d6
changed order of commands
ctrlVnt Sep 22, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion lib/communication/completed_state.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@ import 'package:badgemagic/view/widgets/ble_progress_dialog_controller.dart';
class CompletedState extends NormalBleState {
final bool isSuccess;
final String message;
final bool isNextGen;
final bleDialogController = GetIt.instance<BleDialogController>();

CompletedState({required this.isSuccess, required this.message});
CompletedState(
{required this.isSuccess, required this.message, this.isNextGen = false});

@override
Future<BleState?> processState() async {
Expand Down
65 changes: 65 additions & 0 deletions lib/communication/ng_command_state.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import 'dart:async';
import 'dart:typed_data';
import 'package:badgemagic/others/globals.dart';
import 'package:universal_ble/universal_ble.dart';
import 'base_ble_state.dart';
import 'completed_state.dart';

class NgCommandState extends NormalBleState {
final BleDevice device;
final List<int> command;

NgCommandState({required this.device, required this.command});

@override
Future<BleState?> processState() async {
final deviceId = device.deviceId;
final completer = Completer<int>();

await UniversalBle.discoverServices(deviceId);

await UniversalBle.setNotifiable(
deviceId,
ngServiceUuid,
ngNotifyCharUuid,
BleInputProperty.notification,
);

late final StreamSubscription sub;
sub = UniversalBle.characteristicValueStream(deviceId, ngNotifyCharUuid)
.listen(
(Uint8List value) {
if (!completer.isCompleted) {
completer.complete(value.isNotEmpty ? value[0] : 0xff);
}
},
onError: (error) {
if (!completer.isCompleted) {
completer.completeError(error);
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
},
);

try {
await UniversalBle.write(
deviceId,
ngServiceUuid,
ngWriteCharUuid,
Uint8List.fromList(command),
withoutResponse: false,
);

final code = await completer.future.timeout(const Duration(seconds: 5));

if (code != 0x00) {
throw Exception(
"Command rejected by badge (code 0x${code.toRadixString(16)})");
}

return CompletedState(
isSuccess: true, message: "Command executed", isNextGen: true);
Comment thread
ctrlVnt marked this conversation as resolved.
} finally {
await sub.cancel();
}
}
}
21 changes: 21 additions & 0 deletions lib/communication/write_state.dart
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ class WriteState extends NormalBleState {
static const Duration _disconnectTimeout = Duration(seconds: 2);
static const Duration _postDisconnectDelay = Duration(milliseconds: 500);

bool verifiedNextGen = false;

WriteState({required this.manager, required this.device});

static Future<void> cancelTransfer() async {
Expand Down Expand Up @@ -73,6 +75,12 @@ class WriteState extends NormalBleState {
await Future.delayed(_initialDelay);
if (isCancellationRequested) return _handleAbortedState();

List<BleService> discoveredServices =
await UniversalBle.discoverServices(deviceId);

verifiedNextGen = discoveredServices.any((service) =>
service.uuid.toLowerCase() == ngServiceUuid.toLowerCase());

final services = await UniversalBle.discoverServices(deviceId);
final serviceExists = services.any((s) => s.uuid == serviceUuid);
if (!serviceExists) {
Expand Down Expand Up @@ -106,6 +114,7 @@ class WriteState extends NormalBleState {
return CompletedState(
isSuccess: true,
message: l10n.transferSucceeded,
isNextGen: verifiedNextGen,
);
} catch (e) {
logger.e("Transfer failed: $e");
Expand All @@ -119,6 +128,18 @@ class WriteState extends NormalBleState {
} finally {
progressTimer.cancel();
await _safeDisconnect(deviceId);
if (!verifiedNextGen) {
Comment thread
ctrlVnt marked this conversation as resolved.
try {
logger.d("Disconnecting from legacy device after write...");
await UniversalBle.disconnect(deviceId);
await Future.delayed(const Duration(milliseconds: 700));
} catch (e) {
logger.e("Error during disconnect: $e");
}
} else {
logger
.i("Keeping GATT connection alive for Next-Gen profile commands.");
}
Comment thread
ctrlVnt marked this conversation as resolved.
}
}

Expand Down
32 changes: 32 additions & 0 deletions lib/l10n/app_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,38 @@
"couldNotGenerateQrImage": "Could not generate QR image.",
"couldNotShareQrImage": "Could not share QR image.",
"qrShareInstruction": "Scan this code from another device, or tap share to send the QR image.",
"turnBLEOn": "Please turn on Bluetooth in your settings",
"qrShareInstruction": "Scan this code from another device, or tap share to send the QR image.",
"defaultFont": "Default",
"font": "Font",
"connected": "Connected",
"liveMirroring": "Live Mirroring",
"liveMirroringSubtitle": "Sync the app preview to the badge in real time",
"powerOff": "Turn off Badge",
"disconnect": "Disconnect",
"disconnected": "Disconnected",
"currentName": "Current Name: ",
"renameBadge": "Rename Badge",
"bleAlwaysOn": "BLE Always On",
"bleAlwaysOnSubtitle": "Keep Bluetooth active during animations",
"alwaysOnEnabled": "Always-On Enabled",
"alwaysOnDisabled": "Always-On Disabled",
"savingAndRebooting": "Saving and rebooting badge...",
"nameApplied": "Name applied to device",
"savedToFlash": "Saved to Flash!",
"turnOff": "Turn Off tha badge",
"editingBadgeWithName": "Editing badge: {name}",
"@editingBadgeWithName": {
"placeholders": {
"name": {
"type": "String"
}
}
},
"saveFlashAndReboot": "Save and Reboot the badge",
"appFeaturesTitle": "App Features",
"enableBadheStreaming": "Enable Badge Streaming",
"enableBadheStreamingWarning": "Only FOSSASIA firmware supports this feature",
Comment thread
ctrlVnt marked this conversation as resolved.
"renameBadge": "Rename Badge",
"newName": "New name",
"rename": "Rename",
Expand Down
3 changes: 3 additions & 0 deletions lib/others/globals.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ final scaffoldMessengerKey = GlobalKey<ScaffoldMessengerState>();
final String serviceUuid = "0000fee0-0000-1000-8000-00805f9b34fb";
final String characteristicUuid = "0000fee1-0000-1000-8000-00805f9b34fb";

const String ngServiceUuid = "0000f055-0000-1000-8000-00805f9b34fb";
const String ngWriteCharUuid = "0000f057-0000-1000-8000-00805f9b34fb";
const String ngNotifyCharUuid = "0000f056-0000-1000-8000-00805f9b34fb";
Future<bool> autocheckFirmwareUpdates() async {
final prefs = await SharedPreferences.getInstance();
bool? check = prefs.getBool('auto_check_updates');
Expand Down
Loading
Loading