How to test the return value of a function launched in to a new cog?
rwgast_logicdesign
Posts: 1,464
Ok im still really struggling to wrap my mind around how deal with the parallel processing paradigm, im not sure if I just havent read far enough through the spin books yet, or if I just cant get my thinking on track!! Anyways im writing a driver for the polar Heart Rate Reciver, basically the hardware just flips on hi every time time it detects a beat, very simple hardware interface.
So the first function im writing is to just wait till the sensor returns a HI, and set a variable to one. Im trying to launch part of this in a second cog which runs waitpne, then shuts down the cog when the pin is pulled hi. Basically I just want the user to be able to call a function which will return 1 if there is a heart beat detected... here is what ive written
Once I started writing the public method isSensorUp I realized I cant get the return value of waitForBeat, or at least I don't know how because it is in a new cog. My thinking would usually be to do something like,
but wont that then launch waitforbeat, in the same cog that isSensorUp is running in along with the cog that, cognew launched it in to? Maybe im just over thinking all this or something, but im getting really confused and frustrated.
So the first function im writing is to just wait till the sensor returns a HI, and set a variable to one. Im trying to launch part of this in a second cog which runs waitpne, then shuts down the cog when the pin is pulled hi. Basically I just want the user to be able to call a function which will return 1 if there is a heart beat detected... here is what ive written
{{ FILE: pHeartRateReceiver.spin This is a simple Driver interface for the Wireless Polar Heart Rate Receiver, that is supplied with the Parallax MicroMedic Kit. The Heat Rate Sensor comes with the Polar T34 Heart Rate Trasnsmitter which straps around your chest, and a small 3 pin Reciever module which is compatible with any basic servo header found on Parallax Dev Boards, a servo header is not required though. SCHEMATIC: Wireless ┌----------┐ Signal | Receiver |─────── To Ground/Vss ┌------------------┐   | Module |─────── To + 3.3v/5.0v | Transmitter Band |   | |────┐ └------------------┘   └----------┘  Propeller I/O Pin of Choice Please change receiverPIN, in CON section, to match the Propeller I/O pin wich you have connected Polar Heart Rate Reciver's signal pin too. }} CON receiverPIN = 19 'Change to Prop PIN the Polar Receivers signal line is connected too VAR LONG isBeatingSTACK[50] BYTE polarHeart_COG PUB isSensorUp | newCOG newCOG := cognew(waitForBeat, @isBeatingSTACK) PRI waitForBeat : isBeating waitpne( |< receiverPIN, |< receiverPIN, 0) isBeating := 1
Once I started writing the public method isSensorUp I realized I cant get the return value of waitForBeat, or at least I don't know how because it is in a new cog. My thinking would usually be to do something like,
if waitForBeat == 1 do something or another
but wont that then launch waitforbeat, in the same cog that isSensorUp is running in along with the cog that, cognew launched it in to? Maybe im just over thinking all this or something, but im getting really confused and frustrated.
Comments
Do you actually need to do something in a separate cog? Couldn't your main program wait for the heartbeat? Do you want to just see if a heartbeat has occurred while you're doing something else? How about if you use one of the cog counters instead? You initialize the counter's PHSx register to zero and FRQx register to 1, then set the counter into POSEDGE mode (%01010). Whenever the signal pin goes from 0 to 1, the PHSx counter will increment and your program can just check for non-zero. Look at AN001 for details. You could even see how many pulses occurred in a period of time (using CNT to tell you the elapsed time ... up to about 50 seconds).
If your code doesnt end up helping to enlighten me a little more, im just going to write everything in to a single cog and then come back to it after reading a bit more, and browsing some examples, to implement the multi tasking.
1. write the return value to the return variable
2. get the return-address
3. jump to the return-address
4. decrement stack-pointer
5. if there is an assignment of the return-value, the value of the return-variable is copied
...
The return in a function which is called via cognew would not do anything different. The only exception is, that the return-address it finds on the stack points into some ROM-code which is doing a COGSTOP.
The difference for the caller is, that there is definitely no assignment, as a cognew does not wait. But shouldn't the return-variable still be available on the stack used in cognew?
Nice investigation task ;o) ... unless someone else already knows.
Here is my test-code: Well CogOS_IO(Term) is a simple wrapper and it should be possible to simply replace it with FullDuplexSerial when adapting the start-function according to your settings.
And here is my result:
And as we can see both, the return variable named "result" AND a value set by return instruction are available after returning from the function. So, I'd consider it to being safe for the caller to simply check the stack with myStack[2] or myStack[3] after termination of the SPIN-COG, as the caller should be the real master of the stack. These longs could safely be used as a message-box as well.
hm. Interesting. But why is there result AND return? My understanding from spin was that setting result to a value equals returning that value. But it ends up in two locations on the stack! very interesting.
Enjoy!
Mike
"@Beau, I just realized you added xtal settings to the file" - I was doing this mainly for the serial DEBUG aspect of the program. It's certainly valid to set the xtal settings at a higher hierarchical level in your code.
I did not know this before my testing and actually I can't say why it is like that! Maybe it is somehow related to the abort and catch. Would require some more testing.