Your Universal Remote Control Center
RemoteCentral.com
Philips Pronto Professional Forum - View Post
Previous section Next section Up level
Up level
The following page was printed from RemoteCentral.com:

Login:
Pass:
 
 

Topic:
eval() and InteractiveTCPClient
This thread has 9 replies. Displaying all posts.
Post 1 made on Sunday September 12, 2010 at 14:37
marco0305
Long Time Member
Joined:
Posts:
February 2009
19
Hi,
I'm trying to write myself a Denon module. I know there're several around but I like to make my own.
I read the very interesting post from Lyndel about task based and module based.
So I started using the InteractiveTCPClient from Philips as a start. It does send the commands and receives the feedback. So I declared the var denonTCPClient in the activity level. I also do the parsing in the activity level. The init commands like PW? get sent in the pages so it displays the correct info on first show.
I've created a RESOURCES page with some labels. The labels carry the prontoscript for power on/off. This I do because I want to use them when I launch an activity like watchTV. So I call the script in the home page using eval().
Unfortunatly the variable DenonTCPClient is unknown so it throws an error saying the var is undefined. I think this is normal because the variable only gets declared in the activity script.
Any suggestions on how to get around this?
Post 2 made on Sunday September 12, 2010 at 15:30
buzz
Super Member
Joined:
Posts:
May 2003
4,376
marco0305,

Everything must be loaded, declared, and initialized in each activity. For reusable code, you'll need to use eval(), include(), or libraries in each activity. Use setGlobal() and getGlobal() for saving any values that must survive loading (or reloading) an activity.

The home activity will always be executed after a reboot or fresh download. getGlobal() will return null if the global is not yet defined. You can use this to conditionally set up your globals.
OP | Post 3 made on Sunday September 12, 2010 at 16:05
marco0305
Long Time Member
Joined:
Posts:
February 2009
19
Hi Buzz,

Thanks for the info but the problem is that I made a Denon module(very basic for now)with the InteractiveTCPClient. In the activity I declare a variable called DenonAVCClient = new com.philips.InteractiveTCPClient(ParseData,HandleError,"\r",'IP',23,3). I can only do this in the activity because it calls for the function ParseData. I can declare the variable as a global variable but I can't call for the function. I believe!
So in the denon module I created a Resources page with some labels and call them from the home page. Unfortunatly the variable DenonAVCClient isn't initialised since it doesn't go through the activity script to initialise the variable.
So is there a way to make the variable a global variable so I can call it from within any activity?
Post 4 made on Sunday September 12, 2010 at 16:38
buzz
Super Member
Joined:
Posts:
May 2003
4,376
marco0305,

Object scope begins and ends in an activity. setGlobal() and getGlobal() are the only items that survive. You'll need an activity entrance and exit block to save and restore anything that you need to retain across activity boundaries.

By the way, eval() executes the code in the current activity's scope, not the activity where the string is defined. The target of the eval() is simply a string.
Post 5 made on Sunday September 12, 2010 at 17:02
sWORDs
Long Time Member
Joined:
Posts:
November 2006
373
Why would you use the TCPClient? For single remote operation you could leave the socket open. I do something like this:

        var self = this;
        this.ip = a;
        this.Command = function(a){
            self.socket.write(a + "\r");
        };
        this.Command.Power = {};
        this.Command.Power.On = function(){
            self.Command("PWON");
        };
        this.Command.Power.Off = function(){
            self.Command("PWSTANDBY");
        };
        this.Command.Power.GetStatus = function(){
            self.Command("PW?");
        };
        this.Command.Power.Status = "";
        this.socket = new TCPSocket(false);
        this.socket.connect(self.ip, 23, 3000);
        this.socket.Reconnect = function(){
            self.socket = new TCPSocket(false);
            self.socket.connect(self.ip, 23, 3000);
        };
        this.socket.onIOError = function(){
            Activity.scheduleAfter(5000, self.socket.Reconnect);
        };
        this.socket.onClose = function(){
            Activity.scheduleAfter(5000, self.socket.Reconnect);
        };
        this.Poll = function(){
            if (self.socket.connected === true) {
                self.Command.Power.GetStatus();
                System.delay(10);
                self.Command.ZoneMain.Source.GetStatus();
                System.delay(10);
                self.Command.ZoneMain.Volume.GetStatus();
                System.delay(10);
                self.Command.ZoneMain.SurroundMode.GetStatus();
                System.delay(10);
                self.Command.ZoneMain.Mute.GetStatus();
                System.delay(10);
                self.Command.RoomEQ.GetStatus();
                System.delay(10);
            }
            else {
                Activity.scheduleAfter(1000, self.Poll);
            }
        };
        this.socket.onData = function(){
            a = self.socket.read();
            var b = a.split("\r");
            for (var i = 0; i < b.length; i++) {
                switch (b[i].substr(0, 2)) {
                    case "MV":
                        if (b[i].substr(0, 3) !== "MVM") {
                            self.Command.ZoneMain.Volume.Status = self.parseVolume(b[i]);
                        }
                        break;
                    case "MS":
                        self.Command.ZoneMain.SurroundMode.Status = self.parseSurround(b[i]);
                        break;
                    case "MU":
                        self.Command.ZoneMain.Mute.Status = self.parseMute(b[i]);
                        break;
                    case "PW":
                        self.Command.Power.Status = self.parsePower(b[i]);
                        break;
                    case "SI":
                        self.Command.ZoneMain.Source.Status = self.parseInput(b[i]);
                        break;
                    case "PS":
                        self.Command.RoomEQ.Status = self.parseRoomEQ(b[i]);
                        break;
                }
            }
            self.UpdateGUI();
        };


This code needed some rewrite. Socket re-use is not recommended like this and the code is faster in object style (like: this.Action={act1:function(){self.Command("Action1");},act2:function(){self.Command("Action2");}};) .

Last edited by sWORDs on September 12, 2010 17:12.
Post 6 made on Sunday September 12, 2010 at 20:10
Lyndel McGee
RC Moderator
Joined:
Posts:
August 2001
12,996
Declare the variable at activity level, then you can reference it anywhere in eval().

To make things work properly, you may need to scope the eval to something other than the 'global' scope. For example:

CF.activity().eval(mycodestring);
or
this.eval(mycodestring); // from the activity level.

vs just the simple

eval();
Lyndel McGee
Philips Pronto Addict/Beta Tester
Post 7 made on Sunday September 12, 2010 at 20:19
Lyndel McGee
RC Moderator
Joined:
Posts:
August 2001
12,996
On September 12, 2010 at 16:38, buzz said...
marco0305,

By the way, eval() executes the code in the current activity's scope, not the activity where the string is defined. The target of the eval() is simply a string.

Buzz,

A simple eval() does behave like this. However, not publicly documented, you can control the scope by calling the eval() function in context of a particular object. For example... CF.page().eval() or CF.activity().eval() or widget().eval() as I posted above.
Lyndel McGee
Philips Pronto Addict/Beta Tester
Post 8 made on Sunday September 12, 2010 at 21:25
buzz
Super Member
Joined:
Posts:
May 2003
4,376
Lyndel McGee,

That's interesting. I'm not sure that I want to use private features because they can come and go a little easier than published features.

Isn't the construct CF.activity().eval(myString) just another way of referencing the string to be evaluated? The scope of any objects created or referenced during evaluation would still remain within the current activity.

This could be convenient for the same code replicated on multiple pages and activities or deadly in the case of recursive eval()'s gone wild.
OP | Post 9 made on Monday September 13, 2010 at 13:14
marco0305
Long Time Member
Joined:
Posts:
February 2009
19
Hi Lyndel,

So I created on the home page a button with the following script
CF.activity("DENON TCP").eval(DenonTCPClient.execute("ZMOFF\r"));
The variable DenonTCPClient is declared in the activity DENON TCP. The buttons in the activity on page level use the same command, DenonTCPClient.execute("ZMOFF\r") and the command gets executed. Unfortunatly this doesn't work from within an other activity!
Do I get it wrong?
Can you just get me back on track?
Post 10 made on Monday September 13, 2010 at 17:03
Lyndel McGee
RC Moderator
Joined:
Posts:
August 2001
12,996
Marco,

The parameter to eval() must be a string, not a call to a function which is what you are doing.

DenonTCPClient.execute("ZMOFF\r")

In short, you put common code as a string (Panel label) and then eval() the contents of the panel label in the activity where you need to run the code. You cannot, for example, share a socket or an instance of your DenonTCPClient across multiple activities. Upon entry into each activity, you would need to create an instance of the DenonTCPClient. This could be done by defining your class and putting the definition code into a panel label and then ....

// forward declaration of the class you will be filling out in eval()
var DenonTCPClient;

// load the class definition from the panel label.
CF.activity.eval(CF.widget('DENON_CLASS', 'SCRIPTS', 'DENON_CORE_ACTIVITY').label);

// create an instance using class just loaded.
var myInstance = new DenonTCPClient();
// startup the instance.
myInstance.connect("127.0.0.1",3000);

@Buzz,

Yes, CF.activity().eval() is same as eval() or this.eval() if the statement is called from within the activity script.

And yes, you can do evals from different scopes and it is supported by Spidermonkey and is simply a side-effect of calling a function from within the current scope, Philips does not control this and therefore will never restrict it.

The use of eval() as such is an advanced topic and you really need to know and understand what is going behind the scenes and the ramifications that follow.

CF.page().eval() will evaluate the script in the context of the page scope which is a child of the activity scope. And therefore, variable shadowing could/would occur. Note that the eval() cannot declare any variables and have them persist upon return. However, if a variable is declared prior to execution of eval(), the string that is evaluated CAN modify the variable. That's why the var declaration of DenonTCPClient class above is required prior to calling eval.

However, the last statement evaluated is returned from a call to eval so, you could do something like.

// Example loading a class from a panel label and then instantiating an instance of said class in an activity.

// Panel label text Prontoscript name is 'MY_CLASS' on Page 'SCRIPTS', activity 'ACTIVITY_CLASSES'.
// A simple constructor function.
function MyClass(x)
{
this.text = x;
}
// a prototypical function.
MyClass.prototype.sayHello() = function()
{
System.print("Hello " + this.text);
}
// last statement executed is what is returned.
MyClass;
// End of Panel label.

// Now, in activity script, do the following. eval returns actual class and eliminates need to declare MyClass as forward declaration from previous example.

var renamedClass = CF.activity().eval(CF.widget('MY_CLASS', 'SCRIPTS', 'ACTIVITY_CLASSES').label);
var y = new renamedClass('Lyndel');
y.sayHello();
System.print(y.constructor.toSource());
// above line prints original function source with name === 'MyClass'.
Lyndel McGee
Philips Pronto Addict/Beta Tester


Jump to


Protected Feature Before you can reply to a message...
You must first register for a Remote Central user account - it's fast and free! Or, if you already have an account, please login now.

Please read the following: Unsolicited commercial advertisements are absolutely not permitted on this forum. Other private buy & sell messages should be posted to our Marketplace. For information on how to advertise your service or product click here. Remote Central reserves the right to remove or modify any post that is deemed inappropriate.

Hosting Services by ipHouse