## Where communities thrive

• Join over 1.5M+ people
• Join over 100K+ communities
• Free without limits
##### Activity
Chris
@cmidgley
OK - so the heltec board should have one, but doesn't yet. I'll ignore it for now then.
Chris
@cmidgley
Do you have a 3d printer? I designed a case for them, that also holds the battery if wanted. Glad to share if interested.
Peter Hoddie
@phoddie
Very nice. I don't have a 3D printer, but I have friends. ;)
Chris
@cmidgley
Here are the files: Heltec V2 Bottom and Heltec V2 Top
Andy Carle
Yes, actually, I have noticed some weirdness with xsbug on Windows. That crept in sometime quite recently -- I was blaming a recent video driver update on my machine, but @cmidgley's experience suggests otherwise. I'll see if I can figure out when that started.
Chris
@cmidgley
@PrototypingAndy_twitter I recall this issue when I was using Moddable a year ago ... so not sure it's a new issue. Just FYI. Thx.
Andy Carle
Interesting. It definitely hasn't been happening on my machine for more than a couple of weeks. I wonder if something did change on my machine that puts me into that camp now. I'll take a look.
Andy Carle

@cmidgley When you get a chance, could you try something for me? I just want to make sure we're looking at the same problem. In %MODDABLE%\tools\xsbug\behaviors.js and %MODDABLE%\tools\xsbug\ConsolePane.js, comment out the lines (three total) that reference application.cursor, then close xsbug and rebuild tools (build.bat).

The diffs for the changes are:

$cd$MODDABLE/tools/xsbug

andyc@ANDY-SURFACE MINGW64 /c/moddable/tools/xsbug (master)
$git diff behaviors.js diff --git a/tools/xsbug/behaviors.js b/tools/xsbug/behaviors.js index e41106e31..4aa9d9f71 100644 --- a/tools/xsbug/behaviors.js +++ b/tools/xsbug/behaviors.js @@ -51,7 +51,7 @@ export class ButtonBehavior extends Behavior { this.changeState(container, container.active ? 1 : 0); } onMouseEntered(container, x, y) { - application.cursor = cursors.arrow; + // application.cursor = cursors.arrow; this.changeState(container, 2); } onMouseExited(container, x, y) { @@ -379,7 +379,7 @@ export class CodeBehavior extends Behavior { return true; } onMouseEntered(code, x, y) { - application.cursor = cursors.iBeam; + // application.cursor = cursors.iBeam; } onReveal(code) { this.getScroller(code).reveal(code.selectionBounds); andyc@ANDY-SURFACE MINGW64 /c/moddable/tools/xsbug (master)$ git diff ConsolePane.js
diff --git a/tools/xsbug/ConsolePane.js b/tools/xsbug/ConsolePane.js
index 12daa115d..899c9bbc7 100644
--- a/tools/xsbug/ConsolePane.js
+++ b/tools/xsbug/ConsolePane.js
@@ -108,7 +108,7 @@ class ConsoleCodeBehavior extends CodeBehavior {
let bounds = code.bounds;
let offset = code.findLineBreak(code.hitOffset(x - bounds.x, y - bounds.y), false);
let color = this.colors.find(color => color.offset == offset);
-               application.cursor = color ? cursors.link :  cursors.iBeam;
+               // application.cursor = color ? cursors.link :  cursors.iBeam;
}
onTouchEnded(code, id, x, y, ticks) {
super.onTouchEnded(code, id, x, y, ticks);
That eliminates the performance problem for me, at the cost of making the cursor not look correct when hovering over text. If it's the same for you, we'll work on sorting out how to fix that without disabling features. :)
Chris
@cmidgley
@PrototypingAndy_twitter That looks like it's it! Nice and smooth.
Chris
@cmidgley
@phoddie I updated the gist with the code. Spent most of today doing a refactor for Ecma-419. Much nicer interface - very easy to use , and the chip is abstracted away from the interface. It also now fully supports interrupts, and will operate async if you supply onReadable / onWritable else will do sync. It's likely ... but no way for me to confirm right now ... that it will work on other processors that have the ST127x chip as it sits on top of SPI and Digital and does nothing otherwise that is platform aware/specific. It's likely I misunderstand 419 so if you see something odd, let me know. Tomorrow I plan on adding a few features I learned the chip can do, but otherwise I think it's pretty complete (though I'm sure there are bugs lurking...)
You are welcome to use, or not use, the code as you please. The only license restriction I have is from the original author (MIT), two ports back, that has some fragments left but not much from a legal perspective. I'm no attorney, but if there was a desire to change the license, I think we have some leeway (especially since what little code remains is simply implementing against a documented chip interface). Either way, I will be using this for my project.
Peter Hoddie
@phoddie
@cmidgley - that all sounds (really) great. I will take a look this weekend and get back to you.
Andy Carle
@cmidgley Thank you for the report! We'll take a look at a real fix for that, but glad to hear that the workaround works as expected.
Chris
@cmidgley
I'm trying to build a mod (mcrun -m -p <myplatform> -o build) but I just want a build without launching tools like xsbug or serial2xsbug. Not using -d at least stops xsbug from launching, and -p stops the simulator from running, but it always launches serial2xsbug. With mcconfig I can use -t build but that isn't available with mcrun. Any recommendations on how to build a mod, without launching the debugger or serial2xsbug? This is for an automated build system that I'm putting together inside Docker.
Chris
@cmidgley
My current idea, which likely will work (not yet tested, but wondering if there is a better one), is to use sed to remove the line referencing SERIAL2XSBUG in makefile:
mcrun -p <myplatform> -o build
pushd build/tmp/esp32/release/mod
sed '/$(SERIAL2XSBUG)$(UPLOAD_PORT) $(DEBUGGER_SPEED) 8N1 -install$(ARCHIVE)/d' makefile >makefile >makefile
make
popd
Chris
@cmidgley
Slight update to script... this one is working. Is this the best approach for now?
rm -rf build
mkdir build
mcrun -p esp32/heltec_wifi_kit_32 -o build
pushd build/tmp/esp32/release/mod
sed -i '/$(SERIAL2XSBUG)$(UPLOAD_PORT) $(DEBUGGER_SPEED) 8N1 -install$(ARCHIVE)/d' makefile
make
popd
Peter Hoddie
@phoddie
For consistency, the right thing would be to implement -d for mcrun. I don't think that should be too difficult (but I'm notorious bad with make scripts). Calling serial2xsbug directly is fine.
Chris
@cmidgley
Do you mean -t? (for -t build)? -d is implemented - to trigger xsbug at least (doesn't do anything else as I can see)

You may like this... I now have a Google Cloud Run container that has Moddable, with a REST API. You just call the endpoint like this:

{
"config": {"mySetting": "one", "anotherSetting": "two"},
"script": "console.log('test');\nconsole.log('two');"
}

And then Cloud Run launches a Docker contains with a REST API that returns something like:

{
"compileErrors": [],
}

or in the case of a compile error:

{
"compileErrors": [
"/workspace/builds/build-2/mod.js:2: error: end of file in string!",
"/workspace/builds/build-2/mod.js:2: error: missing ,!",
"/workspace/builds/build-2/mod.js:2: error: missing )!"
]
}

And thanks to Google Run pricing, it costs only 3/month to run 30,000 compiles, complete with geographic distribution (runs closest to the user) and with scale up/down on demand. Pretty cool! Blake Burkhart @bburky I've been enjoying playing with Moddable over the weekend, it seems nice overall. I wanted an easy to use framework to play with the M5Paper I got recently. One issue with switching to fast refresh modes like A2, is it the full screen may not be cleared on startup and filled areas are poorly drawn. It was even noticeable on the epaper-flashcards demo, old content from other demos wasn't cleared off the screen. I ended up with this code which seems to work well. First, clear the screen. Then draw content on screen with a high quality mode to draw all the UI well. Then defer changing the refresh mode to something like A2 (it must be deferred, or the mode changes before the UI is initially drawn). class AppBehavior extends Behavior { onDisplaying(application) { if (screen.configure && screen.refresh) { screen.configure({updateMode: "GC16"}); // Any high quality mode screen.refresh(); // Use INIT mode to clear the screen fully (optional, and slow. It causes a double flash, but is needed to clear all ghosting) application.defer("finishedOnDisplaying") // Must be deferred so that the screen can finish drawing } } finishedOnDisplaying() { screen.configure({updateMode: "A2"}); } } Is this the best way to do this? You may want to update some of the examples to do this if so, this draws with much better quality. Is application.defer() the best way to run something after UI has finished rendering? Alternately, something like a "temporarily use this mode for the next update" command could achieve this too, but I couldn't see how to do that. Peter Hoddie @phoddie @bburky - Thanks for giving the Moddable SDK a try. On the M5 Paper unit that I used to implement the ePaper display driver (and that @lprader used to implement the example apps) we didn't see the visual glitch you describe. We do have one report of it happening on a different M5 Paper unit though, so perhaps there is some variation or something we've overlooked. The approach you took looks pretty reasonable as a solution to the problem you describe. The finishedOnDisplaying function should be invoked after both the refresh and first frame update are complete. (The checks for screen.configure and screen.refresh is unnecessary if running on M5 Paper. I'm guessing that's so you can run in the simulator?) Blake Burkhart @bburky Yes that's for the simulator, I think the example code used an if (config.updateMode) check which is about the same. Peter Hoddie @phoddie "temporarily use this mode for the next update" could be done in the IT8951 driver, though that kind of behavior introduces state that could be confusing. I'm a few miles away from my M5 Paper device at the moment. I'll try this out when I can. If your approach generates better results, we should update the examples (and perhaps the driver?) to implement your behavior. Blake Burkhart @bburky Agreed. Reusing the application events with onDisplaying() and defer() is pretty easy and works. I don't think it needs to be done at the driver level if this covers all use cases. Epaper is just a bit weird, there are times you want fast refresh and times you want high quality. The Moddable app I made over the weekend was a replacement for a horrible phone app that interfaces with a BLE kitchen scale. A2 refresh does a good job of quickly updating the UI with new live data, but I used the high quality mode at startup to draw the main UI crisply. Peter Hoddie @phoddie Yea, every ePaper display has its own special behavior. It is always a bit of challege, though the results often look really great. Cool that you were able to get BLE + Piu working together on M5 Paper. Please consider sharing a video, if not the code. I suspect a lot of people could learn from that. Blake Burkhart @bburky I'll think about it, so far I just got the BLE connection and really really simple UI. Needs a few more features, then I'll post it somewhere. Peter Hoddie @phoddie Cool. Peter Hoddie @phoddie @cmidgley - The LoRa driver looks pretty good. You've gotten much of the Ecma-419 stuff right. I put together some notes on where some fine tuning would help to sync it with the intent of the spec. Those are a little long for here, so they are in a gist. I'm happy to try making some of these changes when my boards arrive, so please don't feel obligated. If something isn't clear or doesn't make sense, just let me know. Chris @cmidgley Great review - thanks Peter! Right off the bat I have a couple questions, but may have more as I work on this. 1) Logically I see why Peripheral is the right base class as it's a device on top of other interfaces, but from an interface perspective it aligns with IO better. Peripheral doesn't have read/write (so those are extensions) and instead expects Sample to be used. 2) Breaking up the options on the constructor makes sense - I'll pull out the SPI pins so they can live in device.io.SPI (clock, in, out, ...) which I think was your intent as well. I'll need Heltec_Wifi_Kit_32 defined for the device.io.* object (or perhaps we create a new one for Heltec_Wifi_LoRa_32_V2?). What's the best way to go about that? Here are the Heltec Wifi LoRa 32 V2 pins 3) configure vs. get/set - Set is used in the Serial driver so that's what I adopted as it matched the best. Perhaps Peripheral.configure is the better interface, in which case I'd drop get as I only added it to comply with how Serial did it. If using IO base class, maybe get/set is better and if using Peripheral configure is? 4) read - I'd like to keep pre-allocated buffers for my use case, but can implement read(number) which returns a dynamically allocated buffer up to max(number) bytes. Chris @cmidgley Update to the above: 2) Ignore my pull-out of SPI, I see that is "lora" in your example. But since that is SPI, where do I put radio configuration settings like bandwidth, codingRate, frequency, etc? Should "lora" be renamed to something like "interface" and then "lora" have configuration settings? Likewise, where does "onReadable"/"onWritable" go - at the root of the object? Chris @cmidgley For Write, you suggested eliminating the size parameter (and on read to always just dynamically allocate). I've always tried to eliminate dynamic allocations as much as possible in embedded systems as it increases risk of fragmentation and failure on long running systems. Are you not concerned about this with XS? Chris @cmidgley All recommended changes are made, but will further alter based on any feedback from above. Constructor dictionary has sections lora/interrupt/reset as recommended, all other values sit at the root of the dictionary. Now uses configure() instead of set() but still has get(). Close is now safe to call multiple times. Read supports read(buffer) as well as read(number). Write is no longer blocks as is the same for sync/async. typeof undefined changed as recommended. Also extended the library with several new features for the ST127x chip (such as more statistics, gain control, and small packet / high speed chip optimization). Here is the latest version as well as a crappy test main to run it (uses build parameter "transmit=0" to build a receive node, and "transmit=1" to build a transmit node). Note: If there is a better way to convert strings to/from ArrayBuffer (see main.js) I'm all ears! FYI: Small bug in xsbug when running multiple devices. First machine launches fine in a tab. Second machine starts serial2xsbug and the output window shows interspersed output from both devices. Switching between tabs cleans up the output to be per-device again. Peter Hoddie @phoddie Changes look good. Just a few quick comments: • Agreed that Lora is more IO than Peripheral. I think configure makes sense here, since that's exactly the behavior you implemented. get/set is specific for Serial and named to match Web Serial, but I can see how that would be unclear from just the spec. • I think write call should use size instead of buf.byteLength when looping to send bytes to the FIFO. • I got it wrong when suggesting lora for the property name. The Microchip digital expander is a good example - either spi or i2c is specified depending on the interface. Even with only one supported interface here, I think would make sense to follow here too, so spi instead or lora. • This undefined !== typeof options.enableReceiver doesn't avoid the string compare (but make it harder to see!). undefined !== options.enableReceiver does. I'm really looking forward to trying this out. Peter Hoddie @phoddie On garbage collection, I'm 1001% with you -- I try to keep that to a minimum. But.... some GC is inevitable and XS is more than fast enough, especially with the small heap sizes on a microcontroller. So, I try to focus on the places that run often. The Ecma-419 APIs are designed to work either way -- using a provided buffer or allocating one -- to be convenient to use when not worrying about GC and efficient when you are. It does put some burden on the implementation of the classes to support that though. Peter Hoddie @phoddie FYI: Small bug in xsbug when running multiple devices. First machine launches fine in a tab. Second machine starts serial2xsbug and the output window shows interspersed output from both devices. Switching between tabs cleans up the output to be per-device again. That's a feature, not a bug, When a machine tab is selected, it shows that tab's output. When nothing is selected, it shows them all (merged in time order). That let's you watch several machines at once. Chris @cmidgley All above makes sense. I'll send over an update likely later tonight. I didn't mean to leave the "typeof" there ... that was a global search/replace screw-up! Anyway - fixes seem to be: but in write (size), switch from "lora" to "spi", and remove the "typeof". Trivial - but always feel free to recommend other changes. At some point, if you want, it may make sense to move it into the Moddable tree. I have it in a github repo, but it's a private one along with a bunch of other (currently closed) code. Andy Carle @PrototypingAndy_twitter @bburky Thank you for the M5Paper suggestion above! I can confirm that that looks a lot better when switching between apps on my M5Paper device. @phoddie and I have been iterating a bit on the tidiest way to implement this idea in the examples. I think we've settled on this: class AppBehavior extends Behavior { onDisplaying(application) { screen.refresh?.(); screen.configure?.({updateMode: config.firstDrawMode ?? config.updateMode}); if (config.firstDrawMode) application.defer("onFinishedFirstDraw", config.updateMode); } onFinishedFirstDraw(application, mode) { screen.configure({updateMode: mode}); } That allows for setting both firstDrawMode and updateMode per-device in the manifest and also works in the simulator. I'm going to go ahead and make that change in the examples and add a note to our M5Paper documentation. Chris @cmidgley @phoddie Here are those tiny changes as discussed. Peter Hoddie @phoddie Thanks, @cmidgley! I'll wait to dive into that until I have the hardware. That will give me a better perspective than scanning in an editor. Chris @cmidgley Can you confirm if my understanding is correct that only one mod (.xsa/archive, which might contain multiple modules) can be loaded on a host? I don't see much API (other than xsMachine.archive having a unique archive pointer per machine) to support otherwise. Peter Hoddie @phoddie Correct, there is a single mod. It can contain multiple modules and resources. Chris @cmidgley Question on JSON.stringify with newlines in strings. If I say JSON.stringify('test\n') I get "test\n" from Moddable, but I get "test\\n" (with the newline encoded) from my Chrome browser. I need it to be encoded, so trying to understand if this is expected (and I need to write some encoder that works on the messages) or if it's perhaps a bug? Chris @cmidgley Also in a quick hack to do encoding is failing with an XS abort: dead strip! error (windows simulator). Code that fails is: function testEncode(string) { return string.replace(/([\n"\&\r\t\b\f])/g, "\\1");
}
Peter Hoddie
@phoddie

Is that just how Chrome outputs string in the console? I tried this:

let foo = JSON.stringify('test\n');
for (let i = 0; i < foo.length; i++)
trace(foo.charCodeAt(i), " ", foo[i], "\n");

And the output seems correct?

34 "
116 t
101 e
115 s
116 t
92 \
110 n
34  "