Passing data between objects
Penguin-fach
Posts: 11
I have been working through the Propeller labs manual and a couple of other guide books but am finding the explantion of variables fragmented and poorly drawn together. I am sure that this will be basic stuff to everyone else but I am having trouble getting my head around the correct way to pass values between various objects.
Here is a stripped down example that hopefully indicates where I am at.
My top object references another object called 'Switch.spin' that will continuously scan a set of key switches and other input devices in another cog. The first method in the top object calls the start method in this second object.
Top Object
OBJ
scan : "Switch"
PUB main
scan.start
repeat
other stuff happens here
The start method in the 'Switch object' begins by launching a new cog, sets the data direction for the input keys and starts scanning and debouncing (only 1 switch here).
CON
Switch = 1
VAR
long stack[30], cog_okay,
OBJ
delay: "Timing"
PUB start
cog_okay := cognew(ScanSwitch, @stack)
PUB ScanSwitch : Run
dira[Switch]~
repeat
if ina[Switch] == 1 & Run == 0
delay.pause1ms(20)
if ina[Run_Stop_SW] == 1
Run := 1
else if ina[Run_Stop_SW] == 0 & Run == 1
delay.pause1ms(20)
if ina[Run_Stop_SW] == 0
Run := 0
My questions are these.
1. Are global variables declared in the top object accessible to any daughter objects (like 'Switch' or 'Timing')? What about the other way around: can the top object see global variables declared in daughter objects?
2. Have I correctly used the local declaration of the 'Run' variable in ScanSwitch so that the value of this variable would be visible and useable in the top object?
3. Am I correct in thinking that if Scan_Switch were a private method then access is restricted to only the local object and values cannot be passed to another object?
4. If a method were to appear as follows,
PUB ScanSwitch (pin, debounce) : Run | Temp
then am I correct in thinking that the first two values, 'pin' & 'debounce' a local vraibles that nevertheless can be passed in when the method is called, 'Run' is a local variable whose value can be passed back and Temp is a local variable only accessible to the method?
Here is a stripped down example that hopefully indicates where I am at.
My top object references another object called 'Switch.spin' that will continuously scan a set of key switches and other input devices in another cog. The first method in the top object calls the start method in this second object.
Top Object
OBJ
scan : "Switch"
PUB main
scan.start
repeat
other stuff happens here
The start method in the 'Switch object' begins by launching a new cog, sets the data direction for the input keys and starts scanning and debouncing (only 1 switch here).
CON
Switch = 1
VAR
long stack[30], cog_okay,
OBJ
delay: "Timing"
PUB start
cog_okay := cognew(ScanSwitch, @stack)
PUB ScanSwitch : Run
dira[Switch]~
repeat
if ina[Switch] == 1 & Run == 0
delay.pause1ms(20)
if ina[Run_Stop_SW] == 1
Run := 1
else if ina[Run_Stop_SW] == 0 & Run == 1
delay.pause1ms(20)
if ina[Run_Stop_SW] == 0
Run := 0
My questions are these.
1. Are global variables declared in the top object accessible to any daughter objects (like 'Switch' or 'Timing')? What about the other way around: can the top object see global variables declared in daughter objects?
2. Have I correctly used the local declaration of the 'Run' variable in ScanSwitch so that the value of this variable would be visible and useable in the top object?
3. Am I correct in thinking that if Scan_Switch were a private method then access is restricted to only the local object and values cannot be passed to another object?
4. If a method were to appear as follows,
PUB ScanSwitch (pin, debounce) : Run | Temp
then am I correct in thinking that the first two values, 'pin' & 'debounce' a local vraibles that nevertheless can be passed in when the method is called, 'Run' is a local variable whose value can be passed back and Temp is a local variable only accessible to the method?
Comments
2) No. Local variables are local. Their names are only available from within the method. They're allocated in the stack when the method is called and cease to exist when the method exits.
3) Sort of. A PRI method is known only to the object containing it.
4) Mostly. 'pin' and 'debounce' are parameters, local variables whose initial values are provided when 'ScanSwitch' is called. 'Run' is an explicit name for the return value. The default name for the return value is RESULT and it's always there whether used or not. It's initialized to zero when the method is called. If the method call is used as a function call, this value is the value of the function call when the method exits. As you mentioned, 'Temp' is local to the method.
However in my particular circumstance I have a method in child object that writes three values. Briefly my top object launches a start method from the child object which launches a new cog which then repeats a sequence of three methods. Each of these methods generates a value that needs to be accessible to the top object. I can think of a couple of ways to get around this but none of them are convenient.
So to clarify, I can pass multiple parameters from a method in the top object to a method in a child object. How do I pass multiple values back?
Regards, Simon
Another related technique is to pass the address of the first element of an array where each element of the array is a value to pass either into or out of the object. You can use 'long[ address ][ index ]' to access the index'th element of the array.
Last technique is to use the start method of the object and pass one or more addresses into the object as parameters to the start method which saves the addresses in variables within the object. The object then uses those addresses to pass information back to the caller as a 'side-effect' of the use of the object.
VariablePassingTest.spin
TopObject.spin
Where am I going wrong in my understanding?
Look at this test code I wrote for you.
You simply need to declare a hub memory variable in your Object (hub memory variables can be accessed by any cog). Then you need to share that variable using helper methods.
You can do this one of 2 ways. I have demonstrated both ways in the sample code attached to this post.
1. Top object launches a start method in a child object into a new cog.
2. New cog runs whatever processes are required (my code is grossly simplified in my original example) and return values can be passed to global vars declared in the child object.
3. Global vars declared in separate objects are not directly accessible to each other but helper methods can be used either to pass the address of the variable or pass the value itself indirectly. These helper methods do not themselves run within the new cog but are in the child object and so have direct access to the global variables in that object.
Does this sound right?
When an initial object (Master Control Progam) activates a new cog to run a new object ( Program for Cog1), I am having a tough time comprehending how to pass values from the new cog object back to the initial cog. Mike Green above was kind to provide a simple explanation along with code, but I must be pretty dense on this issue as I have tried various code lines in both the initial calling object as well as in the activated cog, but I am missing the point. The activated cog monitors a sensor that takes continuous readings and I would like to continuously update the main calling object with these readings so that calculations may be performed on them. Below are stipped down versions of these two objects. If someone would kindly insert the correct format for the calling object to receive the updated range values as well as the code to send these values I would greatly appreciate it. Thank you
I'll give this a try and post back here in a bit.
The program starts out waiting for the using to press a key.
I like to add this feature to programs which require serial input. This way I can be sure the user didn't miss any output between the time they loaded the program and the time they opened a terminal window.
The parent has four global variables.
The "childCog" variable just stores the cog number returned from the child's "Start" method. This variable is written a single time and then read each loop of the main program.
The "readFromChild" variable is only written when the user presses the "c" key. This variable is stores the value read from the child's "GetValueFromChild" method.
The address of the variable "topObjectValueA" is sent to child object as part of the "Start" method. The program offers the user the opportunity to have the child write date to either "topObjectValueA" or "topObjectValueB".
The child object increments both in internal variable "childVariable" and it also increments a long at an address provided by the parent.
If you experiment with this demo program, you'll find the code :
is very different from the following:
Do you see why? (This difference surprised me initially.)
There is usually more than one way to accomplish a task when programming. This example program uses multiple ways to retrieve data from a child object. Normally one would use just one of the techniques shown.
In my opinion the technique shown by the method "GetValue" is the technique most frequently used.
Normally one doesn't have a child object write data to a variable in the parent object unless the child object is running PASM.
Of course there are many exceptions to this general trend.
I'm attaching an archive of the parent object but I'll also post the code inline here.
Here's the child object:
The program looks more complicated than it is. Most of the code takes care of displaying the data and options for the user. Don't let the serial output section intimidate you.
Here's some example output from the program:
Let me know if you have any questions.
I'm certainly willing to help with code specific for your project but I thought I'd start out with this general code showing multiple ways of doing the same thing.
Many thanks Duane! There is certainly a lot to digest. I'l be going through it tomorrow and will let you know if any questions.
Thank you again for your great detail.
Your examples helped greatly and my application works now.
Thanks again for your kind help and offer for additional assistance!