From 1a51b4cdb784cc6f02d5b2389a64088049250170 Mon Sep 17 00:00:00 2001 From: Ernesto Castellotti Date: Fri, 2 Jun 2023 23:51:03 +0200 Subject: rootLantiq: Fix BREAK received on FTDI using Uint8Array directly (#214) --- assets/js/rootLantiq.js | 66 ++++++++++++++++------------------ assets/js/serialUtil.js | 94 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 124 insertions(+), 36 deletions(-) diff --git a/assets/js/rootLantiq.js b/assets/js/rootLantiq.js index 317a438..e592e63 100644 --- a/assets/js/rootLantiq.js +++ b/assets/js/rootLantiq.js @@ -2,42 +2,38 @@ const LOAD_ADDR = "80800000" const IMAGE0_ADDR = "C0000 740000"; const IMAGE1_ADDR = "800000 800000"; -async function detectUboot(reader) { - while (true) { - const { value, done } = await reader.read(); - - if (value.startsWith('U-Boot')) { - return; +async function detectUboot(serial) { + await serial.readLine((line) => { + if (line.startsWith('U-Boot')) { + return true; } - } + }); } -async function waitUbootStop(writer, reader, sfpModel, outputMsgCallback) { +async function waitUbootStop(serial, sfpModel, outputMsgCallback) { + const interruptChar = String.fromCharCode(3); + const interval = setInterval(function() { - writer.write(String.fromCharCode(3)); + serial.writeString(interruptChar); }, 10); - await detectUboot(reader); + await detectUboot(serial); outputMsgCallback(`Root in progress: Trigger characters received. DO NOT TOUCH THE ${sfpModel} UNTIL THE PROCEDURE IS COMPLETED!`); await delay(5000); clearInterval(interval); } -async function checkUbootUnlocked(reader) { - while (true) { - try { - const { value, done } = await Promise.race([ - reader.read(), - new Promise((_, reject) => setTimeout(reject, 2000, new Error("timeout"))) - ]); - - if (value.startsWith('Press SPACE to delay and Ctrl-C to abort autoboot')) { - return true; - } - } catch (err) { - return false; +async function checkUbootUnlocked(serial) { + let unlocked = false; + + await serial.readLine((line) => { + if (line.startsWith('Press SPACE to delay and Ctrl-C to abort autoboot')) { + unlocked = true; + return true } - } + }, 2000); + + return unlocked; } async function waitFailbackShell(writer, reader, outputMsgCallback) { @@ -72,46 +68,44 @@ async function waitFailbackShell(writer, reader, outputMsgCallback) { } async function lantiqRootUboot(port, sfpModel, outputMsgCallback, outputErrorCallback, baudRate = 115200) { - let reader,writer, readableStreamClosed, writerStreamClosed; + const serial = new SerialReadWrite(port, baudRate); try { outputMsgCallback(`Please disconnect the ${sfpModel} from the SFP adapter if it is currently plugged in!`); - ({ reader, writer, readableStreamClosed, writerStreamClosed } = await openPortLineBreak(port, baudRate)); - await delay(10000); outputMsgCallback(`Now you need to insert the ${sfpModel} into the SFP adapter, if the procedure does not go ahead, check the connections and then remove and reconnect the ${sfpModel} again`); while(true) { - await waitUbootStop(writer, reader, sfpModel, outputMsgCallback); - const ubootUnlocked = await checkUbootUnlocked(reader); + await waitUbootStop(serial, sfpModel, outputMsgCallback); + const ubootUnlocked = await checkUbootUnlocked(serial); if (ubootUnlocked == true) { break; } outputMsgCallback("Root in progress: Set U-Boot bootdelay to 5..."); - writer.write('setenv bootdelay 5\n'); + await serial.writeString('setenv bootdelay 5\n'); await delay(1000); outputMsgCallback("Root in progress: Enable ASC serial..."); - writer.write('setenv asc0 0\n'); + await serial.writeString('setenv asc0 0\n'); await delay(1000); outputMsgCallback("Root in progress: Set GPIO to unlock serial..."); - writer.write('setenv preboot "gpio set 3;gpio input 2;gpio input 105;gpio input 106;gpio input 107;gpio input 108"\n'); + await serial.writeString('setenv preboot "gpio set 3;gpio input 2;gpio input 105;gpio input 106;gpio input 107;gpio input 108"\n'); await delay(1000); outputMsgCallback("Root in progress: Save changes..."); - writer.write('saveenv\n'); + await serial.writeString('saveenv\n'); await delay(1000); outputMsgCallback("Root in progress: Rebooting..."); - writer.write('reset\n'); + await serial.writeString('reset\n'); await delay(1000); } - await closePortLineBreak(port, reader, writer, readableStreamClosed, writerStreamClosed); return true; } catch (err) { outputErrorCallback(`Error: ${err.message}`); - await closePortLineBreak(port, reader, writer, readableStreamClosed, writerStreamClosed); return false; + } finally { + await serial.closePort(); } } diff --git a/assets/js/serialUtil.js b/assets/js/serialUtil.js index 9624619..1d58e29 100644 --- a/assets/js/serialUtil.js +++ b/assets/js/serialUtil.js @@ -19,6 +19,100 @@ class LineBreakTransformer { } } +class SerialReadWrite { + constructor(port, baudrate) { + this.port = port; + this.baudRate = baudrate; + this.isPortOpen = false; + this.textDecoder = new TextDecoder(); + this.textEncoder = new TextEncoder(); + } + + async openPort() { + await this.port.open({ baudRate: this.baudRate }); + } + + async closePort() { + await this.port.close(); + } + + async readLine(readCallback, timeout = undefined) { + let reader = undefined; + let extraChunk = ""; + + if (this.isPortOpen === false) { + await this.openPort(); + this.isPortOpen = true; + } + + while (true) { + try { + if (reader === undefined) { + reader = this.port.readable.getReader(); + } + + let serialValue; + if (timeout === undefined) { + const { value, done } = await reader.read(); + serialValue = value; + } else { + const { value, done } = await Promise.race([ + reader.read(), + new Promise((_, reject) => setTimeout(reject, timeout, new Error("timeout"))) + ]); + serialValue = value; + } + + const linesValue = this.textDecoder.decode(serialValue).split('\n'); + linesValue[0] = extraChunk + linesValue[0]; + extraChunk = linesValue[linesValue.length - 1]; + + for (const line of linesValue) { + if (readCallback(line) === true) { + return; + } + } + } catch (e) { + if (e instanceof DOMException && + (e.name === "BreakError" || e.name === "FramingError" || e.name === "ParityError")) { + console.log(e); + } else if (e instanceof Error && e.message === "timeout") { + return; + } else { + throw e; + } + } finally { + if (reader) { + reader.releaseLock(); + reader = undefined; + } + } + } + } + + async writeString(str) { + let writer = undefined; + + if (this.isPortOpen === false) { + await this.openPort(); + this.isPortOpen = true; + } + + try { + if (writer === undefined) { + writer = this.port.writable.getWriter(); + } + + writer.write(textEncoder.encode(str)); + } finally { + if (writer) { + writer.releaseLock(); + writer = undefined; + } + } + } +} + async function openPortLineBreak(port, baudRate) { await port.open({ baudRate: baudRate }); const textDecoder = new TextDecoderStream(); -- cgit v1.2.3