tanakamasayuki / WebSerialEsptool

esptool using the Web Serial API
Creative Commons Zero v1.0 Universal
4 stars 1 forks source link

Nice work. Like to change your esptool.js to a Nodejs class. #1

Open nielsnl68 opened 3 years ago

nielsnl68 commented 3 years ago

Hi,

Nice work. Like to change your esptool.js to a Nodejs class.

Do you care to help out a little bit, when needed?

tanakamasayuki commented 3 years ago

I'm sorry. I've never used Nodejs.

nielsnl68 commented 3 years ago

I was just searching for a solution like this myself and luckily i found your everts on creating this example.

Not sure of you know, Node JS is a standalone Javascript interpreter like Java and PHP etc.

With Nodejs i use https://serialport.io/ to communicate with the serial port. When we can somehow modify the above functions to allow to use navigator.serial or an external serial port class like the one from serialport.io this lib will get a lot of attention, I think.

As it seems most of your code can be untouched only the following functions need a change:

BTW. do you know that espUploadBaudrate in espConnect is not used yet? Or did i missed something while searching? msCode shown it as well, by making the value gray.

Also, what is the different use case of espSelectPort from what is see espConnect those the same and more.

tanakamasayuki commented 3 years ago

At first, you need to connect with 115200. After that, you can change it with espChangeBaudrate.

nielsnl68 commented 3 years ago

Yes, thats what i seeing, indeed in the espConnect() method. Only from what i can tell you use only the default values not the value that you put in the espUploadBaudrate variable.

tanakamasayuki commented 3 years ago

It was... I no longer need it.

This is an experimental program. It does not support compressed transfer. It doesn't work on Chromebooks (ARM).

This project is dedicated to Pure JavaScript. I would like to see it launched as another project.

nielsnl68 commented 3 years ago

Little off-topic, maybe you can help or it is also use full for you.

i'm playing around with the Serial API as you have implemented it.

One issue i found with my own code is that when you have the timeout canceling the read. it will not read again later. Although that's what i'm seeing. Did you saw that as well? when so, did you find a solution for that? What i'm trying to do is before i start flushing the existing read buffer to prevent false data while reading results from requested data.

I made the following code based on your code, and changed your function espSelectPort() so it returns the espPort value now.

 let espPort;

    async function nowTalkSend(packet) {
        if (typeof packet === "string") {
            packet = new TextEncoder("utf-8").encode(packet);
        }
        const espWriter = espPort.writable.getWriter();
        console.log("Send", packet);
        await espWriter.write(packet);
        espWriter.releaseLock();

        // Wait
        await new Promise(resolve => setTimeout(resolve, 100));
    }

    async function nowTalkTimeout(espReader) {

        if (espReader) {
            console.info("timeout", espReader);
            espReader.cancel("cancel at Timeout");
        }
    }

    async function nowTalkReceive(timeOut = 200) {
        let espReader = espPort.readable.getReader();
        let timer = setTimeout(nowTalkTimeout, timeOut, espReader);
        let result = "";
        console.warn(espReader);
        showlog("start reading");
        try {
            while (true) {
                const { value, done } = await espReader.read();
                if (done) {
                    showlog("done");
                    break;
                }
                result += new TextDecoder().decode(value);
            }
        } finally {
            clearTimeout(timer);
            espReader.cancel("cancel at done");
            await espReader.releaseLock();
            espReader = null;
        }
        return result;
    }

    $("#btnConnect").on('click', writeBtn);
    async function writeBtn() {
        espSetOutput(showlog);
        try {
            espPort = await espSelectPort();
            await nowTalkReceive(); // this breaks future read attempts.
            nowTalkSend("###info~" + config.bridge.mac + "\n");
            let value = await nowTalkReceive();
            showlog(value);
            if (value) {
                value = value.split("~");
                showlog(value);
            }
        } catch (error) {
            showlog(error);
        } finally {
            await espDisconnect(true);
        }

    };
tanakamasayuki commented 3 years ago

https://github.com/adafruit/Adafruit_WebSerial_ESPTool/blob/main/js/script.js https://github.com/sohtamei/scratch-vm/blob/develop/src/extensions/scratch3_tukurutch/comlib.js

Here is another sample.

Error handling is an issue for the future.

nielsnl68 commented 3 years ago

I like the way Ada did there read handling. it is very clean and understandable. That other one is way to complicated and suffers, i think, from the same issue ... that after calling read.cancel() no new read attempts are working. but i could be wrong about that, i only did some code read.

What are you going to do? Are you going to use AdaFruits version, or (and i hope you do) go ahead with your version? I love the idea to have a sperate script for interacting and gui control as you have set it up. Maybe you (we) can use parts of adafruits code to enhance this one?

tanakamasayuki commented 3 years ago

Adafruit is a port from Python code. It is not JavaScript style.

The other is an extension of scratch3. scratch3 seems to be a style that doesn't use await.

Mine is in the original code to make it a clean license. I am working on a base code that will be easy to port.

nielsnl68 commented 3 years ago

Cool, sorry for the late reply. Been working on an other project, to read a Blood Glucose Meter with the web-serial.

And i learning a lot on how it works. There are still some parts i need to figure out. But mostly i have it now under control. It is a whole different way of thinking, but coming from nodejs's serialport lib it is not that different.

I love to see what you will cook together and i'm sure i will use it in my other project.

here is a snapshot of what i have now:


let serialString = "";
let port = null;

async function connect() {
    // - Request a port and open a connection.
    if (port === null) {
        port = await navigator.serial.requestPort();
    }
    // - Wait for the port to open.toggleUIConnected
    if (getChromeVersion() < 86) {
        await port.open({ baudrate: 9600 });
    } else {
        await port.open({ baudRate: 9600 });
    }

    // await new Promise(resolve => setTimeout(resolve, 1000));
}

/**
 * @name disconnect
 * Closes the Web Serial connection.
 */
async function disconnect() {
    if (!port) return;
    try {
        if (port.readable && port.readable.locked) {
            await port.readable.cancel();
        }

        if (port.writable && port.writable.locked) {
            // this will not happen, in normal case. 
            // because after writing the output stream is already closed
            await port.writable.close();
        }

        if (port) {
            await port.close();
            port = null;
        }
    } finally {
        reader = null;
    }
}

/**
 * @name writeToStream
 * Gets a writer from the output stream and send the raw data over WebSerial.
 */
async function writeToStream(data) {
    const writer = port.writable.getWriter();
    await writer.write(new Uint8Array(data));
    writer.releaseLock();
}

/**
 * @name readLoop
 * Reads data from the input stream and places it in the inputBuffer
 */
async function readLine() {
    let reader = port.readable.getReader();
    let line = "";
    while (true) {
        let { value, done } = await reader.read();
        if (done) {
            reader.releaseLock();
            return line;
        }
        if (value.length === 0) continue;
        value = Array.from(value);

        value.forEach(byte => {

            if (byte === LF) {
                reader.releaseLock();
                return line;
            } else {
                line += String.fromCharCode(byte); //< this is not good practice it will not handle none chars very well.
            }
        });
    }
}
tanakamasayuki commented 3 years ago

It's a beautiful code!