Help Please. Variables with multiple cogs and objects
I read that a variable defined in the VAR block can be seen by all the methods of that object, but what about in other Cogs running other objects?
What I have is a method in one object that polls the user for input and saves the input to a variable (say desiredX) in another object I have a method that looks for that variable (desiredX) to change and when it does it executes a subroutine. The problem is that the subroutine never gets executed. I imagine it is because one object/cog can't see what is going on in another.
So the question is how do I get the second cog to see that the variable has changed in the first cog?
Thanks for your help,
-Brad
What I have is a method in one object that polls the user for input and saves the input to a variable (say desiredX) in another object I have a method that looks for that variable (desiredX) to change and when it does it executes a subroutine. The problem is that the subroutine never gets executed. I imagine it is because one object/cog can't see what is going on in another.
So the question is how do I get the second cog to see that the variable has changed in the first cog?
Thanks for your help,
-Brad

Comments
If we're talking about PASM there is an extra step of getting the COG data to HUB memory.
It helps if you post your code.
I am coding in Spin and here is my code:
{{__________________________________________________________ Author: Bradley Bauer Date: 11-3-11 __________________________________________________________ }} CON _clkmode = xtal1 + pll16x 'Crystal and PLL settings. _xinfreq = 5_000_000 '5 MHz crystal (5 MHz x 16 = 80 MHz) VAR Word desiredX 'Variable to store desired X position Word desiredY 'Variable to store desired Y position Byte XResolveCog 'Stores cog ID that runs XResolve Byte YResolveCog 'Stores cog ID that runs YResolve Byte PotWatchCog 'Stores cod ID that runs PotWatch Byte SwitchMonitorCog 'Stores cog ID that runs SwitchMonitor Byte laserState 'Variable to store desired laser state (ON/OFF) Byte laserB 'Variable to store desired laser brightness level (0-100) OBJ Resolve : "ResolveXY" 'Used to resolve X-Y disparities SerialCom : "Extended_FDSerial" 'Used for serial communications Pot : "PotResolve" 'Used to resolve laser brightness disparities Switch : "Switch Monitor" 'Watches for input from foot pedal 'delete below after testing Debug : "Parallax Serial Terminal"'Calls "Parallax Serial Terminal" object "Debug" Pub Main {Starts all the objects and methods then runs SerialMonitor on Cog 0} Resolve.Start 'Starts 2 Cogs Pot.Start 'Starts 1 Cog Switch.Start 'Starts 1 Cog 'SerialMonitor 'Uses Cog 0 'Total of 5 Cogs running 'Delete remaining code in method when done testing Debug.Start(115_200) repeat Debug.Str(String("Enter an X value: ")) 'Prompt user to enter a number; uses immediate string. desiredX := Debug.DecIn Debug.Str(String("Enter an Y value: ")) 'Prompt user to enter a number; uses immediate string. desiredY := Debug.DecInOther object:{{__________________________________________________________ Author: Bradley Bauer __________________________________________________________ Known bug: Does not accept negative "RX_______" values }} CON _clkmode = xtal1 + pll16x 'Crystal and PLL settings. _xinfreq = 5_000_000 '5 MHz crystal (5 MHz x 16 = 80 MHz) XPlus = 13 'Defines pin for CW motion input on M1 XMinus = 15 'Defines pin for CCW motion input on M1 YPlus = 19 'Defines pin for CW motion input on M2 YMinus = 16 'Defines pin for CCW motion input on M2 XDir = 4 'Defines pin for X direction output XStep = 5 'Defines pin for X axis step output YDir = 6 'Defines pin for Y direction output YStep = 7 'Defines pin for Y axis step output XMAX = 200 'Defines positive X step limit XMIN = 0 'Defines negative X step limit YMAX = 200 'Defines negative Y step limit YMIN = 0 'Defines negative Y step limit MS1 = 14 'Pin for Mode select 1 Microstep resolution selection MS2 = 13 'Pin for Mode select 2 See Allegro A4983 data sheet MS3 = 12 'Pin for Mode select 3 for truth table CW = 1 'Defines CW direction CCW = 0 'Defines CCW direction StepWait = 500 'Defines step pulse intervals (clkfreq/StepWait + cnt) Count = 10 '-----Defines a default count value VAR Word XCount 'Variable to keep track of X steps Word YCount 'Variable to keep track of Y steps Word desiredX 'Variable to store desired X position Word desiredY 'Variable to store desired Y position Byte XResolveCog 'Stores cog ID that runs XResolve Byte YResolveCog 'Stores cog ID that runs YResolve Long Stack1[100] 'Cog stack space Long Stack2[100] 'Cog stack space OBJ Debug : "Parallax Serial Terminal" 'Calls "Parallax Serial Terminal" object "Debug" PUB Main Debug.Start(115_200) waitcnt(clkfreq/100 + cnt) Debug.Str(String("Program is running...")) Debug.NewLine Start PUB Start XResolveCog := cognew(XResolve, @Stack1) YResolveCog := cognew(YResolve, @Stack2) dira[MS1..MS3]~~ 'Sets Stepper drivers to 1/16 microstep mode !outa[MS1..MS3] 'by setting MS1, MS2, and MS3 pins high PRI XResolve dira[XDir..XStep]~~ 'Set stepper control pins as outputs repeat if (XCount < desiredX) repeat while (XCount < desiredX) and (XCount < XMax) Resolver(CW, XStep) XCount++ else repeat while (XCount > desiredX) and (XCount > XMin) Resolver(CCW, XStep) XCount-- PRI YResolve dira[YDir..YStep]~~ 'Set stepper control pins as outputs repeat if (YCount < desiredY) repeat while (YCount < desiredY) and (YCount < YMax) Resolver(CW, YStep) YCount++ else repeat while (YCount > desiredY) and (YCount > YMin) Resolver(CCW, YStep) YCount-- PRI Resolver (direction, motorSelect) | DirPin {{Sets step direction and steps motor once}} if (motorSelect == XStep) DirPin := XDir else DirPin := YDir outa[DirPin] := direction !outa[motorSelect] waitcnt(clkfreq/StepWait + cnt) !outa[motorSelect] waitcnt(clkfreq/StepWait + cnt)In a nutshell... Ask user for X and Y points then run the Resolve subroutine until there is no more disparity between desiredX and Xcount and desiredY and YCount
I don't see how I can store a variable in the DAT block, maybe someone could show me?
Thanks
Your going to need have the parent object pass a pointer, to the variable, to the child object.
Look for information in the manual about the "@" operator.
The child method would then read the variable with word[addressOfWord].
I don't see an advantage to having the variable in the DAT section unless muliple instances of an object are used.
Locks are sometimes needed. It depends on the situation.
I'll look around for an example of passing a pointer and post one if someone else doesn't bet me to it.
Duane
I haven't found a clear example yet.
When the parent starts the child use:
Modify the child object to:
Hopefully that's enough to get you started.
Look up "@" and word to see what the code above is doing.
Duane
Thank you, an example would be great!
CON _clkmode = xtal1 + pll16x _xinfreq = 5_000_000 DAT command byte $00 SemID byte $00 VAR long ReadStack[20] long WriteStack[20] OBJ pst : "Parallax Serial Terminal" PUB Main 'Start PST pst.Start(115_200) pause(200) ' Get a lock ID if(semId := locknew) == -1 pst.str(string("Error, semaphore Id available", 13)) else pst.str(string("Semaphore Id : ")) pst.dec(SemID) pst.char(13) ' Start the Read and Write processes cognew(Write, @WriteStack) cognew(Read, @ReadStack) PUB Read | value '' Write to the terminal when '' the command equals $10 repeat 'forever 'Wait for the lock to clear repeat until not lockset(SemID) if(command == $10) pst.str(string("We got a winner!: ")) pst.hex(command, 2) pst.char(13) 'Clear the lock lockclr(SemID) ' Give Write some time to write pause(1) PUB Write | i repeat 'forever 'Wait for the lock to clear repeat until not lockset(SemID) command := i++ pause(10) 'Clear the lock lockclr(SemID) ' Give Read some time to read pause(1) PRI Pause(Duration) waitcnt(((clkfreq / 1_000 * Duration - 3932) #> 381) + cnt) returnIf the Read and Write processes were encapsulated in an object, then you would pass the address (pass by reference) of the command variable, @command, to the object's Start method. In this example, you would also pass the ID of the memory lock. Pass by value should be fine. Hope that helps.
I still have two questions though:
1) I followed Duane's example and it is working except something is happening to the values. The code works perfectly in the single object, but when I use another cog to store the values are getting changed somehow.
DAT XSpace Long $AAAAAA YSpace Long $BBBBBB OBJ Resolve : "ResolveXY" 'Used to resolve X-Y disparities SerialCom : "Extended_FDSerial" 'Used for serial communications Pot : "PotResolve" 'Used to resolve laser brightness disparities Switch : "Switch Monitor" 'Watches for input from foot pedal 'delete below after testing Debug : "Parallax Serial Terminal"'Calls "Parallax Serial Terminal" object "Debug" Pub Main {Starts all the objects and methods then runs SerialMonitor on Cog 0} Resolve.Start(@XSpace, @YSpace) 'Starts 2 Cogs Pot.Start 'Starts 1 Cog Switch.Start 'Starts 1 Cog 'SerialMonitor 'Uses Cog 0 'Total of 5 Cogs running 'Delete remaining code in method when done testing Debug.Start(115_200) waitcnt(clkfreq/100 + cnt) repeat Debug.Str(String("Enter an X value: ")) 'Prompt user to enter a number; uses immediate string. long[@XSpace] := Debug.DecIn debug.dec(long[@XSpace]) Debug.Str(String("Enter an Y value: ")) 'Prompt user to enter a number; uses immediate string. long[@YSpace] := Debug.DecIn debug.dec(long[@YSpace])Resolve Object:
DAT XSpace Long $AAAAAA YSpace long $BBBBBB OBJ Debug : "Parallax Serial Terminal" 'Calls "Parallax Serial Terminal" object "Debug" PUB Main Debug.Start(115_200) waitcnt(clkfreq/100 + cnt) Debug.Str(String("Program is running...")) Debug.NewLine Start(@XSpace,@YSpace) PUB Start(desiredXaddress, desiredYaddress) XResolveCog := cognew(XResolve(desiredXaddress), @Stack1) YResolveCog := cognew(YResolve(desiredYaddress), @Stack2) dira[MS1..MS3]~~ 'Sets Stepper drivers to 1/16 microstep mode !outa[MS1..MS3] 'by setting MS1, MS2, and MS3 pins high 'Delete remaining code in method when interfaced with LaserPOP-Parent { repeat Debug.Str(String("Enter an X value: ")) 'Prompt user to enter a number; uses immediate string. long[@XSpace] := Debug.DecIn Debug.Str(String("Enter an Y value: ")) 'Prompt user to enter a number; uses immediate string. long[@YSpace] := Debug.DecIn } PRI XResolve(desiredXaddress) dira[XDir..XStep]~~ 'Set stepper control pins as outputs repeat if (XCount < long[desiredXaddress]) repeat while (XCount < long[desiredXaddress]) and (XCount < XMax) Resolver(CW, XStep) XCount++ else repeat while (XCount > long[desiredXaddress]) and (XCount > XMin) Resolver(CCW, XStep) XCount-- PRI YResolve(desiredYaddress) dira[YDir..YStep]~~ 'Set stepper control pins as outputs repeat if (YCount < long[desiredYaddress]) repeat while (YCount < long[desiredYaddress]) and (YCount < YMax) Resolver(CW, YStep) YCount++ else repeat while (YCount > long[desiredYaddress]) and (YCount > YMin) Resolver(CCW, YStep) YCount--2) I'm still not sure how Mike's code applies to this, but I'm all for an explanation... It perhaps is what's causing my problem?
Thanks again
Sounds like you need a memory lock.
The code simply spins up two process in separate COGs; 1 and 2. Each process has access to the variable created in the top level object. You could, move the Read and Write process to separate files, reference the objects, and start the objects in the top level object. Pass the command variable by reference; @command, to the referenced objects (as you did) along with the semaphore. In the child objects, make sure memory access is not checked out by another process. If memory is available check out the memory lock, Read/Write, release the lock.
The Propeller manual has an excellent explanation of memory locks.