diff --git a/lib/model/shifter_types.dart b/lib/model/shifter_types.dart index cb57b6b..55fc959 100644 --- a/lib/model/shifter_types.dart +++ b/lib/model/shifter_types.dart @@ -10,14 +10,103 @@ const String universalShifterCommandCharacteristicUuid = '0993826f-0ee4-4b37-9614-d13ecba40005'; const String universalShifterGearRatiosCharacteristicUuid = '0993826f-0ee4-4b37-9614-d13ecba40006'; +const String universalShifterDfuControlCharacteristicUuid = + '0993826f-0ee4-4b37-9614-d13ecba40008'; +const String universalShifterDfuDataCharacteristicUuid = + '0993826f-0ee4-4b37-9614-d13ecba40009'; +const String universalShifterDfuAckCharacteristicUuid = + '0993826f-0ee4-4b37-9614-d13ecba4000a'; const String ftmsServiceUuid = '00001826-0000-1000-8000-00805f9b34fb'; +const int universalShifterDfuOpcodeStart = 0x01; +const int universalShifterDfuOpcodeFinish = 0x02; +const int universalShifterDfuOpcodeAbort = 0x03; + +const int universalShifterDfuFrameSizeBytes = 64; +const int universalShifterDfuFramePayloadSizeBytes = 63; + +const int universalShifterDfuFlagEncrypted = 0x01; +const int universalShifterDfuFlagSigned = 0x02; + const int errorSequence = 1; const int errorFtmsMissing = 2; const int errorPairingAuth = 3; const int errorPairingEncrypt = 4; const int errorFtmsRequiredCharMissing = 5; +enum DfuUpdateState { + idle, + starting, + waitingForAck, + transferring, + finishing, + completed, + aborted, + failed, +} + +class DfuUpdateFlags { + const DfuUpdateFlags({ + this.encrypted = false, + this.signed = false, + }); + + final bool encrypted; + final bool signed; + + int get rawValue { + var value = 0; + if (encrypted) { + value |= universalShifterDfuFlagEncrypted; + } + if (signed) { + value |= universalShifterDfuFlagSigned; + } + return value; + } + + static DfuUpdateFlags fromRaw(int rawValue) { + return DfuUpdateFlags( + encrypted: (rawValue & universalShifterDfuFlagEncrypted) != 0, + signed: (rawValue & universalShifterDfuFlagSigned) != 0, + ); + } +} + +class DfuUpdateProgress { + const DfuUpdateProgress({ + required this.state, + required this.totalBytes, + required this.sentBytes, + required this.lastAckedSequence, + required this.sessionId, + required this.flags, + this.errorMessage, + }); + + final DfuUpdateState state; + final int totalBytes; + final int sentBytes; + final int lastAckedSequence; + final int sessionId; + final DfuUpdateFlags flags; + final String? errorMessage; + + double get fractionComplete { + if (totalBytes <= 0) { + return 0; + } + return sentBytes.clamp(0, totalBytes) / totalBytes; + } + + int get percentComplete => (fractionComplete * 100).round(); + + bool get isTerminal => + state == DfuUpdateState.completed || + state == DfuUpdateState.aborted || + state == DfuUpdateState.failed; +} + class ShifterErrorInfo { const ShifterErrorInfo({ required this.code,