-
@DrAzzy, cool thing your are up to... #webserver
you can go even further... as you know, require() can load dynamically - at runtime - module from the card and there is also a way to unload it afterwards.
Depending on the extension, you first check for a statically loaded function, if it is not there, go for a module, and if there is no module loaded, throw the error... 404.
What about below code (used long names help with documentation):
var requestHandler = { handlers: // handlers for extension and file|page (=function) name: { json: { status: { function() { // handles status.json // status function code accepting with 'arguments' - either specified or as array } , history: function() { // handles history.json // history function code ... } , etc: function() { // handles etc.json ... } , _: function() // default handler for json extension using file(content) as parm ... } } // /json , xml: { status: function() { // handles status.xml // status function code ... } , history: function() { // handles history.xml // history function code ... } , etc: function() { // handles etc.xml ... } , _: function() // default handler for xml extension using file(content) as parm ... } } // /xml } // handlers , statistics: { // houskeeping for to make it really 'smart'/controlled: // managing handlers like virtual memory managment // or old (non-virtual) drop and reload of exec code. // detect limit on load (see below) and purge // least used stuff... you can reload later anyway ... } , load: function(extension,functionName,funktion) { // load a handler function var handlers = this.handlers[extension]; if (!handlers) { handlers = (this.handlers[extension] = {}); } if (handlers[functionName]) { console.log("function " + functionName + " already loaded"); } handler[functionName] = funktion; // load it anyway? } , purge: function(extension,functionName) { // purge handler function to free memory var handlers = this.handlers[extension]; if (handlers && handlers[functionName]) { delete handlers[functionName]); if (handlers.length === 0) { delete this.handlers[extension]; } } } , handle: function(path,fileDotExtension,parms,response) { // request ... // request may be url w/ query string and/or body from http request // path / uri can be normalized by replacing / with _ and // become part of the file and thus function name (for now not considered) var fileDotExtensionElements.split("."), file = fdees[0], ext = fdees[1]; var handlers = this.handlers[ext], funktion; if (handlers) { // if you do not purge handler extensions and start with set of // predefined handler extensions, then you can take this set as // the criteria to detect invalid / unimplemented extensions... // or put this instead into the stats / housekeeping / control var functionName = (file.charAt === "_") ? "_" : file; // do some defaulting: // do default _ function for files beginning w/ _, for example .jpg, etc funktion = handlers[functionName]); if (!funktion && (funktion = require(functionName + "_"+ ext + ".js")) { // function not in handler but found a module (module name syntax to be defined) this.load(ext,functionName,funktion); } } if (funktion) { // function available, finally do something... funktion(parms,....); // ...invoke (or you may also use call or apply) } else { console.log("no handler for extension " + ext + " and file " + file); // you may want to put also something on the response. } } }; // /handler
Are you also thinking of a file type / extension that can include references to other files and
is recursively interpreted (with this handler) to allow page / response composition? ...for example as a nested structure of divs of a streamed out html page?The handler as module could also have ways to go after 'load code from EPROM'. Btw, if managed code is eval-ed, it is not THAT a bad thing to do...
PS: I'm currently in a time/resource bind, otherwise the code above would be tested... ;-)
-
-
-
'screen'-scraping an html page is quite challenging, because the 'embedded' javascript dynamically changes the page content. You would only succeed by doing what a browser does... and thats a lot.
Does your embedded application/linux/computer an API that you can tap into?
From what I understand is that the embedded application/linux/computer is the vehicle to read/collect/save data from your devices, including register/config/control them. The application has a Web interface which you open in a browser and this gives you the user interface to the data and functions.
...but luckily it seems to be filled at regular intervals anyway.
This hints to me that there is some code that runs constantly/triggered on timers to collect the data and stick it into the xml file / update the xml file.
The Web app - which may just consist of some static html and some javascript - then just reads and presents the content of the xml file. This static html and some javascript is served by some (Apache) Web server. The xml is placed in a spot where the Web server has access to.
Do you have access to the Linux of this embedded computer? Scout for some apache / httpd / .cfg / ... directory / files. In the (apache/httpd) config you can find out if it is plain html or if other stuff is involved, such as server side logic executed with php modules. Server side logic is used to access files outside of the Web server's accessible directories. By changing the config you can give access to the xml file and pull it with what ever you want, such as Espruino with an XHR, and then do some processing.
There is xml to json converters in javascript that can run on Espruino to give then javascript object access to the data (trees,collections).
Javascript has its tricks up the sleeves, but approaching it with an object-oriented mind will get you quickly into some robust useful coding.
-
@DrAzzy, the milling would have to be done by the user who does not want Pico 'to stick out'. So your initial approach is the default one.
-
-
internal #NVRAM
...nice to know, just right for saving some ID / basic config / state information.
-
@Gordon, are you saying there is a lower limit for the sampling/output rate in WafeForm?
-
...where is the n in line 6 come from / defined? - I assumed this is the buffer size... (see example in post).
-
Cool mechanism this double buffering to take advantage of internal speed and 'external' coding simplicity!...
Lowering the sampling rate to give enough time to do the (filter/average) calculations would be the point. For example, a sampling rate of 128[samples] / 3[secs] = 43 [samples/sec] would deliver enough time - 3 seconds - to do the work. Depending how 'fast' temperature is changing though, only a segment of the 128 samples should then be taken... If this does not deliver enough samples, buffer size and sampling rate can to be increased proportionally.
Another solution - with high(er) sampling rate / samplings over a shorter period - for example, 0.5[secs], but allowing a longer period - for example, 5[secs] - can be achieved by option repeat:false. After processing the samples, issueing a .startInput() with a timeout will for sure prevent overruns. A third option is to put start with no-repeat into a function and invoke it on the desired interval. For example:
Every ... milliseconds, take 128 samples over a period of 0.5 seconds and average over 124 :
var samplingInterval = null; var wf = new Waveform(128,{doubleBuffer:false, bits:16}); wf.on("buffer", function(arr) { arr.sort(); var view = new Uint16Array(arr.buffer, 4, 128 - 4); console.log((E.sum(view)/65536)/view.length); }); var startSampling = function(interval) { var si = isNaN(interval) ? 5000 : (interval < 1000) ? 1000 : interval; samplingInterval = setInterval(function(){ wf.startInput(pin,256) ,{repeat:false}); },si); }; var stopSampling = function() { if (samplingInterval) { clearInterval(samplingInterval); } samplingInterval = null; };
To start the sampling, issue:
startSampling(5000);
To stop the sampling, issue:
stopSampling();
-
Space for USB - Yipes! Good catch. I just removed all the exposed ground from that 1.2" section, and slid everything over 0.1", so, if you wanted people to laugh at you, you could plug the whole damned board into your USB port (assuming it's not recessed).
Even 'it' is not recessed, usually there is other stuff connected right next to (one of the many) USB(s) where you could plug it. Then for putting it into a box or somewhere else, Pico's USB will stick out and make a waste of space for the rest of the board.
Acknowledged, it is not easy to meet all 'requirements'... could you think moving it and allow a breaking(cut)-0ut/away the area that a USB B connector would need when Pico is soldered to the board? - Yes, there would be some loss of prototype area / wholes, but in the end it would give a nice shaped overall boundary.
Just had the idea to provide two rows of the .5" places... they way the current layout shows, and another one inset for when Pico's USB 'tongue'-tip is flush with the board...
-
I see your point! Going instant into a place, (additional) cables are not an option... so you need reliable communication. Setting up your own access point(s) and networks is the way to go. Did you ever think of directed micro-waves? So you could place the access points even away and have robust / solid connectivity... Yo can go directed because things do not move anymore after setup. I'm thinking about little - micro - mirrors / yagis... ;-)
Thanks for the pic... it just passes on a lot of context.
-
Going wifi / bluetooth in a 'public environment with lots of people' needs some special measures to stay all times in (timely) control of your equipment... I just recently observed the updating of a decent sized 'room' with very modern (digital) audio equipment, and it's all cables, even the control. Only a few hand and head microphones are wireless...
There are options to access the digitized mixer - a Linux hosted application running audio dedicated hardware - but for stability purposes, it has not happened yet.
-
IDE is (still) responsive, and so so is Espruino. But:
It looks like that your code makes Espruino so busy, that only little is left to answer your terminal input. Try to time a single run. It will tell you whether 3 seconds are enough to take the readings, process them, and display the consolidated value on your display. Just for the sake of this theory, choose 10 seconds (10000 ms), and watch the terminal interaction behavior then.
You can visualize how busy Espruino is by putting LED3.set() as your first expression in your MedianRead() function, and LED3.reset() as your last. If the LED3 is on (for you eye) all the time, 3 seconds is not enough to go through with all your code.
-
-
@d0773d, @Gordon just most recently made .bind() work / implemented... see this conversation. Now you do not need the application defined anonymous function anymore, and the .bind() is more efficient in all ways.
-
@Gordon, thanks for the comparison of .bind() vs anonymous function in app.
@DrAzzy, eval() has the smell of a Trojan Horse... Any option to avoid it is useful... Since you do not 'grow' - increase the functionality - of the code, think of your 'pre-defined source code expressions' as prebuilt functions... held in an arrays and object properties (just as you already hold the expressions now).
You can then even think of a plug-in mechanism: pairs of voice recognizable commands and execution functions... a cool thing... (and I guess, will in the end also having this thing talking back to you... audibly...)
Since a while I have on my desk laying around some external audio player modules that I wanted to connect, but I'm bound into something else right now. = I know that Espruino can play wave forms and do that too, but I want offload that part.
-
-
-
Btw, code in post #20 has to be changed to make proper direction changes in all step phases.
Current code has a step sequence discontinuity / hick-up when changing direction in lines 36 and 43.
After issuing a stop, there is also a small issue: if stopping in an 'instable' step phase - where two magnetic fields 'fight' for the rotor and move the rotor between the fighting poles - it may come to rest in either pole position - back or forward after digitalWrite of 0b000 / taking the power off. To compensate for that when continuing, power with the same last step phase has to be applied before moving on... - of course for the proper amount of time. Implementation depends on whether the setInterval(...) invokes the function the first time at beginning or end of the first interval, which I do not know.
Simplest resolution is to remove the stop() in the direction change, change the stop, and - most important - change the sequence in the backward steps sequence and adjust the step adjustment in direction change.
This are the 4 changed lines:
16.
var stBW = [0b1001,0b0001,0b0011,0b0010,0b0110,0b0100,0b1100,0b1000];
36.
} else { if (stT) { st = Math.abs(st - 7); } if (!stI) { st--; } setI((stT = t),stFW," FW"); }
43.
} else { if (stT) { st = Math.abs(st - 7); } if (!stI) { st--; } setI(-(stT = t),stBW," BW"); }
49.
if (stI) { stI = clearInterval(stI); stI = null; }
Resulting code:
// stPs stepper pins // st step 0..8 // stT step Time in milliseconds [ms] // stI step Interval (from setInterval() and for clearInterval() // sts steps 0001,0011,0010,... pin signals // stBW sts - steps Backwards // stFW sts - steps Forward // dmy ...because of (cond) ? exprT : exprF needs something to assign to var run = false; var st = 0; var stT = 0; var stI = null; var sts = null; var stSt = 0b0000; var stFW = [0b1000,0b1100,0b0100,0b0110,0b0010,0b0011,0b0001,0b1001]; var stBW = [0b1001,0b0001,0b0011,0b0010,0b0110,0b0100,0b1100,0b1000]; var stPs = [C6,C7,C8,C9]; // setI setInterval(i,stsC) i in [ms] with (optionl) step Change (if not null), // and direction info (string) var setI = function(t,stsN,d) { console.log("t = ",t, d); if (stI) clearInterval(stI); if (stsN) sts = stsN; run = true; stI = setInterval(stp,t); }; // stp step var stp = function() { digitalWrite(stPs, sts[st = ++st % 8]); }; // _sFW step ForWard var _sFW = function(t) { console.log("FW w/ " + t); if (stT > 0) { setI((stT = t),null," ~F"); } else { if (stT) { st = Math.abs(st - 7); } if (!stI) { st--; } setI((stT = t),stFW," FW"); } }; // _sBW step BackWards var _sBW = function(t) { console.log("BW w/ " + t); if (stT < 0) { setI(-(stT = t),null," ~B"); } else { if (stT) { st = Math.abs(st - 7); } if (!stI) { st--; } setI(-(stT = t),stBW," BW"); } }; // stop var stop = function() { console.log("stop"); if (stI) { stI = clearInterval(stI); stI = null; } console.log(stI); run = false; digitalWrite(stPs, stSt); }; // run function - t is stepping interval in [ms] var r = function(t) { if (typeof t === "undefined" ) { if (stT) { console.log((stT > 0) ? "F>B" : "B>F"); r(-stT); } else { console.log("What ?"); } } else { dmy = (t) ? (t>0) ? _sFW(t) : _sBW(t) : stop(); } };
-
There is currently a conversation going in that respect - Serial.on() issues - which is actually more a about this, context classes, objects (instances of classes), functions, methods, callbacks, etc.
Javascript has a bit a quirky looking way of instantiating an object from a given class: issuing
var inst1 = new MyFunction()
makesMyFunction()
a class definition - or constructor function - that defines - and constructs - (usally the state of) an object - hence the convention of starting Uppercase. Issuing it a second timevar inst2 = new MyFunction()
creates actually a second, different instance - but with the same properties - state (and behavior).Invoking a capability, function, or behavior of that class of objects is then more suitably called invoking a method. Defining methods (behavior) is done by assigning functions to the prototype of the (state) defining function.
To make it more obvious, lets, call the "MyFunction" a "Person", and provide it with a name 'when born' / created / instantiated:
var Person = function(name) { this.name = name; };
Now we provide a behavior to the Person - class of instances:
Person.prototype.introduceYourself = function() { console.log("Hi, my name is " + this.name); };
Creating susan and mark and ask them to introduce themselves would then go like this - notice the 'politically not so correct all lower case beginning, but convention complying useful distinction of instance vs. class casing:
var susan = new Person("Susan"); var mark = new Person("Mark"); susan.introduceYourself(); // ---> console shows: Hallo, my name is Susan mark.introduceYourself(); // ---> console shows: Hallo, my name is Mark
Note that we had to make the definition only once as a class, but get multiple instances with same state - .name - and behavior - .introducesYourself().
Unfortunately, the way (most) modules are built and used is the way of singleton. Singleton means: there can exists only / exactly (math.) one instance of that class (so not really a class, because what is a class with one member...). Bit what do you do when you have multiple sensors, and the sensor is made available / connectable via a module that is thinking 'in singleton' (only)?
Sometimes, you get away by storing the module in a variable and invoke it several times with connect. This works though only when the module is built in a particular way and returning the instance from the constructor function. (Depending how the require("moduleName") is implemented (with or without caching), instead of storing the module reference in a variable, you just repeat the require(...) with no significant performance penalty.)
You can instantiate objects within other object instantiations... nothing wrong with that. It just creates dependencies - which you may have anyway. A less intertwined approach would be to create the containing object with null values for the contained objects first, and then assign the object instance to in a separate step, where you compose the complete containing object (or you go very sophisticated and use a micro / pico container supporting IoC / DI ... pico has nothing to do with Espruino Pico except that it is a smaller version of a bigger thing...)
In order to access properties - state and behavior - of a contained object, you can call the objects nested -
containingObj.containedObj1.getTemperature();
- which is not the best from an oo point of view. You rather add a facade or delegate method.getTemperature()
- ContainingObj.prototype.getTemperature = function() { return this.containedObj1.getTemperature(); }; - to the containing object. With that you can hide the implementation of ContainingObj and you can change it at a later time without having to change where and how it is used (so far). -
Take a look at Photomicrosensor (Transmissive) - Omron EE-SJ5 conversation.
The difference is 'reflect' vs. 'not interrupt'. the Photomicrosensor (Transmissive) - Omron EE-SJ5 has the receiving phototransistor opposite of the infrared emitting diode. Something (blocking) in between stops the phototransistor from 'conducting' / to switch off, where - in your case - something reflecting will make it to conduct / to switch on.
Using the analog read is a good idea to measure the amount of reflection... most phototransistors have though a more switching behavior than (linear) amplifying one. I used the analog read to figure out what is going on, because I had some strange behavior with a material I expected to block the infrared light. The material looked very blocking to my naked eye, but it was not blockin infrared. Weird... that's all what I can say, since did not do more research on that particular material.
As @Gordon mentioned - with the digital ready, you could eliminate the external resistor that I use in my circuitry:
pinMode(pin,"input_pulldown");
. Unfortunately, with the analog read, internal pull up/down is not possible. So you need an external resistor.To drive the infrared LED, you still need an external resistor to limit the current (and give the LED a life) - if the LED has not a built-in resistor.
-
Thinking through what an implementation of getPrototypeOf() or getClass() (='the function object') could entail, it may not be easily done... Shims or fillins do that by creating an extra instance variable and assign the constructor function - or class (function). Since it is in the constructor itself, it is nothing wrong to 'globally' reference it in there. Taking the same approach for referencing the constructor function - self in itself - and use the (now) available .bind(), simplifies above approach to this:
function EasyVR(...) { ... this.ser.on('data',EasyVR.prototype.onWatch.bind(this)); ... }
@DrAzzy, renaming onWatch (vs. onTimeout) to onData would go in synch with serial.onData()... ;-)
-
With the newly implemented bind and the just to implement
Object.getPrototypeOf()
- as many Javascript engines implement - including IE9+'s - the_this
orthat
can be eliminated - including the more serious issue of having a global reference to evr (which locks the application down to a given variable name, like a reserved word...).this.ser.on('data',Object.getPrototypeOf(this).onWatch.bind(this));
@Gordon, if there are a few bytes left to be 'wasted' on Object.getPrototypeOf(object), that would be cool too.
@Gordon - sorry, again - from your knowledge of the internals of the bind() implementation, what is the memory footprint compared to creating an anonymous function instead? MSDN describes bind() as creating a function with same body on the bound object...
@DrAzzy, is that the requirement?