Skip to content

Commit f034b5e

Browse files
author
Stefania
authored
Merge pull request #23 from arduino/fix-provisioning
Fix provisioning
2 parents 0013208 + 7e9dcfd commit f034b5e

File tree

4 files changed

+95
-65
lines changed

4 files changed

+95
-65
lines changed

src/boardConfiguration.js

Lines changed: 68 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,11 @@
1818
*
1919
*/
2020

21-
import { BehaviorSubject } from 'rxjs';
21+
import { BehaviorSubject, timer } from 'rxjs';
2222
import { takeUntil, filter, first } from 'rxjs/operators';
2323
import { provisioningSketch } from './sketches/provisioning.ino';
2424

2525
const BAUDRATE = 9600;
26-
2726
export default class BoardConfiguration {
2827
constructor(daemon) {
2928
this.CONFIGURE_IN_PROGRESS = 'CONFIGURE_IN_PROGRESS';
@@ -34,12 +33,22 @@ export default class BoardConfiguration {
3433
this.daemon = daemon;
3534
this.serialMonitorContent = '';
3635
this.configuring = new BehaviorSubject({ status: this.CONFIGURE_NOPE });
37-
36+
this.configureDone = this.configuring.pipe(filter(configure => configure.status === this.CONFIGURE_DONE));
37+
this.configureInProgress = this.configuring.pipe(filter(configure => configure.status === this.CONFIGURE_IN_PROGRESS));
38+
this.configureError = this.configuring.pipe(filter(configure => configure.status === this.CONFIGURE_ERROR));
3839
this.daemon.serialMonitorMessages.subscribe(message => {
3940
this.serialMonitorContent += message;
4041
});
4142
}
4243

44+
initConfig() {
45+
this.configuring.next({ status: this.CONFIGURE_IN_PROGRESS, msg: 'Starting board configuration...' });
46+
}
47+
48+
notifyError(msg) {
49+
this.configuring.next({ status: this.CONFIGURE_ERROR, msg: msg, err: msg});
50+
}
51+
4352
/**
4453
* Returns the correct Provisioning sketch after adding fqbn
4554
* @param {string} fqbn
@@ -55,7 +64,6 @@ export default class BoardConfiguration {
5564
let partialMessage = '';
5665
const gettingCsr = new Promise((resolve, reject) => {
5766
const parseCsrQuestions = message => {
58-
// TODO: store partial messages
5967
partialMessage += message;
6068

6169
if (partialMessage.indexOf('No ECCX08 present') !== -1) {
@@ -72,19 +80,11 @@ export default class BoardConfiguration {
7280
}
7381
if (partialMessage.indexOf('Would you like to generate a new private key and CSR (y/N):') !== -1) {
7482
partialMessage = '';
75-
const serialData = {
76-
com_name: board.port,
77-
data: 'y\n'
78-
};
79-
this.daemon.writeSerial(board.port, serialData);
83+
this.daemon.writeSerial(board.port, 'y\n');
8084
}
8185
if (partialMessage.indexOf('Your ECCX08 is unlocked, would you like to lock it (y/N):') !== -1) {
8286
partialMessage = '';
83-
const serialData = {
84-
com_name: board.port,
85-
data: 'y\n'
86-
};
87-
this.daemon.writeSerial(board.port, serialData);
87+
this.daemon.writeSerial(board.port, 'y\n');
8888
}
8989

9090
const begin = partialMessage.indexOf('-----BEGIN CERTIFICATE REQUEST-----');
@@ -125,36 +125,13 @@ export default class BoardConfiguration {
125125
(notAfter.getUTCFullYear() - notBefore.getUTCFullYear()) + '\n' +
126126
compressedCert.serial + '\n' +
127127
compressedCert.signature + '\n';
128-
129-
const serialData = {
130-
com_name: board.port,
131-
data: answers
132-
};
133-
this.daemon.writeSerial(board.port, serialData);
128+
this.daemon.writeSerial(board.port, answers);
134129
});
135130

136131
return storing.finally(() => this.serialMessagesSubscription.unsubscribe());
137132
}
138133

139-
/**
140-
* Uploads the sketch and performs action in order to configure the board for Arduino Cloud
141-
* @param {Object} compiledSketch the Object containing the provisioning sketch, ready to be compiled
142-
* @param {Object} board contains the board data
143-
* @param {function} createDeviceCb used to create the device associated to the user
144-
*/
145-
configure(compiledSketch, board, createDeviceCb) {
146-
this.configuring.next({ status: this.CONFIGURE_IN_PROGRESS, msg: 'Starting board configuration' });
147-
if (!this.daemon.channelOpen.getValue()) {
148-
const errorMessage = `Couldn't configure board at port ${board.port} because we there is no open channel to the Arduino Create Plugin.`;
149-
this.configuring.next({
150-
status: this.CONFIGURE_ERROR,
151-
msg: errorMessage,
152-
err: 'cannot find plugin'
153-
});
154-
return;
155-
}
156-
this.serialMonitorContent = '';
157-
134+
uploadSketch(compiledSketch, board) {
158135
const uploadTarget = {
159136
board: board.fqbn,
160137
port: board.port,
@@ -172,12 +149,34 @@ export default class BoardConfiguration {
172149
signature: board.upload[0].options.signature,
173150
extrafiles: [],
174151
options: {
175-
wait_for_upload_port: (board.upload[0].options.wait_for_upload_port === true || board.upload[0].options.wait_for_upload_port === 'true'), // eslint-disable-line camelcase
176-
use_1200bps_touch: (board.upload[0].options.use_1200bps_touch === true || board.upload[0].options.use_1200bps_touch === 'true'), // eslint-disable-line camelcase
177-
params_verbose: '-v' // eslint-disable-line camelcase
152+
wait_for_upload_port: (board.upload[0].options.wait_for_upload_port === true || board.upload[0].options.wait_for_upload_port === 'true'),
153+
use_1200bps_touch: (board.upload[0].options.use_1200bps_touch === true || board.upload[0].options.use_1200bps_touch === 'true'),
154+
params_verbose: '-v'
178155
}
179156
};
180157

158+
this.daemon.upload(uploadTarget, uploadData);
159+
}
160+
161+
/**
162+
* Uploads the sketch and performs action in order to configure the board for Arduino Cloud
163+
* @param {Object} compiledSketch the Object containing the provisioning sketch, ready to be compiled
164+
* @param {Object} board contains the board data
165+
* @param {function} createDeviceCb used to create the device associated to the user
166+
*/
167+
configure(compiledSketch, board, createDeviceCb) {
168+
this.configuring.next({ status: this.CONFIGURE_IN_PROGRESS, msg: 'Uploading provisioning sketch...' });
169+
if (!this.daemon.channelOpen.getValue()) {
170+
const errorMessage = `Couldn't configure board at port ${board.port} because we there is no open channel to the Arduino Create Plugin.`;
171+
this.configuring.next({
172+
status: this.CONFIGURE_ERROR,
173+
msg: errorMessage,
174+
err: 'cannot find plugin'
175+
});
176+
return;
177+
}
178+
this.serialMonitorContent = '';
179+
181180
// check the uploading status:
182181
if (this.daemon.uploading.getValue().status === this.daemon.UPLOAD_IN_PROGRESS) {
183182
// if there is an upload in course, notify observers;
@@ -190,32 +189,53 @@ export default class BoardConfiguration {
190189
}
191190

192191
this.daemon.uploadingDone.pipe(first()).subscribe(() => {
192+
this.configuring.next({
193+
status: this.CONFIGURE_IN_PROGRESS,
194+
msg: 'Provisioning sketch uploaded successfully. Opening serial monitor...'
195+
});
193196
this.daemon.serialMonitorOpened.pipe(takeUntil(this.daemon.serialMonitorOpened.pipe(filter(open => open))))
194197
.subscribe(() => {
198+
this.configuring.next({
199+
status: this.CONFIGURE_IN_PROGRESS,
200+
msg: 'Serial monitor opened. Generating CSR...'
201+
});
195202
this.getCsr(board)
196-
.then(csr => createDeviceCb(csr))
197-
.then(data => this.storeCertificate(data.compressed))
203+
.then(csr => {
204+
this.configuring.next({
205+
status: this.CONFIGURE_IN_PROGRESS,
206+
msg: 'CSR generated. Creating device...'
207+
});
208+
return createDeviceCb(csr)
209+
})
210+
.then(data => {
211+
this.configuring.next({
212+
status: this.CONFIGURE_IN_PROGRESS,
213+
msg: 'Device created. Storing certificate...'
214+
});
215+
return this.storeCertificate(data.compressed, board);
216+
})
198217
.then(() => this.configuring.next({ status: this.CONFIGURE_DONE }))
199218
.catch(reason => this.configuring.next({
200219
status: this.CONFIGURE_ERROR,
201-
msg: `Couldn't configure board at port ${board.port}. Configuration failed with error: ${reason}`,
220+
msg: `Couldn't configure board at port ${board.port}. Configuration failed with error: ${reason.message}`,
202221
err: reason.toString()
203222
}))
204223
.finally(() => this.daemon.closeSerialMonitor(board.port, BAUDRATE));
205224
}, error => {
206225
this.configuring.next({
207226
status: this.CONFIGURE_ERROR,
208-
msg: `Couldn't configure board at port ${board.port}. Configuration failed with error: ${error}`,
227+
msg: `Couldn't configure board at port ${board.port}. Configuration failed with error: ${error.message}`,
209228
err: error.toString()
210229
});
211230
});
212-
this.daemon.openSerialMonitor(board.port, BAUDRATE);
231+
this.daemon.openSerialMonitor(board.port, BAUDRATE);
213232
});
214233

215234
this.daemon.uploadingError.pipe(first()).subscribe(upload => {
216235
this.configuring.next({ status: this.CONFIGURE_ERROR, err: `Couldn't configure board at port ${board.port}. Upload failed with error: ${upload.err}` });
217236
});
218237

219-
this.daemon.upload(uploadTarget, uploadData);
238+
this.daemon.initUpload();
239+
this.uploadSketch(compiledSketch, board);
220240
}
221241
}

src/daemon.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,4 +113,8 @@ export default class Daemon {
113113
}
114114
throw new Error('Stop Upload not supported on Chrome OS');
115115
}
116+
117+
initUpload() {
118+
this.uploading.next({ status: this.UPLOAD_NOPE });
119+
}
116120
}

src/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,5 +25,5 @@ import BoardConfiguration from './boardConfiguration';
2525

2626
const Daemon = window.navigator.userAgent.indexOf(' CrOS ') !== -1 ? ChromeOsDaemon : SocketDaemon;
2727

28-
export { BoardConfiguration };
28+
export { Daemon, BoardConfiguration };
2929
export default Daemon;

src/socket-daemon.js

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,15 @@ import semVerCompare from 'semver-compare';
2323
import { detect } from 'detect-browser';
2424

2525
import { BehaviorSubject, timer } from 'rxjs';
26-
import { filter, takeUntil } from 'rxjs/operators';
26+
import { filter, takeUntil, first } from 'rxjs/operators';
2727

2828
import Daemon from './daemon';
2929

3030
// Required agent version
3131
const MIN_VERSION = '1.1.71';
3232
const browser = detect();
3333
const POLLING_INTERVAL = 2500;
34+
const UPLOAD_DONE_TIMER = 5000;
3435

3536
const PROTOCOL = {
3637
HTTP: 'http',
@@ -312,7 +313,7 @@ export default class SocketDaemon extends Daemon {
312313
}
313314
const serialPort = this.devicesList.getValue().serial.find(p => p.Name === port);
314315
if (!serialPort) {
315-
return this.serialMonitorOpened.error(new Error(`Can't find port ${port}`));
316+
return this.serialMonitorOpened.error(new Error(`Can't find board at ${port}`));
316317
}
317318
this.appMessages
318319
.pipe(takeUntil(this.serialMonitorOpened.pipe(filter(open => !open))))
@@ -321,7 +322,7 @@ export default class SocketDaemon extends Daemon {
321322
this.serialMonitorOpened.next(false);
322323
}
323324
if (message.Cmd === 'CloseFail') {
324-
this.serialMonitorOpened.error(new Error(`Failed to close serial ${port}`));
325+
this.serialMonitorOpened.error(new Error(`Failed to close serial monitor at ${port}`));
325326
}
326327
});
327328
this.socket.emit('command', `close ${port}`);
@@ -332,8 +333,8 @@ export default class SocketDaemon extends Daemon {
332333
return;
333334
}
334335
if (message.Flash === 'Ok' && message.ProgrammerStatus === 'Done') {
335-
this.uploading.next({ status: this.UPLOAD_DONE, msg: message.Flash });
336-
return;
336+
// After the upload is completed the port goes down for a while, so we have to wait a few seconds
337+
return timer(UPLOAD_DONE_TIMER).subscribe(() => this.uploading.next({ status: this.UPLOAD_DONE, msg: message.Flash }));
337338
}
338339
switch (message.ProgrammerStatus) {
339340
case 'Starting':
@@ -439,17 +440,22 @@ export default class SocketDaemon extends Daemon {
439440
payload.extrafiles.push({ filename: data.files[i].name, hex: data.files[i].data });
440441
}
441442

442-
fetch(`${this.pluginURL}/upload`, {
443-
method: 'POST',
444-
headers: {
445-
'Content-Type': 'text/plain; charset=utf-8'
446-
},
447-
body: JSON.stringify(payload)
448-
})
449-
.catch(error => {
450-
this.uploading.next({ status: this.UPLOAD_ERROR, err: error });
451-
});
452-
}
443+
this.serialMonitorOpened.pipe(filter(open => !open))
444+
.pipe(first())
445+
.subscribe(() => {
446+
447+
fetch(`${this.pluginURL}/upload`, {
448+
method: 'POST',
449+
headers: {
450+
'Content-Type': 'text/plain; charset=utf-8'
451+
},
452+
body: JSON.stringify(payload)
453+
})
454+
.catch(error => {
455+
this.uploading.next({ status: this.UPLOAD_ERROR, err: error });
456+
});
457+
})
458+
}
453459

454460
/**
455461
* Download tool

0 commit comments

Comments
 (0)