Shop OBEX P1 Docs P2 Docs Learn Events
Help with Var sharing between objects — Parallax Forums

Help with Var sharing between objects

lmclarenlmclaren Posts: 104
edited 2011-06-11 15:57 in Propeller 1
Hi,
I am struggling a bit trying to get my head around sharing variables between objects, this is what I have:

Roaster_Main.spin

├──PhaseDimmer.spin (runs in own cog)

├──Simple_Numbers.spin

├──SPI_Devices.spin
│ │
│ └──SPI_Spin.spin (runs in own cog)

├──VGA64_TMPEngine.spin

├──Artisan.spin (runs in own cog)
│ │
│ └──pcFullDuplexSerial4FC.spin (2nd port, not started, using the one started in Roaster_Main)

└──pcFullDuplexSerial4FC.spin (1st port, runs in own cog, started from Roaster_Main



How I would like it to work is:

Data collected in SPI_Devices,
Data used by, Roaster_Main, Artisan

I have setup an OBJ in Artisan for SPI_Devices and called this method:

VAR
long MAX1_C

PUB Get_MAX1
return MAX1_C

If I call the method from Roaster_Main it works and returns the value, If I call it from Artisan, it does not.

I have read the doc a few times and I am missing something.

Is there a way to refer from Artisan to a var in Roaster_Main?

I will have a number of objects in seperate cogs collecting infromation and this information will be sent out from other objects in other cogs, eg some will go out as serial, some will go out to the video display.

btw, Am I using the pcFullDuplexSerial4FC incorrectly by starting it in Roaster_Main and then using the second port in Artisan?

many thanks

Lee

Comments

  • kuronekokuroneko Posts: 3,623
    edited 2011-06-10 21:13
    lmclaren wrote: »
    Is there a way to refer from Artisan to a var in Roaster_Main?
    In general, global variables are private to the object they are declared in. Which means a parent object could only access child object variables through access methods. It doesn't work the other way though (child -> parent). To make this work the parent object should inform the child object about the address(es) of the variable(s) in question:
    ' parent object
    
    VAR
      [COLOR="blue"]long[/COLOR]  shared
    
    OBJ
      helper: "child"
    
    PUB main
    
      helper.setup([COLOR="red"]@[/COLOR]shared)                ' make [COLOR="red"]location/address[/COLOR] public
    
    The child object then squirrels away this address and can access the variable it represents like this:
    ' child object
    
    VAR
      long  location
    
    PUB setup(address)
    
      location := address
    
    PRI read
    
      return [COLOR="blue"]long[/COLOR][location]
    
    PRI write(value)
    
      [COLOR="blue"]long[/COLOR][location] := value
    
  • lmclarenlmclaren Posts: 104
    edited 2011-06-10 21:28
    Thanks Kuroneko,

    If I want to share child to child, is that where I have to use a DAT?
  • kuronekokuroneko Posts: 3,623
    edited 2011-06-10 21:37
    lmclaren wrote: »
    If I want to share child to child, is that where I have to use a DAT?
    That depends on the child, if it's the same object (e.g. multiple use of FullDuplexSerial) then their DAT section is shared implicitly between the instances. Different child objects need to find a way to communicate addresses (most likely setup phase from a common parent object). Then access those locations as described above.

    Sometimes it's easier to keep a shared storage area at the parent level and just tell the child objects where it is. Otherwise you'd need to ask child 1 for its address, tell child 2 and vice versa.
  • jazzedjazzed Posts: 11,803
    edited 2011-06-10 22:07
    kuroneko wrote: »
    Sometimes it's easier to keep a shared storage area at the parent level and just tell the child objects where it is. Otherwise you'd need to ask child 1 for its address, tell child 2 and vice versa.

    That's what I've concluded having looked at the same situation earlier today for a different reason. Being able to share the FullDuplexSerial object "as-is" would be great. I remember someone creating a "wrapper" for FullDuplexSerial and claiming that fixed the problem. Well, it doesn't because even though the object was included only once, the including object is included more than once so the VAR addresses were different. Bummer.

    So if i want to get away with not using a DAT section for variables, the only way to share the object is by "tell the child objects where it is" as you said. I get to add another method to FullDuplexSerial for that to work ... :sick:
  • lmclarenlmclaren Posts: 104
    edited 2011-06-10 22:12
    So if I am understanding correctly, best practice for the following requirement is:

    TopObject
    Child1 8 long vars
    Child2 8 long vars
    Child3 8 long vars


    To start Child1, I do the following:
    from TopObject,

    Child1.Start(@Child1Vars_in_TopObject, @Child2Var_in_TopObject, @Child3Vars_in_TopObject)
    Child2.Start(@Child1Vars_in_TopObject, @Child2Var_in_TopObject, @Child3Vars_in_TopObject)
    Child3.Start(@Child1Vars_in_TopObject, @Child2Var_in_TopObject, @Child3Vars_in_TopObject)

    With all the VARs in the TopObject only.

    many thanks
  • Duane DegnDuane Degn Posts: 10,588
    edited 2011-06-10 22:23
    Actually, I think pcFullDuplexSerial4FC only uses the dat section. You might be able to have each child call the addPort method and use it normally (as long as each child was using a different port (and I don't think you can share tx and rx pins among ports). You'd need to make sure the Start method wasn't called until all the ports were added.

    I've spent a lot of time hacking pcFullDuplexSerial4FC, but I'm not sure it the above technique would work or not.
  • lmclarenlmclaren Posts: 104
    edited 2011-06-10 22:31
    Is there a nice way to be able to call the Vars by name, even in a lookup function, eg:

    Can I have a shared object that has been told the address of all the vars and then reuse the object in each child.

    as an example,
    OBJ
    VARSHARE "VARSHAREOBJ"

    From Top Object
    VarShare.Init(@location_of_Vars_in_TopObject)


    from ChildObject
    OBJ
    VARSHARE "VARSHAREOBJ"

    CON
    FRED,CAT,DOG

    VarShare.GetFred
    Return @location + Fred
  • lmclarenlmclaren Posts: 104
    edited 2011-06-10 22:43
    What I am trying to say in almost code is:


    SHARE.spin
    CONS
    Var1
    Var2
    Var3
    Var4
    Var5

    PUB SET(VarOffset,Value)

    PUB GET(VarOffset) Value

    DAT
    long[5]

    In each child,

    OBJ
    S : "Share"

    S.GET(S#VAR1)

    or
    S.SET(S#VAR1)


    Am I on the right track?

    many thanks
  • kuronekokuroneko Posts: 3,623
    edited 2011-06-10 22:47
    @lmclaren: Define nice. But yes, provided your constants (offsets relative to location) are correct that should work. However, as location is already an address it should read return location+Fred instead. Your choice really but should GetFred return the address instead of the value (i.e. return long[location][member])?

    Note that variables get re-ordered according to type, i.e. longs come first followed by word and byte variables. The order within each group stays the same.
  • Duane DegnDuane Degn Posts: 10,588
    edited 2011-06-10 22:53
    I think something like that should work.

    I have a "header" object I use to keep all my constants in. I add the Header object to the top and all child objects. I can then use Header#CONSTANT_NAME to access the constants. You could keep your "FRED, CAT, DOG" constants in a header so all your objects use the same offset from @location.

    You do need one PUB method. Just add:
    CON
     
      FRED = 0
      CAT = 4  
      DOG = 8  
      '  Assuming you want offsets for long addresses.
      ' Add other constants here.
     
    PUB ThrowAwayMethod
    

    This isn't my idea. I learned from someone here on the forum.

    Duane

    Edit: I was typing while you added another post. Yes you're on the right track.
  • kuronekokuroneko Posts: 3,623
    edited 2011-06-10 23:04
    This is just cobbled together but may do what you want. It uses a shared object with DAT storage and two child objects accessing it through predefined offsets. HTH
  • lmclarenlmclaren Posts: 104
    edited 2011-06-10 23:28
    Thank you, I am reading carefully.

    best regards

    Lee
  • Dave HeinDave Hein Posts: 6,347
    edited 2011-06-11 07:41
    The way I handle it in CSPIN is to generate byte offsets for the elements of a data structure and then access them with the BYTE, WORD and LONG operators. It looks something like this:
    CON
    ' typedef struct StorageS
      dog = 0 'long variable
      cat = 4 'word variable
      fish = 6 'word variable
      pig = 8 'byte variable
      cow = 9 'byte variable
    
    PUB main | Storage[3]
      LONG[@Storage + dog] := 1
      WORD[@Storage + cat] := 2
      WORD[@Storage + fish] := 3
      BYTE[@Storage + pig] := 4
      BYTE[@Storage + cow] := 5
      Compute(@Storage)
    
    PUB Compute(s)
      LONG[s + dog] := WORD[s + cat] + WORD[s + fish]
      BYTE[s + pig] -= BYTE[s + cow]
    

    You can pass a pointer to the structure to methods that are in the same object or in different objects. The offsets can be defined in separate object like kuroneko suggests. If all data structure elements are the same size you can just define byte, word or long offsets and access them as an array, such as WORD[cat].
  • lmclarenlmclaren Posts: 104
    edited 2011-06-11 15:57
    Thanks everyone, I have solved my problems and learnt a few things on the way.

    best regards

    Lee
Sign In or Register to comment.