Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 36 additions & 3 deletions src/rawmode.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,16 @@

import { report } from "./utils"

let replPrompts = []

export class MpRawMode {
constructor(port) {
this.port = port
}

static async begin(port, soft_reboot=false) {
const res = new MpRawMode(port)
await res.detectPrompt()
await res.enterRawRepl(soft_reboot)
try {
await res.exec(`import sys,os`)
Expand All @@ -25,13 +28,43 @@ export class MpRawMode {
return res
}

async detectPrompt() {
const release = await this.port.startTransaction()

// >>> is the standard MicroPython prompt
// --> is the aiorepl prompt
replPrompts = ['>>> ', '--> ']

try {
await this.port.write('\r\x01') // Ctrl-A: enter raw REPL
await this.port.readUntil('raw REPL; CTRL-B to exit\r\n')
// detect what the system prompt is and add it to our list of prompts to look for
const userPrompt = `${(await this.exec('import sys; print(sys.ps1)')).trim()} `
if (!replPrompts.includes(userPrompt)) {
console.log(`Detected user prompt as ${userPrompt}`)
replPrompts.push(userPrompt)
}
await this.port.write('\x02') // Ctrl-B: exit raw REPL
await this.port.readUntil('>\r\n')
let activePrompt = await this.port.readUntil(replPrompts)
// this is a hack because in the other cases, the prompt gets printed agian, but in the
// aiorepl case, it doesn't. Not sure why at the moment so I'm doing this
if (activePrompt == '--> ') {
await this.port.write(activePrompt)
}
} finally {
release()
}
}

async interruptProgram(timeout=20000) {
const endTime = Date.now() + timeout
while (timeout <= 0 || (Date.now() < endTime)) {
await this.port.write('\x03') // Ctrl-C: interrupt any running program
try {
let banner = await this.port.readUntil('>>> ', 500)
if (this.port.prevRecvCbk && banner != '\r\n>>> ') {
let banner = await this.port.readUntil(replPrompts, 500)
let promptRegex = RegExp(`\r\n(?:${replPrompts.join('|')})`)
if (this.port.prevRecvCbk && !promptRegex.test(banner)) {
this.port.prevRecvCbk(banner)
}
await this.port.flushInput()
Expand Down Expand Up @@ -60,7 +93,7 @@ export class MpRawMode {
try {
await this.port.write('\x02') // Ctrl-B: exit raw REPL
await this.port.readUntil('>\r\n')
await this.port.readUntil('>>> ')
await this.port.readUntil(replPrompts)
} finally {
release()
}
Expand Down
21 changes: 14 additions & 7 deletions src/transports.js
Original file line number Diff line number Diff line change
Expand Up @@ -127,25 +127,32 @@ export class Transport {
throw new Error('Timeout')
}

async readUntil(ending, timeout=5000) {
async readUntil(endings, timeout=5000) {
let err_message = 'any of the ending sequences'
if (!Array.isArray(endings)) {
endings = [endings]
err_message = 'the ending sequence'
}
if (!this.inTransaction) {
throw new Error('Not in transaction')
}
let endTime = Date.now() + timeout
while (timeout <= 0 || (Date.now() < endTime)) {
const idx = this.receivedData.indexOf(ending) + ending.length
if (idx >= ending.length) {
const res = this.receivedData.substring(0, idx)
this.receivedData = this.receivedData.substring(idx)
return res
for (let ending of endings) {
const idx = this.receivedData.indexOf(ending) + ending.length
if (idx >= ending.length) {
const res = this.receivedData.substring(0, idx)
this.receivedData = this.receivedData.substring(idx)
return res
}
}
const prev_avail = this.receivedData.length
await sleep(10)
if (this.receivedData.length > prev_avail) {
endTime = Date.now() + timeout
}
}
throw new Error('Timeout reached before finding the ending sequence')
throw new Error(`Timeout reached before finding ${err_message}`)
}
}

Expand Down