Coder Social home page Coder Social logo

Comments (5)

sbc100 avatar sbc100 commented on May 30, 2024

Can you add a console.log to the end of write_data function and just before the call the emscripten_sleep to confirm that write_data doesn't return to the caller until after the last of the 3 await statements?

I imagine what is happening here is that the webserial API requires you to return to event loop in order to do what i needs to do. emscripten_sleep is just one way to return to the event loop. You could also try using emscripten_set_main_loop.

BTW is this code running in on the main browser thread? If so I guess you have to be returning to the event loops anyway.

As always, could you share the full set of link flags you are using?

from emscripten.

koen1711 avatar koen1711 commented on May 30, 2024

Thank you for your reply!

First I'll give some more context, I am porting avrdude to webassembly, and yes it runs on the main browser thread, but I get the same results using pthread.

Here are my flags for with pthread:

-- CMAKE_CXX_FLAGS: -fPIC -s ALLOW_BLOCKING_ON_MAIN_THREAD -s PROXY_TO_PTHREAD -s EXPORT_NAME=avrdude -pthread -s ASYNCIFY_IMPORTS=['serialPortWrite','serialPortRecv'] -s ERROR_ON_UNDEFINED_SYMBOLS=0 -s MAIN_MODULE -s WASM=1 -s FORCE_FILESYSTEM -s ASYNCIFY=1 -s INVOKE_RUN=0 -s WASM_BIGINT=1 -s MODULARIZE=1 -s EXPORT_KEEPALIVE=1 --bind -s "EXPORTED_FUNCTIONS=['_startAvrdude','_main','_malloc']" -s EXPORTED_RUNTIME_METHODS='["cwrap", "writeStringToMemory", "FS", "allocate", "intArrayFromString"]'

And without:

-- CMAKE_CXX_FLAGS: -fPIC -s ASYNCIFY_IMPORTS=['serialPortWrite','serialPortRecv'] -s ERROR_ON_UNDEFINED_SYMBOLS=0 -s MAIN_MODULE -s WASM=1 -s FORCE_FILESYSTEM -s ASYNCIFY=1 -s INVOKE_RUN=0 -s WASM_BIGINT=1 -s MODULARIZE=1 -s EXPORT_KEEPALIVE=1 --bind -s "EXPORTED_FUNCTIONS=['_startAvrdude','_main','_malloc']" -s EXPORTED_RUNTIME_METHODS='["cwrap", "writeStringToMemory", "FS", "allocate", "intArrayFromString"]'

My first thought was also that the write_data function was completed later or something but it is not sadly. But here is the updated code and respective output just to make sure.

EM_ASYNC_JS(void, write_data, (EM_VAL data), {
    data = new Uint8Array(Emval.toValue(data));
    console.log("Sending: ", data);
    const port = window.activePort;
    await window.writeStream.ready;
    await window.writeStream.write(data);
    await window.writeStream.ready;
    console.log("Data sent");
});

void serialPortWrite(const unsigned char *buf, size_t len) {
    std::vector<unsigned char> data(buf, buf + len);
    write_data(val(typed_memory_view(data.size(), data.data())).as_handle());
    printf("Data sent from C\n");
    emscripten_sleep(0);
}

Output:
Sending: Uint8Array(2) [48, 32, buffer: ArrayBuffer(2), byteLength: 2, byteOffset: 0, length: 2, Symbol(Symbol.toStringTag): 'Uint8Array'] avrdude.js:8 Data sent avrdude.js:8 Data sent from C

from emscripten.

sbc100 avatar sbc100 commented on May 30, 2024

What is your program doing right after the serialPortWrite? Assuming its sitting the event loop then I don't see who emscripten_sleep can be helping since all it does is return to the event loop anyway.

from emscripten.

koen1711 avatar koen1711 commented on May 30, 2024

It runs some more webassembly code it sends the 48,32 packet three times to my arduino. When it is done with those operations it will read the return data of the arduino.

EM_ASYNC_JS(void, read_data, (int timeoutMs), {
    const reader = window.activePort.readable.getReader();
    console.log("Reading data");
    async function receive() {
        const { value } = await reader.read();
        return value;
    }

    async function timeout(timeoutMs) {
        await new Promise(resolve => setTimeout(resolve, timeoutMs));
        return "timeout";
    }

    var returnBuffer = new Uint8Array();
    while (true) {
        let result = await Promise.race([receive(), timeout(timeoutMs)]);

        if (result instanceof Uint8Array) {
            // check if it is twice the same data so check if the first half is the same as the second half if so remove the second half
            let firstHalf = result.slice(0, result.length / 2);
            let secondHalf = result.slice(result.length / 2, result.length);
            if (firstHalf.every((value, index) => value === secondHalf[index])) {
                result = firstHalf;
            }

            console.log("Received: ", result);
            const ptr = window.funcs._malloc(result.length * Uint8Array.BYTES_PER_ELEMENT);
            window.funcs.HEAPU8.set(result, ptr);

            // Call the C++ function with the pointer and the length of the array
            window.funcs._dataCallback(ptr, result.length);
            break;
        } else {
            console.log("Timeout", result);
            break;
        }
    }
    reader.releaseLock();
    return;
});


int serialPortRecv(unsigned char *buf, size_t len, int timeoutMs) {
    std::vector<unsigned char> data = {};
    data.reserve(len);
    // check if there is leftover data from previous reads
    if (!readBuffer.empty()) {
        if (readBuffer.size() >= len) {
            data = std::vector<unsigned char>(readBuffer.begin(), readBuffer.begin() + len);
            readBuffer.erase(readBuffer.begin(), readBuffer.begin() + len);
            std::copy(data.begin(), data.end(), buf);
            return 0;
        } else {
            data = std::vector<unsigned char>(readBuffer.begin(), readBuffer.end());
            readBuffer.clear();
        }
    }
    read_data(timeoutMs);
    if (!readBuffer.empty()) {
        // check how much data is needed and add that much to the buffer
        if (readBuffer.size() >= len) {
            data = std::vector<unsigned char>(readBuffer.begin(), readBuffer.begin() + len);
            readBuffer.erase(readBuffer.begin(), readBuffer.begin() + len);
        } else {
            data = std::vector<unsigned char>(readBuffer.begin(), readBuffer.end());
            readBuffer.clear();
        }
    }
    if (data.empty()) {
        // fill data buf with 1s if no data was received
        printf("No data received\n");
        return -1;
    } else {
        std::copy(data.begin(), data.end(), buf);
    }
    return 0;
}

from emscripten.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.