@@ -22,6 +22,14 @@ import store from './../js/store';
2222import dialog from '../js/dialog.js' ;
2323
2424TABS . firmware_flasher = { } ;
25+
26+ // Normalize target names to underscores for consistent dictionary lookups.
27+ // Hyphens supported as workaround for 9.0.0 filename inconsistency.
28+ function normalizeTargetName ( name ) {
29+ if ( name == null ) return '' ;
30+ return String ( name ) . replace ( / - / g, '_' ) ;
31+ }
32+
2533TABS . firmware_flasher . initialize = function ( callback ) {
2634
2735 if ( GUI . active_tab != 'firmware_flasher' ) {
@@ -72,17 +80,18 @@ TABS.firmware_flasher.initialize = function (callback) {
7280 //var targetFromFilenameExpression = /inav_([\d.]+)?_?([^.]+)\.(.*)/;
7381 // inav_8.0.0_TUNERCF405_dev-20240617-88fb1d0.hex
7482 // inav_8.0.0_TUNERCF405_ci-20240617-88fb1d0.hex
75- var targetFromFilenameExpression = / ^ i n a v _ ( \d + ) ( [ \d . ] + ) _ ( [ A - Z a - z 0 - 9 _ ] + ) _ ( c i | d e v ) - ( \d { 4 } ) ( \d { 2 } ) ( \d { 2 } ) - ( \w + ) \. ( h e x ) $ / ;
83+ var targetFromFilenameExpression = / ^ i n a v _ ( \d + ) ( [ \d . ] + ) _ ( [ A - Z a - z 0 - 9 _ - ] + ) _ ( c i | d e v ) - ( \d { 4 } ) ( \d { 2 } ) ( \d { 2 } ) - ( \w + ) \. ( h e x ) $ / ;
7684 var match = targetFromFilenameExpression . exec ( filename ) ;
7785
7886 if ( ! match ) {
7987 console . log ( filename + " not matched" ) ;
8088 return null ;
8189 }
8290
91+ var rawMatch = match [ 3 ] ; // e.g., "TBS-LUCID-H7-WING" or "TBS_LUCID_H7_WING"
8392 return {
84- raw_target : match [ 3 ] ,
85- target : match [ 3 ] . replace ( "_" , " " ) ,
93+ target_id : normalizeTargetName ( rawMatch ) ,
94+ target : rawMatch . replace ( / _ / g , " " ) . replace ( / - / g , " " ) , // Display: "TBS LUCID H7 WING"
8695 format : match [ 9 ] ,
8796 version : match [ 1 ] + match [ 2 ] ,
8897 major : match [ 1 ]
@@ -100,9 +109,10 @@ TABS.firmware_flasher.initialize = function (callback) {
100109
101110 //GUI.log("non dev: match[2]: " + match[2] + " match[3]: " + match[3]);
102111
112+ var rawMatch = match [ 2 ] ; // e.g., "MATEKF405" or "MATEK-F405"
103113 return {
104- raw_target : match [ 2 ] ,
105- target : match [ 2 ] . replace ( "_" , " " ) ,
114+ target_id : normalizeTargetName ( rawMatch ) ,
115+ target : rawMatch . replace ( / _ / g , " " ) . replace ( / - / g , " " ) , // Display: "MATEKF405"
106116 format : match [ 3 ] ,
107117 } ;
108118 }
@@ -115,7 +125,7 @@ TABS.firmware_flasher.initialize = function (callback) {
115125 if ( selectedTarget === "0" ) {
116126 TABS . firmware_flasher . getTarget ( ) ;
117127 } else {
118- $ ( 'select[name="board"] option[value=' + selectedTarget + ']' ) . attr ( "selected" , "selected" ) ;
128+ $ ( 'select[name="board"] option[value=" ' + selectedTarget + '" ]' ) . attr ( "selected" , "selected" ) ;
119129 $ ( 'select[name="board"]' ) . trigger ( 'change' ) ;
120130 }
121131 } ) ;
@@ -158,8 +168,8 @@ TABS.firmware_flasher.initialize = function (callback) {
158168 if ( ( ! showDevReleases && release . prerelease ) || ! result ) {
159169 return ;
160170 }
161- if ( $ . inArray ( result . target , unsortedTargets ) == - 1 ) {
162- unsortedTargets . push ( result . target ) ;
171+ if ( $ . inArray ( result . target_id , unsortedTargets ) == - 1 ) {
172+ unsortedTargets . push ( result . target_id ) ;
163173 }
164174 } ) ;
165175 } ) ;
@@ -170,8 +180,10 @@ TABS.firmware_flasher.initialize = function (callback) {
170180 release . assets . forEach ( function ( asset ) {
171181 var result = parseDevFilename ( asset . name ) ;
172182
173- if ( result && $ . inArray ( result . target , unsortedTargets ) == - 1 ) {
174- unsortedTargets . push ( result . target ) ;
183+ if ( result ) {
184+ if ( $ . inArray ( result . target_id , unsortedTargets ) == - 1 ) {
185+ unsortedTargets . push ( result . target_id ) ;
186+ }
175187 }
176188 } ) ;
177189 } ) ;
@@ -214,13 +226,16 @@ TABS.firmware_flasher.initialize = function (callback) {
214226 "version" : release . tag_name ,
215227 "url" : asset . browser_download_url ,
216228 "file" : asset . name ,
217- "raw_target" : result . raw_target ,
229+ "target_id" : result . target_id ,
218230 "target" : result . target ,
219231 "date" : formattedDate ,
220232 "notes" : release . body ,
221233 "status" : release . prerelease ? "release-candidate" : "stable"
222234 } ;
223- releases [ result . target ] . push ( descriptor ) ;
235+ // Skip duplicate entries (e.g. both hyphen and underscore variants of same target+version)
236+ if ( ! releases [ result . target_id ] . some ( d => d . version === descriptor . version && d . status === descriptor . status ) ) {
237+ releases [ result . target_id ] . push ( descriptor ) ;
238+ }
224239 } ) ;
225240 } ) ;
226241
@@ -268,13 +283,16 @@ TABS.firmware_flasher.initialize = function (callback) {
268283 "version" : release . tag_name ,
269284 "url" : asset . browser_download_url ,
270285 "file" : asset . name ,
271- "raw_target" : result . raw_target ,
286+ "target_id" : result . target_id ,
272287 "target" : result . target ,
273288 "date" : formattedDate ,
274289 "notes" : release . body ,
275290 "status" : release . prerelease ? "nightly" : "stable"
276291 } ;
277- releases [ result . target ] . push ( descriptor ) ;
292+ // Skip duplicate entries (e.g. both hyphen and underscore variants of same target+version)
293+ if ( ! releases [ result . target_id ] . some ( d => d . version === descriptor . version && d . status === descriptor . status ) ) {
294+ releases [ result . target_id ] . push ( descriptor ) ;
295+ }
278296 } ) ;
279297 } ) ;
280298 }
@@ -289,7 +307,7 @@ TABS.firmware_flasher.initialize = function (callback) {
289307 selectTargets . push ( target ) ;
290308 var select_e =
291309 $ ( "<option value='{0}'>{1}</option>" . format (
292- descriptor . raw_target ,
310+ descriptor . target_id ,
293311 descriptor . target
294312 ) ) . data ( 'summary' , descriptor ) ;
295313 boards_e . append ( select_e ) ;
@@ -324,6 +342,7 @@ TABS.firmware_flasher.initialize = function (callback) {
324342
325343 $ ( "a.load_remote_file" ) . addClass ( 'disabled' ) ;
326344 var target = $ ( this ) . children ( "option:selected" ) . val ( ) ;
345+ var targetDisplay = $ ( this ) . children ( "option:selected" ) . text ( ) ;
327346
328347 if ( ! GUI . connect_lock ) {
329348 $ ( '.progress' ) . val ( 0 ) . removeClass ( 'valid invalid' ) ;
@@ -336,7 +355,7 @@ TABS.firmware_flasher.initialize = function (callback) {
336355 if ( target == 0 ) {
337356 versions_e . append ( $ ( "<option value='0'>{0}</option>" . format ( i18n . getMessage ( 'firmwareFlasherOptionLabelSelectFirmwareVersion' ) ) ) ) ;
338357 } else {
339- versions_e . append ( $ ( "<option value='0'>{0} {1}</option>" . format ( i18n . getMessage ( 'firmwareFlasherOptionLabelSelectFirmwareVersionFor' ) , target ) ) ) ;
358+ versions_e . append ( $ ( "<option value='0'>{0} {1}</option>" . format ( i18n . getMessage ( 'firmwareFlasherOptionLabelSelectFirmwareVersionFor' ) , targetDisplay ) ) ) ;
340359 }
341360
342361 if ( typeof TABS . firmware_flasher . releases [ target ] ?. forEach === 'function' ) {
@@ -862,14 +881,15 @@ TABS.firmware_flasher.onValidFirmware = function() {
862881 MSP . send_message ( MSPCodes . MSP_BUILD_INFO , false , false , function ( ) {
863882 MSP . send_message ( MSPCodes . MSP_BOARD_INFO , false , false , function ( ) {
864883 var boardSelect = $ ( 'select[name="board"]' ) ;
865- boardSelect . val ( FC . CONFIG . target ) ;
884+ var normalizedTarget = normalizeTargetName ( FC . CONFIG . target ) ;
885+ boardSelect . val ( normalizedTarget ) ;
866886
867887 GUI . log ( i18n . getMessage ( 'targetPrefetchsuccessful' ) + FC . CONFIG . target ) ;
868888
869889 TABS . firmware_flasher . closeTempConnection ( ) ;
870890
871891 // Only trigger change if the board was actually found and selected
872- if ( boardSelect . val ( ) === FC . CONFIG . target ) {
892+ if ( boardSelect . val ( ) === normalizedTarget ) {
873893 boardSelect . trigger ( 'change' ) ;
874894 }
875895 } ) ;
0 commit comments