PDA

View Full Version : Passing and Returning Arrays



reppig
10-14-2011, 06:13 PM
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)

Mike G
10-14-2011, 06:39 PM
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 Hein
10-14-2011, 07:45 PM
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.

MagIO2
10-14-2011, 07:50 PM
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 ....

reppig
10-15-2011, 05:28 PM
Thank you all for your help. You have help to explain what the manual did not.

Mike G
10-15-2011, 06:00 PM
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.

reppig
10-17-2011, 05:44 PM
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)

kuroneko
10-18-2011, 12:01 AM
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)

reppig
10-18-2011, 01:03 PM
Thanks. I need to put this project away for a while. I am making stupid mistakes.