src/eric7/MicroPython/UF2FlashDialog.py

branch
eric7
changeset 9221
bf71ee032bb4
parent 9209
b99e7fd55fd3
child 9248
3859ac3b012a
equal deleted inserted replaced
9220:e9e7eca7efee 9221:bf71ee032bb4
26 26
27 SupportedUF2Boards = { 27 SupportedUF2Boards = {
28 "circuitpython": { 28 "circuitpython": {
29 "volumes": { 29 "volumes": {
30 (0x03EB, 0x2402): [ 30 (0x03EB, 0x2402): [
31 "SAMD21", # SAMD21 Board 31 "SAMD21", # SAMD21 Board
32 "SAME54", # SAME54 Board 32 "SAME54", # SAME54 Board
33 ], 33 ],
34 (0x04D8, 0xEC44): [ 34 (0x04D8, 0xEC44): [
35 "PYCUBEDBOOT", # PyCubedv04 35 "PYCUBEDBOOT", # PyCubedv04
36 ], 36 ],
37 (0x04D8, 0xEC63): [ 37 (0x04D8, 0xEC63): [
38 "BOOT", # CircuitBrains Basic 38 "BOOT", # CircuitBrains Basic
39 ], 39 ],
40 (0x04D8, 0xEC64): [ 40 (0x04D8, 0xEC64): [
41 "BOOT", # CircuitBrains Deluxe 41 "BOOT", # CircuitBrains Deluxe
42 ], 42 ],
43 (0x04D8, 0xED5F): [ 43 (0x04D8, 0xED5F): [
44 "UCHIPYBOOT", # uChip CircuitPython 44 "UCHIPYBOOT", # uChip CircuitPython
45 ], 45 ],
46 (0x04D8, 0xEDB3): [ 46 (0x04D8, 0xEDB3): [
47 "USBHUBBOOT", # Programmable USB Hub 47 "USBHUBBOOT", # Programmable USB Hub
48 ], 48 ],
49 (0x04D8, 0xEDBE): [ 49 (0x04D8, 0xEDBE): [
50 "SAM32BOOT", # SAM32 50 "SAM32BOOT", # SAM32
51 ], 51 ],
52 (0x04D8, 0xEF66): [ 52 (0x04D8, 0xEF66): [
53 "SENSEBOX", # senseBox MCU 53 "SENSEBOX", # senseBox MCU
54 ], 54 ],
55 (0x1209, 0x2017): [ 55 (0x1209, 0x2017): [
56 "MINISAMBOOT", # Mini SAM M4 56 "MINISAMBOOT", # Mini SAM M4
57 ], 57 ],
58 (0x1209, 0x3252): [ 58 (0x1209, 0x3252): [
59 "MCBS2OMBOOT", # Module Clip w/Wroom 59 "MCBS2OMBOOT", # Module Clip w/Wroom
60 ], 60 ],
61 (0x1209, 0x3253): [ 61 (0x1209, 0x3253): [
62 "MCBS2ERBOOT", # Module Clip w/Wrover 62 "MCBS2ERBOOT", # Module Clip w/Wrover
63 ], 63 ],
64 (0x1209, 0x4D44): [ 64 (0x1209, 0x4D44): [
65 "ROBOM0BOOT", # Robo HAT MM1 65 "ROBOM0BOOT", # Robo HAT MM1
66 "ROBOM4BOOT", # Robo HAT MM1 M4 66 "ROBOM4BOOT", # Robo HAT MM1 M4
67 ], 67 ],
68 (0x1209, 0x4DDD): [ 68 (0x1209, 0x4DDD): [
69 "SapBOOT", # CP Sapling 69 "SapBOOT", # CP Sapling
70 ], 70 ],
71 (0x1209, 0x7102): [ 71 (0x1209, 0x7102): [
72 "MINISAMBOOT", # Mini SAM M0 72 "MINISAMBOOT", # Mini SAM M0
73 ], 73 ],
74 (0x1209, 0x7A01): [ 74 (0x1209, 0x7A01): [
75 "MIKOTO-BOOT", # Mikoto nRF52840 75 "MIKOTO-BOOT", # Mikoto nRF52840
76 ], 76 ],
77 (0x1209, 0x805A): [ 77 (0x1209, 0x805A): [
78 "BASTBLE", # Bast BLE 78 "BASTBLE", # Bast BLE
79 ], 79 ],
80 (0x1209, 0xE3E2): [ 80 (0x1209, 0xE3E2): [
81 "StackRduino", # StackRduino M0 PRO 81 "StackRduino", # StackRduino M0 PRO
82 ], 82 ],
83 (0x1209, 0xF501): [ 83 (0x1209, 0xF501): [
84 "M4SHIMBOOT", # M4-Shim 84 "M4SHIMBOOT", # M4-Shim
85 ], 85 ],
86 (0x15BA, 0x28DC): [ 86 (0x15BA, 0x28DC): [
87 "OLMLIPOBOOT", # ESP32S2 DevKit Lipo 87 "OLMLIPOBOOT", # ESP32S2 DevKit Lipo
88 ], 88 ],
89 (0x16D0, 0x0CDA): [ 89 (0x16D0, 0x0CDA): [
90 "AUTOMAT", # automat 90 "AUTOMAT", # automat
91 ], 91 ],
92 (0x1B4F, 0x0022): [ 92 (0x1B4F, 0x0022): [
93 "SFMM852BOOT", # MicroMod nRF52840 93 "SFMM852BOOT", # MicroMod nRF52840
94 ], 94 ],
95 (0x1B4F, 0x002C): [ 95 (0x1B4F, 0x002C): [
96 "THNG+32BOOT", # Thing Plus - STM32 96 "THNG+32BOOT", # Thing Plus - STM32
97 ], 97 ],
98 (0x1B4F, 0x0D22): [ 98 (0x1B4F, 0x0D22): [
99 "SPARKFUN", # SAMD21 Mini Breakout 99 "SPARKFUN", # SAMD21 Mini Breakout
100 ], 100 ],
101 (0x1B4F, 0x0D23): [ 101 (0x1B4F, 0x0D23): [
102 "SPARKFUN", # SAMD21 Dev Breakout 102 "SPARKFUN", # SAMD21 Dev Breakout
103 ], 103 ],
104 (0x1D50, 0x6110): [ 104 (0x1D50, 0x6110): [
105 "ROBOTICS", # Robotics 105 "ROBOTICS", # Robotics
106 ], 106 ],
107 (0x1D50, 0x6112): [ 107 (0x1D50, 0x6112): [
108 "RCBOOT", # Wattuino RC 108 "RCBOOT", # Wattuino RC
109 ], 109 ],
110 (0x1D50, 0x6157): [ 110 (0x1D50, 0x6157): [
111 "BBOARDBOOT", # nRF52840 BBoard 111 "BBOARDBOOT", # nRF52840 BBoard
112 ], 112 ],
113 (0x1D50, 0x6160): [ 113 (0x1D50, 0x6160): [
114 "BLUEMICRO", # BlueMicro 114 "BLUEMICRO", # BlueMicro
115 ], 115 ],
116 (0x1D50, 0x616F): [ 116 (0x1D50, 0x616F): [
117 "BLUEMICRO", # BlueMicro 117 "BLUEMICRO", # BlueMicro
118 ], 118 ],
119 (0x1FC9, 0x0094): [ 119 (0x1FC9, 0x0094): [
120 "DblM33BOOT", # Double M33 120 "DblM33BOOT", # Double M33
121 "LPC5528BOOT", # LPCXpresso 55s28 121 "LPC5528BOOT", # LPCXpresso 55s28
122 "LPC5569BOOT", # LPCXpresso 55s69 122 "LPC5569BOOT", # LPCXpresso 55s69
123 ], 123 ],
124 (0x1FC9, 0x0154): [ 124 (0x1FC9, 0x0154): [
125 "K32L2BOOT", # FRDM-K32L2B3 125 "K32L2BOOT", # FRDM-K32L2B3
126 "K32L2BOOT", # KUIIC 126 "K32L2BOOT", # KUIIC
127 ], 127 ],
128 (0x230A, 0x00E9): [ 128 (0x230A, 0x00E9): [
129 "TAU_BOOT", # Tau 129 "TAU_BOOT", # Tau
130 ], 130 ],
131 (0x2341, 0x0057): [ 131 (0x2341, 0x0057): [
132 "NANOBOOT", # NANO 33 IoT 132 "NANOBOOT", # NANO 33 IoT
133 ], 133 ],
134 (0x2341, 0x8053): [ 134 (0x2341, 0x8053): [
135 "MKR1300", # MKR1300 135 "MKR1300", # MKR1300
136 ], 136 ],
137 (0x239A, 0x000F): [ 137 (0x239A, 0x000F): [
138 "ITSYBOOT", # ItsyBitsy M0 Express 138 "ITSYBOOT", # ItsyBitsy M0 Express
139 ], 139 ],
140 (0x239A, 0x0013): [ 140 (0x239A, 0x0013): [
141 "METROBOOT", # Metro M0 141 "METROBOOT", # Metro M0
142 ], 142 ],
143 (0x239A, 0x0015): [ 143 (0x239A, 0x0015): [
144 "FEATHERBOOT", # Feather M0 144 "FEATHERBOOT", # Feather M0
145 ], 145 ],
146 (0x239A, 0x0018): [ 146 (0x239A, 0x0018): [
147 "CPLAYBOOT", # CPlay Express 147 "CPLAYBOOT", # CPlay Express
148 ], 148 ],
149 (0x239A, 0x001B): [ 149 (0x239A, 0x001B): [
150 "FEATHERBOOT", # Feather M0 Express 150 "FEATHERBOOT", # Feather M0 Express
151 ], 151 ],
152 (0x239A, 0x001C): [ 152 (0x239A, 0x001C): [
153 "GEMMABOOT", # Gemma M0 153 "GEMMABOOT", # Gemma M0
154 ], 154 ],
155 (0x239A, 0x001E): [ 155 (0x239A, 0x001E): [
156 "TRINKETBOOT", # Trinket M0 156 "TRINKETBOOT", # Trinket M0
157 ], 157 ],
158 (0x239A, 0x0021): [ 158 (0x239A, 0x0021): [
159 "METROM4BOOT", # Metro M4 Express 159 "METROM4BOOT", # Metro M4 Express
160 ], 160 ],
161 (0x239A, 0x0022): [ 161 (0x239A, 0x0022): [
162 "ARCADE-D5", # Feather Arcade D51 162 "ARCADE-D5", # Feather Arcade D51
163 "FEATHERBOOT", # Feather M4 Express 163 "FEATHERBOOT", # Feather M4 Express
164 ], 164 ],
165 (0x239A, 0x0024): [ 165 (0x239A, 0x0024): [
166 "RADIOBOOT", # Radiofruit M0 166 "RADIOBOOT", # Radiofruit M0
167 ], 167 ],
168 (0x239A, 0x0027): [ 168 (0x239A, 0x0027): [
169 "PIRKEYBOOT", # pIRKey M0 169 "PIRKEYBOOT", # pIRKey M0
170 ], 170 ],
171 (0x239A, 0x0029): [ 171 (0x239A, 0x0029): [
172 "ARGONBOOT ", # Argon 172 "ARGONBOOT ", # Argon
173 "BORONBOOT ", # Boron 173 "BORONBOOT ", # Boron
174 "FTHR840BOOT", # Feather nRF52840 Express 174 "FTHR840BOOT", # Feather nRF52840 Express
175 "MDK840DONGL", # MDK nRF52840 USB Dongle 175 "MDK840DONGL", # MDK nRF52840 USB Dongle
176 "WS52840EVK", # Waveshare nRF52840 Eval 176 "WS52840EVK", # Waveshare nRF52840 Eval
177 "XENONBOOT ", # Xenon 177 "XENONBOOT ", # Xenon
178 ], 178 ],
179 (0x239A, 0x002B): [ 179 (0x239A, 0x002B): [
180 "ARCADE-D5", # Itsy Arcade D51 180 "ARCADE-D5", # Itsy Arcade D51
181 "ITSYM4BOOT", # ItsyBitsy M4 Express 181 "ITSYM4BOOT", # ItsyBitsy M4 Express
182 ], 182 ],
183 (0x239A, 0x002D): [ 183 (0x239A, 0x002D): [
184 "CRICKITBOOT", # crickit 184 "CRICKITBOOT", # crickit
185 ], 185 ],
186 (0x239A, 0x002F): [ 186 (0x239A, 0x002F): [
187 "TRELM4BOOT", # Trellis M4 Express 187 "TRELM4BOOT", # Trellis M4 Express
188 ], 188 ],
189 (0x239A, 0x0031): [ 189 (0x239A, 0x0031): [
190 "GCM4BOOT", # Grand Central M4 Express 190 "GCM4BOOT", # Grand Central M4 Express
191 ], 191 ],
192 (0x239A, 0x0033): [ 192 (0x239A, 0x0033): [
193 "PYBADGEBOOT", # PyBadge 193 "PYBADGEBOOT", # PyBadge
194 ], 194 ],
195 (0x239A, 0x0034): [ 195 (0x239A, 0x0034): [
196 "BADGELCBOOT", # BadgeLC 196 "BADGELCBOOT", # BadgeLC
197 "PEWBOOT", # PewPew 197 "PEWBOOT", # PewPew
198 ], 198 ],
199 (0x239A, 0x0035): [ 199 (0x239A, 0x0035): [
200 "MKRZEROBOOT", # MKRZero 200 "MKRZEROBOOT", # MKRZero
201 "PORTALBOOT", # PyPortal M4 Express 201 "PORTALBOOT", # PyPortal M4 Express
202 ], 202 ],
203 (0x239A, 0x0037): [ 203 (0x239A, 0x0037): [
204 "METROM4BOOT", # Metro M4 AirLift 204 "METROM4BOOT", # Metro M4 AirLift
205 ], 205 ],
206 (0x239A, 0x003D): [ 206 (0x239A, 0x003D): [
207 "PYGAMERBOOT", # PyGamer 207 "PYGAMERBOOT", # PyGamer
208 ], 208 ],
209 (0x239A, 0x003F): [ 209 (0x239A, 0x003F): [
210 "METR840BOOT", # Metro nRF52840 Express 210 "METR840BOOT", # Metro nRF52840 Express
211 ], 211 ],
212 (0x239A, 0x0045): [ 212 (0x239A, 0x0045): [
213 "CPLAYBTBOOT", # Circuit Playground nRF52840 213 "CPLAYBTBOOT", # Circuit Playground nRF52840
214 ], 214 ],
215 (0x239A, 0x0047): [ 215 (0x239A, 0x0047): [
216 "MASKM4BOOT", # Hallowing Mask M4 216 "MASKM4BOOT", # Hallowing Mask M4
217 ], 217 ],
218 (0x239A, 0x0049): [ 218 (0x239A, 0x0049): [
219 "HALLOM4BOOT", # HalloWing M4 219 "HALLOM4BOOT", # HalloWing M4
220 ], 220 ],
221 (0x239A, 0x004D): [ 221 (0x239A, 0x004D): [
222 "SNEKBOOT", # snekboard 222 "SNEKBOOT", # snekboard
223 ], 223 ],
224 (0x239A, 0x0051): [ 224 (0x239A, 0x0051): [
225 "ITSY840BOOT", # ItsyBitsy nRF52840 Express 225 "ITSY840BOOT", # ItsyBitsy nRF52840 Express
226 ], 226 ],
227 (0x239A, 0x0057): [ 227 (0x239A, 0x0057): [
228 "SERPENTBOOT", # Serpente 228 "SERPENTBOOT", # Serpente
229 ], 229 ],
230 (0x239A, 0x0059): [ 230 (0x239A, 0x0059): [
231 "FTHR405BOOT", # Feather STM32F405 Express 231 "FTHR405BOOT", # Feather STM32F405 Express
232 ], 232 ],
233 (0x239A, 0x005D): [ 233 (0x239A, 0x005D): [
234 "BlackPill", # STM32F401CxUx 234 "BlackPill", # STM32F401CxUx
235 "STMF411BOOT", # STM32F411 Discovery 235 "STMF411BOOT", # STM32F411 Discovery
236 ], 236 ],
237 (0x239A, 0x0061): [ 237 (0x239A, 0x0061): [
238 "SOLBOOT", # Sol 238 "SOLBOOT", # Sol
239 ], 239 ],
240 (0x239A, 0x0063): [ 240 (0x239A, 0x0063): [
241 "NANO33BOOT", # Nano 33 BLE 241 "NANO33BOOT", # Nano 33 BLE
242 ], 242 ],
243 (0x239A, 0x0065): [ 243 (0x239A, 0x0065): [
244 "ND6BOOT", # ndBit6 244 "ND6BOOT", # ndBit6
245 ], 245 ],
246 (0x239A, 0x0069): [ 246 (0x239A, 0x0069): [
247 "STMF411BOOT", # STM32F411 BlackPill 247 "STMF411BOOT", # STM32F411 BlackPill
248 ], 248 ],
249 (0x239A, 0x006B): [ 249 (0x239A, 0x006B): [
250 "shIRtty", # shIRtty 250 "shIRtty", # shIRtty
251 ], 251 ],
252 (0x239A, 0x0071): [ 252 (0x239A, 0x0071): [
253 "CLUEBOOT", # CLUE nRF52840 253 "CLUEBOOT", # CLUE nRF52840
254 ], 254 ],
255 (0x239A, 0x0077): [ 255 (0x239A, 0x0077): [
256 "RT1010BOOT", # RT1010 EVK 256 "RT1010BOOT", # RT1010 EVK
257 ], 257 ],
258 (0x239A, 0x0079): [ 258 (0x239A, 0x0079): [
259 "ARAMBOOT", # ARAMCON Badge 2019 259 "ARAMBOOT", # ARAMCON Badge 2019
260 ], 260 ],
261 (0x239A, 0x007B): [ 261 (0x239A, 0x007B): [
262 "ARAMBOOT", # ARAMCON2 Badge 262 "ARAMBOOT", # ARAMCON2 Badge
263 ], 263 ],
264 (0x239A, 0x007D): [ 264 (0x239A, 0x007D): [
265 "BOOKBOOT", # The Open Book Feather 265 "BOOKBOOT", # The Open Book Feather
266 ], 266 ],
267 (0x239A, 0x007F): [ 267 (0x239A, 0x007F): [
268 "BADGEBOOT", # OHS2020 Badge 268 "BADGEBOOT", # OHS2020 Badge
269 ], 269 ],
270 (0x239A, 0x0081): [ 270 (0x239A, 0x0081): [
271 "RT1020BOOT", # RT1020 EVK 271 "RT1020BOOT", # RT1020 EVK
272 "RT1024BOOT", # RT1024 EVK 272 "RT1024BOOT", # RT1024 EVK
273 ], 273 ],
274 (0x239A, 0x0083): [ 274 (0x239A, 0x0083): [
275 "RT1060BOOT", # RT1060 EVK 275 "RT1060BOOT", # RT1060 EVK
276 "RT1064BOOT", # RT1064 EVK 276 "RT1064BOOT", # RT1064 EVK
277 ], 277 ],
278 (0x239A, 0x0087): [ 278 (0x239A, 0x0087): [
279 "FTHRSNSBOOT", # Feather nRF52840 Sense 279 "FTHRSNSBOOT", # Feather nRF52840 Sense
280 ], 280 ],
281 (0x239A, 0x0093): [ 281 (0x239A, 0x0093): [
282 "ISVITABoot", # IkigaiSense Vita nRF52840 282 "ISVITABoot", # IkigaiSense Vita nRF52840
283 ], 283 ],
284 (0x239A, 0x0095): [ 284 (0x239A, 0x0095): [
285 "UARTLOGBOOT", # UARTLogger II 285 "UARTLOGBOOT", # UARTLogger II
286 ], 286 ],
287 (0x239A, 0x009F): [ 287 (0x239A, 0x009F): [
288 "ADM840BOOT", # AtelierDuMaker NRF52840 Breakout 288 "ADM840BOOT", # AtelierDuMaker NRF52840 Breakout
289 ], 289 ],
290 (0x239A, 0x00A5): [ 290 (0x239A, 0x00A5): [
291 "S3DKC1BOOT", # ESP32S3 DevKitC 1 291 "S3DKC1BOOT", # ESP32S3 DevKitC 1
292 "S3DKM1BOOT", # ESP32S3 DevKitM 1 292 "S3DKM1BOOT", # ESP32S3 DevKitM 1
293 "SAOLA1RBOOT", # Saola 1R WROVER 293 "SAOLA1RBOOT", # Saola 1R WROVER
294 ], 294 ],
295 (0x239A, 0x00A7): [ 295 (0x239A, 0x00A7): [
296 "SAOLA1MBOOT", # Saola 1M WROOM 296 "SAOLA1MBOOT", # Saola 1M WROOM
297 ], 297 ],
298 (0x239A, 0x00AB): [ 298 (0x239A, 0x00AB): [
299 "UFTHRS2BOOT", # FeatherS2 299 "UFTHRS2BOOT", # FeatherS2
300 ], 300 ],
301 (0x239A, 0x00AF): [ 301 (0x239A, 0x00AF): [
302 "FLUFFBOOT", # Fluff M0 302 "FLUFFBOOT", # Fluff M0
303 ], 303 ],
304 (0x239A, 0x00B3): [ 304 (0x239A, 0x00B3): [
305 "NICENANO", # nice!nano 305 "NICENANO", # nice!nano
306 ], 306 ],
307 (0x239A, 0x00B5): [ 307 (0x239A, 0x00B5): [
308 "E54XBOOT", # SAME54 Xplained 308 "E54XBOOT", # SAME54 Xplained
309 ], 309 ],
310 (0x239A, 0x00B9): [ 310 (0x239A, 0x00B9): [
311 "ND7BOOT", # ndBit7 311 "ND7BOOT", # ndBit7
312 ], 312 ],
313 (0x239A, 0x00BB): [ 313 (0x239A, 0x00BB): [
314 "MDBT50QBOOT", # Raytac MDBT50Q Demo Board 40 314 "MDBT50QBOOT", # Raytac MDBT50Q Demo Board 40
315 ], 315 ],
316 (0x239A, 0x00BF): [ 316 (0x239A, 0x00BF): [
317 "BADGEBOOT", # BLM Badge 317 "BADGEBOOT", # BLM Badge
318 ], 318 ],
319 (0x239A, 0x00C3): [ 319 (0x239A, 0x00C3): [
320 "GEMINIBOOT", # Gemini 320 "GEMINIBOOT", # Gemini
321 ], 321 ],
322 (0x239A, 0x00C5): [ 322 (0x239A, 0x00C5): [
323 "MICROS2BOOT", # microS2 323 "MICROS2BOOT", # microS2
324 ], 324 ],
325 (0x239A, 0x00C7): [ 325 (0x239A, 0x00C7): [
326 "KALUGA1BOOT", # Kaluga 1 326 "KALUGA1BOOT", # Kaluga 1
327 ], 327 ],
328 (0x239A, 0x00C9): [ 328 (0x239A, 0x00C9): [
329 "MATRIXBOOT", # Matrix Portal M4 329 "MATRIXBOOT", # Matrix Portal M4
330 ], 330 ],
331 (0x239A, 0x00CB): [ 331 (0x239A, 0x00CB): [
332 "QTPY_BOOT", # QT Py M0 332 "QTPY_BOOT", # QT Py M0
333 ], 333 ],
334 (0x239A, 0x00CD): [ 334 (0x239A, 0x00CD): [
335 "FTHRCANBOOT", # Feather M4 CAN Express 335 "FTHRCANBOOT", # Feather M4 CAN Express
336 ], 336 ],
337 (0x239A, 0x00DE): [ 337 (0x239A, 0x00DE): [
338 "NANOESPBOOT", # nanoESP32-S2 WROOM 338 "NANOESPBOOT", # nanoESP32-S2 WROOM
339 ], 339 ],
340 (0x239A, 0x00DF): [ 340 (0x239A, 0x00DF): [
341 "METROS2BOOT", # Metro ESP32-S2 341 "METROS2BOOT", # Metro ESP32-S2
342 ], 342 ],
343 (0x239A, 0x00E1): [ 343 (0x239A, 0x00E1): [
344 "METROM7BOOT", # Metro M7 iMX RT1011 344 "METROM7BOOT", # Metro M7 iMX RT1011
345 ], 345 ],
346 (0x239A, 0x00E5): [ 346 (0x239A, 0x00E5): [
347 "MAGTAGBOOT", # Metro MagTag 2.9 Grayscale 347 "MAGTAGBOOT", # Metro MagTag 2.9 Grayscale
348 "MAGTAGBOOT", # MagTag 2.9 Grayscale 348 "MAGTAGBOOT", # MagTag 2.9 Grayscale
349 ], 349 ],
350 (0x239A, 0x00EB): [ 350 (0x239A, 0x00EB): [
351 "FTHRS2BOOT", # Feather ESP32-S2 351 "FTHRS2BOOT", # Feather ESP32-S2
352 ], 352 ],
353 (0x239A, 0x00ED): [ 353 (0x239A, 0x00ED): [
354 "FTHRS2BOOT", # Feather ESP32-S2 Reverse TFT 354 "FTHRS2BOOT", # Feather ESP32-S2 Reverse TFT
355 ], 355 ],
356 (0x239A, 0x00EF): [ 356 (0x239A, 0x00EF): [
357 "TRINKEYBOOT", # NeoPixel Trinkey M0 357 "TRINKEYBOOT", # NeoPixel Trinkey M0
358 ], 358 ],
359 (0x239A, 0x00F5): [ 359 (0x239A, 0x00F5): [
360 "STARBOOT", # Binary Star 360 "STARBOOT", # Binary Star
361 ], 361 ],
362 (0x239A, 0x00F9): [ 362 (0x239A, 0x00F9): [
363 "HOUSEBOOT", # FunHouse 363 "HOUSEBOOT", # FunHouse
364 ], 364 ],
365 (0x239A, 0x00FB): [ 365 (0x239A, 0x00FB): [
366 "TRINKEYBOOT", # Rotary Trinkey M0 366 "TRINKEYBOOT", # Rotary Trinkey M0
367 ], 367 ],
368 (0x239A, 0x00FF): [ 368 (0x239A, 0x00FF): [
369 "TRINKEYBOOT", # NeoKey Trinkey M0 369 "TRINKEYBOOT", # NeoKey Trinkey M0
370 ], 370 ],
371 (0x239A, 0x0101): [ 371 (0x239A, 0x0101): [
372 "TRINKEYBOOT", # Slide Trinkey M0 372 "TRINKEYBOOT", # Slide Trinkey M0
373 ], 373 ],
374 (0x239A, 0x0103): [ 374 (0x239A, 0x0103): [
375 "TRINKEYBOOT", # ProxSense Trinkey M0 375 "TRINKEYBOOT", # ProxSense Trinkey M0
376 ], 376 ],
377 (0x239A, 0x010B): [ 377 (0x239A, 0x010B): [
378 "MDBT50QBOOT", # Raytac MDBT50Q-RX 378 "MDBT50QBOOT", # Raytac MDBT50Q-RX
379 ], 379 ],
380 (0x239A, 0x010D): [ 380 (0x239A, 0x010D): [
381 "GLASSESBOOT", # LED Glasses Driver nRF52840 381 "GLASSESBOOT", # LED Glasses Driver nRF52840
382 ], 382 ],
383 (0x239A, 0x010F): [ 383 (0x239A, 0x010F): [
384 "FTHRS2BOOT", # Feather ESP32-S2 TFT 384 "FTHRS2BOOT", # Feather ESP32-S2 TFT
385 ], 385 ],
386 (0x239A, 0x0111): [ 386 (0x239A, 0x0111): [
387 "QTPYS2BOOT", # QT Py ESP32-S2 387 "QTPYS2BOOT", # QT Py ESP32-S2
388 ], 388 ],
389 (0x239A, 0x0113): [ 389 (0x239A, 0x0113): [
390 "FTHRS3BOOT", # Feather ESP32-S3 No PSRAM 390 "FTHRS3BOOT", # Feather ESP32-S3 No PSRAM
391 ], 391 ],
392 (0x239A, 0x0115): [ 392 (0x239A, 0x0115): [
393 "FEATHERBOOT", # Feather M4 Adalogger 393 "FEATHERBOOT", # Feather M4 Adalogger
394 ], 394 ],
395 (0x239A, 0x0117): [ 395 (0x239A, 0x0117): [
396 "CAMERABOOT", # Camera 396 "CAMERABOOT", # Camera
397 ], 397 ],
398 (0x239A, 0x0119): [ 398 (0x239A, 0x0119): [
399 "QTPYS3BOOT", # QT Py ESP32-S3 399 "QTPYS3BOOT", # QT Py ESP32-S3
400 ], 400 ],
401 (0x239A, 0x800B): [ 401 (0x239A, 0x800B): [
402 "ATMZBOOT", # ATMegaZero ESP32-S2 402 "ATMZBOOT", # ATMegaZero ESP32-S2
403 ], 403 ],
404 (0x239A, 0xB000): [ 404 (0x239A, 0xB000): [
405 "HALLOWBOOT", # Hallowing M0 405 "HALLOWBOOT", # Hallowing M0
406 ], 406 ],
407 (0x239A, 0xE005): [ 407 (0x239A, 0xE005): [
408 "HONKBOOT", # Big Honking Button 408 "HONKBOOT", # Big Honking Button
409 ], 409 ],
410 (0x2886, 0x000D): [ 410 (0x2886, 0x000D): [
411 "Grove Zero", # Grove Zero 411 "Grove Zero", # Grove Zero
412 ], 412 ],
413 (0x2886, 0x002F): [ 413 (0x2886, 0x002F): [
414 "Seeed XIAO", # Seeeduino XIAO 414 "Seeed XIAO", # Seeeduino XIAO
415 ], 415 ],
416 (0x2886, 0xF00E): [ 416 (0x2886, 0xF00E): [
417 "PITAYAGO", # Pitaya Go 417 "PITAYAGO", # Pitaya Go
418 ], 418 ],
419 (0x2886, 0xF00F): [ 419 (0x2886, 0xF00F): [
420 "M60KEYBOARD", # MakerDiary M60 Mechanical Keyboard 420 "M60KEYBOARD", # MakerDiary M60 Mechanical Keyboard
421 "nRF52840M2", # MakerDiary nRF52840 M.2 Module 421 "nRF52840M2", # MakerDiary nRF52840 M.2 Module
422 ], 422 ],
423 (0x303A, 0x7000): [ 423 (0x303A, 0x7000): [
424 "ESPHMI1BOOT", # HMI 1 424 "ESPHMI1BOOT", # HMI 1
425 ], 425 ],
426 (0x303A, 0x8005): [ 426 (0x303A, 0x8005): [
427 "TINYS2BOOT", # TinyS2 427 "TINYS2BOOT", # TinyS2
428 ], 428 ],
429 (0x303A, 0x8008): [ 429 (0x303A, 0x8008): [
430 "TTGOS2BOOT", # TTGO_T8_S2_Display 430 "TTGOS2BOOT", # TTGO_T8_S2_Display
431 ], 431 ],
432 (0x303A, 0x800E): [ 432 (0x303A, 0x800E): [
433 "CCMBRISBOOT", # CucumberRIS v1.1 433 "CCMBRISBOOT", # CucumberRIS v1.1
434 ], 434 ],
435 (0x303A, 0x80B0): [ 435 (0x303A, 0x80B0): [
436 "RD00RBOOT", # Reference Design RD00 436 "RD00RBOOT", # Reference Design RD00
437 ], 437 ],
438 (0x303A, 0x80B3): [ 438 (0x303A, 0x80B3): [
439 "NANOESPBOOT", # nanoESP32-S2 WROVER 439 "NANOESPBOOT", # nanoESP32-S2 WROVER
440 ], 440 ],
441 (0x303A, 0x80B5): [ 441 (0x303A, 0x80B5): [
442 "FS2NEOBOOT", # FeatherS2 Neo 442 "FS2NEOBOOT", # FeatherS2 Neo
443 ], 443 ],
444 (0x303A, 0x80B6): [ 444 (0x303A, 0x80B6): [
445 "MORPHBOOT", # MORPHESP-240 445 "MORPHBOOT", # MORPHESP-240
446 ], 446 ],
447 (0x303A, 0x80C4): [ 447 (0x303A, 0x80C4): [
448 "S2MINIBOOT", # S2 Mini 448 "S2MINIBOOT", # S2 Mini
449 ], 449 ],
450 (0x303A, 0x80C7): [ 450 (0x303A, 0x80C7): [
451 "S2PICOBOOT", # S2 Pico 451 "S2PICOBOOT", # S2 Pico
452 ], 452 ],
453 (0x303A, 0x80D2): [ 453 (0x303A, 0x80D2): [
454 "TINYS3BOOT", # TinyS3 454 "TINYS3BOOT", # TinyS3
455 ], 455 ],
456 (0x303A, 0x80D5): [ 456 (0x303A, 0x80D5): [
457 "PROS3BOOT", # ProS3 457 "PROS3BOOT", # ProS3
458 ], 458 ],
459 (0x303A, 0x80D8): [ 459 (0x303A, 0x80D8): [
460 "UFTHRS3BOOT", # FeatherS3 460 "UFTHRS3BOOT", # FeatherS3
461 ], 461 ],
462 (0x303A, 0x80DA): [ 462 (0x303A, 0x80DA): [
463 "HEXKYBOOT", # HexKy-S2 463 "HEXKYBOOT", # HexKy-S2
464 ], 464 ],
465 (0x303A, 0x80DE): [ 465 (0x303A, 0x80DE): [
466 "LEAFS3BOOT", # BPI-Leaf-S3 466 "LEAFS3BOOT", # BPI-Leaf-S3
467 ], 467 ],
468 (0x303A, 0x80E1): [ 468 (0x303A, 0x80E1): [
469 "LEAFS2BOOT", # BPI-Leaf-S2 469 "LEAFS2BOOT", # BPI-Leaf-S2
470 ], 470 ],
471 (0x303A, 0x80E4): [ 471 (0x303A, 0x80E4): [
472 "BITS2BOOT", # BPI-BIT-S2 472 "BITS2BOOT", # BPI-BIT-S2
473 ], 473 ],
474 (0x303A, 0x80EB): [ 474 (0x303A, 0x80EB): [
475 "TTGOS2BOOT", # TTGO_T8_S2_WROOM 475 "TTGOS2BOOT", # TTGO_T8_S2_WROOM
476 ], 476 ],
477 (0x303A, 0x80EE): [ 477 (0x303A, 0x80EE): [
478 "TTGOS2BOOT", # TTGO_T8_S2 478 "TTGOS2BOOT", # TTGO_T8_S2
479 ], 479 ],
480 (0x3171, 0x0100): [ 480 (0x3171, 0x0100): [
481 "CMDBOOT", # COMMANDER 481 "CMDBOOT", # COMMANDER
482 ], 482 ],
483 (0x80E7, 0x8111): [ 483 (0x80E7, 0x8111): [
484 "IOTS2BOOT", # HiiBot IoTs2 484 "IOTS2BOOT", # HiiBot IoTs2
485 ], 485 ],
486 (0xCAFE, 0xFFFF): [ 486 (0xCAFE, 0xFFFF): [
487 "F303BOOT", # STM32F303 Discovery 487 "F303BOOT", # STM32F303 Discovery
488 ], 488 ],
489 }, 489 },
490 "instructions": QCoreApplication.translate( 490 "instructions": QCoreApplication.translate(
491 "UF2FlashDialog", 491 "UF2FlashDialog",
492 "<h3>CircuitPython Board</h3>" 492 "<h3>CircuitPython Board</h3>"
499 " pauses between presses.)</li>" 499 " pauses between presses.)</li>"
500 "<li>Ensure the boot volume is available (this may require" 500 "<li>Ensure the boot volume is available (this may require"
501 " mounting it).</li>" 501 " mounting it).</li>"
502 "<li>Select the firmware file to be flashed and click the" 502 "<li>Select the firmware file to be flashed and click the"
503 " flash button.</li>" 503 " flash button.</li>"
504 "</ol>" 504 "</ol>",
505 ), 505 ),
506 "show_all": True, 506 "show_all": True,
507 "firmware": "CircuitPython", 507 "firmware": "CircuitPython",
508 }, 508 },
509
510 "circuitpython_rp2040": { 509 "circuitpython_rp2040": {
511 "volumes": { 510 "volumes": {
512 (0x239A, 0x80F4): [ 511 (0x239A, 0x80F4): [
513 "RPI-RP2", # Raspberry Pi Pico loaded with CircuitPython 512 "RPI-RP2", # Raspberry Pi Pico loaded with CircuitPython
514 ], 513 ],
515 }, 514 },
516 "instructions": QCoreApplication.translate( 515 "instructions": QCoreApplication.translate(
517 "UF2FlashDialog", 516 "UF2FlashDialog",
518 "<h3>Pi Pico (RP2040) Board</h3>" 517 "<h3>Pi Pico (RP2040) Board</h3>"
532 "<li>Wait until the device has entered 'bootloader' mode.</li>" 531 "<li>Wait until the device has entered 'bootloader' mode.</li>"
533 "<li>Ensure the boot volume is available (this may require" 532 "<li>Ensure the boot volume is available (this may require"
534 " mounting it).</li>" 533 " mounting it).</li>"
535 "<li>Select the firmware file to be flashed and click the" 534 "<li>Select the firmware file to be flashed and click the"
536 " flash button.</li>" 535 " flash button.</li>"
537 "</ol>" 536 "</ol>",
538 ), 537 ),
539 "show_all": False, 538 "show_all": False,
540 "firmware": "CircuitPython", 539 "firmware": "CircuitPython",
541 }, 540 },
542
543 "rp2040": { 541 "rp2040": {
544 "volumes": { 542 "volumes": {
545 (0x0000, 0x0000): [ 543 (0x0000, 0x0000): [
546 "RPI-RP2", # Raspberry Pi Pico does not present a TTY 544 "RPI-RP2", # Raspberry Pi Pico does not present a TTY
547 ], 545 ],
548 }, 546 },
549 "instructions": QCoreApplication.translate( 547 "instructions": QCoreApplication.translate(
550 "UF2FlashDialog", 548 "UF2FlashDialog",
551 "<h3>Pi Pico (RP2040) Board</h3>" 549 "<h3>Pi Pico (RP2040) Board</h3>"
565 "<li>Wait until the device has entered 'bootloader' mode.</li>" 563 "<li>Wait until the device has entered 'bootloader' mode.</li>"
566 "<li>Ensure the boot volume is available (this may require" 564 "<li>Ensure the boot volume is available (this may require"
567 " mounting it).</li>" 565 " mounting it).</li>"
568 "<li>Select the firmware file to be flashed and click the" 566 "<li>Select the firmware file to be flashed and click the"
569 " flash button.</li>" 567 " flash button.</li>"
570 "</ol>" 568 "</ol>",
571 ), 569 ),
572 "show_all": True, 570 "show_all": True,
573 "firmware": "MicroPython / CircuitPython", 571 "firmware": "MicroPython / CircuitPython",
574 }, 572 },
575 } 573 }
576 574
577 575
578 def getFoundDevices(boardType=""): 576 def getFoundDevices(boardType=""):
579 """ 577 """
580 Function to get the list of known serial devices supporting UF2. 578 Function to get the list of known serial devices supporting UF2.
581 579
582 @param boardType specific board type to search for 580 @param boardType specific board type to search for
583 @type str 581 @type str
584 @return list of tuples with the board type, the port description, the 582 @return list of tuples with the board type, the port description, the
585 VID and PID 583 VID and PID
586 @rtype list of tuple of (str, str, int, int) 584 @rtype list of tuple of (str, str, int, int)
587 """ 585 """
588 from PyQt6.QtSerialPort import QSerialPortInfo 586 from PyQt6.QtSerialPort import QSerialPortInfo
589 587
590 foundDevices = [] 588 foundDevices = []
591 589
592 availablePorts = QSerialPortInfo.availablePorts() 590 availablePorts = QSerialPortInfo.availablePorts()
593 for port in availablePorts: 591 for port in availablePorts:
594 vid = port.vendorIdentifier() 592 vid = port.vendorIdentifier()
595 pid = port.productIdentifier() 593 pid = port.productIdentifier()
596 594
597 if vid == 0 and pid == 0: 595 if vid == 0 and pid == 0:
598 # no device detected at port 596 # no device detected at port
599 continue 597 continue
600 598
601 for board in SupportedUF2Boards: 599 for board in SupportedUF2Boards:
602 if ( 600 if (not boardType or (board.startswith(boardType))) and (
603 (not boardType or (board.startswith(boardType))) and 601 vid,
604 (vid, pid) in SupportedUF2Boards[board]["volumes"] 602 pid,
605 ): 603 ) in SupportedUF2Boards[board]["volumes"]:
606 foundDevices.append(( 604 foundDevices.append(
607 board, 605 (
608 port.description(), 606 board,
609 (vid, pid), 607 port.description(),
610 )) 608 (vid, pid),
611 609 )
610 )
611
612 # second run for boards needing special treatment (e.g. RP2040) 612 # second run for boards needing special treatment (e.g. RP2040)
613 for board in SupportedUF2Boards: 613 for board in SupportedUF2Boards:
614 if not boardType or (board == boardType): 614 if not boardType or (board == boardType):
615 with contextlib.suppress(KeyError): 615 with contextlib.suppress(KeyError):
616 # find mounted volume 616 # find mounted volume
617 volumes = SupportedUF2Boards[board]["volumes"][(0, 0)] 617 volumes = SupportedUF2Boards[board]["volumes"][(0, 0)]
618 foundVolumes = [] 618 foundVolumes = []
619 for volume in volumes: 619 for volume in volumes:
620 foundVolumes += Utilities.findVolume(volume, findAll=True) 620 foundVolumes += Utilities.findVolume(volume, findAll=True)
621 if foundVolumes: 621 if foundVolumes:
622 foundDevices.append(( 622 foundDevices.append(
623 board, 623 (
624 QCoreApplication.translate( 624 board,
625 "UF2FlashDialog", "'{0}' Board").format(board), 625 QCoreApplication.translate(
626 (0, 0), # VID/PID of (0, 0) is special 626 "UF2FlashDialog", "'{0}' Board"
627 )) 627 ).format(board),
628 628 (0, 0), # VID/PID of (0, 0) is special
629 )
630 )
631
629 return foundDevices 632 return foundDevices
630 633
631 634
632 class UF2FlashDialog(QDialog, Ui_UF2FlashDialog): 635 class UF2FlashDialog(QDialog, Ui_UF2FlashDialog):
633 """ 636 """
634 Class implementing a dialog to flash any UF2 capable device. 637 Class implementing a dialog to flash any UF2 capable device.
635 """ 638 """
639
636 DeviceTypeRole = Qt.ItemDataRole.UserRole 640 DeviceTypeRole = Qt.ItemDataRole.UserRole
637 DeviceVidPidRole = Qt.ItemDataRole.UserRole + 1 641 DeviceVidPidRole = Qt.ItemDataRole.UserRole + 1
638 642
639 def __init__(self, boardType="", parent=None): 643 def __init__(self, boardType="", parent=None):
640 """ 644 """
641 Constructor 645 Constructor
642 646
643 @param boardType specific board type to show the dialog for 647 @param boardType specific board type to show the dialog for
644 @type str 648 @type str
645 @param parent reference to the parent widget (defaults to None) 649 @param parent reference to the parent widget (defaults to None)
646 @type QWidget (optional) 650 @type QWidget (optional)
647 """ 651 """
648 super().__init__(parent) 652 super().__init__(parent)
649 self.setupUi(self) 653 self.setupUi(self)
650 654
651 self.refreshButton.setIcon(UI.PixmapCache.getIcon("rescan")) 655 self.refreshButton.setIcon(UI.PixmapCache.getIcon("rescan"))
652 656
653 self.firmwarePicker.setMode(EricPathPickerModes.OPEN_FILE_MODE) 657 self.firmwarePicker.setMode(EricPathPickerModes.OPEN_FILE_MODE)
654 self.firmwarePicker.setFilters( 658 self.firmwarePicker.setFilters(
655 self.tr("MicroPython/CircuitPython Files (*.uf2);;" 659 self.tr("MicroPython/CircuitPython Files (*.uf2);;" "All Files (*)")
656 "All Files (*)")) 660 )
657 661
658 self.bootPicker.setMode(EricPathPickerModes.DIRECTORY_SHOW_FILES_MODE) 662 self.bootPicker.setMode(EricPathPickerModes.DIRECTORY_SHOW_FILES_MODE)
659 self.bootPicker.setEnabled(False) 663 self.bootPicker.setEnabled(False)
660 664
661 self.__mandatoryStyleSheet = ( 665 self.__mandatoryStyleSheet = (
662 "QLineEdit {border: 2px solid; border-color: #dd8888}" 666 "QLineEdit {border: 2px solid; border-color: #dd8888}"
663 if ericApp().usesDarkPalette() else 667 if ericApp().usesDarkPalette()
664 "QLineEdit {border: 2px solid; border-color: #800000}" 668 else "QLineEdit {border: 2px solid; border-color: #800000}"
665 ) 669 )
666 self.__manualType = "<manual>" 670 self.__manualType = "<manual>"
667 671
668 self.__boardType = boardType 672 self.__boardType = boardType
669 673
670 self.__populate() 674 self.__populate()
671 675
672 self.__updateFlashButton() 676 self.__updateFlashButton()
673 677
674 def __populate(self): 678 def __populate(self):
675 """ 679 """
676 Private method to (re-)populate the dialog. 680 Private method to (re-)populate the dialog.
677 """ 681 """
678 # save the currently selected device 682 # save the currently selected device
679 currentDevice = self.devicesComboBox.currentText() 683 currentDevice = self.devicesComboBox.currentText()
680 firmwareFile = self.firmwarePicker.text() 684 firmwareFile = self.firmwarePicker.text()
681 685
682 # clear the entries first 686 # clear the entries first
683 self.devicesComboBox.clear() 687 self.devicesComboBox.clear()
684 self.firmwarePicker.clear() 688 self.firmwarePicker.clear()
685 self.bootPicker.clear() 689 self.bootPicker.clear()
686 self.infoLabel.clear() 690 self.infoLabel.clear()
687 self.infoEdit.clear() 691 self.infoEdit.clear()
688 692
689 # now populate the entries with data 693 # now populate the entries with data
690 devices = getFoundDevices(boardType=self.__boardType) 694 devices = getFoundDevices(boardType=self.__boardType)
691 if len(devices) == 0: 695 if len(devices) == 0:
692 # no device detected 696 # no device detected
693 devices = list(filter( 697 devices = list(
694 lambda x: x[0] in SupportedUF2Boards, 698 filter(
695 MicroPythonDevices.getFoundDevices()[0] 699 lambda x: x[0] in SupportedUF2Boards,
696 )) 700 MicroPythonDevices.getFoundDevices()[0],
701 )
702 )
697 if devices: 703 if devices:
698 self.__showSpecificInstructions(list(devices)) 704 self.__showSpecificInstructions(list(devices))
699 else: 705 else:
700 self.__showAllInstructions() 706 self.__showAllInstructions()
701 self.devicesComboBox.addItem("") 707 self.devicesComboBox.addItem("")
702 self.devicesComboBox.addItem(self.tr("Manual Select")) 708 self.devicesComboBox.addItem(self.tr("Manual Select"))
703 self.devicesComboBox.setItemData(1, self.__manualType, 709 self.devicesComboBox.setItemData(1, self.__manualType, self.DeviceTypeRole)
704 self.DeviceTypeRole)
705 elif len(devices) == 1: 710 elif len(devices) == 1:
706 # set the board type to the found one 711 # set the board type to the found one
707 self.__boardType = devices[0][0] 712 self.__boardType = devices[0][0]
708 713
709 self.devicesComboBox.addItem(devices[0][1]) 714 self.devicesComboBox.addItem(devices[0][1])
710 self.devicesComboBox.setItemData( 715 self.devicesComboBox.setItemData(0, devices[0][0], self.DeviceTypeRole)
711 0, devices[0][0], self.DeviceTypeRole) 716 self.devicesComboBox.setItemData(0, devices[0][2], self.DeviceVidPidRole)
712 self.devicesComboBox.setItemData(
713 0, devices[0][2], self.DeviceVidPidRole)
714 self.devicesComboBox.addItem(self.tr("Manual Select")) 717 self.devicesComboBox.addItem(self.tr("Manual Select"))
715 self.devicesComboBox.setItemData(1, self.__manualType, 718 self.devicesComboBox.setItemData(1, self.__manualType, self.DeviceTypeRole)
716 self.DeviceTypeRole)
717 self.on_devicesComboBox_currentIndexChanged(0) 719 self.on_devicesComboBox_currentIndexChanged(0)
718 else: 720 else:
719 self.devicesComboBox.addItem("") 721 self.devicesComboBox.addItem("")
720 for index, (boardType, description, 722 for index, (boardType, description, vidpid) in enumerate(
721 vidpid) in enumerate(sorted(devices), 1): 723 sorted(devices), 1
724 ):
722 self.devicesComboBox.addItem(description) 725 self.devicesComboBox.addItem(description)
723 self.devicesComboBox.setItemData( 726 self.devicesComboBox.setItemData(index, boardType, self.DeviceTypeRole)
724 index, boardType, self.DeviceTypeRole) 727 self.devicesComboBox.setItemData(index, vidpid, self.DeviceVidPidRole)
725 self.devicesComboBox.setItemData(
726 index, vidpid, self.DeviceVidPidRole)
727 self.devicesComboBox.addItem(self.tr("Manual Select")) 728 self.devicesComboBox.addItem(self.tr("Manual Select"))
728 self.devicesComboBox.setItemData(index + 1, self.__manualType, 729 self.devicesComboBox.setItemData(
729 self.DeviceTypeRole) 730 index + 1, self.__manualType, self.DeviceTypeRole
730 731 )
732
731 # reselect the remembered device, if it is still there 733 # reselect the remembered device, if it is still there
732 if currentDevice: 734 if currentDevice:
733 self.devicesComboBox.setCurrentText(currentDevice) 735 self.devicesComboBox.setCurrentText(currentDevice)
734 self.firmwarePicker.setText(firmwareFile) 736 self.firmwarePicker.setText(firmwareFile)
735 else: 737 else:
736 self.devicesComboBox.setCurrentIndex(0) 738 self.devicesComboBox.setCurrentIndex(0)
737 739
738 def __updateFlashButton(self): 740 def __updateFlashButton(self):
739 """ 741 """
740 Private method to update the state of the Flash button and the retest 742 Private method to update the state of the Flash button and the retest
741 button. 743 button.
742 """ 744 """
744 if self.devicesComboBox.currentData(self.DeviceTypeRole) is not None: 746 if self.devicesComboBox.currentData(self.DeviceTypeRole) is not None:
745 if bool(firmwareFile) and os.path.exists(firmwareFile): 747 if bool(firmwareFile) and os.path.exists(firmwareFile):
746 self.firmwarePicker.setStyleSheet("") 748 self.firmwarePicker.setStyleSheet("")
747 else: 749 else:
748 self.firmwarePicker.setStyleSheet(self.__mandatoryStyleSheet) 750 self.firmwarePicker.setStyleSheet(self.__mandatoryStyleSheet)
749 751
750 if bool(self.bootPicker.text()): 752 if bool(self.bootPicker.text()):
751 self.bootPicker.setStyleSheet("") 753 self.bootPicker.setStyleSheet("")
752 else: 754 else:
753 self.bootPicker.setStyleSheet(self.__mandatoryStyleSheet) 755 self.bootPicker.setStyleSheet(self.__mandatoryStyleSheet)
754 else: 756 else:
755 self.firmwarePicker.setStyleSheet("") 757 self.firmwarePicker.setStyleSheet("")
756 self.bootPicker.setStyleSheet("") 758 self.bootPicker.setStyleSheet("")
757 759
758 enable = ( 760 enable = (
759 bool(self.bootPicker.text()) and 761 bool(self.bootPicker.text())
760 bool(firmwareFile) and 762 and bool(firmwareFile)
761 os.path.exists(firmwareFile) 763 and os.path.exists(firmwareFile)
762 ) 764 )
763 self.flashButton.setEnabled(enable) 765 self.flashButton.setEnabled(enable)
764 766
765 def __showAllInstructions(self): 767 def __showAllInstructions(self):
766 """ 768 """
767 Private method to show instructions for resetting devices to bootloader 769 Private method to show instructions for resetting devices to bootloader
768 mode. 770 mode.
769 """ 771 """
770 self.infoLabel.setText(self.tr("Reset Instructions:")) 772 self.infoLabel.setText(self.tr("Reset Instructions:"))
771 773
772 htmlText = self.tr( 774 htmlText = self.tr(
773 "<h4>No known devices detected.</h4>" 775 "<h4>No known devices detected.</h4>"
774 "<p>Follow the appropriate instructions below to set <b>one</b>" 776 "<p>Follow the appropriate instructions below to set <b>one</b>"
775 " board into 'bootloader' mode. Press <b>Refresh</b> when ready." 777 " board into 'bootloader' mode. Press <b>Refresh</b> when ready."
776 "</p>" 778 "</p>"
777 ) 779 )
778 for boardType in SupportedUF2Boards: 780 for boardType in SupportedUF2Boards:
779 if SupportedUF2Boards[boardType]["show_all"]: 781 if SupportedUF2Boards[boardType]["show_all"]:
780 htmlText += ( 782 htmlText += "<hr/>" + SupportedUF2Boards[boardType]["instructions"]
781 "<hr/>" +
782 SupportedUF2Boards[boardType]["instructions"]
783 )
784 self.infoEdit.setHtml(htmlText) 783 self.infoEdit.setHtml(htmlText)
785 784
786 def __showSpecificInstructions(self, devices): 785 def __showSpecificInstructions(self, devices):
787 """ 786 """
788 Private method to show instructions for resetting devices to bootloader 787 Private method to show instructions for resetting devices to bootloader
789 mode for a list of detected devices. 788 mode for a list of detected devices.
790 789
791 @param devices list of detected devices 790 @param devices list of detected devices
792 @type list of str 791 @type list of str
793 """ 792 """
794 boardTypes = {x[0] for x in devices} 793 boardTypes = {x[0] for x in devices}
795 794
796 self.infoLabel.setText(self.tr("Reset Instructions:")) 795 self.infoLabel.setText(self.tr("Reset Instructions:"))
797 796
798 if self.__boardType: 797 if self.__boardType:
799 htmlText = self.tr( 798 htmlText = self.tr(
800 "<h4>Flash {0} Firmware</h4>" 799 "<h4>Flash {0} Firmware</h4>"
801 "<p>Follow the instructions below to set <b>one</b> board into" 800 "<p>Follow the instructions below to set <b>one</b> board into"
802 " 'bootloader' mode. Press <b>Refresh</b> when ready.</p>" 801 " 'bootloader' mode. Press <b>Refresh</b> when ready.</p>"
810 "<h4>Potentially UF2 capable devices found</h4>" 809 "<h4>Potentially UF2 capable devices found</h4>"
811 "<p>Found these potentially UF2 capable devices:</p>" 810 "<p>Found these potentially UF2 capable devices:</p>"
812 "<ul><li>{0}</li></ul>" 811 "<ul><li>{0}</li></ul>"
813 "<p>Follow the instructions below to set <b>one</b> board into" 812 "<p>Follow the instructions below to set <b>one</b> board into"
814 " 'bootloader' mode. Press <b>Refresh</b> when ready.</p>" 813 " 'bootloader' mode. Press <b>Refresh</b> when ready.</p>"
815 ).format( 814 ).format("</li><li>".join(sorted(x[1] for x in devices)))
816 "</li><li>".join(sorted(x[1] for x in devices))
817 )
818 for boardType in sorted(boardTypes): 815 for boardType in sorted(boardTypes):
819 htmlText += ( 816 htmlText += "<hr/>" + SupportedUF2Boards[boardType]["instructions"]
820 "<hr/>" + SupportedUF2Boards[boardType]["instructions"]
821 )
822 self.infoEdit.setHtml(htmlText) 817 self.infoEdit.setHtml(htmlText)
823 818
824 def __showTypedInstructions(self, boardType): 819 def __showTypedInstructions(self, boardType):
825 """ 820 """
826 Private method to show instructions for resetting devices to bootloader 821 Private method to show instructions for resetting devices to bootloader
827 mode for a specific board type. 822 mode for a specific board type.
828 823
829 @param boardType type of the board to show instructions for 824 @param boardType type of the board to show instructions for
830 @type str 825 @type str
831 """ 826 """
832 self.infoLabel.setText(self.tr("Reset Instructions:")) 827 self.infoLabel.setText(self.tr("Reset Instructions:"))
833 828
834 htmlText = self.tr( 829 htmlText = self.tr(
835 "<h4>No known devices detected.</h4>" 830 "<h4>No known devices detected.</h4>"
836 "<p>Follow the instructions below to set <b>one</b> board into" 831 "<p>Follow the instructions below to set <b>one</b> board into"
837 " 'bootloader' mode. Press <b>Refresh</b> when ready.</p>" 832 " 'bootloader' mode. Press <b>Refresh</b> when ready.</p>"
838 ) 833 )
839 htmlText += "<hr/>" + SupportedUF2Boards[boardType]["instructions"] 834 htmlText += "<hr/>" + SupportedUF2Boards[boardType]["instructions"]
840 self.infoEdit.setHtml(htmlText) 835 self.infoEdit.setHtml(htmlText)
841 836
842 def __showManualInstructions(self): 837 def __showManualInstructions(self):
843 """ 838 """
844 Private method to show instructions for flashing devices manually. 839 Private method to show instructions for flashing devices manually.
845 """ 840 """
846 self.infoLabel.setText(self.tr("Flash Instructions:")) 841 self.infoLabel.setText(self.tr("Flash Instructions:"))
847 842
848 htmlText = self.tr( 843 htmlText = self.tr(
849 "<h4>Flash method 'manual' selected.</h4>" 844 "<h4>Flash method 'manual' selected.</h4>"
850 "<p>Follow the instructions below to flash a device by entering" 845 "<p>Follow the instructions below to flash a device by entering"
851 " the data manually.</p><ol>" 846 " the data manually.</p><ol>"
852 "<li>Change the device to 'bootloader' mode.</li>" 847 "<li>Change the device to 'bootloader' mode.</li>"
858 "</ol>" 853 "</ol>"
859 ) 854 )
860 for boardType in SupportedUF2Boards: 855 for boardType in SupportedUF2Boards:
861 htmlText += "<hr/>" + SupportedUF2Boards[boardType]["instructions"] 856 htmlText += "<hr/>" + SupportedUF2Boards[boardType]["instructions"]
862 self.infoEdit.setHtml(htmlText) 857 self.infoEdit.setHtml(htmlText)
863 858
864 def __showNoVolumeInformation(self, volumes, boardType): 859 def __showNoVolumeInformation(self, volumes, boardType):
865 """ 860 """
866 Private method to show information about the expected boot volume(s). 861 Private method to show information about the expected boot volume(s).
867 862
868 @param volumes list of expected volume names 863 @param volumes list of expected volume names
869 @type list of str 864 @type list of str
870 @param boardType type of the board to show instructions for 865 @param boardType type of the board to show instructions for
871 @type str 866 @type str
872 """ 867 """
873 self.infoLabel.setText(self.tr("Boot Volume not found:")) 868 self.infoLabel.setText(self.tr("Boot Volume not found:"))
874 869
875 htmlText = self.tr( 870 htmlText = self.tr(
876 "<h4>No Boot Volume detected.</h4>" 871 "<h4>No Boot Volume detected.</h4>"
877 "<p>Please ensure that the boot volume of the device to be flashed" 872 "<p>Please ensure that the boot volume of the device to be flashed"
878 " is available. " 873 " is available. "
879 ) 874 )
886 htmlText += self.tr( 881 htmlText += self.tr(
887 "This volume should have one of these names.</p>" 882 "This volume should have one of these names.</p>"
888 "<ul><li>{0}</li></ul>" 883 "<ul><li>{0}</li></ul>"
889 "<p>Press <b>Refresh</b> when ready.</p>" 884 "<p>Press <b>Refresh</b> when ready.</p>"
890 ).format("</li><li>".join(sorted(volumes))) 885 ).format("</li><li>".join(sorted(volumes)))
891 886
892 if boardType: 887 if boardType:
893 htmlText += self.tr( 888 htmlText += self.tr(
894 "<h4>Reset Instructions</h4>" 889 "<h4>Reset Instructions</h4>"
895 "<p>Follow the instructions below to set the board into" 890 "<p>Follow the instructions below to set the board into"
896 " 'bootloader' mode. Press <b>Refresh</b> when ready.</p>" 891 " 'bootloader' mode. Press <b>Refresh</b> when ready.</p>"
897 ) 892 )
898 htmlText += "<hr/>" + SupportedUF2Boards[boardType]["instructions"] 893 htmlText += "<hr/>" + SupportedUF2Boards[boardType]["instructions"]
899 894
900 self.infoEdit.setHtml(htmlText) 895 self.infoEdit.setHtml(htmlText)
901 896
902 def __showMultipleVolumesInformation(self, volumePaths): 897 def __showMultipleVolumesInformation(self, volumePaths):
903 """ 898 """
904 Private method to show information because multiple devices of the 899 Private method to show information because multiple devices of the
905 same type are ready for flashing. 900 same type are ready for flashing.
906 901
907 Note: This is a dangerous situation! 902 Note: This is a dangerous situation!
908 903
909 @param volumePaths list of volume paths 904 @param volumePaths list of volume paths
910 @type list of str 905 @type list of str
911 """ 906 """
912 self.infoLabel.setText(self.tr("Multiple Boot Volumes found:")) 907 self.infoLabel.setText(self.tr("Multiple Boot Volumes found:"))
913 908
914 htmlText = self.tr( 909 htmlText = self.tr(
915 "<h4>Multiple Boot Volumes were found</h4>" 910 "<h4>Multiple Boot Volumes were found</h4>"
916 "<p>These volume paths were found.</p><ul><li>{0}</li></ul>" 911 "<p>These volume paths were found.</p><ul><li>{0}</li></ul>"
917 "<p>Please ensure that only one device of a type is ready for" 912 "<p>Please ensure that only one device of a type is ready for"
918 " flashing. Press <b>Refresh</b> when ready.</p>" 913 " flashing. Press <b>Refresh</b> when ready.</p>"
919 ).format("</li><li>".join(sorted(volumePaths))) 914 ).format("</li><li>".join(sorted(volumePaths)))
920 self.infoEdit.setHtml(htmlText) 915 self.infoEdit.setHtml(htmlText)
921 916
922 @pyqtSlot() 917 @pyqtSlot()
923 def on_flashButton_clicked(self): 918 def on_flashButton_clicked(self):
924 """ 919 """
925 Private slot to flash the selected MicroPython or CircuitPython 920 Private slot to flash the selected MicroPython or CircuitPython
926 firmware onto the device. 921 firmware onto the device.
929 firmwarePath = self.firmwarePicker.text() 924 firmwarePath = self.firmwarePicker.text()
930 volumePath = self.bootPicker.text() 925 volumePath = self.bootPicker.text()
931 if os.path.exists(firmwarePath) and os.path.exists(volumePath): 926 if os.path.exists(firmwarePath) and os.path.exists(volumePath):
932 if boardType == self.__manualType: 927 if boardType == self.__manualType:
933 self.infoLabel.setText(self.tr("Flashing Firmware")) 928 self.infoLabel.setText(self.tr("Flashing Firmware"))
934 self.infoEdit.setHtml(self.tr( 929 self.infoEdit.setHtml(
935 "<p>Flashing the selected firmware to the device. Please" 930 self.tr(
936 " wait until the device resets automatically.</p>") 931 "<p>Flashing the selected firmware to the device. Please"
932 " wait until the device resets automatically.</p>"
933 )
937 ) 934 )
938 else: 935 else:
939 firmwareType = SupportedUF2Boards[boardType]["firmware"] 936 firmwareType = SupportedUF2Boards[boardType]["firmware"]
940 self.infoLabel.setText( 937 self.infoLabel.setText(self.tr("Flashing {0}").format(firmwareType))
941 self.tr("Flashing {0}").format(firmwareType)) 938 self.infoEdit.setHtml(
942 self.infoEdit.setHtml(self.tr( 939 self.tr(
943 "<p>Flashing the {0} firmware to the device. Please wait" 940 "<p>Flashing the {0} firmware to the device. Please wait"
944 " until the device resets automatically.</p>" 941 " until the device resets automatically.</p>"
945 ).format(firmwareType)) 942 ).format(firmwareType)
943 )
946 QCoreApplication.processEvents( 944 QCoreApplication.processEvents(
947 QEventLoop.ProcessEventsFlag.ExcludeUserInputEvents) 945 QEventLoop.ProcessEventsFlag.ExcludeUserInputEvents
946 )
948 shutil.copy2(firmwarePath, volumePath) 947 shutil.copy2(firmwarePath, volumePath)
949 QThread.sleep(1) 948 QThread.sleep(1)
950 self.on_refreshButton_clicked() 949 self.on_refreshButton_clicked()
951 950
952 @pyqtSlot() 951 @pyqtSlot()
953 def on_refreshButton_clicked(self): 952 def on_refreshButton_clicked(self):
954 """ 953 """
955 Private slot to refresh the dialog. 954 Private slot to refresh the dialog.
956 """ 955 """
957 # special treatment for RPi Pico 956 # special treatment for RPi Pico
958 if self.__boardType == "circuitpython_rp2040": 957 if self.__boardType == "circuitpython_rp2040":
959 self.__boardType = "rp2040" 958 self.__boardType = "rp2040"
960 959
961 self.__populate() 960 self.__populate()
962 961
963 @pyqtSlot(int) 962 @pyqtSlot(int)
964 def on_devicesComboBox_currentIndexChanged(self, index): 963 def on_devicesComboBox_currentIndexChanged(self, index):
965 """ 964 """
966 Private slot to handle the selection of a board. 965 Private slot to handle the selection of a board.
967 966
968 @param index selected index 967 @param index selected index
969 @type int 968 @type int
970 """ 969 """
971 vidpid = self.devicesComboBox.itemData(index, self.DeviceVidPidRole) 970 vidpid = self.devicesComboBox.itemData(index, self.DeviceVidPidRole)
972 boardType = self.devicesComboBox.itemData(index, self.DeviceTypeRole) 971 boardType = self.devicesComboBox.itemData(index, self.DeviceTypeRole)
973 972
974 self.bootPicker.setEnabled(boardType == self.__manualType) 973 self.bootPicker.setEnabled(boardType == self.__manualType)
975 if boardType == self.__manualType: 974 if boardType == self.__manualType:
976 self.__showManualInstructions() 975 self.__showManualInstructions()
977 976
978 if vidpid is None: 977 if vidpid is None:
979 if boardType is None: 978 if boardType is None:
980 self.bootPicker.clear() 979 self.bootPicker.clear()
981 else: 980 else:
982 volumes = SupportedUF2Boards[boardType]["volumes"][vidpid] 981 volumes = SupportedUF2Boards[boardType]["volumes"][vidpid]
983 foundVolumes = [] 982 foundVolumes = []
984 for volume in volumes: 983 for volume in volumes:
985 foundVolumes += Utilities.findVolume(volume, findAll=True) 984 foundVolumes += Utilities.findVolume(volume, findAll=True)
986 985
987 if len(foundVolumes) == 0: 986 if len(foundVolumes) == 0:
988 self.__showNoVolumeInformation(volumes, boardType) 987 self.__showNoVolumeInformation(volumes, boardType)
989 self.bootPicker.clear() 988 self.bootPicker.clear()
990 elif len(foundVolumes) == 1: 989 elif len(foundVolumes) == 1:
991 self.bootPicker.setText(foundVolumes[0]) 990 self.bootPicker.setText(foundVolumes[0])
992 else: 991 else:
993 self.__showMultipleVolumesInformation() 992 self.__showMultipleVolumesInformation()
994 self.bootPicker.clear() 993 self.bootPicker.clear()
995 994
996 self.__updateFlashButton() 995 self.__updateFlashButton()
997 996
998 @pyqtSlot(str) 997 @pyqtSlot(str)
999 def on_firmwarePicker_textChanged(self, text): 998 def on_firmwarePicker_textChanged(self, text):
1000 """ 999 """
1001 Private slot handling a change of the firmware file. 1000 Private slot handling a change of the firmware file.
1002 1001
1003 @param text current text of the firmware edit 1002 @param text current text of the firmware edit
1004 @type str 1003 @type str
1005 """ 1004 """
1006 self.__updateFlashButton() 1005 self.__updateFlashButton()
1007 1006
1008 @pyqtSlot(str) 1007 @pyqtSlot(str)
1009 def on_bootPicker_textChanged(self, text): 1008 def on_bootPicker_textChanged(self, text):
1010 """ 1009 """
1011 Private slot handling a change of the boot volume. 1010 Private slot handling a change of the boot volume.
1012 1011
1013 @param text current text of the boot volume edit 1012 @param text current text of the boot volume edit
1014 @type str 1013 @type str
1015 """ 1014 """
1016 self.__updateFlashButton() 1015 self.__updateFlashButton()

eric ide

mercurial