From ed42ac7a996ef49249b67594635d800aae7dc711 Mon Sep 17 00:00:00 2001 From: Simone <26844016+simonebortolin@users.noreply.github.com> Date: Mon, 16 Jan 2023 21:44:44 +0100 Subject: Add serial-ymodem flash web-app (#77) (#96) * add gui form ymodem * Remove LineBreakTransformer and add async * Add function to start ymodem in uboot * Add XYMini implementation * Remove delay from startYmodemLoad * update gui * Fix broken script code * Split waitUbootStop * Add changeBaudrate * Fix changeBaudrate * Add sendImageMtd * Add waitEndImageLoad * Add flashImageMtd * Implement flash firmware * fix js code Co-authored-by: Ernesto Castellotti --- assets/js/xymini.js | 147 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 assets/js/xymini.js (limited to 'assets/js/xymini.js') diff --git a/assets/js/xymini.js b/assets/js/xymini.js new file mode 100644 index 0000000..a1fd1ca --- /dev/null +++ b/assets/js/xymini.js @@ -0,0 +1,147 @@ +/* XYMini Sender - Minimal implementation of file transfer through serial + * Copyright (C) Ernesto Castellotti + * SPDX-License-Identifier: MPL-2.0-no-copyleft-exception + * + * Warning: This does not comply with XMODEM and YMODEM standards +*/ + +const STX = 0x02; +const ACK = 0x06; +const NAK = 0x15; +const EOF = 0x04; +const XYMINI_1K_MAGIC = 0x43; +const PAYLOAD_LEN = 1024; +const BLOCK_LEN = PAYLOAD_LEN + 5; +const CRC_POLY = 0x1021; + +function uint16 (n) { + return n & 0xFFFF; +} + +function updateCrc(crcIn, incr) { + const xor = uint16(crcIn >> 15); + let result = uint16(crcIn << 1); + + if (incr) { + result = uint16(result + 1); + } + + if (xor) { + result = uint16(result ^= CRC_POLY); + } + + return result; +} + +function crc16(data) { + let crc; + + for (let i = 0; i < data.length; i++) { + for (let j = 0x80; j; j >>= 1) { + crc = updateCrc(crc, data[i] & j); + } + } + + for (let n = 0; n < 16; n++) { + crc = updateCrc(crc, 0); + } + + return crc; +} + +async function detectXYMini(reader) { + const textDecoder = new TextDecoder(); + + while (true) { + const { value, done } = await reader.read(); + + if (value[0] == XYMINI_1K_MAGIC) { + console.log("XYMini: detected"); + break; + } + } +} + +function generateXYMiniBlock(blockId, payload) { + let buf = new Uint8Array(BLOCK_LEN); + let i = 0; + + buf[i++] = STX; + buf[i++] = blockId; + buf[i++] = 0xFF - blockId; + + if (payload.length > PAYLOAD_LEN) { + throw new Error("Payload too large to be transmitted in one block"); + } + + for (let j = 0; j < payload.length; j++) { + buf[i++] = payload[j]; + } + + while (i < BLOCK_LEN - 2) { + buf[i++] = 0xFF; + } + + let crcBuf = buf.slice(3, PAYLOAD_LEN + 3) + let crc = crc16(crcBuf); + + buf[i++] = (crc >> 8) & 0xFF; + buf[i++] = crc & 0xFF; + + return buf; +} + +async function sendXYMini(portReader, portWriter, data, baudRate = 115200, progressCallback) { + let blockId = 1; + let size = data.length; + let i = 0; + let nakN = 0; + let wrongCharN = 0; + + await detectXYMini(portReader); + + while(true) { + const payloadSize = Math.min(PAYLOAD_LEN, size); + + if (size) { + const payload = data.slice(i, payloadSize + i); + + const block = generateXYMiniBlock(blockId, payload); + await portWriter.write(block); + } else { + portWriter.write(new Uint8Array([EOF])); + } + + const { value, done } = await portReader.read(); + + if (value[0] == ACK) { + if (!size) { + console.log("XYMini: End of transmission"); + + return; + } + + blockId++; + size -= payloadSize; + i += payloadSize; + nakN = 0; + wrongCharN = 0; + progressCallback(data.length - size); + } else if (value[0] == NAK) { + if (nakN >= 10) { + throw new Error("Received 10 NAK, receiver is rejecting file transmission"); + } + + console.log("XYMini: NAK"); + nakN++; + } else { + if (wrongCharN >= 30) { + throw new Error("Received 30 wrong characters, the receiver is rejecting the transmission or the connection is too noisy"); + } + + console.log("XYMini: wrong character"); + console.log(value); + wrongCharN++; + } + } +} -- cgit v1.2.3