Accessing a method's Return Value
JeremyJ
Posts: 30
I'm trying to access the return value of one of my methods in another method, but I cannot figure out how to call the return value. Here's an example:
PUB throttlePosition(statePin) : dutyCycle | throttleInput
What syntax should I use to do this? I cannot find anything in the Propeller Manual v1.0 that discusses how RValues for a certain method are accessed....
PUB throttlePosition(statePin) : dutyCycle | throttleInput
'Purpose of this code is to detect the throttle input on "statePin" and output dutyCycle value between 0-100
dira[statePin] :=0
throttleInput := ina[statePin]
IF throttleInput == 0
PUB speedControl
dira[statePin] :=0
throttleInput := ina[statePin]
IF throttleInput == 0
dutyCycle := 10
IF throttleInput == 1
dutyCycle := 90
'in this method I want to call the 'throttlePosition' method for a specific pin and access the return value, which in this case is 'dutyCycle'
What syntax should I use to do this? I cannot find anything in the Propeller Manual v1.0 that discusses how RValues for a certain method are accessed....
Comments
A derivative of what Mike showed you, if you need to access multiple variables within a PUB, change...
...so that it reads ...
...Then in your PUB speedControl you can access statePin, dutyCycle and throttleInput like this...
How can that work reliably? Aren't a methods local variables on the stack? Technically they do not exist after the method has returned and they may be overwritten by other activity before you come to use them. Or am I missing a point here?
you are correct ... "Aren't a methods local variables on the stack? Technically they do not exist after the method has returned and they may be overwritten by other activity before you come to use them." ... If you want to read the values from the PUB you need to read them when you return. They will stay intact and not be overwritten as long as you don't call another PUB.
PUB speedControl | aVariable, bVariable, cVariable
aVariable := throttlePosition(positionPin) ' where positionPin is a variable either in speedControl or globally
bVariable := aVariable[0]
cVariable := aVariable[1]
....use some method to access the individual values that were passed with the array.
That method won't work because aVariable is local to speedControl ... I say that, but there is calculated offset based on the size of PUB speedControl upon compile time.... a way around that it to find the starting address of the PUB you want to read from.... placing a return within the PUB and using the @ modifier to return the address essentially locates the offset I mentioned earlier.
Perhaps it works but it relies on a bunch of undocumented features of the Spin compiler:
1. A methods parameter(s) are passed on the stack. Not in registers for example.
2. A methods parameter(s) and local variables are laid out contiguously on the stack.
3. The stack grows upwards.
As these assumptions are undocumented it cannot be assumed that they will always work. For example if the compiler were changed.
Further, in your example you show setting a methods local var after it has returned. To what purpose? that is just now a slot on unused stack that may well be overwritten by subsequent method cals or othe stack using activity.
It would be better to do this by having the calling function opass a pointer to some of it's local variables to the method such that they are at least sure to exist when the called method returns. But even that is making some assumptions about the compiler and stack lay out.
I akin local variables within a PUB to a method very similar to how the res works in assembly language.
It's nice to have methods that are self-contained but when you start accessing these local variables from another method they are hardly self-contained anymore and I'd think using a global variable would make the program easier to read and maintain. I think using global variables would probably use less memory than using multiple local variables to store the same data.
Is there really a need for these tricks? (I do think they are cool tricks and I'm glad to learn them.)
Duane
Firstly if the way the compiler works changes with some future version (the Prop II version for example) then your code will fail in hard to figure out ways. Parallax should not be constrained to ensuring all such hacks work for all compilers forever.
Secondly you may one day change the called function, say adding or removing local vars, and then spend a lot of time wondering why your program does not work. There is nothing in the function to remind you of the dependencies you have created.
One place where this sort of trick is used to good effect is in the way Lonesock passes data in and out of his float 32 object. There it can be justified as a means of compacting code and gaining speed in a commonly used library function that is unlikely yo change much and is carefully documented.