<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class="">I debugged the memory leak. Whenever I call the PubSub.publish function, Duktape allocates about 288bytes of SPIRAM, and that grows with each call. But, every minute or so, a bunch of RAM gets magically freed. So, I tried:<div class=""><br class=""></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">OVMS# module memory</span></font></div><div class=""><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">OVMS# script eval 'PubSub.publish("test","test");’</span></font></div><div class=""><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">OVMS# script eval 'PubSub.publish("test","test");’</span></font></div><div class=""><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">OVMS# script eval 'PubSub.publish("test","test");’</span></font></div><div class=""><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">OVMS# script eval 'PubSub.publish("test","test");’</span></font></div><div class=""><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">OVMS# script eval 'PubSub.publish("test","test");’</span></font></div><div class=""><div class=""><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">OVMS# module memory</span></font></div></div><div class=""><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">OVMS# script eval 'Duktape.gc()’</span></font></div><div class=""><div class=""><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">OVMS# module memory</span></font></div></div></blockquote><div class=""><br class=""></div><div class="">and no overall memory leak. The Duktape.gc() freed all the allocations. The issue is just general delayed memory garbage collection within Duktape.</div><div class=""><br class=""></div><div class="">Over time, relying only on automatic garbage collection (which seems to be every minute or so), it looks like this:<div class=""><br class=""></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">OVMS# module memory</span></font></div><div class=""><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">Free 8-bit 79168/230296, 32-bit 900/2808, SPIRAM 3993620/4194252</span></font></div><div class=""><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">--Task--     Total DRAM D/IRAM   IRAM SPIRAM   +/- DRAM D/IRAM   IRAM SPIRAM</span></font></div><div class=""><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">OVMS DukTape        188      0      0  29844         +0     +0     +0   +864</span></font></div><div class=""><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">OVMS DukTape        188      0      0  30996         +0     +0     +0  +1152</span></font></div><div class=""><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">OVMS DukTape        188      0      0  35640         +0     +0     +0  +4644</span></font></div><div class=""><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">OVMS DukTape        188      0      0  38808         +0     +0     +0  +3168</span></font></div><div class=""><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">OVMS DukTape        188      0      0  40824         +0     +0     +0  +2016</span></font></div><div class=""><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">OVMS DukTape        188      0      0  15668         +0     +0     +0 -25156</span></font></div><div class=""><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">OVMS DukTape        188      0      0  17756         +0     +0     +0  +2088</span></font></div></blockquote><div class=""><br class=""></div><div class="">I don’t see the base SPIRAM memory allocation changing much, even after running for a couple of hours. I just see the SPIRAM rise up to 40KB, then drop down to 16KB, repeatedly. Anyway, I added ’script compact’ to be able to manually force a garbage collection (equivalent to "script eval 'Duktape.gc()’”).</div><div class=""><br class=""></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><div class=""><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">OVMS# module memory</span></font></div><div class=""><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">Free 8-bit 79168/230296, 32-bit 900/2808, SPIRAM 3991068/4194252</span></font></div><div class=""><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">--Task--     Total DRAM D/IRAM   IRAM SPIRAM   +/- DRAM D/IRAM   IRAM SPIRAM</span></font></div><div class=""><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">OVMS DukTape        188      0      0  31636         +0     +0     +0 +13880</span></font></div><div class=""><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">OVMS# script compact</span></font></div><div class=""><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">Compacting javascript memory</span></font></div><div class=""><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">I (263066) script: Duktape: Compacting DukTape memory</span></font></div><div class=""><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">OVMS# module memory</span></font></div><div class=""><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">Free 8-bit 79168/230296, 32-bit 900/2808, SPIRAM 4014624/4194252</span></font></div><div class=""><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">--Task--     Total DRAM D/IRAM   IRAM SPIRAM   +/- DRAM D/IRAM   IRAM SPIRAM</span></font></div><div class=""><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">OVMS DukTape        188      0      0  15092         +0     +0     +0 -16544</span></font></div></div></blockquote><div class=""><div><br class=""></div><div>I also included Michael’s JSON.js module as an internal module, as it is pretty useful. Now that I’ve implemented two of these, I know how to do it and will write some better support utility to make including these easier. I used <a href="https://javascript-minifier.com" class="">https://javascript-minifier.com</a> to reduce the code size (the original module code is in the jsmodsrc directory of ovms_script component, and minimised version in jsmodembed ready for embedding into firmware). Now, after boot you can simply call:</div><div><br class=""></div></div></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><div class=""><div><div><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">OVMS# script eval 'JSON.print(this);'</span></font></div><div><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">{</span></font></div><div><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">  "OvmsCommand": function () { [native code] },</span></font></div><div><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">  "OvmsLocationStatus": function () { [native code] },</span></font></div><div><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">  "OvmsMetricFloat": function () { [native code] },</span></font></div><div><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">  "OvmsMetricValue": function () { [native code] },</span></font></div><div><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">  "assert": function () { [native code] },</span></font></div><div><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">  "print": function () { [native code] },</span></font></div><div><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">  "PubSub": {</span></font></div><div><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">    "publish": function () { [ecmascript code] },</span></font></div><div><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">    "subscribe": function () { [ecmascript code] },</span></font></div><div><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">    "clearAllSubscriptions": function () { [ecmascript code] },</span></font></div><div><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">    "clearSubscriptions": function () { [ecmascript code] },</span></font></div><div><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">    "unsubscribe": function () { [ecmascript code] }</span></font></div><div><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">  },</span></font></div><div><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">  "JSON": {</span></font></div><div><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">    "print": function () { [ecmascript code] }</span></font></div><div><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">  }</span></font></div><div><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">}</span></font></div></div></div></div></blockquote><div class=""><div class=""><div><br class=""></div><div>Scripting from /store/scripts works well, and the ovmsmain.js is loaded on startup (AutoInit). Michael’s web based editor also works well for this.</div><div><br class=""></div></div></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><div class=""><div><div><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">OVMS# vfs cat /store/scripts/ovmsmain.js</span></font></div><div><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">print("Hello world\n");</span></font></div></div></div></div></blockquote><div class=""><div><br class=""></div><div>With events now enabled, you can use the PubSub framework to subscribe to events, and have the code run persistently (most importantly with persistent state). Much better than having to evaluate fire-and-forget scripts off flash. The usual place would be in ovmsmain.js, but you can also modify the live running environment directly:</div><div><br class=""></div></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><div><div><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">OVMS# script eval 'var myTicker=function(msg,data){print("Event: "+msg+"\n");}; PubSub.subscribe("ticker.10",myTicker);'</span></font></div><div><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">I (950636) script: Event: ticker.10</span></font></div><div><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">I (960636) script: Event: ticker.10</span></font></div><div><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">I (970636) script: Event: ticker.10</span></font></div></div></div></blockquote><div class=""><div><br class=""></div><div>An example would be to create a function ‘arrivedHome()’ then PubSub.subscribe(‘location.enter.homeloc’,arrivedHome). Within arrivedHome() you could do whatever is required.</div><div><br class=""></div><div>Another example would be to create a function ‘chargingReady()’ and hook it into the vehicle.charge.pilot.on event. Then, when the pilot signal appears, the function could call OvmsLocationStatus() to see if you are home, and act appropriately.</div><div><br class=""></div><div>The ticker.* events can be used to periodically poll for things.</div><div><br class=""></div><div>Perhaps a javascript function to check if we have been home for an hour, but wifi hasn’t connected, so power off/on the wifi?</div><div><br class=""></div><div>The engine itself is pretty much feature complete and usable at the moment. If you change the ovmsmain.js, or just want to clear out the environment, you can ’script reload’ and everything is restored to what it was at boot.</div><div><br class=""></div><div>Work now needs to be done on the support modules, to make things easier. Sure, we can call OvmsCommand(‘lock 1234’) to lock the car, but it would be much cleaner to have a vehicle support module so we can just call vehicle.lock(‘1234’). Other parts of the system also need to be extended into this, for things like notifications. Individual vehicles can also extend their own functionality. This all runs in SPIRAM, so memory should not be an issue.</div><div><br class=""></div><div>Looking in the extras/console directory of Duktape source tree, there is an example for a pure C implementation of a console object. That is exactly what we want - an object with property functions that can be called. My next job is to add support for that, similar to our existing RegisterDuktapeFunction. Then we can implement objects for vehicles, metrics, etc.</div><div><br class=""></div><div>Regards, Mark</div><div><br class=""></div><div><blockquote type="cite" class=""><div class="">On 16 Jan 2019, at 3:22 PM, Mark Webb-Johnson <<a href="mailto:mark@webb-johnson.net" class="">mark@webb-johnson.net</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><meta http-equiv="Content-Type" content="text/html; charset=utf-8" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class="">Well, the javascript framework re-work has now been committed, and is working well for me. Only one more major outstanding TODO remaining. Some comments:<div class=""><br class=""></div><div class=""><ul class="MailOutline"><li class="">To do anything useful with modules, I had to increase the stack size. It is now 12,288 bytes. I’ve seen just under 10KB in normal use, so a few more KB added as a margin. It won’t work with the old 8192 byte default. At least it doesn’t use IRAM, and the majority of storage (code, execution stack, etc) is in SPIRAM.<br class=""><br class=""></li><li class="">Duktape now starts up as part of the normal AutoInit system (so if it does crash, at least the rest of the system will continue to run).<br class=""><br class=""></li><li class="">Modules have been fully implemented. Very nice.<br class=""><br class=""></li><li class="">An internal module system has been implemented, and a first module 'int/pubsub' provided embedded in the firmware.<br class=""><br class=""></li><li class="">Breaking Change: The old ’script <path>’ command has changed to ’script run <path>’. The ‘.’ alternative is unchanged.<br class=""><br class=""></li><li class="">A ’script reload’ command has been provided to reload the framework.<br class=""><br class=""></li><li class="">A ’script eval’ command has been provided as a quick-and-dirty javascript evaluator (for testing purposes).<br class=""><br class=""></li><li class="">TODO: There is a memory leak in the PubSub event framework, so I’ve disabled it for the moment.</li></ul></div><div class=""><br class=""></div><div class="">For example:</div><div class=""><br class=""></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><div class=""><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">OVMS# script eval 'JSON=require("lib/JSON");'</span></font></div><div class=""><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">OVMS# script eval 'JSON.print(this)'</span></font></div><div class=""><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">{</span></font></div><div class=""><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">  "OvmsCommand": function () { [native code] },</span></font></div><div class=""><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">  "OvmsLocationStatus": function () { [native code] },</span></font></div><div class=""><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">  "OvmsMetricFloat": function () { [native code] },</span></font></div><div class=""><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">  "OvmsMetricValue": function () { [native code] },</span></font></div><div class=""><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">  "assert": function () { [native code] },</span></font></div><div class=""><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">  "print": function () { [native code] },</span></font></div><div class=""><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">  "PubSub": {</span></font></div><div class=""><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">    "publish": function () { [ecmascript code] },</span></font></div><div class=""><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">    "subscribe": function () { [ecmascript code] },</span></font></div><div class=""><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">    "clearAllSubscriptions": function () { [ecmascript code] },</span></font></div><div class=""><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">    "clearSubscriptions": function () { [ecmascript code] },</span></font></div><div class=""><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">    "unsubscribe": function () { [ecmascript code] }</span></font></div><div class=""><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">  },</span></font></div><div class=""><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">  "JSON": {</span></font></div><div class=""><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">    "print": function () { [ecmascript code] }</span></font></div><div class=""><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">  }</span></font></div></div><div class=""><font face="Andale Mono" class=""><span style="font-size: 18px;" class=""><br class=""></span></font></div><div class=""><div class=""><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">OVMS# script reload</span></font></div><div class=""><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">Reloading javascript engine</span></font></div><div class=""><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">I (277675) script: Duktape: Clearing existing context</span></font></div><div class=""><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">I (277685) script: Duktape: Creating heap</span></font></div><div class=""><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">I (277685) script: Duktape: Initialising module system</span></font></div><div class=""><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">I (277685) script: Duktape: Pre-Registered function OvmsCommand</span></font></div><div class=""><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">I (277685) script: Duktape: Pre-Registered function OvmsLocationStatus</span></font></div><div class=""><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">I (277685) script: Duktape: Pre-Registered function OvmsMetricFloat</span></font></div><div class=""><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">I (277685) script: Duktape: Pre-Registered function OvmsMetricValue</span></font></div><div class=""><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">I (277685) script: Duktape: Pre-Registered function assert</span></font></div><div class=""><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">I (277685) script: Duktape: Pre-Registered function print</span></font></div><div class=""><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">I (277685) script: Duktape: Preload internal module PubSub</span></font></div><div class=""><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">I (277825) script: Duktape: Executing ovmsmain.js</span></font></div><div class=""><font face="Andale Mono" class=""><span style="font-size: 18px;" class="">I (277835) script: Hello world</span></font></div></div></blockquote><div class=""><div class=""><br class=""></div><div class="">Still a bunch to do, but the basics seem there and working well.</div><div class=""><br class=""></div><div class="">Regards, Mark.</div><div class=""><br class=""><blockquote type="cite" class=""><div class="">On 11 Jan 2019, at 9:23 AM, Mark Webb-Johnson <<a href="mailto:mark@webb-johnson.net" class="">mark@webb-johnson.net</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><meta http-equiv="Content-Type" content="text/html; charset=utf-8" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class="">Your example is a little more involved than my ‘hello world’, and much cooler. Perhaps Robert can use it as a starting point in the user guide.<div class=""><br class=""></div><div class="">Any ideas how to handle events? We need an event module in javascript, and some way for extension scripts/modules to hook into the reception of events? The events are already routed into the duktape task - just not decided what to do with them yet. This leads into the bigger question of a server-side framework to run in the Duktape task. I can see some common pub/sub frameworks:</div><div class=""><br class=""></div><div class=""><ul class="MailOutline"><li class=""><a href="https://github.com/mroderick/PubSubJS" class="">PubSub.JS</a></li><li class=""><a href="https://github.com/pmelander/Subtopic" class="">Subtopic</a></li><li class=""><a href="http://amplifyjs.com/api/pubsub/" class="">Amplify JS</a></li><li class=""><a href="https://github.com/postaljs/postal.js" class="">Postal JS</a></li></ul></div><div class=""><br class=""></div><div class="">The last one (postal js) seems a good balance of complexity vs functionality, but goes beyond the minimum we need and may be too big. The first one is the absolute minimum, and the compressed (min) version is <2KB.</div><div class=""><br class=""></div><div class="">I guess the bigger question is does anyone know of any very lightweight server side frameworks that we should be looking at (rather than rolling our own - aka OpenVehicles.JS)?</div><div class=""><br class=""></div><div class="">It also would seem to make more sense to have the C interfaces as module objects with methods. So, rather than calling OvmsMetricFloat(), you get a handle to a metric object and then call a method to obtain its float value. Not sure how Duktape handles that, but I will check. Having a rich set of interfaces to our objects would be very useful and clean. Another example would be the vehicle object with methods StartCharge, StopCharge, UnlockCar, etc - rather than calling OvmsCommand(“charge start").</div><div class=""><br class=""></div><div class="">Regards, Mark.<br class=""><div class=""><br class=""><blockquote type="cite" class=""><div class="">On 11 Jan 2019, at 12:38 AM, Michael Balzer <<a href="mailto:dexter@expeedo.de" class="">dexter@expeedo.de</a>> wrote:</div><br class="Apple-interchange-newline"><div class="">
  
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" class="">
  
  <div text="#000000" bgcolor="#FFFFFF" class="">
    Works like a charm :)<br class="">
    <br class="">
    I've added the autoinit option to the web UI.<br class="">
    <br class="">
    Important for all script writers is to keep in mind we now have a
    global shared context.<br class="">
    <br class="">
    That is very useful to share data between scripts, but needs a
    little bit of discipline to avoid polluting the global context with
    local variables and functions. Any "var", "const", "function" etc.
    placed into the top level of a script file now is added to the
    global context.<br class="">
    <br class="">
    The best approach is to encourage users to use closures by default
    for all their scripts, i.e.<br class="">
    <blockquote class=""><font size="-1" class=""><tt class="">(function(){<br class="">
              … user code …<br class="">
        </tt></font><font size="-1" class=""><tt class="">})();</tt></font><br class="">
    </blockquote>
    The same rule applies to web plugins.<br class="">
    <br class="">
    Node style modules also work nicely. A simple test module:<br class="">
    <blockquote class=""><tt class=""><font size="-1" class="">// Module       : JSON (not
          compatible with the browser component!)<br class="">
          // State        : test/demo<br class="">
          // Install as   : /store/scripts/lib/JSON.js<br class="">
          // Load         : JSON = require("lib/JSON");<br class="">
          // Use          : JSON.print(object);<br class="">
          <br class="">
          exports.print = function(obj, ind) {<br class="">
            var type = typeof obj;<br class="">
            if (type == "object" && Array.isArray(obj)) type =
          "array";<br class="">
            if (!ind) ind = '';<br class="">
          <br class="">
            switch (type) {<br class="">
              case "string":<br class="">
                print('"' + obj.replace(/\"/g, '\\\"') + '"');<br class="">
                break;<br class="">
              case "array":<br class="">
                print('[\n');<br class="">
                for (var i = 0; i < obj.length; i++) {<br class="">
                  print(ind + '  ');<br class="">
                  exports.print(obj[i], ind + '  ');<br class="">
                  if (i != obj.length-1) print(',');<br class="">
                  print('\n');<br class="">
                }<br class="">
                print(ind + ']');<br class="">
                break;<br class="">
              case "object":<br class="">
                print('{\n');<br class="">
                var keys = Object.keys(obj);<br class="">
                for (var i = 0; i < keys.length; i++) {<br class="">
                  print(ind + '  "' + keys[i] + '": ');<br class="">
                  exports.print(obj[keys[i]], ind + '  ');<br class="">
                  if (i != keys.length-1) print(',');<br class="">
                  print('\n');<br class="">
                }<br class="">
                print(ind + '}');<br class="">
                break;<br class="">
              default:<br class="">
                print(obj);<br class="">
            }<br class="">
          <br class="">
            if (ind == '') print('\n');<br class="">
          }</font></tt><br class="">
    </blockquote>
    <br class="">
    Using it:<br class="">
    <blockquote class=""><font size="-1" class=""><tt class="">JSON = require("lib/JSON");<br class="">
          <br class="">
          print("Global context:\n");<br class="">
          JSON.print(this);<br class="">
          <br class="">
          (function(){<br class="">
            var x = { a: 42, b: "a \"foo\" is no 'bar'", c: [1,2,3], d:
          { sub: true }, e: ["q","w",17, { e1:22, e2:33 }] };<br class="">
            print("\nLocal object:\n");<br class="">
            JSON.print(x);<br class="">
          })();</tt></font><br class="">
    </blockquote>
    <br class="">
    Execution:<br class="">
    <blockquote class=""><tt class="">OVMS# . test.js</tt><tt class=""><br class="">
      </tt><tt class="">Global context:</tt><tt class=""><br class="">
      </tt><tt class="">{</tt><tt class=""><br class="">
      </tt><tt class="">  "print": function () { [native code] },</tt><tt class=""><br class="">
      </tt><tt class="">  "assert": function () { [native code] },</tt><tt class=""><br class="">
      </tt><tt class="">  "OvmsMetricValue": function () { [native code] },</tt><tt class=""><br class="">
      </tt><tt class="">  "OvmsMetricFloat": function () { [native code] },</tt><tt class=""><br class="">
      </tt><tt class="">  "OvmsLocationStatus": function () { [native code] },</tt><tt class=""><br class="">
      </tt><tt class="">  "OvmsCommand": function () { [native code] },</tt><tt class=""><br class="">
      </tt><tt class="">  "JSON": {</tt><tt class=""><br class="">
      </tt><tt class="">    "print": function () { [ecmascript code] }</tt><tt class=""><br class="">
      </tt><tt class="">  }</tt><tt class=""><br class="">
      </tt><tt class="">}</tt><tt class=""><br class="">
      </tt><tt class=""><br class="">
      </tt><tt class="">Local object:</tt><tt class=""><br class="">
      </tt><tt class="">{</tt><tt class=""><br class="">
      </tt><tt class="">  "a": 42,</tt><tt class=""><br class="">
      </tt><tt class="">  "b": "a \"foo\" is no 'bar'",</tt><tt class=""><br class="">
      </tt><tt class="">  "c": [</tt><tt class=""><br class="">
      </tt><tt class="">    1,</tt><tt class=""><br class="">
      </tt><tt class="">    2,</tt><tt class=""><br class="">
      </tt><tt class="">    3</tt><tt class=""><br class="">
      </tt><tt class="">  ],</tt><tt class=""><br class="">
      </tt><tt class="">  "d": {</tt><tt class=""><br class="">
      </tt><tt class="">    "sub": true</tt><tt class=""><br class="">
      </tt><tt class="">  },</tt><tt class=""><br class="">
      </tt><tt class="">  "e": [</tt><tt class=""><br class="">
      </tt><tt class="">    "q",</tt><tt class=""><br class="">
      </tt><tt class="">    "w",</tt><tt class=""><br class="">
      </tt><tt class="">    17,</tt><tt class=""><br class="">
      </tt><tt class="">    {</tt><tt class=""><br class="">
      </tt><tt class="">      "e1": 22,</tt><tt class=""><br class="">
      </tt><tt class="">      "e2": 33</tt><tt class=""><br class="">
      </tt><tt class="">    }</tt><tt class=""><br class="">
      </tt><tt class="">  ]</tt><tt class=""><br class="">
      </tt><tt class="">}</tt><tt class=""><br class="">
      </tt><br class="">
    </blockquote>
    Nice :)<br class="">
    <br class="">
    Regards,<br class="">
    Michael<br class="">
    <br class="">
    <br class="">
    <div class="moz-cite-prefix">Am 10.01.19 um 10:10 schrieb Mark
      Webb-Johnson:<br class="">
    </div>
    <blockquote type="cite" cite="mid:DF73994D-9A32-4391-AFC7-EE157683A77B@webb-johnson.net" class="">
      <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" class="">
      I’ve committed my work on a production javascript framework. The
      changes are quite extensive, and with the one exception of
      ‘ovmsprint’, should be backwards compatible.
      <div class=""><br class="">
      </div>
      <div class="">The overall goal is to be able to run a javascript
        code system alongside our standard firmware code. Users could
        then write javascript, and modify scripts already running on the
        device (without firmware changes). Unlike the previous version
        (where scripts were loaded, compiled, run, then dumped), this
        approach is designed to keep scripts in memory; this vastly
        increases the opportunities for what can be done with the
        system.</div>
      <div class=""><br class="">
      </div>
      <div class="">Changes made include:<br class="">
        <div class=""><br class="">
        </div>
        <div class="">
          <div class="">
            <ul class="MailOutline">
              <li class="">Move scripting to be a component</li>
              <li class="">Make DukTape use SPIRAM for as much as
                possible</li>
              <li class="">Run the javascript engine in it's own task
                (OVMS DukTape)</li>
              <li class="">Change the way extensions functions are
                registered<br class="">
                (just call RegisterDuktapeFunction, rather than messing
                around with the internals of Duktape)</li>
              <li class="">Catch compilation and parsing errors (fail
                gracefully - finally!)</li>
              <li class="">Support 'print' and 'assert' javascript
                framework</li>
              <li class="">Output (via print) goes to current console,
                or logged if no console</li>
              <li class="">Autoinit (and run) /store/scripts/ovmsmain.js</li>
              <li class="">Support node.js style modules</li>
              <li class="">Control with config auto javascript (default
                enable)</li>
            </ul>
          </div>
          <div class=""><br class="">
          </div>
          <div class="">The main TODO is to provide a facility for
            reloading the engine (new scripts/modules). At the moment,
            the module needs to be rebooted (ugly). There is also a lot
            of work still to do on making some actually useful modules.
            And we also need to work out what to do with events (now
            that they can be delivered to running javascripts).</div>
          <div class=""><br class="">
          </div>
          <div class="">But, anyway, for the moment:</div>
        </div>
        <div class=""><br class="">
        </div>
      </div>
      <blockquote style="margin: 0 0 0 40px; border: none; padding:
        0px;" class="">
        <div class="">
          <div class="">
            <div class=""><font class="" face="Andale Mono"><span style="font-size: 18px;" class="">I (128) script:
                  Initialising SCRIPTS (1600)</span></font></div>
            <div class=""><font class="" face="Andale Mono"><span style="font-size: 18px;" class="">I (132) script:
                  Using DUKTAPE javascript engine</span></font></div>
          </div>
        </div>
        <div class="">
          <div class=""><font class="" face="Andale Mono"><span style="font-size: 18px;" class="">I (0) script: Duktape:
                Creating heap</span></font></div>
          <div class=""><font class="" face="Andale Mono"><span style="font-size: 18px;" class="">I (10) script:
                Duktape: Initialising module system</span></font></div>
          <div class=""><font class="" face="Andale Mono"><span style="font-size: 18px;" class="">I (20) script:
                Duktape: Scripting task is running</span></font></div>
        </div>
        <div class=""><font class="" face="Andale Mono"><span style="font-size: 18px;" class="">I (906) script: Duktape:
              Executing ovmsmain.js</span></font></div>
        <div class=""><font class="" face="Andale Mono"><span style="font-size: 18px;" class="">I (936) script: Hello
              world</span></font></div>
        <div class=""><font class="" face="Andale Mono"><span style="font-size: 18px;" class=""><br class="">
            </span></font></div>
        <div class="">
          <div class=""><font class="" face="Andale Mono"><span style="font-size: 18px;" class="">OVMS# vfs cat
                /store/scripts/ovmsmain.js</span></font></div>
          <div class=""><font class="" face="Andale Mono"><span style="font-size: 18px;" class="">print("Hello
                world\n”);</span></font></div>
        </div>
        <div class=""><font class="" face="Andale Mono"><span style="font-size: 18px;" class=""><br class="">
            </span></font></div>
        <div class=""><font class="" face="Andale Mono"><span style="font-size: 18px;" class="">OVMS# test javascript<br class="">
              Javascript 1+2=3</span></font></div>
      </blockquote>
      <div class="">
        <div class=""><br class="">
        </div>
        <div class="">Regards, Mark.<br class="">
          <div class=""><br class="">
            <blockquote type="cite" class="">
              <div class="">On 8 Jan 2019, at 11:00 PM, Michael Balzer
                <<a href="mailto:dexter@expeedo.de" class="" moz-do-not-send="true">dexter@expeedo.de</a>>
                wrote:</div>
              <br class="Apple-interchange-newline">
              <div class="">
                <div class="">Mark,<br class="">
                  <br class="">
                  welcome back, awesome news on the JS and FCC stuff :)<br class="">
                  <br class="">
                  I've got some fixes and some feedback on the web
                  plugins in progress, I'll get that done until the
                  weekend (got some free days left).<br class="">
                  <br class="">
                  Regards,<br class="">
                  Michael<br class="">
                  <br class="">
                  <br class="">
                  Am 08.01.19 um 05:27 schrieb Mark Webb-Johnson:<br class="">
                  <blockquote type="cite" class="">Firstly, a very
                    belated merry xmas, and happy 2019 to everyone. I
                    hope that you all got to spend good times with
                    friends and family, as I did. I’ve been travelling,
                    and just got back home to a very large eMail inbox.<br class="">
                    <br class="">
                    During my travels, I did manage to re-work the
                    javascript framework to be single task based. That
                    seems to work well, and now I’m back I will test on
                    my car. The new framework is backwards compatible -
                    apart from memory usage (one more task with a
                    stack), it has no impact to the flow. It will,
                    however, allow us to extend this a lot more and
                    become much more useful. Assuming no issues, I will
                    be able to commit that soon.<br class="">
                    <br class="">
                    As we are up to 144 commits since 3.1.011, perhaps
                    it is well past due for 3.1.012? I was hoping that
                    Espressif would have fixed the bug related to wear
                    levelling version upgrades that Michael helped to
                    identify, but not yet. Any objections to a 3.1.012
                    release to EAP at the end of this week?<br class="">
                    <br class="">
                    The CE/FCC certification work is progressing. No
                    issues so far. I’ll let you know as soon as we get
                    near completion for this.<br class="">
                    <br class="">
                    I’m working through my inbox now, and will reply
                    individually to questions there.<br class="">
                    <br class="">
                    Regards, Mark.<br class="">
                    <br class="">
                    _______________________________________________<br class="">
                    OvmsDev mailing list<br class="">
                    <a href="mailto:OvmsDev@lists.openvehicles.com" class="" moz-do-not-send="true">OvmsDev@lists.openvehicles.com</a><br class="">
<a class="moz-txt-link-freetext" href="http://lists.openvehicles.com/mailman/listinfo/ovmsdev">http://lists.openvehicles.com/mailman/listinfo/ovmsdev</a><br class="">
                  </blockquote>
                  <br class="">
                  -- <br class="">
                  Michael Balzer * Helkenberger Weg 9 * D-58256
                  Ennepetal<br class="">
                  Fon 02333 / 833 5735 * Handy 0176 / 206 989 26<br class="">
                  <br class="">
                  <br class="">
                  _______________________________________________<br class="">
                  OvmsDev mailing list<br class="">
                  <a href="mailto:OvmsDev@lists.openvehicles.com" class="" moz-do-not-send="true">OvmsDev@lists.openvehicles.com</a><br class="">
                  <a class="moz-txt-link-freetext" href="http://lists.openvehicles.com/mailman/listinfo/ovmsdev">http://lists.openvehicles.com/mailman/listinfo/ovmsdev</a><br class="">
                </div>
              </div>
            </blockquote>
          </div>
          <br class="">
        </div>
      </div>
      <br class="">
      <fieldset class="mimeAttachmentHeader"></fieldset>
      <pre class="moz-quote-pre" wrap="">_______________________________________________
OvmsDev mailing list
<a class="moz-txt-link-abbreviated" href="mailto:OvmsDev@lists.openvehicles.com">OvmsDev@lists.openvehicles.com</a>
<a class="moz-txt-link-freetext" href="http://lists.openvehicles.com/mailman/listinfo/ovmsdev">http://lists.openvehicles.com/mailman/listinfo/ovmsdev</a>
</pre>
    </blockquote>
    <br class="">
    <pre class="moz-signature" cols="160">-- 
Michael Balzer * Helkenberger Weg 9 * D-58256 Ennepetal
Fon 02333 / 833 5735 * Handy 0176 / 206 989 26
</pre>
  </div>

_______________________________________________<br class="">OvmsDev mailing list<br class=""><a href="mailto:OvmsDev@lists.openvehicles.com" class="">OvmsDev@lists.openvehicles.com</a><br class=""><a href="http://lists.openvehicles.com/mailman/listinfo/ovmsdev" class="">http://lists.openvehicles.com/mailman/listinfo/ovmsdev</a><br class=""></div></blockquote></div><br class=""></div></div>_______________________________________________<br class="">OvmsDev mailing list<br class=""><a href="mailto:OvmsDev@lists.openvehicles.com" class="">OvmsDev@lists.openvehicles.com</a><br class=""><a href="http://lists.openvehicles.com/mailman/listinfo/ovmsdev" class="">http://lists.openvehicles.com/mailman/listinfo/ovmsdev</a><br class=""></div></blockquote></div><br class=""></div></div></div></blockquote></div><br class=""></div></body></html>