-
Just had a glance at it and it looks neat.
Currently my Espruinos have a small 'bootloader' set viaE.setBootCode
(I think I understand now how to tokenise it). It receives strings via TCP and evals them - large strings with class definitions, instantiation etc. Does the code processed by eval get pretokenised, provided the flag is set?(side note: I once had a Sinclair ZX81 with 1kB of RAM. The code was immediately entered as tokens.)
-
-
It doesn't seem to work from the console neither from the IDE.
AfterE.setFlags({pretokenise:1}) function test() {print('Hallo')} dump()
function test ...
is shown as plain text, no tokens.
The output of E.getFlags() is>E.getFlags() ={ deepSleep: 0, pretokenise: 1, unsafeFlash: 0, unsyncFiles: 0 }
Version is 2v02, Espruino Wifi.
There seems to be something I'm missing. -
-
I've stumbled upon the pretokenise flag (
E.setFlags({pretokenise:1})
) and I'm wondering if it's worth setting it on an Espruino Puck or WiFi.
As far as I can guess pretokenised JS code doesn't need to get eval'ed anymore, which has the potential to speed up execution significantly.
Does it accelerate the execution of long running code, or has the code already been pretokenised after a while?
Are there any gotchas except of readability and changeability of the tokenised code?
Any comments are appreciated.- Steffen
- Steffen
-
-
Socket instances don't seem to use the attached 'error' listener on error:
>s = net.connect({host: 'xxx', port: 1883}, print) >s.on('error', (e)=>print('EEE',e)) >s.end() >s =Socket: { type: 0, "#onconnect": function () { [native code] }, opt: { host: "neptune", port: 1883 }, conn: false, "#onerror": function (e) { ... }, clsNow: true, cls: true, endd: true } >s.write('x') Uncaught Error: This socket is closed. at line 1 col 12 s.write('x') ^
Is this expected behaviour?
I'm asking because in NodeJS, when an error listener is attached, no exception is thrown but the listener called (with the exception message) instead. If Espruino did the same, the last line should read like this:
EEE Error: This socket is closed. ...
(EEE because the listener prints it, then the error.) -
tinyMQTT does not have last will, neither the retain flag on publish nor qos for subscribe (QoS 1 might be useful).
Reconnect seems to be implemented for CONNECT only, while the new module reconnects also if a socket.write fails later or a PINGACK is missing.
In case somewhat less than 127 bytes are enough for topic and payload combined tinyMQTT is an excellent choice though. -
I was in need for a small MQTT module with Last Will support and builtin reconnect. I've created one for Node and a derived version for Espruino.
The code has been written from scratch after the OASIS 3.1.1 spec (without implementing stateful sessions, with some side glances at Paco-MQTT and Espruino MQTT). It is smaller than the existing MQTT module and very fast.
Is there an interest in having yet another one (file is attached)?- Steffen
- Steffen
-
You are right, it works perfectly well on a clean device.
It seems like passing a wrong argument (the '\x07' string) causes the error:>String.fromCharCode('\x07') // wrong argument, but no complaint ="\0FD" >String.fromCharCode(7) // correct argument, but extra chars ="\7FD" >String.fromCharCode(8) // correct argument (above 8 every value gives the correct result) ="\b" >String.fromCharCode(7) // correct argument below 8, always with extra chars ="\7FD"
(It was pretty hard to find out how to reproduce the effect.)
-
-
-
-
After putting
process.memory()
at the end of the callback the errors seem to be gone, along with the inexplicable delays.@allObjects: On top of this, I've replaced setInterval with setTimeouts as you suggested. This ensures that the intervals never overlap, allowing to use much shorter intervals.
Leaves the - somewhat academic - question open why explicitly calling the garbage collection via process.memory was necessary. GC takes about 15 ms, while the idle time between intervals is about 200 ms. I don't mind calling it, quite the contrary. Just thought that > 100 ms were enough for Espruino to decide to do it itself.
-
.. published part of the code: well, it is pretty nested.
The code is basically a presence sensor that needs to react snappy (turning on the kitchen light!!).
I like your suggestion of using setTimeout instead of the more rigid setInterval. Although I think this way the root cause of the (very rare but annoying) delays is only obfuscated.
I was trying something in the line of setTimeout within the callback but it didn't help so far. I obviously missed some point :( -
I'm using Waveform to rapidly read a sequence of data, very successfully. The code is like this:
wfrm = new Waveform(5) wfrm.on('finish', callback) setInterval(() => { wfrm.startInput(A0, 50) }, 500) function callback(buf) { // do something with buf }
Every 500 ms a 'task' is started to do an A/D converesion, 5 times, at 50 Hz.
When ready the callback evaluates the passed Uint8Array (argument 'buf') very quickly -> no problem at all.
Sometimes, however, there are errorsUncaught Error: Waveform is already running Uncaught InternalError: Timeout on ADC
Sometimes the callback has to do more, including an HTTP call. This might take longer than the repat interval of 500 ms an cause these errors.
Does a long running callback (longer than 500 ms) really make the Waveform complain at the next startInput, as I'm thinking?
Is there a way to effectively make the callback appear as completed although parts of the code still need to be executed - like process.nextTick? -
-
Yes, I've made good experience prefixing all commands with
\x15\x10
.
Once I've disovered these magic characters a lot of trouble was gone! There are still constellations where an additional echo(0) seems to be required but I cannot tell which ones specifically.
Btw, I understand that for\x10print(1);print(2)\n
echo is off for both print statements, while for\x10print(1)\nprint(2)\n
the second print statement is echoed (if echo was on). I believe that my need for echo(0) comes from more complex code snippets that are separated by \n. -
Thanks for your replies.
@Gordon: Yes, it is mostly when starting a small "session" after a while. I agree with your concerns about accidentially pasted code, that's why I didn't just suggest it as enhancement.
And for the exactly same reason the example has \x1f instead of \x02 (Ctrl-b).
@Wilberforce: E.getTemperature was just an example. I don't always know which code is needed. If it's more than 1 line of code the only safe way is to send echo(0) first.Although I'm able to make code changes I don't want to run propriatary code builds. A year from now I might have lost interest in making own Espruino builds (not in Espruino) - then I'll loose either the official Espruino improvements or my propriatary enhancements.
So I'll continue wasting 20 bytes with each session :) -
When connecting to Espruino programmatically I send for example
'\x15\x10echo(0);print(E.getTemperature())\n'
This works well, but besides looking a little ugly it is a big waste when connected over BLE.If the were a key, say \x1f, that makes jsiHandleChar
- delete the current line like Ctrl-U (\x15)
- turn echo off permanently until re-enabled by echo(1)
the command sent became
'\x1fprint(E.getTemperature())\n'
.This saves 9 bytes (almost halve of one BLE packet's payload, and probably a little overhead for parsing and interpreting the echo(0) call.
Is this something to consider as an enhancement?Regards, Steffen
- delete the current line like Ctrl-U (\x15)
-
-
-
-
Glad to hear eval does it :)
I've actually grabbed your pretokenise.js from EspruinoTools and done something similar already. First the code was not executable because "return" is defined twice, as LEX_R_BREAK and as LEX_R_RETURN. The returns from a function need to be tokenised as the latter one, but the pretokenise routine returns the first one. After obfuscating the token for LEX_R_BREAK (as "XXreturn") everything runs fine.
The pre-tokenised code uses many of the tokens including class, new, switch/case, try/catch and some bit shift operators.