-
• #2
There is no such thing as a generic wait function. If you have done something and you want to wait for example for a minute before doing something else or resuming, you use the setTimeout(function,timeout) function.
This has though some impact in how you break up your code into function. I assume you want to do something like that - in pseudo code:
myfunction() - definition: - do thing A(); - wait(1 minute); - do thing B(); ... myfunction() - invocation
The myfunction() construct has to be broken up into two pieces(*):
var myfunctionPartA = function() { code that does the A()-thing setTimeout(function(){ myfunctionPartB(); },60000); // after 60 secs invoke ...partB }; var myfunctionPartB = function() { code that does the B()-thing }; myfunctionPartA(); // invocation
In case you have first to do something A(), then do something else and repeat it every minute until a condition is met, and then - finally - something B(), the construction looks like this:
var myfunction = function() { code do the A()-thing; myfunctionRepeatPart(); }; var myfunctionRepeatPart = function() { code that does the repeat thing; if (conditionNotMetYet) { setTimeout(function(){ myfunctionRepeatPart(); },60000); // after 60 secs invoke repeat-thing again } else { code that does the B()-thing } }; myfunction(); // invocation
-
• #3
There's setTimeout, and there is also digitalPulse which can be used to send carefully timed pulses.
An actual delay function isn't implemented because it encourages you to write code that causes problems for Espruino. As Espruino doesn't have preemptive multitasking, other tasks cannot execute until the current task has finished. If you make your current task take a long time to execute then it will probably cause problems for other tasks - if serial data or pin changes can't be processed in a sensible time period, the input buffers might overflow and data will be lost.
You can still delay your code quite easily (
var t=getTime()+1000;while(getTime()<t);
), but you should seriously consider re-writing your code to use setTimeout and/or digitalPulse - the end result will be a much faster, more efficient piece of code.If you tell us what you want to do, we can maybe suggest a way of doing it?
-
• #4
What I am attempting to do is write a function to handle the "i2c read request" for all of the sensor modules; I would also like to repeat the "all the sensor readings" every 5 seconds or possibly longer than 5 seconds.
Depending on what command I send to the module indicates how long I should wait in milliseconds. For example if I send the "R" command, I am required to wait 1second or 1000milliseconds to invoke the I2C1.readFrom function. Most of the other commands that I send only require that I wait a total of 300milliseconds before I invoke the I2C1.readFrom function. This just insures that I give the sensor modules enough time to calculate the results before I readFrom the sensor module.
I am not sure If i should write multiple functions for the different sensors(ph, ec, temp) or just write one function to read from them all? So far I started to write a function before I asked this question to read from them all, but only started with the ph sensor as I would like to get something working and then branch off from there.
Code:
function getphi2cData(phi2c) { var data = I2C1.readFrom(phi2c); var toChar=""; var i; for(i=0; i<d.length; i++) { toChar += String.fromCharCode(d[i]); if(i==(d.length-1)) { console.log(toChar); toChar=""; } } } function geteci2cData(eci2c) { } function geti2cData(phi2c, eci2c) { I2C1.writeTo(phi2c, "R,25.3"); setTimeout(function (e) { getphi2cData(phi2c); }, 1000); //setTimeout(function (e) { geteci2cData(eci2c); }, 1000); }
I remed out the geteci2cData(eci2c) function because I wasn't sure if that would execute before the getphi2cData(phi2c) finished processing the data. However, I think I should be ok because as Gordon mentioned, "other tasks cannot execute until the current task has finished."?
-
• #5
setTimeout() is what you want - that way, you can have it doing other things during that 1 second, like reading other sensors, updating an LCD, etc.
Your code is structured right, I see two issues keeping it from working:
I2C.readFrom() needs a second argument specifying how many bytes to read.
Data is read into variable 'data' on line 2, but call same variable 'd' on lines 6 and 9. -
• #6
Data is read into variable 'data' on line 2, but call same variable 'd' on lines 6 and 9.
And that explaines why I keep getting the error message that d is undefined. Thank you, for pointing that out!
-
• #7
I'd keep a table of profiles of all sensors. A profile includes all the sensor specifics, including what the callback(s)/callback chain is(are) for processing of the read data. At the end of the processing of an individual event, I would calculate next setTimeout() based on the running time and the reading schedule. With calculated timeout time closing in on 0 - and setBusyIndicator(LED#) #=1..3 in the code - you can figure out how busy you can define your schedule and whether your system 'is getting late' or you have still cycles in reserve.
-
• #8
@allObjects So far I have:
I2C1.setup({scl:b6, sda:b7}); function Sensor (theType, theAddress) { this.type = theType; //i.e. PH this.address = theAddress; //i2c Address this.sensorResult = 0; //Store sensor result this.cmdTable = { 'Calibrate' : { //List of Calibration commands and timeout value. "clear" : { "cmd" : "Cal,Clear", "wait" : 300 }, "mid" : { "cmd" : "Cal,mid,7.00", "wait" : 1300 }, "low" : { "cmd" : "Cal,low,4.00", "wait" : 1300 }, "high" : { "cmd" : "Cal,high,10.00", "wait" : 1300 }, "query" : { "cmd" : "Cal,?", "wait" : 300 } }, 'Information' : { //Device Information }, 'LED' : { //Enable / Disable or Query the LEDs "L0" : { "cmd" : "L,0", "wait" : 300 }, "L1" : { "cmd" : "L,1", "wait" : 300 }, "L?" : { "cmd" : "L,?", "wait" : 300 } }, 'Reading' : { //Takes a single reading "R" : { "cmd" : "R,?", "wait" : 1000 } //Takes a single temperature compensated reading }, 'Serial' : { //Switch back to UART mode }, 'Sleep' : { //Enter low power sleep mode }, 'Status' : { //Retrieve status information }, 'Temperature' : { //Set or Query the temperature compensation "T" : { "cmd" : "T,19.5", "wait" : 300 }, //Where the temperature is any value; floating point, or int, in ASCII form "T?" : { "cmd" : "T,?", "wait" : 300 } //Query the set temerature }, 'Factory' : { //Factory reset }, }; } Sensor.prototype = { constructor: Sensor, getSensorType:function () { return this.type; //Get Sensor type }, getSensorAddress:function () { return this.address; //Get Sensor address }, getSensorResult:function () { //I2C1.read }, storeSensorResult:function () { }, updateResTemp:function (temp) { var reading = cmdTable.Reading.R.cmd; reading = "R," + temp; Console.log(reading); } }; var ph = new Sensor("ph", 0x63); ph.updateResTemp(90.5);
Is that what you are refering too? I am new to Javascript objects and etc... For example, in order for me to get the sensor result I would invoke getSensorResult and grab the values from the cooresponding Sensor object and setTimeout to whatever the wait value is of the specific cmd?
Also, to take a Reading in i2c I am required to pass the temperature along with the R to get a temperature compensated result. I have the default command as R,19.5. How would I update the cmd to the newely taken temperature value? I tried to change the value and I receive the following error:
Uncaught Error: Field or method does not already exist, and can't
create it on undefined at line 2 col 27var reading = cmdTable.Reading.R.cmd; e ^ in function "updateResTemp" called rom line 1 col 22
ph.updateResTemp(90.5);
I fixed the error
new and complete code:I2C1.setup({scl:b6, sda:b7}); function Sensor (theType, theAddress) { this.type = theType; //i.e. PH this.address = theAddress; //i2c Address this.sensorResult = 0; //Store sensor result this.cmdTable = { "Calibrate" : { //List of Calibration commands and timeout value. "clear" : { "cmd" : "Cal,Clear", "wait" : 300 }, "mid" : { "cmd" : "Cal,mid,7.00", "wait" : 1300 }, "low" : { "cmd" : "Cal,low,4.00", "wait" : 1300 }, "high" : { "cmd" : "Cal,high,10.00", "wait" : 1300 }, "query" : { "cmd" : "Cal,?", "wait" : 300 } }, "Information" : { //Device Information }, "LED" : { //Enable / Disable or Query the LEDs "L0" : { "cmd" : "L,0", "wait" : 300 }, "L1" : { "cmd" : "L,1", "wait" : 300 }, "L?" : { "cmd" : "L,?", "wait" : 300 } }, "Reading" : { //Takes a single reading "R" : { "cmd" : "R,?", "wait" : 1000 } //Takes a single temperature compensated reading }, "Serial" : { //Switch back to UART mode }, "Sleep" : { //Enter low power sleep mode }, "Status" : { //Retrieve status information }, "Temperature" : { //Set or Query the temperature compensation "T" : { "cmd" : "T,19.5", "wait" : 300 }, //Where the temperature is any value; floating point, or int, in ASCII form "T?" : { "cmd" : "T,?", "wait" : 300 } //Query the set temerature }, "Factory" : { //Factory reset }, }; } Sensor.prototype = { constructor: Sensor, getSensorType:function () { return this.type; //Get Sensor type }, getSensorAddress:function () { return this.address; //Get Sensor address }, getSensorResult:function () { //I2C1.read }, storeSensorResult:function () { }, updateResTemp:function (temp) { console.log("Before: " + this.cmdTable.Reading.R.cmd); //reading; //reading = "R," + temp; //Console.log(reading); this.cmdTable.Reading.R.cmd = "R," + temp; console.log("After: " + this.cmdTable.Reading.R.cmd); } }; var ph = new Sensor("ph", 0x63); ph.updateResTemp(90.5);
-
• #9
Following the thread of thought I read from your code is that after each command you have to wait a certain time until you can issue the next command or continue with the calculation. For example:
A) for a calibrate-clear command you send "Cal,Clear" and then you have to wait 300 [ms] before you can continue. Is that correct? If so, what is the command that has to follow this calibrate-clear command? ...or what is the process/calculation/function that would follow this or any of these commands?
May be you describe me in simple use case(s) what the system will do. To be of more concrete help, I read up on all your posts to get an overall understanding. What I understand so far is that you have the following system and process: The system[Sys] reads[read] temperatures[temp] with temperature sensors[Tempsensor], ph values[ph] with ph sensors, etc. The readings[tmp,ph,etc.] are then somehow displayed, transmitted, or made available otherwise for user or other system consummation. Reading and follow up processing are repeated based on some kind of schedule.
-
• #10
@allObjects I appologize for not explaining myself.
For example I execute:
I2C1.writeTo(0x63, "R,25.3");
That tells the ph sensor to calculate the ph at the temp 25.3C. The ph sensor will take 1 second to calculate the ph, therefor, I will be required to wait 1 second before executing:
I2C1.readFrom(0x63, 7);
So depending on the specific command that i invoke will be require to wait what ever the wait value is before I readFrom the sensor. I hope I did a better job at explaining...
When you said:
What I understand so far is that you have the following system and
process: The system[Sys] reads[read] temperatures[temp] with
temperature sensors[Tempsensor], ph values[ph] with ph sensors, etc.
The readings[tmp,ph,etc.] are then somehow displayed, transmitted, or
made available otherwise for user or other system consummation.
Reading and follow up processing are repeated based on some kind of
schedule.Yes, I am gathering all the sensor data and will eventually send all the calculations to my Intel Edison using UART communication; also out put all the values to 4x 4digit 7-segment displays.
Maybe a better example? :
Sensor.prototype = { constructor: Sensor, getSensorType:function () { return this.type; //Get Sensor type }, getSensorAddress:function () { return this.address; //Get Sensor address }, getSensorReading:function() { a = this.getSensorAddress; d = I2C1.readFrom(a, 7); return d; }, getSensorResult:function () { var a = this.getSensorAddress; var c = this.cmdTable.Reading.R.cmd; var w = this.cmdTable.Reading.R.wait; var that = this; I2C1.writeTo(a, c); setTimeout(function (e) { that.getSensorReading(); }, w); }, storeSensorResult:function () { }, updateResTemp:function (temp) { console.log("Before: " + this.cmdTable.Reading.R.cmd); this.cmdTable.Reading.R.cmd = "R," + temp; console.log("After: " + this.cmdTable.Reading.R.cmd); } }; var ph = new Sensor("ph", 0x63); ph.updateResTemp(90.5); ph.getSensorResult();
That last example doesn't exactly work. I receive the error:
Uncaught Error: Function "getSensorReading" not found! at line 1 col 8 { this.getSensorReading(); } ^ in function called from system
How do I call getSensorReading() function from Sensor.prototype?
I updated my code to my working code. -
• #11
I'm still open for ideas and suggestions about my code structure.
-
• #12
The structure looks pretty tidy - although I'd really recommend doing:
Sensor.prototype.getSensorType = function ... Sensor.prototype.getSensorAddress = function ... // etc
Instead of your
Sensor.prototype = {
. It's probably more personal opinion, but it seems more pleasant than having to redefineconstructor
.You've also defined getters like
getSensorAddress
, which is fine - however you then doa = this.getSensorAddress;
. That'll return the function itself, rather than executing it and getting the result... You might also want to put avar
beforea
, soa
isn't defined as a global variable.In your code
getSensorResult
returns immediately, so while you get a value ingetSensorReading
you're not actually returning it. For that, you'd need to use a callback:getSensorResult:function (callback) { // ... setTimeout(function (e) { callback(that.getSensorReading()); }, w); },
Then you can use it with:
ph.getSensorResult(function(value) { console.log(value); });
Hope that helps!
-
• #13
Hi @Gordon The reason why I chose
Sensor.prototype = {
was, at the time, I didn't care for the repetitiveness of writingSensor.prototype.
However, thats nothing that copy and paste can't fix :). As you recommended, I switched toSensor.prototype.getSensorType = function
. I can appreciate the readability and the code seems to flow a little better and makes sense to me. -
• #14
@d0773d, np - it explains all well in your world... and over time I may know enough about it to come up with some abstraction of the real world into a model expressed in algorithms and data structures.
How would I update the cmd to the newly taken temperature value?
This - taken from a previous post - means, that temperature and ph sensors are paired. For each pair, you read a temperature first, then you ask the ph sensor to calculate the temperature compensated ph value, and then you read it, then you display it and/or send it to some place.
-
• #15
@d0773d, when you say:
Sensor.prototype.getSensorAddress = function() {...};
you add a function property to the prototype object of Sensor.
When you say:
Sensor.prototype = { getSensorAddress: function() {.....},..... };
your replace the existing prototype object with a new one (and loose
the previous one).When you do not want to repeat the assignment 'explicitly', you can use the following code:
var obj; for ( propName in (obj = { getSensorAddress: function() {.....} , getSensorType: function() {.....} , ..... })) Sensor.prototype[propName] = obj[propName];
This is mixing one object's properties into another one.
Btw, this 'mixing' shows you how you can dynamically access value and function properties of an object. Assume you have an object with two function properties (methods) f1 and f2.
var obj = { f1: function(){.....}, f2:function(){.....} };
The following three lines invoke all f2 method of obj object, of which the last one makes is dynamically by the fx variable:
obj.f2(); obj["f2"](); var fx = "f2"; obj[fx]();
-
• #16
@Gordon Its been 4 months since I did anything with my project. My computer crashed and I lost all of my code referring to this post. I copied and pasted my code from this post and tried to implement your suggestions again.
I am trying to pass in the value of this.address and execute the functions instead of returning the function it self.
However, as you explained, I am returning the function itself rather than executing it and getting the result. For example, in
Sensor.prototype.updateResTemp
console.log(a + " " + c);
returns:
function () {
return this.address; //Get Sensor address
} T,19.5Code from this thread and memory:
I2C1.setup({scl:b6, sda:b7}); function Sensor (theType, theAddress) { this.type = theType; //i.e. PH this.address = theAddress; //i2c Address this.sensorResult = 0; //Store sensor result this.cmdTable = { "Calibrate" : { //List of Calibration commands and timeout value. "clear" : { "cmd" : "Cal,Clear", "wait" : 300 }, "mid" : { "cmd" : "Cal,mid,7.00", "wait" : 1300 }, "low" : { "cmd" : "Cal,low,4.00", "wait" : 1300 }, "high" : { "cmd" : "Cal,high,10.00", "wait" : 1300 }, "query" : { "cmd" : "Cal,?", "wait" : 300 } }, "Information" : { //Device Information }, "LED" : { //Enable / Disable or Query the LEDs "L0" : { "cmd" : "L,0", "wait" : 300 }, "L1" : { "cmd" : "L,1", "wait" : 300 }, "L?" : { "cmd" : "L,?", "wait" : 300 } }, "Reading" : { //Takes a single reading "R" : { "cmd" : "R", "wait" : 1000 } //Takes a single temperature compensated reading }, "Serial" : { //Switch back to UART mode }, "Sleep" : { //Enter low power sleep mode }, "Status" : { //Retrieve status information }, "Temperature" : { //Set or Query the temperature compensation "T" : { "cmd" : "T,19.5", "wait" : 300 }, //Where the temperature is any value; floating point, or int, in ASCII form "T?" : { "cmd" : "T,?", "wait" : 300 } //Query the set temerature }, "Factory" : { //Factory reset }, }; } Sensor.prototype.getSensorType = function () { return this.type; //Get Sensor type }; Sensor.prototype.getSensorAddress = function () { return this.address; //Get Sensor address }; Sensor.prototype.getSensorReading = function() { var a = this.getSensorAddress; var d = I2C1.readFrom(a, 7); return d; }; Sensor.prototype.getSensorResult = function () { var a = this.address; var c = this.cmdTable.Reading.R.cmd; var w = this.cmdTable.Reading.R.wait; var that = this; //I2C1.writeTo(a, c); setTimeout(function (e) { callback(that.getSensorReading()); }, w); }; Sensor.prototype.storeSensorResult = function () { }; Sensor.prototype.updateResTemp = function (temp) { var a = this.getSensorAddress; var c = this.cmdTable.Temperature.T.cmd; var w = this.cmdTable.Reading.R.wait; var that = this; console.log(a + " " + c); //I2C1.writeTo(99, "T,19.5"); I2C1.writeTo(a, c); setTimeout(function (e) { that.getSensorReading(); }, w); }; var ph = new Sensor("ph", 0x63); ph.updateResTemp(90.5);
-
• #17
As far as I can tell, don't you just want to do:
var a = this.getSensorAddress();
instead of:
var a = this.getSensorAddress;
That will execute the function on
this
, returning the address itself. -
• #19
...Removed by @Gordon as double-posted at http://forum.espruino.com/conversations/330506/
-
• #20
Note: Post #19 above was started as a new thread and has a few responses there
Home Other Boards ESP8266 Sync delay like Arduino delay function built-in
-
• #21
Yes - please don't double-post, and if you have ESP8266-related questions please post them on the ESP8266 forum.
But to reiterate, not having a
delay()
function was a very conscious decision, because it encourages coding practices that are likely to cause problems exactly like you experienced. If it existed then C developers would just use it without thinking, and would miss out on a lot of Espruino's benefits.
Is there a generic wait function i.e. wait(milliseconds)? Or is there only: function setInterval(function, timeout)
And
function setTimeout(function, timeout)