Fun with an Object and Four Timers

Posted on
  • This project creates an object prototype using the setInterval function, and then creates four instances of the object with different intervals running concurrently.

    The object prototype:

    function testObj(name,mcount,interval){
      this.Name=name;
      this.Mcount=mcount;
      this.Count=0;
      this.Interval=interval;
      this.ID=0;
    
    //Methods
      this.doCount=function(){
       this.Count++;
       if(this.Count <= this.Mcount){
        console.log(this.Name," ",this.Count);
       }else{
        clearInterval(this.ID);
        console.log(this.Name," Finished");
       }//endif
      },//end doCount
    
    }//end testObj
    
    

    Two functions used to test the object:

    // Test the testObj methods 
    function Test(name,mcount, interval){
     // create an instance of testObj
    var Y=new testObj(name,mcount,interval);
    Y.ID=setInterval(function(){Y.doCount();­},Y.Interval);
     console.log(Y.Name," started");
      console.log("Test End");
    }//end Test
    
    function Test1(){
     // create an instance of testObj
    var Y=new testObj("Third",10,1500);
    Y.ID=setInterval(function(){Y.doCount();­},Y.Interval);
    console.log(Y.Name," started");
    console.log("Test End");
    
    var Y1=new testObj("Fourth",10,2000);
    Y1.ID=setInterval(function(){Y1.doCount(­);},Y1.Interval);
    console.log(Y1.Name," started");
    console.log("Test End");
    }//end Test
    
    

    The code that calls the functions:

    console.log(process.memory());
    Test("first",10,500);
    console.log(process.memory());
    Test("second",10,1000);
    console.log(process.memory());
    Test1();
    console.log(process.memory());
    //When Fourth finishes type this into the left side
    //  console.log(process.memory()); 
    //Compare the Usage at the start, as each task is added and at the end
    
    

    Some of the output in the left pane of WebIDE:

    >echo(0);
    { "free": 2144, "usage": 106, "total": 2250, "history": 101,
      "stackEndAddress": 536910652, "flash_start": 134217728, "flash_binary_end": 223300, "flash_code_start": 134449152, "flash_length": 262144 }
    first  started
    Test End
    { "free": 2076, "usage": 174, "total": 2250, "history": 108,
      "stackEndAddress": 536910652, "flash_start": 134217728, "flash_binary_end": 223300, "flash_code_start": 134449152, "flash_length": 262144 }
    second  started
    Test End
    { "free": 2013, "usage": 237, "total": 2250, "history": 112,
      "stackEndAddress": 536910652, "flash_start": 134217728, "flash_binary_end": 223300, "flash_code_start": 134449152, "flash_length": 262144 }
    Third  started
    Test End
    Fourth  started
    Test End
    { "free": 1900, "usage": 350, "total": 2250, "history": 114,
      "stackEndAddress": 536910652, "flash_start": 134217728, "flash_binary_end": 223300, "flash_code_start": 134449152, "flash_length": 262144 }
    =undefined
    first   1
    first   2
    second   1
    first   3
    Third   1
    first   4
    second   2
    Fourth   1
    first   5
    first   6
    second   3
    Third   2
    first   7
    first   8
    second   4
    Fourth   2
    first   9
    Third   3
    first   10
    second   5
    first  Finished
    
    

    1 Attachment

  • I like you're having fun with Espruino...

    I wondered about the comma (,) in line 17 of first code block: Does it not show error in Espruino Web IDE?

    In order to go fully through with Javascript's prototype idea (including the methods), the code may look like below. With methods on prototype - class definition represented by constructor (function) - (each) method exists only once. If the method is assigned with a definition in the constructor, the methods, such as .doCount() exist actually multiple times - once for each of the object instances. To take advantage of object-oriented encapsulation even further, adding .start() and .stop() (and private ._stop()) and .log()` methods simplifies the use and saves also some more space...

    function TestObj(name, mCount, interval) {
      this.name = name;
      this.mCount = mCount;
      this.count = 0;
      this.interval = interval;
      this.id = null;
    } // end testObj - constructor (and state setting)
    // Method definition(s):
    TestObj.prototype.doCount = function() {
      this.count++;
      this.log(this.count);
      if (this.count >= this.mCount) {
        this._stop("");
      } // endif
    }; // end doCount() method of TextObj
    TestObj.prototype.stop = function() {
      this._stop("was ");
    };
    TestObj.prototype.start = function() {
      if (this.id) {
        this.log("already started and is 'running'");
      } else {
        this.count = 0;
        this.id = setInterval( this.doCount.bind(this)
                             , this.interval );
        this.log("started");
      }
    };
    TestObj.prototype._stop = function(reason) {
      if (this.id) {
        clearInterval(this.id);
        this.id = null;
        this.log(reason + "stopped");
      } else {
        this.log("not 'running' (yet or anymore)");
      }
    };
    TestObj.prototype.log = function(info) { 
      console.log(getTime(), this.name, " ", info);
    };
    
    // Test code
    var specs;
    function test() {             // --> t in 100[ms] (seq)
                                  //   10    20    30    40
        (specs =                  // ---|-----|-----|-----|
    [ [ null, "first" , 5,  500 ] // 5 10 15 20 25
    , [ null, "second", 4, 1000 ] //   10    20    30
    , [ null, "third" , 3, 1500 ] //      15       30
    , [ null, "fourth", 2, 2000 ] //         20          40
    ]   ).forEach(function(spec){
            (spec[0] = new TestObj(spec[1],spec[2],spec[3])
            ).start();
          });
    }
    setBusyIndicator(LED1);
    test();
    

    Notice the the Uppercase/lowercase conventions for Class name (Constructor), (state) properties (instance variables) and (behavior) properties (methods). It helps a lot to grasp quickly what's going on and helps with naming.

    Naming is always a struggle for me: id, interval, intervalId, intervalTime,... what is to pick? For example, this.id makes me think of the id of the object... but that may just be my (object-oriented) déformation professionelle... and it's (about) time (for me) to follow your role model: retire... ;-)

    You may also notice a difference in the .doCount(): since the function in setInterval() is executed at the end of the interval, there is no need to keep the object running for one more cycle to just discover that the object has to stop. Therefore, it can stop right away after the maximum count is both reached and printed in the console. Compare the two outputs below: first one was created with your original if-then-else code, and the second was produced with the print alway, fi-then-stop. Looking at and comparing the times - first thing on the line - helps).

     1v85 Copyright 2016 G.Williams
    >echo(0);
    949363502.26460552215 first   started
    949363502.26707267761 second   started
    949363502.26953887939 third   started
    949363502.27200794219 fourth   started
    =undefined
    949363502.76485729217 first   1
    949363503.26484680175 first   2
    949363503.26728725433 second   1
    949363503.76487255096 first   3
    949363503.76985359191 third   1
    949363504.26478481292 first   4
    949363504.26739025115 second   2
    949363504.27227306365 fourth   1
    949363504.76489257812 first   5
    949363505.26525497436 first   stopped
    949363505.26739025115 second   3
    949363505.26994323730 third   2
    949363506.26741886138 second   4
    949363506.27241039276 fourth   2
    949363506.76989746093 third   3
    949363507.26779460906 second   stopped
    949363508.27038764953 third   stopped
    949363508.27290058135 fourth   stopped
    >
    
     1v85 Copyright 2016 G.Williams
    >echo(0);
    949363622.59208297729 first   started
    949363622.59455299377 second   started
    949363622.59703159332 third   started
    949363622.59949874877 fourth   started
    =undefined
    949363623.09226894378 first   1
    949363623.59216308593 first   2
    949363623.59474182128 second   1
    949363624.09227466583 first   3
    949363624.09723472595 third   1
    949363624.59221839904 first   4
    949363624.59468936920 second   2
    949363624.59976100921 fourth   1
    949363625.09221076965 first   5
    949363625.09343433380 first   stopped
    949363625.59484004974 second   3
    949363625.59727954864 third   2
    949363626.59480190277 second   4
    949363626.59602737426 second   stopped
    949363626.59985637664 fourth   2
    949363626.60106182098 fourth   stopped
    949363627.09733486175 third   3
    949363627.09856033325 third   stopped
    >
    

    The log prints the time - first thing on the line - from where you can see that Espruino is pretty fast and keeps the intervals.. ;-). The time shows seconds.

    And last but not least notice the setBusyIndicator(LED1) in second to last line line 54: LED1 - the red on-board LED on classic and PICO Espruino boards - is on when Espruino is busy working... What you will notice is: Espruino is not really busy... ;-)... because it is fully event driven - also in the application code (as opposite to Arduino, which is always busy running the 'loop'). This is a major reason to chose Espruino over other and Arduino like implementations for standalone, battery operated, long-lasting applications.

    Provide a timing that keeps the interval end events separate, delivers a bit more interesting 'busy flicker' pattern (with the original timing, the interval ends fall within a 100st of a second... 0.01s, see console outputs above):

        (specs =                    // --> sequence: t in 100[ms]
    [ [ null, "first" , 5,  500 ] // 5 10  15  20    25
    , [ null, "second", 4, 1100 ] //     11      22      33 44
    , [ null, "third" , 3, 1600 ] //         16        32       48
    , [ null, "fourth", 2, 2300 ] //               23         46
    ]   ).forEach(function(spec){
    

    ...and with time to scale:

    // ----> t in 100[ms]
    //     10        20        30        40        50
    // '----|----'----+----'----|----'----+----­'----+
    // 5   10   15   20   25
    //      11         22         33         44
    //           16              32              48
    //                  23                     46
    

    The setBusyIndicator() is useful to explain what is going on: You mention concurrently running objects... they are in regard of the life cycle of the intervals of the objects. In regard to the code: it is still sequential - one after the other. When a setTimeout() or setInterval() is executed, the related information is place in a (time drive) as work order in work queue and the application code comes to an end - you see this in the output where =undefined shows - and control is returned to the 'operating system' Espruino (firmware). Espruino then looks at this work queue, nothing is there to do, it switches off the pin specified in with setBusyIndicator() and goes to sleep - may be even deep sleep ( see sleep and setDeepsleep() and Power Consumption). When something has to be done right away or on timer / hardware interrupt, it switches the setBusyIndicator() pin on, picks up the work order and does specified work. Having set setBusyIndicator() and typing in the console shows that the console is actually managed by Espruino: every keystroke goes to Espruino and is accordingly processed - echoed back to the console pane in the browser...

    PS:

    
    
    

    specs[1][0]
    ={
    "name": "second",
    "mCount": 4, "count": 4, "interval": 1000, "id": null }

    
    ...and while it is running (with original timing): 
    
    

    949367054.10334491729 first 4
    949367054.10587024688 second 2
    949367054.11077404022 fourth 1
    specs[1][0]
    ={
    "name": "second",
    "mCount": 4, "count": 2, "interval": 1000, "id": 2 }
    949367054.60337352752 first 5
    949367054.60459995269 first stopped
    949367055.10592937469 second 3
    949367055.10837554931 third 2
    ```

  • Thanks for taking the time to rework this code.
    Thanks for the comments. I learned a lot.
    Now for the hard part applying it all.

    WebIDE doesn't flag the extra comma you mentioned.

    I've been wondering if this forum is the right place to post code that I've been working on?

    I would like to think it's useful to others and that feedback such as yours would improve the code and instruct others. All the reference documents can't replace the experience of writing code and tracking down the gotchas and occasional bugs.

    Would GitHub be a better place?
    Perhaps for longer projects that start small and evolve over time?

  • If I could start over, I'd place the code in git hub, because it has repository quality, most of all it has version control. Since this forum started on this platform, most of the code sits spread out in the posts of conversation. I was thinking of writing an extractor that would put the whole forum into a better searchable place. But this may stay just as a thought. For sharing and discussing, the forum has a nicer format than github has with its comments. Often it is not possible to share the full project, so aspects are extracted and abstracted and discussed in a focused form on the forum. Asking for help works better on a narrower scoped subject than a complete project. The completeness of a project complicates the understanding of the issue at hand by others, or at least obfuscates it.

    The reference documentation is complemented by the tutorials and the module examples. Where there is more about a particular feature, the reference documentation points to it. Most of my input I draw from the module examples and what forum members posted about it and their experiences.

    Project with MCs are usually smaller and have a smaller set of - but very distinctive -requirements, last but not least because of the resource restrictions. Pretty quickly I adjusted my style of solutions to preserving resources, even the few there are.

    Writing large (admin and self-service) Web application across full stack with nearly unlimited resources grew a pattern on me that was not portable into the space of IoT peripheral devices. I get remembered the time when business applications had to fit into 16KB or KWords - words of 8...14..18 bit - including indexed/keyed record access software and basic disk access/lock instructions do do multi-user applications. I'm glad these times have passed, but thankful, because the lessons learned still serve me today when in big data performance and footprint tend to stress the limits no matter how much resources are thrown at the problems. Certain things just have to happen full circle within an hour or two to have a global availability. Just like a great infomercial figure claims: *There is always somewhere sunrise that justify eating the favorite cereal any time!

    Is your first application the equipping of the wind direction and speed indicator in the back yard with a MC? The MC could measure direction and speed - and may be temperature as well - and be a wireless connected Web server to provide data for personal weather station on desktop / laptop / wifi gadget?

  • We were first using Espruino at work when I retired.
    The profile photo is a homemade wind turbine. It uses a NEMA 23 stepper motor as the generator and aluminum mini-blind slats for blades. The stepper motor goes through a full wave rectifier into a solar charge controller and into a battery. So far I know that the battery Voltage was higher after charging with the turbine.
    Having worked a number of years in wind energy research, it seems reasonable to come up with a way to measure and log wind input and power generated.

    As far as memory limit experience, I started years ago on an Altair 8800 with 1K of memory.
    I spent lots of time with embedded controllers such as PIC, TI and Stellaris. Do you say Big-Endian/Little-Endian or MAC/INTEL format?

    Average wind direction is a unique problem. If half the time the wind is at 355 degrees and the other half the wind is at 5 degrees. The average is 180 degrees which is wrong.

    Thanks again for the help.

  • Average wind direction as a concept is the problem.

    I mean, the way to average is not simple addition, you'd have to do it like a vector I think

  • polar -> cartesian -> average -> polar looks the chain of keywords for that matter. And being sailor I wonder whether wind speed matters as well, even though direction has nothing to do with it ... until I'm on the water wanting to go somewhere particular. (It works as well without coordinate transformation... because trigonometric libraries weigh heavy... but it gets a bit messy... and in both cases, any calculation fails when trying to find the average between opposite directions... ;-)

  • Here are three references that use the vector method for wind speed and direction.
    http://www.webmet.com/met_monitoring/622­.html
    note the use of the atan2() function
    and,
    http://www.ndbc.noaa.gov/wndav.shtml
    and,
    https://en.wikipedia.org/wiki/Yamartino_­method

    The method of bins is used to estimate wind turbine power from a histogram of wind speeds.
    http://www.nrel.gov/wind/smallwind/pdfs/­power_performance_testing.pdf

    Finally a wind rose:
    https://en.wikipedia.org/wiki/Wind_rose

  • Post a reply
    • Bold
    • Italics
    • Link
    • Image
    • List
    • Quote
    • code
    • Preview
About

Fun with an Object and Four Timers

Posted by Avatar for ClearMemory041063 @ClearMemory041063

Actions