Shop OBEX P1 Docs P2 Docs Learn Events
How to pass pointers with object address — Parallax Forums

How to pass pointers with object address

Henk van BeekHenk van Beek Posts: 11
edited 2014-02-05 13:16 in Propeller 1
Hello,

I'm trying to return more then one pointer.
I took the sample code from the manual.

Simple main program:
CON
  _clkmode    = xtal1 + pll16x    ' 80 MHz
  _xinfreq    = 5_000_000         

  '***************************************
  ' Debug Terminal Definitions
  '***************************************

  _Trm_Rx       = 31
  _Trm_Tx       = 30
  _Trm_Baud     = 115200
  
'***************************************
OBJ
'***************************************

  Trm : "SerialMirror"         
  Txt : "SubTxt"

'***************************************
PUB main | Cog_Trm, Ptr_Txt, Idx 
'***************************************
  WaitCnt(5 * 80_000_000 + Cnt) 
  Cog_Trm := Trm.Start(_Trm_Rx, _Trm_Tx, 0, _Trm_Baud)
  WaitCnt(1 * 80_000_000 + Cnt) 
  Trm.Str(string("Debug Terminal started in Cog: ")) 
  Trm.dec(Cog_Trm)
  Trm.CrLf
  WaitCnt(1 * 80_000_000 + Cnt) 

  Ptr_Txt := Txt.Start
  Trm.Str(string("Ptr_Txt= ")) 
  Trm.Hex(Ptr_Txt,4)
  Trm.CrLf
  Trm.CrLf

  Trm.Str(string("Main: ")) 
  Trm.CrLf
  REPEAT Idx FROM 0 TO 2 
    Trm.Str(Ptr_Txt[Idx])   

  REPEAT


Object code:
''**************************************
''
''  SubTxt.spin
''
''**************************************

DAT 

  Str1 byte "Hello.", 0 
  Str2 byte "This is an example", 0 
  Str3 byte "of strings in a DAT block.",0

  StrAddr word @Str1, @Str2, @Str3

OBJ
'***************************************

  Trm : "SerialMirror"         

'***************************************
PUB Start | Addr_Str, Idx

  Addr_Str := @@StrAddr
  Trm.Str(string("Addr_Str= ")) 
  Trm.Hex(Addr_Str,4)
  Trm.CrLf

  Trm.Str(string("SubTxt: "))
  Trm.CrLf

  REPEAT Idx FROM 0 TO 2 
    Trm.Str(@@StrAddr[Idx])   
  Trm.CrLf
  Trm.CrLf
  Return @@StrAddr
  

Comments

  • Dave HeinDave Hein Posts: 6,347
    edited 2014-02-05 08:27
    The Start method should return @StrAddr, which is the address of the array containing the three object offsets. Since Ptr_Txt is defined with a PUB statement it is treated as a long value. Ptr_Txt[] is indexed as a long array, and it just selects the variables that are defined in the PUB statement. Ptr_Txt[0] is Ptr_Txt itself, and Ptr_Txt[1] is the same as Idx.

    You should use word[Ptr_Txt][Idx] to access the word elements of the array. These are object offsets, so you need to used the @@ operator to get the absolute addresses. So your call to the Str method from the main method should be Trm.Str(@@word[Ptr_Txt][Idx]). I realize this is very confusing, but that's how Spin handles object offsets.
  • Henk van BeekHenk van Beek Posts: 11
    edited 2014-02-05 08:45
    Dave Hein,

    I alterd the program at your instructions but unfortunately, It did not gave the expected results.
  • Dave HeinDave Hein Posts: 6,347
    edited 2014-02-05 09:02
    Sorry, it's even more complicated than I stated in my previous post. This would work if SubTxt.spin was included in your top object, but it doesn't work if SubTxt.spin is a separate object. This is because the @@ operator adds the starting address of the object that it's used in. I think the easiest solution is to fix the string addresses before you access it. I would suggest adding an initialization method to SubTxt.spin as follows:
    PUB Initialize | Idx
      repeat Idx from 0 to 2
        StrAddr[Idx] := @@StrAddr[Idx]
    
    Call Txt.Initialize once from your main method before you access the array, and use Trm.Str(word[Ptr_Txt][Idx]) to print the strings.
  • Henk van BeekHenk van Beek Posts: 11
    edited 2014-02-05 09:25
    Dave Hein,

    Neither unfortunaly,

    I tried even:
    PUB Init | Idx
    
        StrAddr[0] := @@Str1
        StrAddr[1] := @@Str2
        StrAddr[2] := @@Str3
    
    
    

    with no success
  • JonnyMacJonnyMac Posts: 9,107
    edited 2014-02-05 09:43
    I'm a simple guy, so forgive me if I'm missing something here. It seems like the intent is to store strings in a separate object -- makes great sense if you want to re-compile an app in a different language.

    My simple solution to that delima is to have the start method return the highest string index for the object, and then include a text() method that provides the address of the string for a given index. Like this:

    dat
    
      Str0          byte    "Jon McPhalen", 0
      Str1          byte    "Actor / Writer / Maker", 0
      Str2          byte    "Hollywood, CA", 0
    
    
      StrAddr       word    @Str0, @Str1, @Str2
    
    
    pub start
    
    '' Returns highest message index
    
      return 2
      
      
    pub text(idx)
    
    '' Returns string address for idx
    '' -- for use with .str() methods
    
      return @@StrAddr[idx]
    


    You can print a string with:
    repeat idx from 0 to 2
        term.str(messages.text(idx))
        term.tx(CR)
    


    I tested and this works.
  • Henk van BeekHenk van Beek Posts: 11
    edited 2014-02-05 10:03
    Hi JonnyMac,

    The example I gave is a simplyfied one.

    I want to accomplish a general method how one object may access variables, defined in another object.
    In my project thera are several types of variables, strings, bytes, words longs and arrays in main memory.
    These are not well alligned so I like to see a method whereby these vars in an object are accessable by the main program or even by another object.
  • JonnyMacJonnyMac Posts: 9,107
    edited 2014-02-05 10:10
    Generally speaking, one would provide access methods to data and variables that can be accessed for the parent object. IMHO, dealing only with pointers could make an application difficult to follow and maintain.
  • Dave HeinDave Hein Posts: 6,347
    edited 2014-02-05 11:19
    In my case I use code that is converted from C that uses pointers, and arrays of pointers. One example is a list of symbols names that is defined in C as
    char *ops[] = {"++", "+=", "+", "--", "-=",
        ... 
        "?", "===", "==", 0};
    
    I use CSPIN to convert it to Spin, and it generates the following code.
    DAT
      datstr byte "++", 0, "+=", 0, "+", 0, "--", 0, "-=", 0
      ...
      byte "?", 0, "===", 0, "==", 0
      ops long @datstr + 16, @datstr + 19, @datstr + 22, @datstr + 24,@datstr + 27
      ...
      long @datstr + 177, @datstr + 179, @datstr + 183
      long 0
    
    CSPIN adds an offset of 16 to generate absolute addresses for the top object. However, in other objects I have to add the offsets at run time, so I use the following routine to initialize the pointers.
    PUB start | ptr
      ptr := @ops
      repeat while long[ptr]
        long[ptr] += @@0 - 16
        ptr += 4
    
    This routine subtracts the offset of 16 that is used for the top object and adds the object address, which is given by @@0.
  • Henk van BeekHenk van Beek Posts: 11
    edited 2014-02-05 13:16
    Dave Hein,

    This is great.It works indeed ! Especially the @@0 was a revelation to me.
    In retrospect quite logical.
    Obviously you have good understanding how spin works. For me this was a mystery.but yiu solved it. Thanks

    JonnyMac,

    You are right when with a few vars. But, I hope you agree, Dave Hein answered to my expectations.

    Thanks both for your contributions.

    Henk
Sign In or Register to comment.