@@ -25,8 +25,36 @@ import {
2525 takeUntil , filter , startWith , first , distinctUntilChanged
2626} from 'rxjs/operators' ;
2727
28+ const versionsMap = {
29+ wifi101 : {
30+ latestVersion : 'WINC1500 19.5.4' ,
31+ loaderPath : null ,
32+ latestVersionPath : null
33+ } ,
34+ wifiNina : {
35+ latestVersion : 'NINA 1.2.2' ,
36+ loaderPath : null ,
37+ latestVersionPath : null
38+ }
39+ } ;
40+
2841const POLLING_INTERVAL = 1500 ;
2942
43+ /* The status of the Firmware Updater Tool */
44+ const FWUToolStatusEnum = Object . freeze ( {
45+ NOPE : 'NOPE' ,
46+ OK : 'OK' ,
47+ CHECKING : 'CHECKING' ,
48+ ERROR : 'ERROR DOWNLOADING TOOL'
49+ } ) ;
50+
51+ /* The signatures needed to run the commands to use the Firmware Updater Tool */
52+ const signaturesEnum = Object . freeze ( {
53+ GET_FIRMWARE_INFO : 'aceffd98d331df0daa5bb3308bb49a95767d77e7a1557c07a0ec544d2f41c3ec67269f01ce9a63e01f3b43e087ab8eb22b7f1d34135b6686e8ce27d4b5dc083ec8e6149df11880d32486448a71280ef3128efccbd45a84dbd7990a9420a65ee86b3822edba3554fa8e6ca11aec12d4dd99ad072285b98bfdf7b2b64f677da50feb8bddef25a36f52d7605078487d8a5d7cbdc84bfa65d510cee97b46baefea149139a9a6ed4b545346040536e33d850e6ad84c83fe605f677e2ca77439de3fa42350ce504ad9a49cf62c6751d4c2a284500d2c628cd52cd73b4c3e7ef08ae823eb8941383f9c6ff0686da532369d3b266ded8fdd33cca1a128068a4795920f25' ,
54+ UPLOAD_FIRMWARE_BOSSAC : 'b2137435f74601a0b1b090ca1592b14199c1c79c87cecac4bb168456b570f17b635f438f5cd80649a101ab27085394e4a0e92f41a2b1b65932789eee8c3ebf39633a503a8a53d3291944afe10ff88f6ea06b0fd7fd7de6d70b302df3a92091a2abe2691ad1aeee051e4bb69f6afa3bd41e643855769347dca018804ae97bcb1331df796fd8921a11b333b45bebe430d323ddd151a907e8fb0e875a45d093cdb4332ec3dbd72a50341b538e058b3f25d4a528bea514b96b8e0701032d64232b7141c62f2231352f4197a1011292a4c3e900c133824e148f3703ea8374873d9097578146819e62685f1a8cbc442dd435ea603136c86ecf028df39fd10a8b3499c6' ,
55+ UPLOAD_FIRMWARE_AVRDUDE : '68ed3d9abdc7c77d01223d09c7ae55b08b8ff94f2a42d21a672effb4bdeeb12b10177e831805b3037d9f8d38e8eeeb8327b6c4691731a2a146cfd12398e5a12596e097160ae8d84fc488650ee57439f7fcd83f27d01e9834de555ceec7dc6951b3be5e5a3507752dce8e4ba1f6f9e6494162d537009db899882b9c4fca0868ad446b82fdeabf93bc30c5a39f8fe9c25e799842a10f4171e2896a0e19667b34258f06494663a4a102bcf9fd61d1ff8ebec18204bbd1a66de3e0b53e257ce521b41999dc82428539086ae9a4a5ea7112d87c05a2782cdace0e6576b162294f9ba47c658cc40999ba31be8a129689a703f6c4182055a600b6e41d450fad2896180d'
56+ } ) ;
57+
3058export default class Daemon {
3159 constructor ( boardsUrl = 'https://builder.arduino.cc/v3/boards' ) {
3260 this . BOARDS_URL = boardsUrl ;
@@ -78,6 +106,12 @@ export default class Daemon {
78106 this . downloadingError = this . downloading . pipe ( filter ( download => download . status === this . DOWNLOAD_ERROR ) )
79107 . pipe ( first ( ) )
80108 . pipe ( takeUntil ( this . downloadingDone ) ) ;
109+
110+ this . downloadingDone . subscribe ( ( ) => {
111+ this . FWUToolStatus = FWUToolStatusEnum . OK ;
112+ } ) ;
113+
114+ this . FWUToolStatus = FWUToolStatusEnum . NOPE ;
81115 }
82116
83117 notifyUploadError ( err ) {
@@ -177,4 +211,175 @@ export default class Daemon {
177211 } ) ;
178212 this . openSerialMonitor ( port , 1200 ) ;
179213 }
214+
215+ getFirmwareInfo ( boardId , port , wifiModule ) {
216+ return new Promise ( ( resolve , reject ) => {
217+ let versionsList = [ ] ;
218+ let firmwareInfoMessagesSubscription ;
219+
220+ const handleFirmwareInfoMessage = message => {
221+ switch ( message . ProgrammerStatus ) {
222+ case 'Starting' :
223+ break ;
224+ case 'Busy' :
225+ if ( message . Msg . indexOf ( 'Flashing with command:' ) >= 0 ) {
226+ return ;
227+ }
228+ const versions = JSON . parse ( message . Msg ) ;
229+ Object . keys ( versions ) . forEach ( v => {
230+ if ( versions [ v ] [ 0 ] . IsLoader ) {
231+ versionsMap [ wifiModule ] . loaderPath = versions [ v ] [ 0 ] . Path ;
232+ }
233+ else {
234+ versionsList = [ ...versionsList , ...versions [ v ] ] ;
235+ }
236+ } ) ;
237+ const latestVersion = versionsList . find ( version => version . Name === versionsMap [ wifiModule ] . latestVersion )
238+ versionsMap [ wifiModule ] . latestVersionPath = latestVersion . Path ;
239+ break ;
240+ case 'Error' :
241+ return reject ( `Couldn't get firmware info: ${ message } ` )
242+ firmwareInfoMessagesSubscription . unsubscribe ( ) ;
243+ break ;
244+ case 'Done' :
245+ firmwareInfoMessagesSubscription . unsubscribe ( ) ;
246+ return resolve ( versionsList ) ;
247+ break ;
248+ default :
249+ break ;
250+ }
251+ }
252+
253+ if ( this . FWUToolStatus !== FWUToolStatusEnum . OK ) {
254+ return reject ( `Can't get firmware info: couldn't find firmware updater tool` )
255+ }
256+
257+ firmwareInfoMessagesSubscription = this . appMessages . subscribe ( message => {
258+ if ( message . ProgrammerStatus ) {
259+ handleFirmwareInfoMessage ( message ) ;
260+ }
261+ } ) ;
262+ const data = {
263+ board : boardId ,
264+ port,
265+ commandline : `"{runtime.tools.fwupdater.path}/updater" -get_available_for {network.password}` ,
266+ signature : signaturesEnum . GET_FIRMWARE_INFO ,
267+ extra : {
268+ auth : {
269+ password : boardId
270+ }
271+ } ,
272+ filename : 'ListFirmwareVersionsInfo.bin'
273+ } ;
274+
275+ return fetch ( `${ this . pluginURL } /upload` , {
276+ method : 'POST' ,
277+ headers : {
278+ 'Content-Type' : 'text/plain; charset=utf-8'
279+ } ,
280+ body : JSON . stringify ( data )
281+ } ) . then ( response => {
282+ if ( ! response . ok ) {
283+ return reject ( `Error fetching ${ this . pluginURL } /upload` ) ;
284+ }
285+ } ) . catch ( reason => {
286+ return reject ( `Coudln't list firmware versions info.` ) ;
287+ } ) ;
288+ } )
289+ }
290+
291+ /*
292+ wifiModule can be either 'wifiNina' or 'wifi101'
293+ */
294+ updateFirmware ( boardId , port , wifiModule ) {
295+ return new Promise ( ( resolve , reject ) => {
296+ if ( ! port ) {
297+ return reject ( `Can't update Firmware: no port selected.` ) ;
298+ }
299+ this . getFirmwareInfo ( boardId , port , wifiModule ) . then ( versionsList => {
300+ if ( ! versionsMap [ wifiModule ] && ! versionsMap [ wifiModule ] . latestVersion ) {
301+ return reject ( `Can't update Firmware: couldn't find module '${ wifiModule } '` ) ;
302+ }
303+ const latestVersion = versionsList . find ( version => version . Name === versionsMap [ wifiModule ] . latestVersion ) ;
304+ if ( ! latestVersion ) {
305+ return reject ( `Can't update Firmware: couldn't find version '${ versionsMap [ wifiModule ] . latestVersion } ' for module '${ versionsMap [ wifiModule ] } '` ) ;
306+ }
307+
308+ let updateFirmwareMessagesSubscription ;
309+
310+ const handleFirmwareUpdateMessage = message => {
311+ switch ( message . ProgrammerStatus ) {
312+ case 'Error' :
313+ return reject ( `Can't update Firmware: ${ message . Msg } ` )
314+ updateFirmwareMessagesSubscription . unsubscribe ( ) ;
315+ break ;
316+ case 'Done' :
317+ return resolve ( ) ;
318+ updateFirmwareMessagesSubscription . unsubscribe ( ) ;
319+ break ;
320+ default :
321+ break ;
322+ }
323+ }
324+
325+ updateFirmwareMessagesSubscription = this . appMessages . subscribe ( message => {
326+ if ( message . ProgrammerStatus ) {
327+ handleFirmwareUpdateMessage ( message ) ;
328+ }
329+ } ) ;
330+
331+ let addresses = '' ;
332+ const rootCertificates = [ {
333+ domain : 'arduino.cc' ,
334+ port : 443
335+ } ] ;
336+
337+ rootCertificates . forEach ( address => {
338+ if ( address . domain && address . port ) {
339+ addresses += `-address ${ address . domain } :${ address . port } ` ;
340+ }
341+ } ) ;
342+
343+ const isUsingAvrdude = boardId === 'uno2018' ;
344+ const programmer = isUsingAvrdude ? '{runtime.tools.avrdude}/bin/avrdude' : '{runtime.tools.bossac}/bossac' ;
345+
346+ const loaderPath = versionsMap [ wifiModule ] . loaderPath ;
347+ if ( ! loaderPath ) {
348+ return reject ( `Can't update Firmware: invalid loaderPath` ) ;
349+ }
350+
351+ const data = {
352+ board : boardId ,
353+ port,
354+ commandline : `"{runtime.tools.fwupdater.path}/updater" -flasher {network.password} -firmware {upload.verbose} -port {serial.port} -restore_binary "{build.path}/{build.project_name}.bin" -programmer ${ programmer } ` ,
355+ hex : '' ,
356+ extra : {
357+ auth : {
358+ password : loaderPath
359+ } ,
360+ verbose : true ,
361+ params_verbose : `${ versionsMap [ wifiModule ] . latestVersionPath } ${ addresses } ` // eslint-disable-line camelcase
362+ } ,
363+ signature : isUsingAvrdude ? signaturesEnum . UPLOAD_FIRMWARE_AVRDUDE : signaturesEnum . UPLOAD_FIRMWARE_BOSSAC ,
364+ filename : 'CheckFirmwareVersion.bin'
365+ } ;
366+
367+ fetch ( `${ this . pluginURL } /upload` , {
368+ method : 'POST' ,
369+ headers : {
370+ 'Content-Type' : 'text/plain; charset=utf-8'
371+ } ,
372+ body : JSON . stringify ( data )
373+ } ) . then ( response => {
374+ if ( ! response . ok ) {
375+ return reject ( `Can't update Firmware: Error fetching ${ this . pluginURL } /upload` ) ;
376+ }
377+ } ) . catch ( reason => {
378+ return reject ( `Can't update Firmware: ${ reason } ` )
379+ } ) ;
380+ } ) . catch ( reason => {
381+ return reject ( reason )
382+ } ) ;
383+ } )
384+ }
180385}
0 commit comments