dtex / j5e

Framework for embedded devices using ECMA-419, the ECMAScript® embedded systems API specification, based on Johnny-Five's API
https://www.j5e.dev/
MIT License
64 stars 6 forks source link

fix fn/getIO and normalizeIO maby not works. #108

Closed MKGaru closed 2 years ago

MKGaru commented 2 years ago

Fix tutorial code not working.

https://dtex.github.io/j5e/tutorial-C-INSTANTIATING.html

tutorial says:

import LED from "j5e/led";

// Instantiate an LED connected to
// builtin pin 13
const led = await new LED(13);

led.blink();

but I got error. ( # Break: (host): async module!)

then fix to this. my code:

import LED from "j5e/led";

export default async function() {
  // Instantiate an LED connected to
  // builtin pin 13
  const led = await new LED(13);

  led.blink();
}

but I got error. (LED.prototype.write: no function!) image

behavior

new LED(13) -> LED constructor ->  pass 13 to fn.getIO ->    
   (13).constructor.name !== "Object"  then  return 13.  
  io = 13.    
  (13).write no function!  

fix

getIO ioOpts description says:
ioOpts - A pin number, pin identifier or a complete IO options object
change: if typeof ioOpts not object then pass to normalizeIO.

but next error. image

fix

typeof ioDefaults === "string"

next error. image

fix

normalizeIO

// ioOptions = { ioOptions}   // <--- wrong ? change to
ioOptions = { pin: ioOptions }

then

works fine!

phoddie commented 2 years ago

but I got error. ( # Break: (host): async module!)

Don't panic: top-level await still works. ;)

As part of changes to support module loading hooks in Compartments, we now block top-level await on modules loaded synchronously. Since main is loaded synchronously by the host, it generates an exception. The work-around @MKGaru shows above is an easy short-term solution. We would like top-level away to work on main, so will come back to this.

MKGaru commented 2 years ago

@phoddie Thank you for the information. It's not the essential problem with this pull request, but I want to know how change code(or manifest?), if can a top-level await method in the main module.

phoddie commented 2 years ago

The problem is rooted in the host which calls xsAwaitImport which is explicitly a synchronous import (like Compartment.prototype.importNow). Because it is synchronous, it fails if the module uses top-level await.

Your work-around suggests a solution.

Add a file to your project called loadmain.js.

export default async function() {
  await import("main");
}

In your manifest, tell the host to run loadmain instead of main at start-up. If modifying $MODDABLE/examples/helloworld/manifest.json, it would look like this:

{
    "include": "$(MODDABLE)/examples/manifest_base.json",
    "creation": {
        "main": "loadmain"
    },
    "modules": {
        "*": [
            "./loadmain",
            "./main"
        ]
    }
}

This works on ESP8266 and ESP32. It fails in mcsim because it ignores the creation/main. We'll fix that. You can patch it directly yourself by changing this line to:

xsVar(1) = xsAwaitImport(((txPreparation *)xsPreparationAndCreation(NULL))->main, XS_IMPORT_DEFAULT);
MKGaru commented 2 years ago

Thank you for telling me about other workaround suggestions :) I learned how top-level-await work in main. Thank you very much.

dtex commented 2 years ago

Don't panic

Always good advice

@MKGaru Thank you. I think I am missing test coverage here so I missed these. I'll dive in this weekend (traveling tomorrow) and review this but at first blush it all makes sense.