• A story in three pieces ( Intro, Getting there..., Final ):

    - Intro

    Working on something with save() to run it from battery sent me a bit into the boonies...

    When you save() code, it matters very much when you do it... in other words: it matters in what state the board is (after upload) - what initializations have been made, what code did already complete and what code is still running (timeouts, intervalls,...).

    For illustration purpose, I use the code example with module MFRC522 NFC/RFID MODULE is discussed (see attached pic and next post). The example code works well when connected to the IDE (out of box on Espruino standard board, and with two changes for for Espruino Pico: 1st) B2 has to be changed to B1 because B2 is LED1 and not on connectors - and even if connected, it messes with the example; 2nd) LED3 has to be removed from the array of leds because it is undefined).

    PS: It was difficult to catch the green LED on, even though the white RF ID card was laying under the reader and making it flash twice a second for 100ms. The picture shows Espruino Pico 'extended' to 2x14 = 28 pins. The 0.05" connectors are brought to the 'sides' with lacquered wires (plus GND and 3.3V at the rows ends), leaving a prototyping space of 4x5 = 20 wholes. A similar shim could make this into bottom and top SMT areas for I2C / SPI connected EEPROM / FRAM/MRAM / (Atmel) Crypto / security chips.


    1 Attachment

    • PICO_RFID_MRC522_SPI1_B1.jpg
  • A story in three pieces ( Intro, Getting there..., Final ):

    - Getting there...

    To ready this code to run on battery, function onInit() {...} (or E.on("init",function(){...});) has to be added with the appropriate code in the function ...body. Furthermore, all stuff printing on the console with print(...); and console.log(...); has to be removed/commented or - when other display/communication device is available - redirected. If not done so, the code execution will hang and you end up with an executed execution (...wat ever...). For the example at hand it is the line containing print("Found card " + card);.

    The expected code looks then something like this:

    SPI1.setup({sck:B3, miso:B4, mosi:B5 });
    var nfc = require("MFRC522").connect(SPI1, B1/*CS PICO*/);
    function onInit() {
      setInterval(function() {
        nfc.findCards(function(card) {
          // print("Found card "+card);
          card = JSON.stringify(card);
          var leds = [LED1,LED2];
          if (card=="[147,239,211,128]") digitalWrite(leds,1);
          if (card=="[249,192,235,164]") digitalWrite(leds,2);
        });
      }, 1000);
    }
    

    For testing in connected state, upload the code and invoke onInit() from the console (right-hand side of the IDE)... and the code behaves as expected, and is ready for save().

    Because you do not (neccessarily) want to save a running timer... (created by setIntervall()) - and for other reason you will see right away, upload it again without the manual kick-off of onInit(), and enter save() in the right-hand side of the IDE.

    Save reports in the console:

    >save()
    =undefined
    Erasing Flash.....
    Writing..........
    Compressed 81600 bytes to 7173
    Checking...
    Done!
    Running onInit()...
    >
    

    World is still perfectly in order: the code works. It is ready for test as saved code running on battery. Btw - as found out later - you do not need the battery to test, you can just plug-in USB again - just for power - and - as expected on power-on (sinse recent version(s)), onInit() and (all functions registered with E.on("init",function(){...}); actually get invoked.

    Nothing... just nothing. (wiring... all checked again and again... still nothing).

    So I reworked the code a bit before pulling in the source of the module. In the example coe, I did not like all the stuff in the callback, so I changed. I added LED1/LED2.set() at the beginning of the onInit() and ....reset() at the end of it to have an simultaneous flash as indication that onInit() is actually called and completed without hick-up:

    SPI1.setup({sck:B3, miso:B4, mosi:B5 });
    var nfc = require("MFRC522").connect(SPI1, B1/*CS*/);
    var cards = 
        { "[30,60,213,228]"  : function(){ // flash red LED
          LED1.set(); setTimeout("LED1.reset()", 100); }
         , "[244,171,74,25]" : function(){ // flash green LED
          LED2.set(); setTimeout("LED2.reset()", 100); }
        },f;
    function onInit(){
      LED1.set(); LED2.set();
      setInterval(function() {
          nfc.findCards(function(card) { // print("Card: " + card);
              if ((f = cards[JSON.stringify(card)])) { f(); }
          });
      }, 300);
      LED1.reset(); LED2.reset();
    }
    

    As you see in lines 3..8, a cards singleton object is created with the JSON stringified card serial arrays as property names and related (assigned) functions as property values. In other words, when property with name matching the card serial is found in cards, its value - the assigned function - is executed ...as found in line 13 in the callback passed to .findCards(card).

    Code works connected well, but still does not work completely after saving and running on battery. The simultaneous flashing of both leds indicate that onInit() runs perfectly - from begin to end - but still no functionality else.

    Now is the time to find out why it is not working... I proide only a symmary about how to do that in this post:

    • (1). insert the following two (three) lines at the top / very beginning of your code:

      var MFRC522_MODULE = (function(){ var exports = {}; // placed BEFORE module code
      
      return exports; })(); // placed AFTER module code
      
      
    • (2). Pull the non minified nodule from the (MFRC522) module repository on the web at http://www.espruino.com/modules/MFRC522.­js - replacing MFRC522 with your module name and and place it in between above mentioned two lines of code.

    • (3). Replace the line with ...require("MODULENAME").connect(... with this line:

      var nfc = MFRC522_MODULE.connect(SPI1, B1/*CS*/);
      
    • (4). Upload / run your code... now you can 'investigate' what is going on in the module... by adding console.log(...) / print(...) statements and way more sophisticated: use the debugger introduced in version 1v80 with break point and single step and variable value inspection...

    I had not to go that far to see what is really 'broken': having not the .connect() in onInit() just misses the initialization of the device on re-power-up... (m.init(), m being the newly created and returned RFID reader object).

    No point to hold on to the unminified module code... and back to the way things can be done with the require(... and .connect(....

    How to do you split .require() from .connect() to make the require(... happen and provide a handle of the module, and invoke .connect(... within onInit() to make the device initialization happen on re-power-up? - Easy"

    • (1). Have a line for the .require(... just in the original spot( line 2) assigning the module to a module-variable - without the connect(... - and define a variable for what connect(... will return later on.

      var MFRC522_MODULE = require("MFRC522"), nfc;
      
    • (2). Include in onInit(... a line that makes the connect:

      var nfc = MFRC522_MODULE.connect(SPI1, B1/*CS PICO*/);
      

    With the above setup, not just Espruino's timers (created with setInterval(... is recreated/initialized, but also the device...

    Comment about what about require(... 'should' return: From the very beginning provision of just a '.connect()' by the 'require()' felt strange to me. Familiar with a context where 'require()' return class object(s) and not just a function that bundles everything up, such as the constructor and (extended / dynamic) initialization that can - and as just demonstrated - have to happen at a different time, I'd rather have modules return classes. The additional advantage is that other items than the intialization can be tied to the class - such as constants - so they can be as well used later. @Gordon then made the change that require can also just return an object - 'class object' or singleton with value and function/method properties - as the export object itself. Before, the module had to put it into the export object as a property and the application had to pull it again out of it (export.clazz = XyzClazz; and var XyzClazz = require("XyzClazz").clazz, respective). Since with modules namespaces can be created, a more advance approach has not to be implemented, such as requireJS requirejs.org JavaScript module loader which was first introduced by dojo dojotoolkit.org and has become the standard for dynamic, asynchronous, module loader (AMD) optimized for use in the Web world / broser/client side.

  • A story in three pieces ( Intro, Getting there..., Finally )

    - Finally

    The final code (TL;DR) looks like this ('Fritzing' attached as pic):

    // /RFID/PICO_SPI1_B1_SAVED.js
    
    // GND GND        // B3  SCK
    // BAT VCC        // B4  MISO
    // B1  CS/SS/SDA  // B5  MOSI
    
    SPI1.setup({sck:B3, miso:B4, mosi:B5 });
    var MFRC522_MODULE = require("MFRC522"), nfc;
    var cards = 
        { "[30,60,213,229]"  : function(){ // flash red LED
          LED1.set(); setTimeout("LED1.reset()", 100); }
         , "[244,171,74,26]" : function(){ // flash green LED
          LED2.set(); setTimeout("LED2.reset()", 100); }
        },f;
    
    function onInit(){
      LED1.set(); LED2.set();
      nfc = MFRC522_MODULE.connect(SPI1, B1 /*CS PICO*/);
      setInterval(function() {
          nfc.findCards(function(card) {
              if ((f = cards[JSON.stringify(card)])) { f(); }
          });
      }, 300);
      LED1.reset(); LED2.reset();
    }
    

    Note 1: Line 21's logical expression of if has double parenthesis ((...)) because Espruino's Javascript validator throws a 'tantrum': logical expression and not assignment expected... Standard Javascript can handle the concise form of assignment and result left on 'stack top' for 'anonymous' and easy reuse...

    Note 2: The print(card); in line 20 is needed to find out the RFID tag/card/token's serial - an array of 4 integers ranging from 0..255 - if not otherwise known.

    Attachement: 'Fritizing my way...' (one end of the blue needed a bit 'photoshopping' push for visualization)


    1 Attachment

    • FritzingMyWay.png
  • Ahh, so you're saying the issue was that the NFC module wasn't initialised with onInit? Perhaps that should be in the Troubleshooting?

    There's already a I TYPED save() BUT MY CONNECTED DEVICE DOESN'T WORK AT POWER ON (sorry for the caps - I copy-pasted), but it's actually very small and doesn't contain much info.

    I've thought about trying to make those modules use on('init',... to initialise themselves, but to be honest I'm a bit worried. While it would help in the simple case, I wonder if the rest of the time it might actually make a whole new class of confusing errors?

  • For educational 'playing' while connected and without saving, things work just fine.

    For modules that connect to devices with dynamic, volatile configurations, save does - and cannot - save the state of the device, because it lives only inside the device and the device doe not have a save and restore function... and even if they would have, Espruino's save() would have to know about it and also know about how to call the particular device's save...

    Separating the Espruino related initializations from initializations of the connected devices is the key to the solution. It is obvious that build-time oriented things - 'require' - and runtime oriented things - 'connect' - need to be separated - and can therefore not exist in the same statement. Choosing the approach of crating a module reference and use the module reference later in the code is not a viable approach.

    Having the code structured with getting the resources first and apply basic (static) initialization and then issue a save() is the way to go. The onInit() and E.on('init') have to happen afterwards. Observing this pattern of code structure and process timing creates restartable applications.

  • ...just tried to 'save()' a simple ESP8266 example... not working well... will have to dig into the nested require issue... Will raise elaborate on the issues in a separate tread...

  • Please try to capture the debug output from uart1 (gpio pin 2)

  • What is GPIO2 providing?

  • @allObjects I have been at the same point some days ago.
    What I did is to connect GPIO2 to a serial port of an Espruino Board.
    Espruino starts this application:

    var d = "",epc = [];
    Serial3.setup(115200,{rx:C11});
    Serial3.on('data', function(data) {
      var i = 0;
      d += data;
      i = d.indexOf("\n");
      if(i > 0){
        if(d.substr(0,i).indexOf("epc1=") >= 0){
          epc.push(d.substr(0,i));
        }
        console.log(d.substr(0,i));
        d = d.substr(i+1);
      }
      if(d.length >= 128) {
        console.log(d);
        d = "";
      }
    });
    

    In my case Espruino is connected to a local copy of WebIDE and ESP8266 is connected to the original WebIDE.
    Debugging need to be switched on with require("ESP8266").logDebug(true)

  • I wish I had read these experiments before my own work on moving from console-connected to independent operation! Thank you for writing them up.

    Because I am going to be controlling power to all connected devices, I assume that all connected devices may have been independently powered down, and so (and because of not liking to be reliant on save timing) I prefer to reconnect devices again via a deviceInit function in onInit which is also called in the start section of the main app.m

  • @Moray, for your work you may also be interested in these two conversations - a bit a lot delayed - response to your post - but still helpful: simple explanation how to save code that espruino run on start? about things that go on on saving / power cycling, and GPS powered by Espruino pin(s). And if you already plowed through these, just ignore this post.

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

save() with modules where .connect() initializes device (such as RFID reader MFRC522)

Posted by Avatar for allObjects @allObjects

Actions