Shop OBEX P1 Docs P2 Docs Learn Events
Passing and Returning Arrays — Parallax Forums

Passing and Returning Arrays

reppigreppig Posts: 35
edited 2011-10-18 06:03 in Propeller 1
I am trying to follow the examples in the education kit manual but I still most not be doing it right.
In the code below I call geoLlh2Efg(@GS_Llh, @efg_gs) where the first pointer is an array of data coming in and the second is an array to return the answers. The answers coming back are not correct.

Am I passing arrays back and forth correctly??
CON
   _clkmode = xtal1 + pll16x                                       'Standard clock mode * crystal freq. = 80 MHz
   _xinfreq = 5_000_000                                            'Extenal Crystall Freq.

{{********* WGS-84 Constants **********}}                                                                  
   earth_rad = 6378137.0                                           'Radius of a spherical model of the Earth
   flattening = 298.2572236                                        'Flattening - spherical model of the earth


VAR
   long  efg[3], efg_gs[3], efg_tgt[3]                             'efg coords of ground station and target(balloon
   long  xyz[3], rae[3], GS_Llh[3]                                 'xyz or range,az,el or ground station lat, long, height

   
OBJ
   f :  "Float32Full"    
   DBG : "FullDuplexSerialPlus"
   FS : "FloatString"                                              'EX. - DBG.Str(FS.FloatToString(temp))
     
    
PUB Main | ok1, ok2
   WAITCNT(CLKFREQ * 6 + CNT)

'Start FullDuplexSerialPlus Driver for debug. The Driver will launch a
'COG for serial communication with Parallax Serial Terminal
   oK1 := DBG.Start(31, 30, 0, 57600)

   DBG.Str(STRING(16, 1, 10, 13))
   DBG.Str(STRING("  GPS Float Lite Demo v1.0 started...", 10, 13))

   WAITCNT(CLKFREQ * 2 + CNT)

'Start Float32Full
   oK2 := f.Start             'Connection pins are defined in the driver

   IF NOT (oK1 AND oK2)        'Some error occured
      IF oK1                    'We have at least the debug terminal
         DBG.Str(STRING(10, 13))
         DBG.Str(STRING("Some error occurred. Check System!", 10, 13))
         DBG.Stop
      IF oK2
         f.Stop
    
      REPEAT                    'Until Power Off or Reset
  
   GS_Llh[0] := 28.52467
   GS_Llh[1] := -80.68395
   GS_Llh[2] := 14.0

   geoLlh2Efg(@GS_Llh, @efg_gs)

   DBG.Str(FS.FloatToString(efg_gs[0]))
   DBG.Str(STRING(10, 13))
   DBG.Dec(FS.FloatToString(efg_gs[1]))
   DBG.Str(STRING(10, 13))
   DBG.Dec(FS.FloatToString(efg_gs[2]))
 

   repeat


   
{********** Geo_B & Geo_E2 are Functions to do a Geodetic solution **********}   
PUB Geo_B | temp                                                   'Geo_B = (earth_rad * (1.0 - (1.0 / flattening)))
      temp := f.FDiv(1.0, flattening)                              'Geo_B = (earth_rad * (1.0 - temp))
      temp := f.FSub(1.0, temp)                                    'Geo_B = (earth_rad * temp)
      temp := f.FMul(earth_rad, temp)
      DBG.Str(FS.FloatToString(temp))
      DBG.Str(STRING(10, 13))
      result := temp                                               'Return Geo_B
      
      
PUB Geo_E2 | temp, temp1, temp2                                    'Geo_E2 = (((earth_rad * earth_rad) - (GEO_B * GEO_B)) / (earth_rad * earth_rad))
      temp2 := f.FMul(earth_rad, earth_rad)                        'Geo_E2 = ((temp2 - (GEO_B * GEO_B)) / temp2)
      temp1 := f.FMul(GEO_B, GEO_B)                                'Geo_E2 = ((temp2 - temp1) / temp2)
      temp := f.FSub(temp2, temp1)                                 'Geo_E2 = (temp / temp2) 
      temp := f.FDiv(temp, temp2)
      DBG.Str(FS.FloatToString(temp))
      DBG.Str(STRING(10, 13))
      result := temp
      

PUB geoLlh2Efg(LLHaddr, efg_ret) | temp, temp1, sin_lat, cos_lat, N  'Inputs Latitude, longitude, height & return array
      sin_lat := f.Sin(f.Radians(long[LLHaddr][0]))
      cos_lat := f.Cos(f.Radians(long[LLHaddr][0]))
   { Compute the radius of curvature -- N = a / Sqrt(1.0 - Geo_E2 * sin_lat * sin_lat) }
      temp := f.FMul(sin_lat, sin_lat)                             'N = a / Sqrt(1.0 - (Geo_E2 * temp))
      temp := f.FMul(Geo_E2, temp)                                 'N = a / Sqrt(1.0 - temp)
      temp := f.FSub(1.0, temp)                                    'N = a / Sqrt(temp)
      temp := f.FSqr(temp)                                         'N = a / temp
      N := f.FDiv(earth_rad, temp)

   { Compute the EFG(XYZ) coordinates (earth centered)}
      temp1 := f.FAdd(N, long[LLHaddr][2])                         'efg[0] := ((N + height) * cos_lat * Cos(Degree2Radian(lon)))
      temp := f.Cos(f.Radians(long[LLHaddr][1]))                     'efg[0] := (temp1 * cos_lat * temp)
      temp := f.FMul(cos_lat, temp)                                'efg[0] := (temp1 * temp)
      efg_ret[0] := f.FMul(temp1, temp)
                                                                   'efg[1] := ((N + height) * cos_lat * Sin(Degree2Radian(lon)))
      temp := f.Sin(f.Radians(long[LLHaddr][1]))                    'efg[1] := temp1 * cos_lat * temp
      temp := f.FMul(cos_lat, temp)                                'efg[1] := temp1 * temp
      efg_ret[1] := f.FMul(temp1, temp)               
                                                                   'efg[2] := (N * (1.0 - Geo_E2) + height) * sin_lat
      temp := f.FSub(1.0, Geo_E2)                                  'efg[2] := (N * temp + height) * sin_lat
      temp := f.FMul(N, temp)                                      'efg[2] := (temp + height) * sin_lat
      temp := f.FAdd(temp, long[LLHaddr][2])                       'efg[2] := temp * sin_lat 
      efg_ret[2] := f.FMul(temp, sin_lat)

Comments

  • Mike GMike G Posts: 2,702
    edited 2011-10-14 11:39
    GS_Llh and efg_gs are global variables. Just use GS_Llh[n] and efg_gs[n] in the geoLlh2Efg method. No reason to pass a pointer when the members are global.

    Edit: plus in geoLlh2Efg
     efg_ret[0] := f.FMul(temp1, temp)
    

    Should be efg_gs[0] := Fix the other two as well...

    Use the Parallax Serial Terminal to view values/memory. Use meaningful variable names... I found your code hard to follow. I had to use find to track your variables. But that's just me others might not have the same issue.
  • Dave HeinDave Hein Posts: 6,347
    edited 2011-10-14 12:45
    Or you could fix the refetences to efg_ret[n] in geoLlh2Efg to be long[efg_ret][n]. Otherwise, you are just refering to the local stack variable and the longs located after it on the stack, and not the the longs pointed to by efg_ret.
  • MagIO2MagIO2 Posts: 2,243
    edited 2011-10-14 12:50
    Mike is right. We talk about a microcontroller, and it only makes sense to pass parameters to a function if the function is used from several places and there is a chance that the return array could be different in that calls. Otherwise simply accessing the global variable saves runtime (a call without parameters is faster), program space and stack-space.

    But to explain what's wrong with your code:
    In fact SPIN is not type-safe. This means that even if efg_ret is a single long containing the address of the array, it can be used as an array itself without a problem. But without problem only means that the compiler does not complain.
    But the function is different than expected!

    long efg_gs[3]
    creates 3 longs in memory and efg_gs in the program is replaced by the address of the first long in all the code.
    The array-notation will simply add the index to this address wherever used.
    efg_gs := 0 and efg_gs[0] := 0 are the same! (0 will be stored at the memory location that's given by efg_gs respectively efg_gs + 0.
    efg_gs[1] := 0 stores the 0 at the memory location efg_gs + 4 (it's +4 because we talk about a long variable)
    efg_gs[2] := 0 -> efg_gs + 8 .....

    Instructions like efg_gs[1] := will always put a long into the location, whereas an instruction like ret := efg_gs[1] + xxxxx will always read the content and use that.
    A function call like calc(efg_gs) will first read the content and pass this as parameter.
    A function call like calc(@efg_gs) will not read the content, but pass the address insted.
    On the other side of the function, the address is stored IN the parameter-variable.

    PUB calc( efg_ret )

    So, what does it mean?
    efg_ret contains the address
    efg_ret[0] also contains the address. Overwriting efg_ret[0] := 0 will simply put the 0 into efg_ret. Now it no longer contains the address!
    efg_ret[1] := 0 will store the 0 in memory location efg_ret + 4, which is located in the stack-space - if the stack is big enough. If not you overwrite something else!

    To write into the memory that efg_ret points to, you have to write
    long[ efg_ret ][ 0 ] := 0
    long[ efg_ret ][ 1 ] := 0 ....
  • reppigreppig Posts: 35
    edited 2011-10-15 10:28
    Thank you all for your help. You have help to explain what the manual did not.
  • Mike GMike G Posts: 2,702
    edited 2011-10-15 11:00
    You have help to explain what the manual did not.
    It's in there, in the manual I mean. The concept is general and relates to most programming languages.
  • reppigreppig Posts: 35
    edited 2011-10-17 10:44
    I have decided to give up on the array idea for now and just pass global variables. But something is still not right. Can you give a look?
    The debug numbers that come out are:
    Params: 28.52467 <-- correct
    5712 <-- not correct
    5712 <-- not correct
    Main 907832.2 <-- correct

    Why are the second and third parameters not being passed??
    CON
       _clkmode = xtal1 + pll16x                                       'Standard clock mode * crystal freq. = 80 MHz
       _xinfreq = 5_000_000                                            'Extenal Crystall Freq.
    
    {{********* WGS-84 Constants **********}}                                                                  
       earth_rad = 6378137.0                                           'Radius of a spherical model of the Earth
       flattening = 298.2572236                                        'Flattening - spherical model of the earth
       gs_lat = 28.52467                                              'ground station lat
       gs_lon = -80.68395                                             'ground station lon
       gs_ht = 14.0                                                   'ground station height
    
    
    VAR
       long  temp, Geo_B, Geo_E2, temp1, temp2                         'temp vars and calculated constants
       long  efg_gs_lat, efg_gs_lon, efg_gs_ht                           'ground station efg coor.
       
    '   long  xyz[3], rae[3]                                            'xyz or range,az,el or ground station lat, long, height
    '   long  efg[3], efg_gs[3], efg_tgt[3]                             'efg coords of ground station and target(balloon
    
       
    OBJ
       f :  "F32"    
       DBG : "FullDuplexSerialPlus"
       FS : "FloatString"                                              'EX. - DBG.Str(FS.FloatToString(temp))
         
        
    PUB Main | ok1, ok2
       WAITCNT(CLKFREQ * 4 + CNT)
    
    'Start FullDuplexSerialPlus Driver for debug. The Driver will launch a
    'COG for serial communication with Parallax Serial Terminal
       oK1 := DBG.Start(31, 30, 0, 57600)
    
       DBG.Str(STRING(16, 1, 10, 13))
       DBG.Str(STRING("  GPS Ant. started...", 10, 13))
    
       WAITCNT(CLKFREQ * 2 + CNT)
    
    'Start Float32Full
       oK2 := f.Start             'Connection pins are defined in the driver
    
       IF NOT (oK1 AND oK2)        'Some error occured
          IF oK1                    'We have at least the debug terminal
             DBG.Str(STRING(10, 13))
             DBG.Str(STRING("Some error occurred. Check System!", 10, 13))
             DBG.Stop
          IF oK2
             f.Stop
        
          REPEAT                    'Until Power Off or Reset
    
    {********** Geo_B & Geo_E2 are needed to do a Geodetic solution **********}   
      'Geo_B = (earth_rad * (1.0 - (1.0 / flattening)))
       temp := f.FDiv(1.0, flattening)                                 'Geo_B = (earth_rad * (1.0 - temp))
       temp := f.FSub(1.0, temp)                                       'Geo_B = (earth_rad * temp)
       temp := f.FMul(earth_rad, temp)
       Geo_B := temp                                                   'Store Geo_B
       
      'Geo_E2 = (((earth_rad * earth_rad) - (GEO_B * GEO_B)) / (earth_rad * earth_rad))
       temp2 := f.FMul(earth_rad, earth_rad)                           'Geo_E2 = ((temp2 - (GEO_B * GEO_B)) / temp2)
       temp1 := f.FMul(GEO_B, GEO_B)                                   'Geo_E2 = ((temp2 - temp1) / temp2)
       temp := f.FSub(temp2, temp1)                                    'Geo_E2 = (temp / temp2) 
       temp := f.FDiv(temp, temp2)
       Geo_E2 := temp                                                  'Store Geo_B2
    
       geoLlh2Efg(gs_lat, gs_lon, gs_ht)
       DBG.Str(STRING("Main  "))
       DBG.Str(FS.FloatToString(efg_gs_lat))
       DBG.Str(STRING(10, 13))
    
       repeat
     
       
    PUB geoLlh2Efg(lat, lon, ht) | sin_lat, cos_lat, sin_lon, cos_lon, N        'Inputs Latitude, longitude, height
    
       DBG.Str(STRING("Params:  "))
       DBG.Str(FS.FloatToString(lat))
       DBG.Str(STRING(10, 13))
       DBG.Dec(FS.FloatToString(lon))
       DBG.Str(STRING(10, 13))
       DBG.Dec(FS.FloatToString(ht))
       DBG.Str(STRING(10, 13))
       
          sin_lat := f.Sin(f.Radians(lat))
          cos_lat := f.Cos(f.Radians(lat))
          sin_lon := f.Sin(f.Radians(lon))
          cos_lon := f.Cos(f.Radians(lon))
       { Compute the radius of curvature -- N = a / Sqrt(1.0 - Geo_E2 * sin_lat * sin_lat) }
          temp := f.FMul(sin_lat, sin_lat)                             'N = a / Sqrt(1.0 - (Geo_E2 * temp))
          temp := f.FMul(Geo_E2, temp)                                 'N = a / Sqrt(1.0 - temp)
          temp := f.FSub(1.0, temp)                                    'N = a / Sqrt(temp)
          temp := f.FSqr(temp)                                         'N = a / temp
          N := f.FDiv(earth_rad, temp)
    
       { Compute the EFG(XYZ) coordinates (earth centered)}
          temp1 := f.FAdd(N, ht)                                       'efg[0] := ((N + height) * cos_lat * cos_lon)
          temp := f.FMul(cos_lat, cos_lon)                             'efg[0] := (temp1 * cos_lat * cos_lon)
          efg_gs_lat := f.FMul(temp1, temp)                            'efg[0] := (temp1 * temp)
    
    
  • kuronekokuroneko Posts: 3,623
    edited 2011-10-17 17:01
    PUB geoLlh2Efg(lat, lon, ht) | sin_lat, cos_lat, sin_lon, cos_lon, N        'Inputs Latitude, longitude, height
    
       DBG.Str(STRING("Params:  "))
       DBG.[COLOR="blue"]Str[/COLOR](FS.Float[COLOR="blue"]ToString[/COLOR](lat))
       DBG.Str(STRING(10, 13))
       DBG.[COLOR="red"]Dec[/COLOR](FS.Float[COLOR="blue"]ToString[/COLOR](lon))
       DBG.Str(STRING(10, 13))
       DBG.[COLOR="red"]Dec[/COLOR](FS.Float[COLOR="blue"]ToString[/COLOR](ht))
       DBG.Str(STRING(10, 13))
       
          sin_lat := f.Sin(f.Radians(lat))
          cos_lat := f.Cos(f.Radians(lat))
          sin_lon := f.Sin(f.Radians(lon))
          cos_lon := f.Cos(f.Radians(lon))
       { Compute the radius of curvature -- N = a / Sqrt(1.0 - Geo_E2 * sin_lat * sin_lat) }
          temp := f.FMul(sin_lat, sin_lat)                             'N = a / Sqrt(1.0 - (Geo_E2 * temp))
          temp := f.FMul(Geo_E2, temp)                                 'N = a / Sqrt(1.0 - temp)
          temp := f.FSub(1.0, temp)                                    'N = a / Sqrt(temp)
          temp := f.FSqr(temp)                                         'N = a / temp
          N := f.FDiv(earth_rad, temp)
    
       { Compute the EFG(XYZ) coordinates (earth centered)}
          temp1 := f.FAdd(N, ht)                                       'efg[0] := ((N + height) * cos_lat * cos_lon)
          temp := f.FMul(cos_lat, cos_lon)                             'efg[0] := (temp1 * cos_lat * cos_lon)
          efg_gs_lat := f.FMul(temp1, temp)                            'efg[0] := (temp1 * temp)
    
  • reppigreppig Posts: 35
    edited 2011-10-18 06:03
    Thanks. I need to put this project away for a while. I am making stupid mistakes.
Sign In or Register to comment.