Skip to content

Commit 666d690

Browse files
authored
Merge pull request #155 from NordicSemiconductor/feature/suit
[SUIT] Adding UI to display SUIT manifests
2 parents 5222fb0 + df68671 commit 666d690

File tree

11 files changed

+389
-78
lines changed

11 files changed

+389
-78
lines changed

mcumgr-core/src/main/java/io/runtime/mcumgr/managers/SUITManager.java

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,19 @@ public void listManifests(@NotNull McuMgrCallback<McuMgrManifestListResponse> ca
105105
public void getManifestState(int role, @NotNull McuMgrCallback<McuMgrManifestStateResponse> callback) {
106106
HashMap<String, Object> payloadMap = new HashMap<>();
107107
payloadMap.put("role", role);
108-
send(OP_READ, ID_MANIFEST_STATE, payloadMap, SHORT_TIMEOUT, McuMgrManifestStateResponse.class, callback);
108+
send(OP_READ, ID_MANIFEST_STATE, payloadMap, SHORT_TIMEOUT, McuMgrManifestStateResponse.class, new McuMgrCallback<>() {
109+
@Override
110+
public void onResponse(@NotNull McuMgrManifestStateResponse response) {
111+
// The role isn't returned in the response, so we need to set it manually.
112+
response.role = role;
113+
callback.onResponse(response);
114+
}
115+
116+
@Override
117+
public void onError(@NotNull McuMgrException error) {
118+
callback.onError(error);
119+
}
120+
});
109121
}
110122

111123
/**
@@ -120,7 +132,9 @@ public void getManifestState(int role, @NotNull McuMgrCallback<McuMgrManifestSta
120132
public McuMgrManifestStateResponse getManifestState(int role) throws McuMgrException {
121133
HashMap<String, Object> payloadMap = new HashMap<>();
122134
payloadMap.put("role", role);
123-
return send(OP_READ, ID_MANIFEST_STATE, payloadMap, SHORT_TIMEOUT, McuMgrManifestStateResponse.class);
135+
final McuMgrManifestStateResponse response = send(OP_READ, ID_MANIFEST_STATE, payloadMap, SHORT_TIMEOUT, McuMgrManifestStateResponse.class);
136+
response.role = role;
137+
return response;
124138
}
125139

126140
/**
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package io.runtime.mcumgr.response.suit;
2+
3+
import org.jetbrains.annotations.NotNull;
4+
5+
/**
6+
* Known manifest roles.
7+
* This enum is based on <a href="https://github.com/nrfconnect/sdk-nrf/blob/46f6922cce98c9b9ccb69c2458bf57f9bcfb85b9/subsys/suit/metadata/include/suit_metadata.h#L70-L98">suit_metadata.h</a>.
8+
*/
9+
public enum KnownRole {
10+
UNKNOWN(0x00),
11+
/** Manifest describes the entry-point for all Nordic-controlled manifests. */
12+
SEC_TOP(0x10),
13+
/** Manifest describes SDFW firmware and recovery updates. */
14+
SEC_SDFW(0x11),
15+
/** Manifest describes SYSCTRL firmware update and boot procedures. */
16+
SEC_SYSCTRL(0x12),
17+
18+
/** Manifest describes the entry-point for all OEM-controlled manifests. */
19+
APP_ROOT(0x20),
20+
/** Manifest describes OEM-specific recovery procedure. */
21+
APP_RECOVERY(0x21),
22+
/** Manifest describes OEM-specific binaries, specific for application core. */
23+
APP_LOCAL_1(0x22),
24+
/** Manifest describes OEM-specific binaries, specific for application core. */
25+
APP_LOCAL_2(0x23),
26+
/** Manifest describes OEM-specific binaries, specific for application core. */
27+
APP_LOCAL_3(0x24),
28+
29+
/** Manifest describes radio part of OEM-specific recovery procedure. */
30+
RAD_RECOVERY(0x30),
31+
/** Manifest describes OEM-specific binaries, specific for radio core. */
32+
RAD_LOCAL_1(0x31),
33+
/** Manifest describes OEM-specific binaries, specific for radio core. */
34+
RAD_LOCAL_2(0x32);
35+
36+
/** The role value. */
37+
public final int id;
38+
39+
KnownRole(int id) {
40+
this.id = id;
41+
}
42+
43+
/**
44+
* Returns the role as a {@link KnownRole} enum, or null if the role is unknown.
45+
*/
46+
@NotNull
47+
public static KnownRole getOrNull(final int role) {
48+
for (KnownRole knownRole : KnownRole.values()) {
49+
if (knownRole.id == role) {
50+
return knownRole;
51+
}
52+
}
53+
return UNKNOWN;
54+
}
55+
}

mcumgr-core/src/main/java/io/runtime/mcumgr/response/suit/McuMgrManifestListResponse.java

Lines changed: 3 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@
99
import com.fasterxml.jackson.annotation.JsonCreator;
1010
import com.fasterxml.jackson.annotation.JsonProperty;
1111

12-
import org.jetbrains.annotations.Nullable;
13-
1412
import java.util.List;
1513

1614
import io.runtime.mcumgr.McuMgrCallback;
@@ -21,60 +19,13 @@
2119
public class McuMgrManifestListResponse extends McuMgrResponse {
2220

2321
public static class Manifest {
24-
2522
/**
26-
* Known manifest roles.
27-
* This enum is based on <a href="https://github.com/nrfconnect/sdk-nrf/blob/46f6922cce98c9b9ccb69c2458bf57f9bcfb85b9/subsys/suit/metadata/include/suit_metadata.h#L70-L98">suit_metadata.h</a>.
23+
* The manifest role.
24+
*
25+
* @see KnownRole
2826
*/
29-
public enum KnownRole {
30-
/** Manifest describes the entry-point for all Nordic-controlled manifests. */
31-
SEC_TOP(0x10),
32-
/** Manifest describes SDFW firmware and recovery updates. */
33-
SEC_SDFW(0x11),
34-
/** Manifest describes SYSCTRL firmware update and boot procedures. */
35-
SEC_SYSCTRL(0x12),
36-
37-
/** Manifest describes the entry-point for all OEM-controlled manifests. */
38-
APP_ROOT(0x20),
39-
/** Manifest describes OEM-specific recovery procedure. */
40-
APP_RECOVERY(0x21),
41-
/** Manifest describes OEM-specific binaries, specific for application core. */
42-
APP_LOCAL_1(0x22),
43-
/** Manifest describes OEM-specific binaries, specific for application core. */
44-
APP_LOCAL_2(0x23),
45-
/** Manifest describes OEM-specific binaries, specific for application core. */
46-
APP_LOCAL_3(0x24),
47-
48-
/** Manifest describes radio part of OEM-specific recovery procedure. */
49-
RAD_RECOVERY(0x30),
50-
/** Manifest describes OEM-specific binaries, specific for radio core. */
51-
RAD_LOCAL_1(0x31),
52-
/** Manifest describes OEM-specific binaries, specific for radio core. */
53-
RAD_LOCAL_2(0x32);
54-
55-
/** The role value. */
56-
public final int id;
57-
58-
KnownRole(int id) {
59-
this.id = id;
60-
}
61-
}
62-
6327
@JsonProperty("role")
6428
public int role;
65-
66-
/**
67-
* Returns the role as a {@link KnownRole} enum, or null if the role is unknown.
68-
*/
69-
@Nullable
70-
public KnownRole getRoleOrNull() {
71-
for (KnownRole knownRole : KnownRole.values()) {
72-
if (knownRole.id == role) {
73-
return knownRole;
74-
}
75-
}
76-
return null;
77-
}
7829
}
7930

8031
/**

mcumgr-core/src/main/java/io/runtime/mcumgr/response/suit/McuMgrManifestStateResponse.java

Lines changed: 85 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import com.fasterxml.jackson.annotation.JsonProperty;
1111
import com.fasterxml.jackson.annotation.JsonValue;
1212

13+
import org.jetbrains.annotations.NotNull;
1314
import org.jetbrains.annotations.Nullable;
1415

1516
import java.nio.ByteBuffer;
@@ -21,6 +22,13 @@
2122
/** @noinspection unused*/
2223
public class McuMgrManifestStateResponse extends McuMgrResponse {
2324

25+
/**
26+
* The manifest role.
27+
*
28+
* @see KnownRole
29+
*/
30+
public int role;
31+
2432
/**
2533
* Use {@link #getClassId()} to get the class ID as UUID.
2634
*/
@@ -42,7 +50,7 @@ public class McuMgrManifestStateResponse extends McuMgrResponse {
4250
@JsonProperty("digest")
4351
public byte[] digest;
4452
@JsonProperty("digest_algorithm")
45-
public DigestAlgorithm digest_algorithm;
53+
public DigestAlgorithm digestAlgorithm;
4654
@JsonProperty("signature_check")
4755
public SignatureVerification signatureCheck;
4856
@JsonProperty("sequence_number")
@@ -96,6 +104,19 @@ public enum DigestAlgorithm {
96104
DigestAlgorithm(int code) {
97105
this.code = code;
98106
}
107+
108+
@NotNull
109+
@Override
110+
public String toString() {
111+
switch (this) {
112+
case SHA_256:
113+
return "SHA-256";
114+
case SHA_512:
115+
return "SHA-512";
116+
default:
117+
return super.toString();
118+
}
119+
}
99120
}
100121

101122
public enum SignatureVerification {
@@ -109,6 +130,21 @@ public enum SignatureVerification {
109130
SignatureVerification(int code) {
110131
this.code = code;
111132
}
133+
134+
@NotNull
135+
@Override
136+
public String toString() {
137+
switch (this) {
138+
case NOT_CHECKED:
139+
return "Not checked";
140+
case FAILED:
141+
return "Failed";
142+
case PASSED:
143+
return "Passed";
144+
default:
145+
return super.toString();
146+
}
147+
}
112148
}
113149

114150
public enum DowngradePreventionPolicy {
@@ -125,6 +161,21 @@ public enum DowngradePreventionPolicy {
125161
DowngradePreventionPolicy(int code) {
126162
this.code = code;
127163
}
164+
165+
@NotNull
166+
@Override
167+
public String toString() {
168+
switch (this) {
169+
case DISABLED:
170+
return "Disabled";
171+
case ENABLED:
172+
return "Enabled";
173+
case UNKNOWN:
174+
return "Unknown";
175+
default:
176+
return super.toString();
177+
}
178+
}
128179
}
129180

130181
public enum IndependentUpdateabilityPolicy {
@@ -141,6 +192,21 @@ public enum IndependentUpdateabilityPolicy {
141192
IndependentUpdateabilityPolicy(int code) {
142193
this.code = code;
143194
}
195+
196+
@NotNull
197+
@Override
198+
public String toString() {
199+
switch (this) {
200+
case DENIED:
201+
return "Denied";
202+
case ALLOWED:
203+
return "Allowed";
204+
case UNKNOWN:
205+
return "Unknown";
206+
default:
207+
return super.toString();
208+
}
209+
}
144210
}
145211

146212
public enum SignatureVerificationPolicy {
@@ -159,6 +225,24 @@ public enum SignatureVerificationPolicy {
159225
SignatureVerificationPolicy(int code) {
160226
this.code = code;
161227
}
228+
229+
@NotNull
230+
@Override
231+
public String toString() {
232+
switch (this) {
233+
case DISABLED:
234+
return "Disabled";
235+
case ENABLED_ON_UPDATE:
236+
return "Enabled on update";
237+
case ENABLED_ON_UPDATE_AND_BOOT:
238+
return "Enabled on update and boot";
239+
case UNKNOWN:
240+
return "Unknown";
241+
default:
242+
return super.toString();
243+
244+
}
245+
}
162246
}
163247

164248
private enum ReleaseType {

sample/src/main/java/io/runtime/mcumgr/sample/fragment/mcumgr/ImageControlFragment.java

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,18 +27,26 @@
2727
import androidx.fragment.app.DialogFragment;
2828
import androidx.fragment.app.Fragment;
2929
import androidx.lifecycle.ViewModelProvider;
30+
31+
import java.util.List;
32+
import java.util.Locale;
33+
3034
import io.runtime.mcumgr.McuMgrErrorCode;
3135
import io.runtime.mcumgr.exception.McuMgrErrorException;
3236
import io.runtime.mcumgr.exception.McuMgrException;
3337
import io.runtime.mcumgr.response.img.McuMgrImageStateResponse;
38+
import io.runtime.mcumgr.response.suit.KnownRole;
39+
import io.runtime.mcumgr.response.suit.McuMgrManifestStateResponse;
3440
import io.runtime.mcumgr.sample.R;
3541
import io.runtime.mcumgr.sample.databinding.FragmentCardImageControlBinding;
3642
import io.runtime.mcumgr.sample.di.Injectable;
3743
import io.runtime.mcumgr.sample.dialog.HelpDialogFragment;
3844
import io.runtime.mcumgr.sample.dialog.SelectImageDialogFragment;
3945
import io.runtime.mcumgr.sample.utils.StringUtils;
46+
import io.runtime.mcumgr.sample.utils.Utils;
4047
import io.runtime.mcumgr.sample.viewmodel.mcumgr.ImageControlViewModel;
4148
import io.runtime.mcumgr.sample.viewmodel.mcumgr.McuMgrViewModelFactory;
49+
import io.runtime.mcumgr.util.ByteUtil;
4250

4351
public class ImageControlFragment extends Fragment implements Injectable, SelectImageDialogFragment.OnImageSelectedListener {
4452
private static final int REQUEST_TEST = 1;
@@ -89,6 +97,7 @@ public void onViewCreated(@NonNull final View view, @Nullable final Bundle saved
8997
((ViewGroup) view).getLayoutTransition().enableTransitionType(LayoutTransition.CHANGING);
9098

9199
viewModel.getResponse().observe(getViewLifecycleOwner(), this::printImageSlotInfo);
100+
viewModel.getManifests().observe(getViewLifecycleOwner(), this::printSuitManifests);
92101
viewModel.getError().observe(getViewLifecycleOwner(), this::printError);
93102
viewModel.getTestOperationAvailability().observe(getViewLifecycleOwner(),
94103
enabled -> binding.actionTest.setEnabled(enabled));
@@ -107,7 +116,10 @@ public void onViewCreated(@NonNull final View view, @Nullable final Bundle saved
107116
// Other actions will be optionally enabled by other observers
108117
}
109118
});
110-
binding.actionRead.setOnClickListener(v -> viewModel.read());
119+
binding.actionRead.setOnClickListener(v -> {
120+
binding.imageControlValue.setText(R.string.image_control_loading);
121+
viewModel.read();
122+
});
111123
binding.actionTest.setOnClickListener(v -> onActionClick(REQUEST_TEST));
112124
binding.actionConfirm.setOnClickListener(v -> onActionClick(REQUEST_CONFIRM));
113125
binding.actionErase.setOnClickListener(v -> onActionClick(REQUEST_ERASE));
@@ -138,6 +150,37 @@ private void onActionClick(final int requestId) {
138150
}
139151
}
140152

153+
private void printSuitManifests(@Nullable final List<McuMgrManifestStateResponse> manifests) {
154+
if (manifests != null) {
155+
final SpannableStringBuilder builder = new SpannableStringBuilder();
156+
int i = 0;
157+
for (McuMgrManifestStateResponse manifest: manifests) {
158+
final KnownRole role = KnownRole.getOrNull(manifest.role);
159+
final int start = builder.length();
160+
builder.append(getString(R.string.image_suit_manifest_role, ++i, role.toString(), manifest.role));
161+
builder.setSpan(new StyleSpan(Typeface.BOLD),
162+
start, builder.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
163+
final String vendor = manifest.isVendorNordic() ? "Nordic Semiconductor ASA" : "Unknown";
164+
final String version = manifest.getVersion();
165+
builder.append(getString(R.string.image_suit_manifest_details,
166+
manifest.getClassId().toString().toUpperCase(Locale.ROOT), "Unknown",
167+
manifest.getVendorId().toString().toUpperCase(Locale.ROOT), vendor,
168+
manifest.downgradePreventionPolicy,
169+
manifest.independentUpdateabilityPolicy,
170+
manifest.signatureVerificationPolicy,
171+
ByteUtil.byteArrayToHex(manifest.digest, "%02X"),
172+
manifest.digestAlgorithm,
173+
manifest.signatureCheck,
174+
manifest.sequenceNumber,
175+
version != null ? version : "Unknown"));
176+
}
177+
binding.imageControlValue.setText(builder);
178+
binding.imageControlError.setVisibility(View.GONE);
179+
} else {
180+
binding.imageControlValue.setText(null);
181+
}
182+
}
183+
141184
@SuppressLint("StringFormatMatches")
142185
private void printImageSlotInfo(@Nullable final McuMgrImageStateResponse response) {
143186
if (response != null) {

0 commit comments

Comments
 (0)