Add serial support
This commit is contained in:
parent
e8d8222d86
commit
5af3cc4345
11
aux/build.sh
11
aux/build.sh
@ -3,8 +3,15 @@
|
|||||||
LEGO=$HOME/src/lego/lms2012
|
LEGO=$HOME/src/lego/lms2012
|
||||||
P="`pwd`"
|
P="`pwd`"
|
||||||
F="$P"/pxt
|
F="$P"/pxt
|
||||||
set -xe
|
set -e
|
||||||
cd $LEGO/lmssrc/adk/lmsasm
|
cd $LEGO/lmssrc/adk/lmsasm
|
||||||
|
echo "Compiling..."
|
||||||
java -jar assembler.jar $F
|
java -jar assembler.jar $F
|
||||||
cd "$P"
|
cd "$P"
|
||||||
node -p 'require("fs").readFileSync("pxt.rbf").toString("hex").replace(/5858585858(58)+/, "XX")'
|
echo "Hex to paste:"
|
||||||
|
echo
|
||||||
|
echo "const rbfTemplate = \`"
|
||||||
|
node -p 'require("fs").readFileSync("pxt.rbf").toString("hex").replace(/5858585858(58)+/, "XX").replace(/.{1,80}/g, f => f + "\n").trim()'
|
||||||
|
echo "\`"
|
||||||
|
echo
|
||||||
|
rm -f pxt.rbf
|
||||||
|
@ -4,12 +4,15 @@ vmthread MAIN
|
|||||||
DATA8 State
|
DATA8 State
|
||||||
DATA32 Status
|
DATA32 Status
|
||||||
//DATA32 Timer
|
//DATA32 Timer
|
||||||
|
DATA16 Serial
|
||||||
|
|
||||||
UI_WRITE(LED,LED_RED)
|
UI_WRITE(LED,LED_RED)
|
||||||
UI_DRAW(TEXT,FG_COLOR,48,62,'Starting...')
|
UI_DRAW(TEXT,FG_COLOR,48,62,'Starting...')
|
||||||
UI_DRAW(UPDATE)
|
UI_DRAW(UPDATE)
|
||||||
|
// Make sure VM knows that /tmp/serial.txt is open for writing and can stream the content
|
||||||
|
FILE(OPEN_WRITE, '/tmp/serial.txt', Serial)
|
||||||
|
// Actual filename is patched-in here
|
||||||
SYSTEM('XXXXXXXXX', Status)
|
SYSTEM('XXXXXXXXX', Status)
|
||||||
//SYSTEM('../prjs/BrkProg_SAVE/binary.elf', Status)
|
|
||||||
Loop:
|
Loop:
|
||||||
UI_BUTTON(WAIT_FOR_PRESS)
|
UI_BUTTON(WAIT_FOR_PRESS)
|
||||||
UI_BUTTON(SHORTPRESS,BACK_BUTTON,State)
|
UI_BUTTON(SHORTPRESS,BACK_BUTTON,State)
|
||||||
|
BIN
aux/pxt.rbf
BIN
aux/pxt.rbf
Binary file not shown.
@ -8,7 +8,11 @@ eval("if (typeof process === 'object' && process + '' === '[object process]') px
|
|||||||
|
|
||||||
namespace pxt.editor {
|
namespace pxt.editor {
|
||||||
// this comes from aux/pxt.lms
|
// this comes from aux/pxt.lms
|
||||||
const rbfTemplate = "4c45474f5d0000006d000100000000001c0000000000000008000000821b028405018130813e805374617274696e672e2e2e0084006080XX0044830383010640414082f5ff8405018130813e80427965210084000a";
|
const rbfTemplate = `
|
||||||
|
4c45474f710000006d000100000000001c000000000000000a000000821b028405018130813e8053
|
||||||
|
74617274696e672e2e2e008400c002802f746d702f73657269616c2e74787400486080XX00448303
|
||||||
|
83010640414082f5ff8405018130813e80427965210084000a
|
||||||
|
`
|
||||||
|
|
||||||
function hf2Async() {
|
function hf2Async() {
|
||||||
return pxt.HF2.mkPacketIOAsync()
|
return pxt.HF2.mkPacketIOAsync()
|
||||||
@ -44,7 +48,9 @@ namespace pxt.editor {
|
|||||||
let f = U.stringToUint8Array(atob(resp.outfiles[pxt.outputName()]))
|
let f = U.stringToUint8Array(atob(resp.outfiles[pxt.outputName()]))
|
||||||
return w.flashAsync(elfPath, f)
|
return w.flashAsync(elfPath, f)
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
let rbfHex = rbfTemplate.replace("XX", U.toHex(U.stringToUint8Array(elfPath)))
|
let rbfHex = rbfTemplate
|
||||||
|
.replace(/\s+/g, "")
|
||||||
|
.replace("XX", U.toHex(U.stringToUint8Array(elfPath)))
|
||||||
let rbf = U.fromHex(rbfHex)
|
let rbf = U.fromHex(rbfHex)
|
||||||
HF2.write16(rbf, 4, rbf.length)
|
HF2.write16(rbf, 4, rbf.length)
|
||||||
return w.flashAsync(rbfPath, rbf)
|
return w.flashAsync(rbfPath, rbf)
|
||||||
@ -59,10 +65,19 @@ namespace pxt.editor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
initExtensionsAsync = function (opts: pxt.editor.ExtensionOptions): Promise<pxt.editor.ExtensionResult> {
|
initExtensionsAsync = function (opts: pxt.editor.ExtensionOptions): Promise<pxt.editor.ExtensionResult> {
|
||||||
pxt.debug('loading pxt-adafruit target extensions...')
|
pxt.debug('loading pxt-ev3 target extensions...')
|
||||||
const res: pxt.editor.ExtensionResult = {
|
const res: pxt.editor.ExtensionResult = {
|
||||||
deployCoreAsync,
|
deployCoreAsync,
|
||||||
};
|
};
|
||||||
|
initAsync()
|
||||||
|
.then(w => w.streamFileAsync("/tmp/serial.txt", buf => {
|
||||||
|
let str = Util.fromUTF8(Util.uint8ArrayToString(buf))
|
||||||
|
window.postMessage({
|
||||||
|
type: 'serial',
|
||||||
|
id: 'n/a', // TODO
|
||||||
|
data: str
|
||||||
|
}, "*")
|
||||||
|
}))
|
||||||
return Promise.resolve<pxt.editor.ExtensionResult>(res);
|
return Promise.resolve<pxt.editor.ExtensionResult>(res);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,11 +17,12 @@ namespace pxt.editor {
|
|||||||
export class Ev3Wrapper {
|
export class Ev3Wrapper {
|
||||||
msgs = new U.PromiseBuffer<Uint8Array>()
|
msgs = new U.PromiseBuffer<Uint8Array>()
|
||||||
private cmdSeq = U.randomUint32() & 0xffff;
|
private cmdSeq = U.randomUint32() & 0xffff;
|
||||||
|
private lock = new U.PromiseQueue();
|
||||||
|
|
||||||
constructor(public io: pxt.HF2.PacketIO) {
|
constructor(public io: pxt.HF2.PacketIO) {
|
||||||
io.onData = buf => {
|
io.onData = buf => {
|
||||||
buf = buf.slice(0, HF2.read16(buf, 0) + 2)
|
buf = buf.slice(0, HF2.read16(buf, 0) + 2)
|
||||||
// log("DATA: " + U.toHex(buf))
|
//log("DATA: " + U.toHex(buf))
|
||||||
this.msgs.push(buf)
|
this.msgs.push(buf)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -53,27 +54,27 @@ namespace pxt.editor {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
talkAsync(buf: Uint8Array) {
|
talkAsync(buf: Uint8Array, altResponse = 0) {
|
||||||
return this.io.sendPacketAsync(buf)
|
return this.lock.enqueue("talk", () =>
|
||||||
.then(() => this.msgs.shiftAsync(1000))
|
this.io.sendPacketAsync(buf)
|
||||||
.then(resp => {
|
.then(() => this.msgs.shiftAsync(1000))
|
||||||
if (resp[2] != buf[2] || resp[3] != buf[3])
|
.then(resp => {
|
||||||
U.userError("msg count de-sync")
|
if (resp[2] != buf[2] || resp[3] != buf[3])
|
||||||
if (buf[4] == 1) {
|
U.userError("msg count de-sync")
|
||||||
if (resp[5] != buf[5])
|
if (buf[4] == 1) {
|
||||||
U.userError("cmd de-sync")
|
if (resp[5] != buf[5])
|
||||||
if (resp[6] != 0 && resp[6] != 1 /* LS? */ && resp[6] != 8 /* EOF */)
|
U.userError("cmd de-sync")
|
||||||
U.userError("cmd error: " + resp[6])
|
if (altResponse != -1 && resp[6] != 0 && resp[6] != altResponse)
|
||||||
}
|
U.userError("cmd error: " + resp[6])
|
||||||
return resp
|
}
|
||||||
})
|
return resp
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
flashAsync(path: string, file: Uint8Array) {
|
flashAsync(path: string, file: Uint8Array) {
|
||||||
log(`write ${file.length} to ${path}`)
|
log(`write ${file.length} to ${path}`)
|
||||||
let begin = this.allocSystem(4 + path.length + 1, 0x92)
|
|
||||||
HF2.write32(begin, 6, file.length) // fileSize
|
let handle = -1
|
||||||
U.memcpy(begin, 10, U.stringToUint8Array(path))
|
|
||||||
|
|
||||||
let loopAsync = (pos: number): Promise<void> => {
|
let loopAsync = (pos: number): Promise<void> => {
|
||||||
if (pos >= file.length) return Promise.resolve()
|
if (pos >= file.length) return Promise.resolve()
|
||||||
@ -82,11 +83,13 @@ namespace pxt.editor {
|
|||||||
let upl = this.allocSystem(1 + size, 0x93, 0x1)
|
let upl = this.allocSystem(1 + size, 0x93, 0x1)
|
||||||
upl[6] = handle
|
upl[6] = handle
|
||||||
U.memcpy(upl, 6 + 1, file, pos, size)
|
U.memcpy(upl, 6 + 1, file, pos, size)
|
||||||
return this.talkAsync(upl)
|
return this.talkAsync(upl, 8) // 8=EOF
|
||||||
.then(() => loopAsync(pos + size))
|
.then(() => loopAsync(pos + size))
|
||||||
}
|
}
|
||||||
|
|
||||||
let handle = -1
|
let begin = this.allocSystem(4 + path.length + 1, 0x92)
|
||||||
|
HF2.write32(begin, 6, file.length) // fileSize
|
||||||
|
U.memcpy(begin, 10, U.stringToUint8Array(path))
|
||||||
return this.talkAsync(begin)
|
return this.talkAsync(begin)
|
||||||
.then(resp => {
|
.then(resp => {
|
||||||
handle = resp[7]
|
handle = resp[7]
|
||||||
@ -99,7 +102,7 @@ namespace pxt.editor {
|
|||||||
HF2.write16(lsReq, 6, 1024) // maxRead
|
HF2.write16(lsReq, 6, 1024) // maxRead
|
||||||
U.memcpy(lsReq, 8, U.stringToUint8Array(path))
|
U.memcpy(lsReq, 8, U.stringToUint8Array(path))
|
||||||
|
|
||||||
return this.talkAsync(lsReq)
|
return this.talkAsync(lsReq, 8)
|
||||||
.then(resp =>
|
.then(resp =>
|
||||||
U.uint8ArrayToString(resp.slice(12)).split(/\n/).map(s => {
|
U.uint8ArrayToString(resp.slice(12)).split(/\n/).map(s => {
|
||||||
if (!s) return null as DirEntry
|
if (!s) return null as DirEntry
|
||||||
@ -118,6 +121,7 @@ namespace pxt.editor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
rmAsync(path: string): Promise<void> {
|
rmAsync(path: string): Promise<void> {
|
||||||
|
log(`rm ${path}`)
|
||||||
let rmReq = this.allocSystem(path.length + 1, 0x9c)
|
let rmReq = this.allocSystem(path.length + 1, 0x9c)
|
||||||
U.memcpy(rmReq, 6, U.stringToUint8Array(path))
|
U.memcpy(rmReq, 6, U.stringToUint8Array(path))
|
||||||
|
|
||||||
@ -125,6 +129,47 @@ namespace pxt.editor {
|
|||||||
.then(resp => { })
|
.then(resp => { })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
streamFileAsync(path: string, cb: (d: Uint8Array) => void) {
|
||||||
|
let fileSize = 0
|
||||||
|
let filePtr = 0
|
||||||
|
let handle = -1
|
||||||
|
let restart = () => Promise.delay(500).then(() => this.streamFileAsync(path, cb))
|
||||||
|
let resp = (buf: Uint8Array): Promise<void> => {
|
||||||
|
if (buf[6] == 2) {
|
||||||
|
// handle not ready - file is missing
|
||||||
|
return restart()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buf[6] != 0 && buf[6] != 8)
|
||||||
|
U.userError("bad response when streaming file: " + buf[6])
|
||||||
|
|
||||||
|
fileSize = HF2.read32(buf, 7)
|
||||||
|
if (handle == -1)
|
||||||
|
handle = buf[11]
|
||||||
|
let data = buf.slice(12)
|
||||||
|
filePtr += data.length
|
||||||
|
if (data.length > 0)
|
||||||
|
cb(data)
|
||||||
|
|
||||||
|
if (buf[6] == 8) {
|
||||||
|
// end of file
|
||||||
|
return this.rmAsync(path).then(restart)
|
||||||
|
}
|
||||||
|
|
||||||
|
let contFileReq = this.allocSystem(1 + 2, 0x97)
|
||||||
|
HF2.write16(contFileReq, 7, 1000) // maxRead
|
||||||
|
contFileReq[6] = handle
|
||||||
|
return Promise.delay(data.length > 0 ? 0 : 500)
|
||||||
|
.then(() => this.talkAsync(contFileReq, -1))
|
||||||
|
.then(resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
let getFileReq = this.allocSystem(2 + path.length + 1, 0x96)
|
||||||
|
HF2.write16(getFileReq, 6, 1000) // maxRead
|
||||||
|
U.memcpy(getFileReq, 8, U.stringToUint8Array(path))
|
||||||
|
return this.talkAsync(getFileReq, -1).then(resp)
|
||||||
|
}
|
||||||
|
|
||||||
private initAsync() {
|
private initAsync() {
|
||||||
return Promise.resolve()
|
return Promise.resolve()
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user