Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions doc/CAPABILITIES.md
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ Provides firmware slot or image-table state for FOTA backends that expose it.
final slotInfo = wearable.getCapability<FotaSlotInfoCapability>();
if (slotInfo != null) {
final slots = await slotInfo.readFirmwareSlots();
await slotInfo.eraseFirmwareSlot();
}
```

Expand Down
21 changes: 20 additions & 1 deletion doc/FOTA.md
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,25 @@ Each `FirmwareSlotInfo` contains:
This is useful when you want to show the current primary and secondary images
before or after an update.

## Erase An Inactive Firmware Slot

Slot-aware wearables can erase an inactive firmware image slot through
`FotaSlotInfoCapability`:

```dart
final slotInfo = wearable.getCapability<FotaSlotInfoCapability>();
if (slotInfo != null) {
await slotInfo.eraseFirmwareSlot();
await slotInfo.eraseFirmwareSlot(channel: 1);
}
```

When `channel` is omitted, the firmware backend erases its default secondary
image slot. When `channel` is provided, the erase request targets that raw
mcumgr image slot channel. Devices reject erase requests for slots that contain
a confirmed image, an image pending test on the next reboot, or an active
split-image slot.

## What Happens Internally

You do not need to call the lower-level handler classes directly, but it helps to know what `UpdateBloc` is doing:
Expand Down Expand Up @@ -367,7 +386,7 @@ Recommended UX:
- `UnifiedFirmwareRepository` caches results for 15 minutes unless you request a refresh
- The current upload path uses `mcumgr_flutter` under the hood
- `FotaSlotInfoCapability` is optional and only available on wearables whose firmware backend exposes slot-style state
- `mcumgr_flutter 0.6.1` does not expose an API to erase an individual image slot, so this library does not currently offer slot erase either
- The current local `mcumgr_flutter` integration exposes slot erase through `FotaSlotInfoCapability.eraseFirmwareSlot`

## Related Source Files

Expand Down
2 changes: 2 additions & 0 deletions example/macos/Flutter/GeneratedPluginRegistrant.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@ import Foundation

import file_picker
import flutter_archive
import mcumgr_flutter
import universal_ble

func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
FilePickerPlugin.register(with: registry.registrar(forPlugin: "FilePickerPlugin"))
FlutterArchivePlugin.register(with: registry.registrar(forPlugin: "FlutterArchivePlugin"))
McumgrFlutterPlugin.register(with: registry.registrar(forPlugin: "McumgrFlutterPlugin"))
UniversalBlePlugin.register(with: registry.registrar(forPlugin: "UniversalBlePlugin"))
}
33 changes: 25 additions & 8 deletions example/pubspec.lock
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
# Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile
packages:
archive:
dependency: transitive
description:
name: archive
sha256: a96e8b390886ee8abb49b7bd3ac8df6f451c621619f52a26e815fdcf568959ff
url: "https://pub.dev"
source: hosted
version: "4.0.9"
args:
dependency: transitive
description:
Expand Down Expand Up @@ -315,11 +323,12 @@ packages:
mcumgr_flutter:
dependency: "direct main"
description:
name: mcumgr_flutter
sha256: fbf2f621dea23dd5dc70494e700c5d4706010841b9e68739ba563cbd88c7e8ba
url: "https://pub.dev"
source: hosted
version: "0.6.1"
path: "."
ref: master
resolved-ref: "7bec874051397e0e0dcbce4a1a660e14be5a3eb3"
url: "https://github.com/DennisMoschina/Flutter-nRF-Connect-Device-Manager.git"
source: git
version: "0.8.1"
meta:
dependency: "direct main"
description:
Expand Down Expand Up @@ -350,7 +359,7 @@ packages:
path: ".."
relative: true
source: path
version: "2.3.5"
version: "2.3.6"
path:
dependency: transitive
description:
Expand Down Expand Up @@ -487,14 +496,22 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.1.8"
posix:
dependency: transitive
description:
name: posix
sha256: "185ef7606574f789b40f289c233efa52e96dead518aed988e040a10737febb07"
url: "https://pub.dev"
source: hosted
version: "6.5.0"
protobuf:
dependency: transitive
description:
name: protobuf
sha256: de9c9eb2c33f8e933a42932fe1dc504800ca45ebc3d673e6ed7f39754ee4053e
sha256: "75ec242d22e950bdcc79ee38dd520ce4ee0bc491d7fadc4ea47694604d22bf06"
url: "https://pub.dev"
source: hosted
version: "4.2.0"
version: "6.0.0"
provider:
dependency: "direct main"
description:
Expand Down
5 changes: 4 additions & 1 deletion example/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,10 @@ dependencies:
flutter_svg: ^2.0.17
provider: ^6.1.5
file_picker: ^10.3.7
mcumgr_flutter: ^0.6.1
mcumgr_flutter:
git:
url: https://github.com/DennisMoschina/Flutter-nRF-Connect-Device-Manager.git
ref: master
flutter_bloc: ^9.1.1

dev_dependencies:
Expand Down
18 changes: 14 additions & 4 deletions lib/src/fota/firmware_slot_manager_impl.dart
Original file line number Diff line number Diff line change
Expand Up @@ -68,15 +68,25 @@ class McuMgrFotaSlotInfoManager implements FotaSlotInfoCapability {

@override
Future<List<FirmwareSlotInfo>> readFirmwareSlots() async {
final updateManager = await _updateManagerFactory.getUpdateManager(_deviceId);
final updateManager =
await _updateManagerFactory.getUpdateManager(_deviceId);
try {
final slots = await updateManager.readImageList();
if (slots == null) {
return const [];
}
return slots
.map(FirmwareSlotInfo.fromImageSlot)
.toList(growable: false);
return slots.map(FirmwareSlotInfo.fromImageSlot).toList(growable: false);
} finally {
await updateManager.kill();
}
}

@override
Future<void> eraseFirmwareSlot({int? channel}) async {
final updateManager =
await _updateManagerFactory.getUpdateManager(_deviceId);
try {
await updateManager.erase(channel);
} finally {
await updateManager.kill();
}
Expand Down
12 changes: 12 additions & 0 deletions lib/src/models/capabilities/fota_slot_info_capability.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,18 @@ import 'package:mcumgr_flutter/mcumgr_flutter.dart';
abstract class FotaSlotInfoCapability {
/// Reads the firmware images or slots currently reported by the wearable.
Future<List<FirmwareSlotInfo>> readFirmwareSlots();

/// Erases an inactive firmware image slot on the wearable.
///
/// When [channel] is omitted, the underlying firmware backend erases its
/// default secondary image slot. When [channel] is provided, the erase request
/// targets that raw mcumgr image slot channel.
///
/// Devices reject erase requests for slots that contain a confirmed image, an
/// image pending test on the next reboot, or an active split-image slot. Use
/// [readFirmwareSlots] first when the UI needs to decide whether erasing is
/// available.
Future<void> eraseFirmwareSlot({int? channel});
}

/// Snapshot of one firmware image slot reported by the wearable.
Expand Down
5 changes: 4 additions & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,10 @@ dependencies:
flutter_bloc: ^9.1.1
http: ^1.1.2
json_annotation: ^4.8.1
mcumgr_flutter: ^0.6.1
mcumgr_flutter:
git:
url: https://github.com/DennisMoschina/Flutter-nRF-Connect-Device-Manager.git
ref: master
path_provider: ^2.1.1
provider: ^6.1.1
rxdart: ^0.28.0
Expand Down
Loading