Skip to content

Commit 8c1ab7a

Browse files
committed
Fix issue receiving 2 packets in quick succession, add ability to receive files
1 parent 3ee71f8 commit 8c1ab7a

File tree

1 file changed

+64
-4
lines changed

1 file changed

+64
-4
lines changed

uart.js

Lines changed: 64 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -74,11 +74,15 @@ UART.ports = ["Web Serial"]; // force only Web Serial to be used
7474
UART.debug = 3; // show all debug messages
7575
etc...
7676
77-
As of Espruino 2v25 you can also send data packets:
77+
As of Espruino 2v25 you can also send files:
7878
7979
UART.getConnection().espruinoSendFile("test.txt","This is a test of sending data to Espruino").then(_=>console.log("Done"))
8080
UART.getConnection().espruinoSendFile("test.txt","This is a test of sending data to Espruino's SD card",{fs:true}).then(_=>console.log("Done"))
8181
82+
And receive them:
83+
84+
UART.getConnection().espruinoReceiveFile("test.txt", {}).then(contents=>console.log("Received", JSON.stringify(contents)));
85+
8286
Or evaluate JS on the device and return the response as a JS object:
8387
8488
UART.getConnection().espruinoEval("1+2").then(res => console.log("=",res));
@@ -380,6 +384,12 @@ To do:
380384
on(evt,cb) { let e = "on"+evt; if (!this[e]) this[e]=[]; this[e].push(cb); }; // on only works with a single handler
381385
emit(evt,data1,data2) { let e = "on"+evt; if (this[e]) this[e].forEach(fn=>fn(data1,data2)); };
382386
removeListener(evt,callback) { let e = "on"+evt; if (this[e]) this[e]=this[e].filter(fn=>fn!=callback); };
387+
// on("open", () => ... ) connection opened
388+
// on("close", () => ... ) connection closed
389+
// on("data", (data) => ... ) when data is received (as string)
390+
// on("packet", (type,data) => ... ) when a packet is received (if .parsePackets=true)
391+
// on("ack", () => ... ) when an ACK is received (if .parsePackets=true)
392+
// on("nak", () => ... ) when an ACK is received (if .parsePackets=true)
383393
isOpen = false; // is the connection actually open?
384394
isOpening = true; // in the process of opening a connection?
385395
txInProgress = false; // is transmission in progress?
@@ -402,7 +412,7 @@ To do:
402412
let flags = (this.rxDataHandlerPacket.charCodeAt(0)<<8) | this.rxDataHandlerPacket.charCodeAt(1);
403413
let len = flags & 0x1FFF;
404414
let rxLen = this.rxDataHandlerPacket.length;
405-
if (rxLen>2 && rxLen>=(len+2)) {
415+
if (rxLen>=2 && rxLen>=(len+2)) {
406416
log(3, "Got packet end");
407417
if (this.rxDataHandlerTimeout) {
408418
clearTimeout(this.rxDataHandlerTimeout);
@@ -433,7 +443,7 @@ To do:
433443
ch = undefined;
434444
}
435445
if (ch===undefined) { // if we're supposed to remove the char, do it
436-
data = data.substring(0,i-1)+data.substring(i+1);
446+
data = data.substring(0,i)+data.substring(i+1);
437447
i--;
438448
} else
439449
this.rxDataHandlerLastCh = ch;
@@ -465,6 +475,7 @@ To do:
465475
EVENT : 0x4000, // parse as JSON and create `E.on('packet', ...)` event
466476
FILE_SEND : 0x6000, // called before DATA, with {fn:"filename",s:123}
467477
DATA : 0x8000, // Sent after FILE_SEND with blocks of data for the file
478+
FILE_RECV : 0xA000 // receive a file - returns a series of PT_TYPE_DATA packets, with a final zero length packet to end
468479
}
469480
if (!pkType in PKTYPES) throw new Error("'pkType' not one of "+Object.keys(PKTYPES));
470481
let connection = this;
@@ -504,6 +515,7 @@ To do:
504515
noACK : bool // (don't wait to acknowledgements)
505516
chunkSize : int // size of chunks to send (default 1024) for safety this depends on how big your device's input buffer is if there isn't flow control
506517
progress : (chunkNo,chunkCount)=>{} // callback to report upload progress
518+
timeout : int (optional, milliseconds, default=1000)
507519
} */
508520
espruinoSendFile(filename, data, options) {
509521
if ("string"!=typeof data) throw new Error("'data' must be a String");
@@ -539,9 +551,57 @@ To do:
539551
return connection.espruinoSendPacket("DATA", packet, packetOptions).then(sendData);
540552
}
541553
}
554+
/* Receive a file from Espruino using 2v25 packets.
555+
options = { // mainly passed to Espruino
556+
fs : true // optional -> write using require("fs") (to SD card)
557+
timeout : int // milliseconds timeout (default=1000)
558+
}
559+
} */
560+
espruinoReceiveFile(filename, options) {
561+
options = options||{};
562+
options.fn = filename;
563+
let connection = this;
564+
return new Promise((resolve,reject) => {
565+
let fileContents = "", timeout;
566+
function scheduleTimeout() {
567+
if (timeout) clearTimeout(timeout);
568+
timeout = setTimeout(() => {
569+
timeout = undefined;
570+
cleanup();
571+
reject("espruinoReceiveFile Timeout");
572+
}, options.timeout || 1000);
573+
}
574+
function cleanup() {
575+
connection.removeListener("packet", onPacket);
576+
if (timeout) {
577+
clearTimeout(timeout);
578+
timeout = undefined;
579+
}
580+
}
581+
function onPacket(type,data) {
582+
if (type!=0x8000) return; // ignore things that are not DATA packet
583+
if (data.length==0) { // 0 length packet = EOF
584+
cleanup();
585+
resolve(fileContents);
586+
} else {
587+
fileContents += data;
588+
scheduleTimeout();
589+
}
590+
}
591+
connection.parsePackets = true;
592+
connection.on("packet", onPacket);
593+
scheduleTimeout();
594+
connection.espruinoSendPacket("FILE_RECV",JSON.stringify(options)).then(()=>{
595+
// now wait...
596+
}, err => {
597+
cleanup();
598+
reject(err);
599+
});
600+
});
601+
}
542602
/* Send a JS expression to be evaluated on Espruino using using 2v25 packets.
543603
options = {
544-
timeout : int // milliseconds timeout
604+
timeout : int // milliseconds timeout (default=1000)
545605
stmFix : bool // if set, this works around an issue in Espruino STM32 2v24 and earlier where USB could get in a state where it only sent small chunks of data at a time
546606
}*/
547607
espruinoEval(expr, options) {

0 commit comments

Comments
 (0)