Skip to content

Commit 44f43b6

Browse files
Frontend: allow using outdated param sets
1 parent 2a6209a commit 44f43b6

1 file changed

Lines changed: 106 additions & 30 deletions

File tree

core/frontend/src/components/vehiclesetup/overview/ParamSets.vue

Lines changed: 106 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -44,16 +44,37 @@
4444
These are the recommended parameter sets for your vehicle and firmware version. Curated by Blue Robotics
4545
</p>
4646
</v-card-text>
47-
<v-card-actions>
48-
<v-btn
49-
v-for="(paramSet, name) in filtered_param_sets"
50-
:key="name"
51-
color="primary"
52-
@click="loadParams(name, paramSet)"
47+
<v-card-actions class="flex-wrap">
48+
<v-tooltip
49+
v-for="item in filtered_param_sets"
50+
:key="item.name"
51+
bottom
52+
:disabled="!item.outdated"
5353
>
54-
{{ name.split('/').pop() }}
55-
</v-btn>
56-
<p v-if="(Object.keys(filtered_param_sets).length === 0)">
54+
<template #activator="{ on }">
55+
<v-btn
56+
:color="item.outdated ? 'warning' : 'primary'"
57+
:outlined="item.outdated"
58+
@click="loadParams(item.name, item.paramset)"
59+
v-on="on"
60+
>
61+
<v-icon
62+
v-if="item.outdated"
63+
left
64+
small
65+
>
66+
mdi-alert
67+
</v-icon>
68+
{{ item.name.split('/').pop()?.replace(/\.params$/i, '') }}
69+
<span class="version-tag ml-2">v{{ item.version_label }}</span>
70+
</v-btn>
71+
</template>
72+
<span>
73+
Outdated: built for firmware {{ item.version_label }} (current is
74+
{{ version ? `${version.major}.${version.minor}` : 'unknown' }})
75+
</span>
76+
</v-tooltip>
77+
<p v-if="filtered_param_sets.length === 0">
5778
No parameters available for this setup
5879
</p>
5980
</v-card-actions>
@@ -95,6 +116,18 @@ import { frontend_service } from '@/types/frontend_services'
95116
const notifier = new Notifier(frontend_service)
96117
const REPOSITORY_URL = 'https://docs.bluerobotics.com/Blueos-Parameter-Repository/params_v1.json'
97118
119+
interface FilteredParamSet {
120+
name: string
121+
paramset: Dictionary<number>
122+
version: SemVer
123+
version_label: string
124+
outdated: boolean
125+
}
126+
127+
function escapeRegex(value: string): string {
128+
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
129+
}
130+
98131
export default Vue.extend({
99132
name: 'ParamSets',
100133
components: {
@@ -122,30 +155,73 @@ export default Vue.extend({
122155
version(): SemVer | undefined {
123156
return autopilot.firmware_info?.version
124157
},
125-
filtered_param_sets(): Dictionary<Dictionary<number>> | undefined {
126-
const fw_patch = `${this.vehicle}/${this.version}/${this.board}`
127-
const fw_minor = `${this.vehicle}/${this.version?.major}.${this.version?.minor}/${this.board}`
128-
const fw_major = `${this.vehicle}/${this.version?.major}/${this.board}`
129-
130-
// returns a new dict where the keys start with the fullname
131-
// e.g. "ArduSub/BlueROV2/4.0.3" -> "ArduSub/BlueROV2/4.0.3/BlueROV2"
132-
133-
let fw_params = {}
134-
// try to find a paramset that matches the firmware version, starting from patch and walking up to major
135-
for (const string of [fw_patch, fw_minor, fw_major]) {
136-
fw_params = Object.fromEntries(
137-
Object.entries(this.all_param_sets).filter(
138-
// We add a trailing slash to avoid matching Navigator and Navigator64, or any board with suffix
139-
([name]) => name.toLocaleLowerCase().includes(`${string.toLowerCase()}/`),
140-
),
141-
)
142-
if (Object.keys(fw_params).length > 0) {
143-
break
158+
filtered_param_sets(): FilteredParamSet[] {
159+
if (!this.vehicle || !this.board || !this.version) {
160+
return []
161+
}
162+
163+
// Match keys shaped like ".../<vehicle>/<X.Y[.Z]>/<board>/..."
164+
// Trailing slash on the board avoids matching Navigator vs Navigator64, etc.
165+
const pattern = new RegExp(
166+
`/${escapeRegex(this.vehicle)}/(\\d+\\.\\d+(?:\\.\\d+)?)/${escapeRegex(this.board)}/`,
167+
'i',
168+
)
169+
170+
const current = this.version
171+
const candidates: { name: string, paramset: Dictionary<number>, version: SemVer,
172+
version_label: string, has_patch: boolean }[] = []
173+
174+
for (const [name, paramset] of Object.entries(this.all_param_sets)) {
175+
const match = name.match(pattern)
176+
if (!match) {
177+
continue
178+
}
179+
180+
const version_label = match[1]
181+
const has_patch = version_label.split('.').length === 3
182+
let version: SemVer
183+
try {
184+
// Normalize "4.5" -> "4.5.0" so SemVer can parse it
185+
version = new SemVer(has_patch ? version_label : `${version_label}.0`)
186+
} catch {
187+
continue
144188
}
189+
190+
// Skip paramsets targeting a newer firmware than the one currently installed
191+
if (version.compare(current) > 0) {
192+
continue
193+
}
194+
195+
candidates.push({
196+
name, paramset, version, version_label, has_patch,
197+
})
145198
}
146-
return {
147-
...fw_params,
199+
200+
// Specificity: 2 = exact patch match, 1 = same major.minor, 0 = older
201+
function specificity(c: typeof candidates[number]): number {
202+
if (c.has_patch && c.version.compare(current) === 0) return 2
203+
if (c.version.major === current.major && c.version.minor === current.minor) return 1
204+
return 0
148205
}
206+
const best = candidates.reduce((max, c) => Math.max(max, specificity(c)), 0)
207+
208+
const result: FilteredParamSet[] = candidates.map((c) => ({
209+
name: c.name,
210+
paramset: c.paramset,
211+
version: c.version,
212+
version_label: c.version_label,
213+
outdated: best === 0 || specificity(c) < best,
214+
}))
215+
216+
// Current paramsets first, then outdated ones sorted newest-first
217+
result.sort((a, b) => {
218+
if (a.outdated !== b.outdated) {
219+
return a.outdated ? 1 : -1
220+
}
221+
return b.version.compare(a.version)
222+
})
223+
224+
return result
149225
},
150226
warningMessage(): string {
151227
return 'You will lose ALL your parameters, vehicle setup, and calibrations. Are you sure you want to reset?'

0 commit comments

Comments
 (0)