Skip to content
Merged
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
90 changes: 87 additions & 3 deletions photon-client/src/components/settings/DeviceCard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,67 @@ const offlineUpdate = ref();
const openOfflineUpdatePrompt = () => {
offlineUpdate.value.click();
};
const handleOfflineUpdate = async () => {

const offlineUpdateRegex = new RegExp("photonvision-((?:dev-)?v[\\w.-]+)-((?:linux|win|mac)\\w+)\\.jar");
const majorVersionRegex = new RegExp("(?:dev-)?(\\d+)\\.\\d+\\.\\d+");

const offlineUpdateDialog = ref({ show: false, confirmString: "" });

const handleOfflineUpdateRequest = async () => {
const files = offlineUpdate.value.files;
if (files.length === 0) return;

const match = files[0].name.match(offlineUpdateRegex);
if (!match) {
useStateStore().showSnackbarMessage({
message: "Selected file does not match expected naming convention.",
color: "error"
});
return;
}

const version = match[1] as string;
const arch = match[2] as string;

const currentVersion = useSettingsStore().general.imageVersion;
const currentArch = useSettingsStore().general.wpilibArch;

const versionMajor = version.match(majorVersionRegex)?.[1];
const currentVersionMajor = currentVersion?.match(majorVersionRegex)?.[1];

const versionMatch = currentVersion ? versionMajor === currentVersionMajor : false;
const dev = version.includes("dev");

if (currentArch && arch !== currentArch) {
useStateStore().showSnackbarMessage({
message: `Selected file architecture (${arch}) does not match device architecture (${currentArch}).`,
color: "error"
});
return;
} else if (versionMatch && !dev) {
handleOfflineUpdate(files[0]);
} else if (!versionMatch && !dev) {
offlineUpdateDialog.value = {
show: true,
confirmString: `You are attempting to update from PhotonVision ${currentVersion} on image ${useSettingsStore().general.imageVersion} to ${version} from a different FRC year. These versions may be incompatible. Are you sure you want to proceed?`
};
} else if (versionMatch && dev) {
offlineUpdateDialog.value = {
show: true,
confirmString:
"You are attempting to update to a dev version. This could result in instability. Are you sure you want to proceed?"
};
} else if (!versionMatch && dev) {
offlineUpdateDialog.value = {
show: true,
confirmString: `You are attempting to update to a dev version, from PhotonVision ${currentVersion} on image ${useSettingsStore().general.imageVersion} to ${version} from a different FRC year. These versions may be incompatible, and you may experience instability. Are you sure you want to proceed?`
};
}
};

const handleOfflineUpdate = async (file: File) => {
const formData = new FormData();
formData.append("jarData", files[0]);
formData.append("jarData", file);
useStateStore().showSnackbarMessage({
message: "New Software Upload in Progress...",
color: "secondary",
Expand Down Expand Up @@ -134,6 +190,7 @@ interface MetricItem {
const generalMetrics = computed<MetricItem[]>(() => {
const stats = [
{ header: "Version", value: useSettingsStore().general.version || "Unknown" },
{ header: "Image Version", value: useSettingsStore().general.imageVersion || "Unknown" },
{ header: "Hardware Model", value: useSettingsStore().general.hardwareModel || "Unknown" },
{ header: "Platform", value: useSettingsStore().general.hardwarePlatform || "Unknown" },
{ header: "GPU Acceleration", value: useSettingsStore().general.gpuAcceleration || "None detected" }
Expand Down Expand Up @@ -333,7 +390,7 @@ watch(metricsHistorySnapshot, () => {
type="file"
accept=".jar"
style="display: none"
@change="handleOfflineUpdate"
@change="handleOfflineUpdateRequest"
/>
</v-col>
</v-row>
Expand Down Expand Up @@ -483,6 +540,33 @@ watch(metricsHistorySnapshot, () => {
</v-card>
</v-dialog>

<v-dialog v-model="offlineUpdateDialog.show" :width="700" dark>
<v-card color="surface" flat>
<v-card-title style="display: flex; justify-content: center"> Offline Update </v-card-title>
<v-card-text class="pt-0 pb-10px">
<span> {{ offlineUpdateDialog.confirmString }} </span>
</v-card-text>
<v-card-text class="pt-10px">
<v-row class="align-center text-white">
<v-col cols="12">
<v-btn
color="buttonActive"
width="100%"
:variant="theme.global.name.value === 'LightTheme' ? 'elevated' : 'outlined'"
@click="
offlineUpdateDialog.show = false;
handleOfflineUpdate(offlineUpdate.value.files[0]);
"
>
<v-icon start class="open-icon" size="large"> mdi-upload </v-icon>
<span class="open-label"> Confirm Update </span>
</v-btn>
</v-col>
</v-row>
</v-card-text>
</v-card>
</v-dialog>

<a
ref="exportSettings"
style="color: black; text-decoration: none; display: none"
Expand Down
2 changes: 1 addition & 1 deletion photon-client/src/stores/StateStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ export const useStateStore = defineStore("state", {
message: data.message,
color: data.color,
progressBarColor: data.progressBarColor || "",
timeout: data.timeout || 2000
timeout: data.timeout || 5000
};
}
}
Expand Down
4 changes: 4 additions & 0 deletions photon-client/src/stores/settings/GeneralSettingsStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,11 @@ export const useSettingsStore = defineStore("settings", {
state: (): GeneralSettingsStore => ({
general: {
version: undefined,
imageVersion: undefined,
gpuAcceleration: undefined,
hardwareModel: undefined,
hardwarePlatform: undefined,
wpilibArch: undefined,
mrCalWorking: true,
availableModels: [],
supportedBackends: [],
Expand Down Expand Up @@ -155,8 +157,10 @@ export const useSettingsStore = defineStore("settings", {
updateGeneralSettingsFromWebsocket(data: WebsocketSettingsUpdate) {
this.general = {
version: data.general.version || undefined,
imageVersion: data.general.imageVersion || undefined,
hardwareModel: data.general.hardwareModel || undefined,
hardwarePlatform: data.general.hardwarePlatform || undefined,
wpilibArch: data.general.wpilibArch || undefined,
gpuAcceleration: data.general.gpuAcceleration || undefined,
mrCalWorking: data.general.mrCalWorking,
availableModels: data.general.availableModels || undefined,
Expand Down
2 changes: 2 additions & 0 deletions photon-client/src/types/SettingTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@ import { reactive } from "vue";

export interface GeneralSettings {
version?: string;
imageVersion?: string;
gpuAcceleration?: string;
hardwareModel?: string;
hardwarePlatform?: string;
wpilibArch?: string;
mrCalWorking: boolean;
availableModels: ObjectDetectionModelProperties[];
supportedBackends: string[];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,32 +23,38 @@
public class UIGeneralSettings {
public UIGeneralSettings(
String version,
String imageVersion,
String gpuAcceleration,
boolean mrCalWorking,
NeuralNetworkModelsSettings.ModelProperties[] availableModels,
List<String> supportedBackends,
String hardwareModel,
String hardwarePlatform,
String wpilibArch,
boolean conflictingHostname,
String conflictingCameras) {
this.version = version;
this.imageVersion = imageVersion;
this.gpuAcceleration = gpuAcceleration;
this.mrCalWorking = mrCalWorking;
this.availableModels = availableModels;
this.supportedBackends = supportedBackends;
this.hardwareModel = hardwareModel;
this.hardwarePlatform = hardwarePlatform;
this.wpilibArch = wpilibArch;
this.conflictingHostname = conflictingHostname;
this.conflictingCameras = conflictingCameras;
}

public String version;
public String imageVersion;
public String gpuAcceleration;
public boolean mrCalWorking;
public NeuralNetworkModelsSettings.ModelProperties[] availableModels;
public List<String> supportedBackends;
public String hardwareModel;
public String hardwarePlatform;
public String wpilibArch;
public boolean conflictingHostname;
public String conflictingCameras;
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import org.photonvision.common.configuration.NeuralNetworkModelManager;
import org.photonvision.common.configuration.PhotonConfiguration;
import org.photonvision.common.dataflow.networktables.NetworkTablesManager;
import org.photonvision.common.hardware.OsImageData;
import org.photonvision.common.hardware.Platform;
import org.photonvision.common.networking.NetworkManager;
import org.photonvision.common.networking.NetworkUtils;
Expand Down Expand Up @@ -52,6 +53,9 @@ public static UIPhotonConfiguration programStateToUi(PhotonConfiguration c) {
!c.getHardwareConfig().ledPins.isEmpty()),
new UIGeneralSettings(
PhotonVersion.versionString,
OsImageData.IMAGE_METADATA.isPresent()
? OsImageData.IMAGE_METADATA.get().commitTag()
: "",
// TODO add support for other types of GPU accel
LoadJNI.hasLoaded(JNITypes.LIBCAMERA) ? "Zerocopy Libcamera Working" : "",
LoadJNI.hasLoaded(JNITypes.MRCAL),
Expand All @@ -61,6 +65,7 @@ public static UIPhotonConfiguration programStateToUi(PhotonConfiguration c) {
? Platform.getHardwareModel()
: c.getHardwareConfig().deviceName,
Platform.getPlatformName(),
Platform.getNativePlatform(),
NetworkTablesManager.getInstance().conflictingHostname,
NetworkTablesManager.getInstance().conflictingCameras),
c.getApriltagFieldLayout()),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,11 @@ public class OsImageData {
private static Path imageVersionFile = Path.of("/opt/photonvision/image-version");
private static Path imageMetadataFile = Path.of("/opt/photonvision/image-version.json");

/** The OS image version string, if available. This is legacy, use {@link ImageMetadata}. */
public static final Optional<String> IMAGE_VERSION = getImageVersion();
/**
* The OS image version string, if available. This is legacy, use {@link ImageMetadata}.
* Deprecated for removal in 2027.
*/
@Deprecated public static final Optional<String> IMAGE_VERSION = getImageVersion();

private static Optional<String> getImageVersion() {
if (!imageVersionFile.toFile().exists()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

package org.photonvision.common.hardware;

import edu.wpi.first.util.CombinedRuntimeLoader;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
Expand Down Expand Up @@ -139,6 +140,27 @@ public static String getPlatformName() {
}
}

/**
* This function serves to map between formats used in the CombinedRuntimeLoader and the platform
* names used in the wpilib-tools-plugin. This is typically used for native libraries.
*
* @return String representing the platform in the format used by wpilib-tools-plugin, or an empty
* string if the platform is not recognized.
*/
public static String getNativePlatform() {
String platPath = CombinedRuntimeLoader.getPlatformPath();

if (platPath == "/linux/x86-64/") {
return "linuxx64";
} else if (platPath == "/windows/x86-64/") {
return "winx64";
} else if (platPath == "/linux/arm64/") {
return "linuxarm64";
} else {
return "";
}
}

public static String getHardwareModel() {
return currentPlatform.hardwareModel;
}
Expand Down
Loading