/* Generated by XDS Modula-2 to ANSI C v4.20 translator */ #define X2C_int32 #define X2C_index32 #ifndef X2C_H_ #include "X2C.h" #endif #define gpssdr_C_ #ifndef osi_H_ #include "osi.h" #endif #include #include #ifndef aprsstr_H_ #include "aprsstr.h" #endif /* Sat positions/speeds from ephemerides: \brief GNSS core 'c' function library: geodesy related functions. \author Glenn D. MacGougan (GDM) \date 2007-11-28 \since 2005-08-14 \b "LICENSE INFORMATION" \n Copyright (c) 2007, refer to 'author' doxygen tags \n All rights reserved. \n Redistribution and use in source and binary forms, with or without modification, are permitted provided the following conditions are met: \n - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. \n - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. \n - The name(s) of the contributor(s) may not be used to endorse or promote products derived from this software without specific prior written permission. \n THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS `AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * dxlAPRS toolchain * * Copyright (C) oe5dxl * * SPDX-License-Identifier: GPL-2.0+ */ #define gpssdr_PI 3.1415926535898 #define gpssdr_LIGHT 2.99792458E+8 #define gpssdr_KNOTS 1.852 /* nautic miles */ #define gpssdr_FREQ 1.57542E+9 #define gpssdr_EARTH 6.378137E+6 #define gpssdr_RAD 1.7453292519943E-2 #define gpssdr_PI2 6.2831853071796 #define gpssdr_WEEK 604800 #define gpssdr_LF "\012" #define gpssdr_CR "\015" #define gpssdr_NL "\015\012" #define gpssdr_SAMPRATE 2046000 #define gpssdr_SEARCHTIME 4200000 #define gpssdr_GOLDSIZE 1023 #define gpssdr_LONGLOST 613800000 #define gpssdr_MAXINBUF 4096 static double gpssdr_FREQMUL = 4.1984040039101E+3; #define gpssdr_MAXSAT 32 #define gpssdr_IFIRLEN 5 #define gpssdr_IFIRFINEXP 6 #define gpssdr_IFIRFINE 64 /* 1<a) return b; return a; } /* end maxr() */ static void rinexfloat(double x, char s[], uint32_t s_len) { int32_t e; uint32_t n; uint32_t j; uint32_t i0; s[0UL] = ' '; if (x<0.0) { x = -x; s[0UL] = '-'; } e = 0L; if (x>0.0) { while (x<1.0) { x = x*10.0; --e; } while (x>=10.0) { x = x*0.1; ++e; } } s[2UL] = '.'; i0 = 2UL; do { n = (uint32_t)X2C_TRUNCC(x,0UL,X2C_max_longcard); x = (x-(double)n)*10.0; j = i0; if (i0==2UL) j = 1UL; s[j] = (char)(n+48UL); ++i0; } while (i0<=14UL); s[i0] = 'E'; ++i0; s[i0] = '+'; if (e<0L) { e = -e; s[i0] = '-'; } ++i0; s[i0] = (char)(e/10L+48L); ++i0; s[i0] = (char)(e%10L+48L); ++i0; if (s_len-1>=i0) s[i0] = 0; } /* end rinexfloat() */ static void rinexint(int32_t m, uint32_t w, char s[], uint32_t s_len) { uint32_t n; uint32_t j; uint32_t i0; if (m<0L) n = (uint32_t) -m; else n = (uint32_t)m; if (w>0UL) { if (w>s_len-1) w = s_len-1; i0 = w+1UL; do { --i0; if (m<0L) { s[i0] = '-'; m = 0L; } else { s[i0] = (char)(n%10UL+48UL); n = n/10UL; } } while (!(n==0UL || i0==0UL)); j = 0UL; while (jax) { if (ay>0.0f) w = X2C_DIVR(ax,ay); else w = 0.0f; w = 1.5707963267949f-(w*1.055f-w*w*0.267f); /* arctan */ } else { if (ax>0.0f) w = X2C_DIVR(ay,ax); else w = 0.0f; w = w*1.055f-w*w*0.267f; } if (x<0.0f) w = 3.1415926535898f-w; if (y<0.0f) w = -w; return w; } /* end fastatang2() */ static float CABSQ(float a, float b) { return a*a+b*b; } /* end CABSQ() */ /*- fft */ static void genrev(uint32_t size) { uint32_t ri; uint32_t n2; uint32_t s; uint32_t j; uint32_t i0; float w; uint32_t tmp; s = 0UL; ri = 1UL; n2 = size/2UL; tmp = size-1UL; i0 = 1UL; if (i0<=tmp) for (;; i0++) { if (i0Re*B->Re-A->Im*B->Im; h.Im = A->Re*B->Im+A->Im*B->Re; B->Re = R->Re-h.Re; B->Im = R->Im-h.Im; R->Re = R->Re+h.Re; R->Im = R->Im+h.Im; } /* end buttf() */ static void Transform(struct Complex feld[], uint32_t feld_len) { uint32_t N; uint32_t M; uint32_t id; uint32_t idd2; uint32_t z; uint32_t j; uint32_t i0; struct Complex wcpx; struct Complex h; float sko; float sn; float cs; float sk; float r; float ck; struct _1 * anonym; struct Complex * anonym0; uint32_t tmp; uint32_t tmp0; N = (feld_len-1)+1UL; /*bitrev*/ tmp = REVSIZE-1UL; i0 = 0UL; if (i0<=tmp) for (;; i0++) { { /* with */ struct _1 * anonym = &REV[i0]; h = feld[anonym->y]; feld[anonym->y] = feld[anonym->x]; feld[anonym->x] = h; } if (i0==tmp) break; } /* end for */ /*bitrev*/ M = (uint32_t)X2C_TRUNCC(0.5f+osic_ln((float)N)*1.44269504f,0UL,X2C_max_longcard); idd2 = 1UL; sko = FFTSIN[0U]; tmp = M; z = 1UL; if (z<=tmp) for (;; z++) { id = 2UL*idd2; sk = sko; ck = FFTSIN[z]; sko = ck; ck = 2.0f*ck*ck; r = -(2.0f*ck); cs = 1.0f; sn = 0.0f; i0 = 0UL; while (i0Re-h.Re; feld[i0+idd2].Im = anonym0->Im-h.Im; anonym0->Re = anonym0->Re+h.Re; anonym0->Im = anonym0->Im+h.Im; } i0 += id; } if (z!=1UL) { tmp0 = idd2-1UL; j = 1UL; if (j<=tmp0) for (;; j++) { ck = r*cs+ck; cs = cs+ck; sk = r*sn+sk; sn = sn+sk; wcpx.Re = cs; wcpx.Im = sn; i0 = j; while (i0=0L) osic_Close(fd); fd = osi_OpenWrite(fn, fn_len); } createnonblockfile_ret = fd; X2C_PFREE(fn); return createnonblockfile_ret; } /* end createnonblockfile() */ static void Parms(void) { char err; float u; char h[1024]; uint32_t n; almanach.tls = 18L; iqfn[0] = 0; egmfn[0] = 0; isize = 1UL; verb = 0; verb2 = 0; verb3 = 0; err = 0; u8signed = 0; maxsat = 6UL; insamp = 2000000UL; fixsat = 0UL; nmeaintervall = 50UL; searchkhz = 20UL; zerotime = 1554595200UL; nmeafd = -1L; kaldat.strength = 40.0f; soundfd = -1L; for (;;) { osi_NextArg(h, 1024ul); if (h[0U]==0) break; if ((h[0U]=='-' && h[1U]) && h[2U]==0) { if (h[1U]=='i') { osi_NextArg(iqfn, 1024ul); if (iqfn[0U]==0 || iqfn[0U]=='-') Error("-i | ", 30ul); } else if (h[1U]=='W') { osi_NextArg(warmbootfn, 1024ul); if (warmbootfn[0U]==0 || warmbootfn[0U]=='-') Error("-W ", 19ul); } else if (h[1U]=='E') { osi_NextArg(egmfn, 1024ul); if (aprsstr_StrToFix(&u, egmfn, 1024ul)) { egmmeter = u; egmfn[0] = 0; } else if (egmfn[0U]==0 || egmfn[0U]=='-') Error("-E ", 20ul); } else if (h[1U]=='D') { osi_NextArg(debugfn, 1024ul); if (debugfn[0U]==0 || debugfn[0U]=='-') Error("-D ", 19ul); } else if (h[1U]=='R') { osi_NextArg(rinexfn, 1024ul); if (rinexfn[0U]==0 || rinexfn[0U]=='-') Error("-R ", 19ul); } else if (h[1U]=='N') { osi_NextArg(h, 1024ul); if (h[0U]==0 || h[0U]=='-') Error("-N ", 23ul); nmeafd = createnonblockfile(h, 1024ul); if (nmeafd<0L) Error("write nmea file or pipe", 24ul); } else if (h[1U]=='S') { osi_NextArg(h, 1024ul); if (aprsstr_StrToFix(&u, h, 1024ul)) { soundoffset = u; osi_NextArg(h, 1024ul); } if (h[0U]==0 || h[0U]=='-') Error("-S [] ", 34ul); soundfd = createnonblockfile(h, 1024ul); if (soundfd<0L) Error("sound output file or pipe", 26ul); } else if (h[1U]=='f') { osi_NextArg(h, 1024ul); if ((h[0U]=='i' && h[1U]=='1') && h[2U]=='6') isize = 2UL; else if (h[0U]=='u' && h[1U]=='8') isize = 1UL; else if (h[0U]=='i' && h[1U]=='8') { isize = 1UL; u8signed = 1; } else if ((h[0U]=='f' && h[1U]=='3') && h[2U]=='2') isize = 4UL; else Error("-f u8|i8|i16|f32", 17ul); } else if (h[1U]=='r') { osi_NextArg(h, 1024ul); if (!aprsstr_StrToCard(h, 1024ul, &insamp) || insamp<1000000UL) { Error("-r 1800000", 28ul); } } else if (h[1U]=='b') { osi_NextArg(h, 1024ul); if (!aprsstr_StrToCard(h, 1024ul, &n) || n==0UL) { Error("-b ", 12ul); } else if (h[1U]=='L') { osi_NextArg(h, 1024ul); if (!aprsstr_StrToFix(&u, h, 1024ul)) Error("-L ", 22ul); fixpos.lat = (double)(u*1.7453292519943E-2f); osi_NextArg(h, 1024ul); if (!aprsstr_StrToFix(&u, h, 1024ul)) Error("-L ", 22ul); fixpos.long0 = (double)(u*1.7453292519943E-2f); osi_NextArg(h, 1024ul); if (!aprsstr_StrToFix(&u, h, 1024ul)) Error("-L ", 22ul); fixpos.alt = (double)u; if (fixpos.lat==0.0 && fixpos.long0==0.0) fixalt = 1; else fixall = 1; } else if (h[1U]=='m') { osi_NextArg(h, 1024ul); if ((!aprsstr_StrToCard(h, 1024ul, &maxsat) || maxsat<1UL) || maxsat>32UL) { Error("-m <1..32>", 11ul); } } else if (h[1U]=='e') { osi_NextArg(h, 1024ul); if (!aprsstr_StrToCard(h, 1024ul, &n)) Error("-e ", 12ul); zerotime = 315964800UL+619315200UL*n; } else if (h[1U]=='l') { osi_NextArg(h, 1024ul); if (!aprsstr_StrToInt(h, 1024ul, &almanach.tls)) Error("-l <[-]seconds>", 16ul); } else if (h[1U]=='p') { osi_NextArg(h, 1024ul); if ((!aprsstr_StrToCard(h, 1024ul, &n) || n<1UL) || n>32UL) { Error("-p ", 15ul); } fixsat |= (1UL<", 9ul); } else if (h[1U]=='k') { osi_NextArg(h, 1024ul); if (!aprsstr_StrToFix(&kaldat.strength, h, 1024ul)) Error("-k ", 14ul); } else if (h[1U]=='v') verb = 1; else if (h[1U]=='3') noauto23d = 1; else if (h[1U]=='H') healthignore = 1; else if (h[1U]=='V') { verb = 1; osi_NextArg(h, 1024ul); if (h[0U]=='2') verb2 = 1; if (h[0U]=='3') { verb2 = 1; verb3 = 1; } } else { if (h[1U]=='h') { osi_WrStrLn("GPS receiver from iq file or pipe from sdr", 43ul); osi_WrStrLn("eg. rtl-stick with <3ppm and working tuner on 1.575GHz and preamp antenna", 74ul); osi_WrStrLn("with >=1 sats write almanach and ephemeris file, view navigation message, clock", 80ul); osi_WrStrLn("with fix entered position and >=1 sats view freq drift and sat positions", 73ul); osi_WrStrLn("", 1ul); osi_WrStrLn(" -3 switch off auto 2d/3d-fix (3 sat if altitude ok or given -L 0 0 \ )", 94ul); osi_WrStrLn(" -A max altitude, lower for more reliable fix on ground (50000)", 83ul); osi_WrStrLn(" -D write raw 50 baud navigations msg bits to files", 71ul); osi_WrStrLn(" -E | meter or filename of egm96 file (WW15MGH.DAC) for altitude correction\ (else wgs84 altitude)", 115ul); osi_WrStrLn(" -e gps time wraps every about 19year since 1980, enter epoche (2)", 86ul); osi_WrStrLn(" -f u8|i8|i16|f32 IQ data format (u8)", 43ul); osi_WrStrLn(" -H ignore health status of sat (may lead to wrong position/speed)", 86ul); osi_WrStrLn(" -h this", 28ul); osi_WrStrLn(" -i IQ-filename or pipe from sdr receiver", 61ul); osi_WrStrLn(" -k position noise filter 0=off (40)", 56ul); osi_WrStrLn(" -L rx position and altitude degrees in WGS84, or give fix altitude \"0 0\ \"", 104ul); osi_WrStrLn(" to get frequency with 1 sat (see -v) or (initial) 2d fix with 3 sat,\ wrong altitude leads no fix or wrong position", 139ul); osi_WrStrLn(" -l give actual leap seconds to get utc before found in sat data (18)", 89ul); osi_WrStrLn(" -m channels which will search for sats (1..32) more need more cpu (6)", 90ul); osi_WrStrLn(" -N write nmea output to file or pipe", 57ul); osi_WrStrLn(" -p sat number whitch will be continous traced (1..32) may be repeated wi\ th -m 1 do nothing else", 116ul); osi_WrStrLn(" -R write rinex LNAV ephemerides", 52ul); osi_WrStrLn(" -r iq-samplerate in Hz (2000000)", 53ul); osi_WrStrLn(" -S [] output .wav file or pipe, offset(Hz) shifts negative tones thru zero \ to positive tones, ronly locked sat have sound", 139ul); osi_WrStrLn(" -v verbous", 31ul); osi_WrStrLn(" -V [n] more verbous -V 2 -V 3", 46ul); osi_WrStrLn(" -w sat frequency search width in kHz, doppler(4khz)+rx offset, wider for\ fast moving or unexact rx lo (20)", 127ul); osi_WrStrLn("", 1ul); osi_WrStrLn("rtl_sdr -s 2000000 -f 1575420000 - | ./gpssdr -i /dev/stdin -f u8 -r 2000000 -m 6 -v", 85ul); X2C_ABORT(); } err = 1; } } else err = 1; if (err) break; } if (err) { osi_Werr(">", 2ul); osi_Werr(h, 1024ul); osi_Werr("< use -h\012", 10ul); X2C_ABORT(); } } /* end Parms() */ /*-- wav file header */ #define gpssdr_bytes 2 static void wwav(int32_t fd, uint32_t hz, uint32_t ch) { char b[44]; strncpy(b,"RIFF WAVEfmt ",44u); b[4U] = '\377'; /* len */ b[5U] = '\377'; b[6U] = '\377'; b[7U] = '\377'; b[16U] = '\020'; b[17U] = 0; b[18U] = 0; b[19U] = 0; b[20U] = '\001'; /* PCM/ALAW */ b[21U] = 0; b[22U] = (char)ch; /* channels */ b[23U] = 0; b[24U] = (char)(hz&255UL); /* samp */ b[25U] = (char)(hz/256UL&255UL); b[26U] = (char)(hz/65536UL&255UL); b[27U] = (char)(hz/16777216UL); b[28U] = (char)(hz*2UL&255UL); /* byte/s */ b[29U] = (char)((hz*2UL)/256UL&255UL); b[30U] = (char)((hz*2UL)/65536UL); b[31U] = 0; b[32U] = '\002'; /* block byte */ b[33U] = 0; b[34U] = '\020'; /* bit/samp */ b[35U] = 0; b[36U] = 'd'; b[37U] = 'a'; b[38U] = 't'; b[39U] = 'a'; b[40U] = '\377'; /* len */ b[41U] = '\377'; b[42U] = '\377'; b[43U] = '\377'; if (fd>=0L) osi_WrBin(fd, (char *)b, 44u/1u, 44UL); } /* end wwav() */ static void initlp(float fg) { lpAR = X2C_DIVR(fg,4.3773242630385E-1f); lpAL = lpAR*lpAR*2.888f; olpAR = 1.0f-lpAR; } /* end initlp() */ static float lp(struct LPCONTEXT * lpc, float u) { struct LPCONTEXT * anonym; { /* with */ struct LPCONTEXT * anonym = lpc; anonym->uca1 = (anonym->uca1+(u-anonym->uca1)*lpAR)-anonym->ila; anonym->uca2 = anonym->uca2*olpAR+anonym->ila; anonym->ila = anonym->ila+(anonym->uca1-anonym->uca2)*lpAL; return anonym->uca2; } } /* end lp() */ /*-- make sat audible after despreding */ static void soundout(pSATDEMOD s) { uint32_t i0; uint32_t d; float fr; float si; float panr; float panl; float pan; if (lpAR==0.0f) { initlp(1.5625E-2f); wwav(soundfd, 32000UL, 2UL); } if (X2C_IN(s->prn,32,sounddone)) { /*WrStr("b"); */ for (i0 = 0UL; i0<=63UL; i0++) { si = soundsum[i0]*soundgain; soundsum[i0] = 0.0f; if ((float)fabs(si)>20000.0f) soundgain = soundgain*0.95f; else if (soundgain<20000.0f) soundgain = soundgain*1.0002f; if (soundgain<0.00001f) soundgain = 0.00001f; if (si>30000.0f) si = 30000.0f; else if (si<(-3.E+4f)) si = (-3.E+4f); afbuf[afbufw] = (short)(int32_t)X2C_TRUNCI(si,X2C_min_longint,X2C_max_longint); ++afbufw; if (afbufw>4095UL) { osi_WrBin(soundfd, (char *)afbuf, 8192u/1u, 8192UL); afbufw = 0UL; } } /* end for */ /*WrStr(" g:"); WrFixed(soundgain,8,1); */ sounddone = 0UL; } sounddone |= (1UL<prn); pan = (float)(sat[s->prn].satpos.azimuth*1.591549430919E-1); if (pan==0.0f) pan = (float)s->prn*0.03125f; pan = pan*0.8f; panr = 0.9f-pan; panl = 0.1f+pan; fr = (float)((double)s->freq*2.3818574845791E-4+(double)soundoffset); if (fr<(-1.6E+7f)) fr = (-1.6E+4f); else if (fr>16000.0f) fr = 16000.0f; /*WrStr(" fr=");WrFixed(fr,1,1);WrStrLn(""); */ for (i0 = 0UL; i0<=31UL; i0++) { s->sound.dds += (uint32_t)(int32_t)X2C_TRUNCI(fr*1.34217728E+5f,X2C_min_longint,X2C_max_longint); d = (uint32_t)X2C_LSH((uint32_t)s->sound.dds,32,-18); si = lp(&s->sound.lpci, s->sumi)*DDS[d]-lp(&s->sound.lpcq, s->sumq)*DDS[d+4096UL&16383UL]; soundsum[i0*2UL] = soundsum[i0*2UL]+si*panl; soundsum[i0*2UL+1UL] = soundsum[i0*2UL+1UL]+si*panr; } /* end for */ } /* end soundout() */ /*-- generate gold codes with shift registers */ static uint8_t gpssdr_TAPS[64] = {2U,6U,3U,7U,4U,8U,5U,9U,1U,9U,2U,10U,1U,8U,2U,9U,3U,10U,2U,3U,3U,4U,5U,6U,6U,7U,7U, 8U,8U,9U,9U,10U,1U,4U,2U,5U,3U,6U,4U,7U,5U,8U,6U,9U,1U,3U,4U,6U,5U,7U,6U,8U,7U,9U,8U,10U,1U,6U,2U,7U,3U, 8U,4U,9U}; static uint8_t _cnst[64] = {2U,6U,3U,7U,4U,8U,5U,9U,1U,9U,2U,10U,1U,8U,2U,9U,3U,10U,2U,3U,3U,4U,5U,6U,6U,7U,7U,8U,8U, 9U,9U,10U,1U,4U,2U,5U,3U,6U,4U,7U,5U,8U,6U,9U,1U,3U,4U,6U,5U,7U,6U,8U,7U,9U,8U,10U,1U,6U,2U,7U,3U,8U,4U, 9U}; static void goldcode(void) { uint32_t sat0; uint32_t i0; uint16_t b; uint16_t a; for (sat0 = 0UL; sat0<=31UL; sat0++) { a = 0x3FFU; b = 0x3FFU; for (i0 = 1UL; i0<=1023UL; i0++) { /* index+1 for fast demodulation */ GOLD[sat0][i0] = (char)((uint32_t)((0x200U & a)!=0)+(uint32_t)X2C_IN((uint32_t) _cnst[sat0*2UL]-1UL,10,b)+(uint32_t)X2C_IN((uint32_t)_cnst[sat0*2UL+1UL]-1UL,10,b)&1); if (((uint32_t)((0x200U & a)!=0)+(uint32_t)((0x4U & a)!=0)&1)) a = X2C_LSH(a,10,1)|0x1U; else a = X2C_LSH(a,10,1); if (((uint32_t)((0x2U & b)!=0)+(uint32_t)((0x4U & b)!=0)+(uint32_t)((0x20U & b)!=0)+(uint32_t) ((0x80U & b)!=0)+(uint32_t)((0x100U & b)!=0)+(uint32_t)((0x200U & b)!=0)&1)) { b = X2C_LSH(b,10,1)|0x1U; } else b = X2C_LSH(b,10,1); } /* end for */ GOLD[sat0][0U] = GOLD[sat0][1U]; } /* end for */ } /* end goldcode() */ static void wbit(uint32_t sat0, uint32_t frame, const char t[], uint32_t t_len, uint32_t s) { uint32_t i0; osic_WrINT32(sat0+1UL, 2UL); osi_WrStr(",", 2ul); osic_WrINT32(frame, 1UL); osi_WrStr(t, t_len); osi_WrStr("[", 2ul); for (i0 = 29UL;; i0--) { osic_WrINT32((uint32_t)X2C_IN(i0,32,s), 1UL); if (i0==0UL) break; } /* end for */ osi_WrStrLn("]", 2ul); } /* end wbit() */ static void GpsDate(uint32_t wn, uint32_t tow, char s[], uint32_t s_len) { aprsstr_DateToStr((zerotime-(uint32_t)almanach.tls)+wn*604800UL+tow, s, s_len); } /* end GpsDate() */ static void WrDate(uint32_t wn, uint32_t tow) { char h[100]; GpsDate(wn, tow, h, 100ul); osi_WrStr(h, 100ul); } /* end WrDate() */ static uint32_t twnwrap(uint32_t wn, uint32_t tw6, uint32_t to) { tw6 = tw6*6UL; if ((int32_t)(to-tw6)<0L) to += 604800UL; return wn*604800UL+to; } /* end twnwrap() */ static char satgood(uint32_t s) { struct SAT * anonym; { /* with */ struct SAT * anonym = &sat[s]; return (((anonym->insyn && anonym->datasyn) && anonym->satok) && sat[s].bert==0UL) && sat[s].satpos.elevation>0.0; } } /* end satgood() */ /*-------- navigation */ /*-- egm altitude correction */ /*GEOIDFN="WW15MGH.DAC"; */ #define gpssdr_RESOL 4 /* 1/deg */ #define gpssdr_LONGS 1440 /* values in file around a latitude */ static float rdgeoid(int32_t fd, int32_t lat, int32_t long0, char * ok0) { char b[2]; int32_t n; osic_Seek(fd, (uint32_t)((lat*1440L+long0)*2L)); if (osi_RdBin(fd, (char *)b, 2u/1u, 2UL)!=2L) { /* no data in file */ n = 0L; *ok0 = 0; } else { n = (int32_t)((uint32_t)(uint8_t)b[1U]+(uint32_t)(uint8_t)b[0U]*256UL); if (n>=32768L) n -= 65536L; } return (float)n; } /* end rdgeoid() */ static float egm96(float lat, float long0, char * ok0) /* read and interpolate geoid correction from datafile in RAD */ { int32_t ilong; int32_t ilat; int32_t fd; float g; float flong; float flat; *ok0 = 0; if (egmfn[0]) { fd = osi_OpenRead(egmfn, 1024ul); *ok0 = fd>=0L; } g = 0.0f; if (*ok0) { lat = 90.0f-lat*5.7295779513082E+1f; long0 = long0*5.7295779513082E+1f; if (long0<0.0f) long0 = 360.0f+long0; lat = lat*4.0f; long0 = long0*4.0f; if (lat>=0.0f) ilat = (int32_t)(uint32_t)X2C_TRUNCC(lat,0UL,X2C_max_longcard); else ilat = 0L; if (long0>=0.0f) ilong = (int32_t)(uint32_t)X2C_TRUNCC(long0,0UL,X2C_max_longcard); else ilong = 0L; flat = lat-(float)ilat; flong = long0-(float)ilong; g = ((rdgeoid(fd, ilat, ilong, ok0)*(1.0f-flat)+rdgeoid(fd, ilat+1L, ilong, ok0)*flat)*(1.0f-flong)+(rdgeoid(fd, ilat, ilong+1L, ok0)*(1.0f-flat)+rdgeoid(fd, ilat+1L, ilong+1L, ok0)*flat)*flong)*0.01f; osic_Close(fd); } return g; } /* end egm96() */ /*-- egm */ /*-- nmea output */ #define gpssdr_Z 48 static void cstr(uint32_t n, uint32_t f, char s[], uint32_t s_len) { s[f] = 0; while (f>0UL) { --f; s[f] = (char)(48UL+n%10UL); n = n/10UL; } } /* end cstr() */ static uint32_t dB(float u) { float d; d = 0.0f; if (u>0.0001f) d = (float)(log((double)u)*8.68588963); if (d<=0.0f) d = 0.0f; else if (d>99.0f) d = 99.0f; return (uint32_t)X2C_TRUNCC(d,0UL,X2C_max_longcard); } /* end dB() */ static void deg(char s[201], double d, char lon) { uint32_t p; uint32_t n; p = aprsstr_Length(s, 201ul); n = (uint32_t)X2C_TRUNCC(fabs(d)*3.4377467707849E+7,0UL,X2C_max_longcard); if (lon) { s[p] = (char)((n/60000000UL)%10UL+48UL); ++p; } s[p] = (char)((n/6000000UL)%10UL+48UL); ++p; s[p] = (char)((n/600000UL)%10UL+48UL); ++p; s[p] = (char)((n/100000UL)%6UL+48UL); ++p; s[p] = (char)((n/10000UL)%10UL+48UL); ++p; s[p] = '.'; ++p; s[p] = (char)((n/1000UL)%10UL+48UL); ++p; s[p] = (char)((n/100UL)%10UL+48UL); ++p; s[p] = (char)((n/10UL)%10UL+48UL); ++p; s[p] = (char)(n%10UL+48UL); ++p; s[p] = 0; } /* end deg() */ static void sum(char s[201]) { uint32_t p; uint32_t i0; uint8_t cs; uint32_t tmp; p = aprsstr_Length(s, 201ul); s[p] = '*'; ++p; cs = 0U; tmp = p-2UL; i0 = 1UL; if (i0<=tmp) for (;; i0++) { cs = cs^(uint8_t)(uint8_t)s[i0]; if (i0==tmp) break; } /* end for */ s[p] = hex((uint32_t)cs/16UL, 1); ++p; s[p] = hex((uint32_t)cs, 1); ++p; s[p] = '\015'; ++p; s[p] = '\012'; ++p; osi_WrBin(nmeafd, (char *)s, 201u/1u, p); } /* end sum() */ static void date(char h[201], char s[201]) { uint32_t p; p = aprsstr_Length(s, 201ul); s[p] = h[8U]; ++p; s[p] = h[9U]; ++p; s[p] = h[5U]; ++p; s[p] = h[6U]; ++p; s[p] = h[2U]; ++p; s[p] = h[3U]; ++p; s[p] = 0; } /* end date() */ static void time0(char h[201], char s[201]) { uint32_t p; p = aprsstr_Length(s, 201ul); s[p] = h[11U]; ++p; s[p] = h[12U]; ++p; s[p] = h[14U]; ++p; s[p] = h[15U]; ++p; s[p] = h[17U]; ++p; s[p] = h[18U]; ++p; s[p] = 0; aprsstr_Append(s, 201ul, ".000,", 6ul); } /* end time() */ static void apos(char s[201], struct POS pos) { deg(s, pos.lat, 0); if (pos.lat<0.0) aprsstr_Append(s, 201ul, ",S,", 4ul); else aprsstr_Append(s, 201ul, ",N,", 4ul); deg(s, pos.long0, 1); if (pos.long0<0.0) aprsstr_Append(s, 201ul, ",W,", 4ul); else aprsstr_Append(s, 201ul, ",E,", 4ul); } /* end apos() */ static void nmea(uint32_t utc, const struct POS pos, char fix, char noauto, uint32_t satc, float pdop, float hdop, float vdop, float egm) /* RAD */ { char hn[201]; char h[201]; char s[201]; uint32_t sc; uint32_t satcnt; uint32_t sn; char tmp; satcnt = 0UL; for (sn = 0UL; sn<=32UL; sn++) { if (satgood(sn)) ++satcnt; } /* end for */ strncpy(s,"$GPGGA,",201u); aprsstr_DateToStr(utc, h, 201ul); time0(h, s); apos(s, pos); aprsstr_IntToStr((int32_t)(uint32_t)fix, 1UL, hn, 201ul); aprsstr_Append(s, 201ul, hn, 201ul); aprsstr_Append(s, 201ul, ",", 2ul); cstr(satcnt, 2UL, hn, 201ul); aprsstr_Append(s, 201ul, hn, 201ul); aprsstr_Append(s, 201ul, ",", 2ul); aprsstr_FixToStr(hdop, 2UL, hn, 201ul); aprsstr_Append(s, 201ul, hn, 201ul); aprsstr_Append(s, 201ul, ",", 2ul); aprsstr_FixToStr((float)(pos.alt-(double)egm), 2UL, hn, 201ul); aprsstr_Append(s, 201ul, hn, 201ul); aprsstr_Append(s, 201ul, ",M,", 4ul); aprsstr_FixToStr(egm, 2UL, hn, 201ul); aprsstr_Append(s, 201ul, hn, 201ul); aprsstr_Append(s, 201ul, ",M,,0000", 9ul); sum(s); strncpy(s,"$GPRMC,",201u); aprsstr_DateToStr(utc, h, 201ul); time0(h, s); if (fix) aprsstr_Append(s, 201ul, "A,", 3ul); else aprsstr_Append(s, 201ul, "V,", 3ul); apos(s, pos); aprsstr_FixToStr((float)((X2C_DIVL((double)(pos.speed*6.378137E+6f),6.378137E+6+pos.alt))*1.9438444924406), 3UL, hn, 201ul); /* speed over ground wherever ground is */ aprsstr_Append(s, 201ul, hn, 201ul); aprsstr_Append(s, 201ul, ",", 2ul); aprsstr_FixToStr(pos.dir*5.7295779513082E+1f, 3UL, hn, 201ul); aprsstr_Append(s, 201ul, hn, 201ul); aprsstr_Append(s, 201ul, ",", 2ul); date(h, s); aprsstr_Append(s, 201ul, ",,", 3ul); sum(s); strncpy(s,"$GPGSA,",201u); if (noauto) aprsstr_Append(s, 201ul, "M,", 3ul); else aprsstr_Append(s, 201ul, "A,", 3ul); aprsstr_Append(s, 201ul, (char *)(tmp = (char)(49UL+(uint32_t)fix+(uint32_t)(fix && satc>=4UL)),&tmp), 1u/1u); sc = 0UL; for (sn = 0UL; sn<=32UL; sn++) { if (sc<12UL && sat[sn].satok) { aprsstr_Append(s, 201ul, ",", 2ul); cstr(sn+1UL, 2UL, hn, 201ul); aprsstr_Append(s, 201ul, hn, 201ul); ++sc; } } /* end for */ for (sn = sc; sn<=12UL; sn++) { aprsstr_Append(s, 201ul, ",", 2ul); } /* end for */ aprsstr_FixToStr(pdop, 2UL, hn, 201ul); aprsstr_Append(s, 201ul, hn, 201ul); aprsstr_Append(s, 201ul, ",", 2ul); aprsstr_FixToStr(hdop, 2UL, hn, 201ul); aprsstr_Append(s, 201ul, hn, 201ul); aprsstr_Append(s, 201ul, ",", 2ul); aprsstr_FixToStr(vdop, 2UL, hn, 201ul); aprsstr_Append(s, 201ul, hn, 201ul); sum(s); ++vtgcnt; if (vtgcnt>=6UL) { vtgcnt = 0UL; if (satcnt>0UL) { sc = 0UL; for (sn = 0UL; sn<=32UL; sn++) { /* WITH sat[sn] DO */ if (satgood(sn)) { if ((sc&3UL)==0UL) { strncpy(s,"$GPGSV,",201u); cstr((satcnt+3UL)/4UL, 1UL, hn, 201ul); aprsstr_Append(s, 201ul, hn, 201ul); aprsstr_Append(s, 201ul, ",", 2ul); cstr(1UL+sc/4UL, 1UL, hn, 201ul); aprsstr_Append(s, 201ul, hn, 201ul); aprsstr_Append(s, 201ul, ",", 2ul); cstr(satcnt, 2UL, hn, 201ul); aprsstr_Append(s, 201ul, hn, 201ul); aprsstr_Append(s, 201ul, ",", 2ul); } cstr(sn+1UL, 2UL, hn, 201ul); aprsstr_Append(s, 201ul, hn, 201ul); aprsstr_Append(s, 201ul, ",", 2ul); cstr((uint32_t)(int32_t)X2C_TRUNCI(X2C_DIVL(sat[sn].satpos.elevation,1.7453292519943E-2), X2C_min_longint,X2C_max_longint), 2UL, hn, 201ul); aprsstr_Append(s, 201ul, hn, 201ul); aprsstr_Append(s, 201ul, ",", 2ul); cstr((uint32_t)(int32_t)X2C_TRUNCI(X2C_DIVL(sat[sn].satpos.azimuth,1.7453292519943E-2), X2C_min_longint,X2C_max_longint), 3UL, hn, 201ul); aprsstr_Append(s, 201ul, hn, 201ul); aprsstr_Append(s, 201ul, ",", 2ul); cstr(dB(sat[sn].sig), 2UL, hn, 201ul); aprsstr_Append(s, 201ul, hn, 201ul); if ((sc&3UL)==3UL || sc+1UL==satcnt) sum(s); else aprsstr_Append(s, 201ul, ",", 2ul); ++sc; } } /* end for */ } } /* END; */ /* 2019.04.07 23:21:00 knots dir $GPRMC,032855.000,A,4815.0819,N,01302.2757,E,0.29,21.09,160225,,,A*5B $GPVTG,21.09,T,,M,0.29,N,0.5,K,A*39 fix sat hdop alt egm $GPGGA,032856.000,4815.0819,N,01302.2758,E,1,06,1.4,344.8,M,46.5,M,,0000*59 lines line sats prn el az snr $GPGSV,3,1,12,16,68,258,30,18,55,057,18,26,53,197,34,23,48,123,38*73 $GPGSV,3,2,12,27,44,291,20,10,24,167,39,29,12,097,29,08,10,287,*72 $GPGSV,3,3,12,15,08,074,20,07,07,330,,05,03,028,,31,02,211,*79 PDOP HDOP VDOP 12 channels uses sat nr 1 no 2 2d 3 3d fix A/M auto 2d $GPGSA,A,3,07,,,,,,,,,,,,1.7,1.0,0.5*33 */ } /* end nmea() */ /*-- nmea output */ static void wgs84(double lat, double long0, double heig, double * x, double * y, double * z) /* wgs84 ecef */ { double h; double sl; double n; sl = sin(lat); n = X2C_DIVL(6.378137E+6,sqrt(1.0-6.6943799901413E-3*sl*sl)); h = (heig+n)*cos(lat); *z = (n*9.9330562000986E-1+heig)*sl; *y = h*sin(long0); *x = h*cos(long0); } /* end wgs84() */ #define gpssdr_A 6.378137E+6 #define gpssdr_B 6.3567523142452E+6 static void wgs84r(double x, double y, double z, double * lat, double * long0, double * heig) { double n; double p; double s; double d; if (x==0.0 && y==0.0) { *long0 = 0.0; if (z<0.0) { *heig = -z-6.3567523142452E+6; *lat = (-1.5707963267949); } else { *heig = z-6.3567523142452E+6; *lat = 1.5707963267949; } } else { p = sqrt(x*x+y*y); /* best formula for any longitude and applies well near the poles */ *long0 = 2.0*atan2(y, x+p); *lat = atan(X2C_DIVL(z,p*9.9330562000986E-1)); /* set approximate initial latitude assuming a height of 0.0*/ *heig = 0.0; do { d = *heig; s = sin(*lat); n = X2C_DIVL(6.378137E+6,sqrt(1.0-6.6943799901413E-3*s*s)); *heig = X2C_DIVL(p,cos(*lat))-n; *lat = atan(X2C_DIVL(z,p*(1.0-X2C_DIVL(6.6943799901413E-3*n,n+*heig)))); } while (fabs(*heig-d)>0.01); } /* 10mm */ } /* end wgs84r() */ static double dist(double x0, double y00, double z0, double x1, double y1, double z1) { x0 = x0-x1; y00 = y00-y1; z0 = z0-z1; return sqrt(x0*x0+y00*y00+z0*z0); } /* end dist() */ static double angdiff(double a, double b) { a = a-b; if (a<(-3.1415926535898)) a = a+6.2831853071796; else if (a>3.1415926535898) a = a-6.2831853071796; return a; } /* end angdiff() */ /*-- azimuth RAD +-PI of 2 positions fast but only exact for small distance */ static float shortdir(struct POS a, struct POS b) { double y; double x; y = a.lat-b.lat; x = a.long0-b.long0; if (x>3.1415926535898) x = x-6.2831853071796; else if (x<(-3.1415926535898)) x = x+6.2831853071796; x = x*(double)osic_cos((float)((b.lat+a.lat)*0.5)); return (float)atan2(x, y); } /* end shortdir() */ static double shortdist(const struct POS a, const struct POS b) /* only exact on short distance */ { return sqrt(sqrl(angdiff(a.lat, b.lat))+sqrl(angdiff(a.long0, b.long0)*cos((a.lat+b.lat)*0.5)))*6.378137E+6; } /* end shortdist() */ static void rotatexyz(double lat, double long0, double x, double y, double z, double * xr, double * yr, double * zr) { double coslon; double sinlon; double coslat; double sinlat; sinlat = sin(lat); coslat = cos(lat); sinlon = sin(long0); coslon = cos(long0); *xr = (coslat*z-sinlat*coslon*x)-sinlat*sinlon*y; *yr = coslon*y-sinlon*x; *zr = coslat*coslon*x+coslat*sinlon*y+sinlat*z; } /* end rotatexyz() */ /*--- azimuth and elevation from 2 positions */ static void azelxyzxyz(double fromX, double fromY, double fromZ, double toX, double toY, double toZ, double * azimuth, double * elevation) { double tmp; double dUp; double dE; double dN; double dZ; double dY; double dX; double lon; double lat; *elevation = 0.0; *azimuth = 0.0; wgs84r(fromX, fromY, fromZ, &lat, &lon, &tmp); dX = toX-fromX; dY = toY-fromY; dZ = toZ-fromZ; rotatexyz(lat, lon, dX, dY, dZ, &dN, &dE, &dUp); tmp = sqrt(dN*dN+dE*dE); if (tmp==0.0) { if (dUp<0.0) *elevation = (-1.5707963267949); else *elevation = 1.5707963267949; } else *elevation = atan(X2C_DIVL(dUp,tmp)); *azimuth = atan2(dE, dN); if (*azimuth<0.0) *azimuth = *azimuth+6.2831853071796; } /* end azelxyzxyz() */ #define gpssdr_WGS84_EARTH_ROTATION_RA 7.2921151467E-5 static void SatPosVelocity(uint32_t transmission_gpsweek, double transmission_gpstow, uint32_t ephem_week, uint32_t toe, double m0, double delta_n, double ecc, double sqrta, double omega0, double i0, double w, double omegadot, double idot, double cuc, double cus, double crc, double crs, double cic, double cis, double estimateOfTrueRange, double estimteOfRangeRate, double * x, double * y, double * z, double * vx, double * vy, double * vz) { uint32_t j; /* x velocity in the orbital plane [m/s] */ double vy_op; /* y velocity in the orbital plane [m/s] */ /* temp */ double vx_op; /* temp */ double tmpb; /* d/dt of the radius in the orbital plane [m/s] */ double tmpa; /* d/dt of the rate of the inclination angle [rad/s^2] */ double rdot; /* d/dt of argument of latitude [rad/s] */ double idotdot; /* d/dt of true anomaly [rad/s] */ double udot; /* edot = n/(1.0 - ecc*cos(E)), [rad/s] */ double vdot; /* corrected rate of right ascension [rad/s] */ double edot; /* sin(E) */ double omegadotk; /* cos(E) */ double sinE; /* sin(i) */ double cosE; /* cos(i) */ double sini; /* sin(u) */ double cosi; /* cos(u) */ double sinu; /* sin(omegak) */ double cosu; /* cos(omegak) */ double sin_omegak; /* corrected longitude of the ascending node [rad] */ double cos_omegak; /* y position in the orbital plane [m] */ double omegak; /* x position in the orbital plane [m] */ double y_op; /* inclination correction [rad] */ double x_op; /* radius correction [m] */ double d_i; /* argument of latitude correction [rad] */ double d_r; /* sin(2*u) [] */ double d_u; /* cos(2*u) [] */ double sin2u; /* orbital inclination [rad] */ double cos2u; /* radius in the orbital plane [m] */ double i1; /* argument of latitude, corrected [rad] */ double r; /* true anomaly [rad] */ double u; /* eccentric anomaly [rad] */ double v; /* mean anomaly, [rad] (Kepler's equation for eccentric anomaly, solved by iteration) */ double E; /* corrected mean motion [rad/s] */ double M; /* semi-major axis of orbit [m] */ double n; /* time from ephemeris reference epoch [s] */ double a; /* time of transmission (including gps week) [s] */ double tk; double tot; /* compute the times from the reference epochs By including the week in the calculation, week rollover and older ephemeris bugs are mitigated The result should be between -302400 and 302400 if the ephemeris is within one week of transmission */ tot = (double)(transmission_gpsweek*604800UL)+transmission_gpstow; tk = tot-(double)(ephem_week*604800UL+toe); /* compute the corrected mean motion term */ a = sqrta*sqrta; n = sqrt(X2C_DIVL(3.986005E+14,a*a*a)); /* computed mean motion */ n = n+delta_n; /* corrected mean motion */ /* Kepler's equation for eccentric anomaly */ M = m0+n*tk; /* mean anomaly */ E = M; for (j = 0UL; j<=6UL; j++) { E = M+ecc*sin(E); } /* end for */ cosE = cos(E); sinE = sin(E); /* true anomaly */ v = atan2(sqrt(1.0-ecc*ecc)*sinE, cosE-ecc); /* argument of latitude */ u = v+w; /* radius in orbital plane */ r = a*(1.0-ecc*cos(E)); /* orbital inclination */ i1 = i0; /* second harmonic perturbations */ cos2u = cos(2.0*u); sin2u = sin(2.0*u); /* argument of latitude correction */ d_u = cuc*cos2u+cus*sin2u; /* radius correction */ d_r = crc*cos2u+crs*sin2u; /* correction to inclination */ d_i = cic*cos2u+cis*sin2u; /* corrected argument of latitude */ u = u+d_u; /* corrected radius */ r = r+d_r; /* corrected inclination */ i1 = i1+d_i+idot*tk; /* positions in orbital plane */ cosu = cos(u); sinu = sin(u); x_op = r*cosu; y_op = r*sinu; /* compute the corrected longitude of the ascending node This equation deviates from that in Table 20-IV p. 100 GPSICD200C with the inclusion of the signal propagation time (estimateOfTrueRange/LIGHTSPEED) term. This compensates for the Sagnac effect. The omegak term is thus sensitive to the estimateOfTrueRange term which is usually unknown without prior information. The average signal propagation time/range (70ms * c) can be used on first use and this function must be called again to iterate this term. The sensitivity of the omegak term typically requires N iterations - GDM_DEBUG{find out how many iterations are needed, how sensitive to the position? */ omegak = (omega0+(omegadot-7.2921151467E-5)*tk)-7.2921151467E-5*((double)toe+X2C_DIVL(estimateOfTrueRange, 2.99792458E+8)); /* compute the WGS84 ECEF coordinates, vector r with components x & y is now rotated using, R3(-omegak)*R1(-i) */ cos_omegak = cos(omegak); sin_omegak = sin(omegak); cosi = cos(i1); sini = sin(i1); *x = x_op*cos_omegak-y_op*sin_omegak*cosi; *y = x_op*sin_omegak+y_op*cos_omegak*cosi; *z = y_op*sini; /* Satellite Velocity Computations are below see Reference Remodi, B. M (2004). GPS Tool Box: Computing satellite velocities using the broadcast ephemeris. GPS Solutions. Volume 8(3), 2004. pp. 181-183 example source code was available at [http:www.ngs.noaa.gov/gps-toolbox/bc_velo/bc_velo.c] recomputed the cos and sin of the corrected argument of latitude */ cos2u = cos(2.0*u); sin2u = sin(2.0*u); edot = X2C_DIVL(n,1.0-ecc*cosE); vdot = X2C_DIVL(sinE*edot*(1.0+ecc*cos(v)),sin(v)*(1.0-ecc*cosE)); udot = vdot+2.0*(cus*cos2u-cuc*sin2u)*vdot; rdot = X2C_DIVL(a*ecc*sinE*n,1.0-ecc*cosE)+2.0*(crs*cos2u-crc*sin2u)*vdot; idotdot = idot+(cis*cos2u-cic*sin2u)*2.0*vdot; vx_op = rdot*cosu-y_op*udot; vy_op = rdot*sinu+x_op*udot; /* corrected rate of right ascension including similarily as above, for omegak, compensation for the Sagnac effect */ omegadotk = omegadot-7.2921151467E-5*(1.0+X2C_DIVL(estimteOfRangeRate,2.99792458E+8)); tmpa = vx_op-y_op*cosi*omegadotk; tmpb = (x_op*omegadotk+vy_op*cosi)-y_op*sini*idotdot; *vx = tmpa*cos_omegak-tmpb*sin_omegak; *vy = tmpa*sin_omegak+tmpb*cos_omegak; *vz = vy_op*sini+y_op*cosi*idotdot; } /* end SatPosVelocity() */ #define gpssdr_CLOCK_CORRECTION_RELATI (-4.442807633E-10) #define gpssdr_RATIO_OF_SQUARED_FREQUE 1.6469444444444 static void ClockCorrDrift(uint32_t transmission_gpsweek, double transmission_gpstow, uint32_t ephem_week, uint32_t toe, uint32_t toc, double af0, double af1, double af2, double ecc, double sqrta, double delta_n, double m0, double tgd, uint32_t mode, double * clock_correction, double * clock_drift) { uint32_t i0; double E; double M; double n; double a; double d_tsv; double d_tr; double tc; double tk; double tot; /* compute the times from the reference epochs By including the week in the calculation, week rollover and old ephmeris bugs are mitigated The result should be between -302400 and 302400 if the ephemeris is within one week of transmission */ tot = (double)(transmission_gpsweek*604800UL)+transmission_gpstow; tk = tot-(double)(ephem_week*604800UL+toe); tc = tot-(double)(ephem_week*604800UL+toc); /* compute the corrected mean motion term */ a = sqrta*sqrta; n = sqrt(X2C_DIVL(3.986005E+14,a*a*a)); n = n+delta_n; /* Kepler's equation for eccentric anomaly */ M = m0+n*tk; E = M; for (i0 = 0UL; i0<=6UL; i0++) { E = M+ecc*sin(E); } /* end for */ /* relativistic correction*/ d_tr = (-4.442807633E-10)*ecc*sqrta*sin(E); /* clock correcton */ d_tsv = af0+af1*tc+af2*tc*tc; if (mode==0UL) { /* L1 only */ d_tsv = d_tsv-tgd; } else if (mode==1UL) { /* L2 only */ d_tsv = d_tsv-tgd*1.6469444444444; } *clock_correction = (d_tsv+d_tr)*2.99792458E+8; *clock_drift = (af1+2.0*af2*tc)*2.99792458E+8; } /* end ClockCorrDrift() */ /*--- calculate position of sat */ static void SatPos(double userX, double userY, double userZ, uint32_t gpsweek, double gpstow, uint32_t ephem_week, uint32_t toe, uint32_t toc, double af0, double af1, double af2, double tgd, double m0, double delta_n, double ecc, double sqrta, double omega0, double i0, double w, double omegadot, double idot, double cuc, double cus, double crc, double crs, double cic, double cis, double * clock_correction, double * clock_drift, double * satX, double * satY, double * satZ, double * satVx, double * satVy, double * satVz, double * azimuth, double * elevation, double * doppler) /* !< time of week of signal transmission (gpstow-psr/c) [s] */ /* !< ephemeris: GPS week (0-1024+) [weeks] */ /* !< ephemeris: time of week [s] */ /* !< ephemeris: clock reference time of week [s] */ /* !< ephemeris: polynomial clock correction coefficient [s], Note: parameters from ephemeris preferred vs almanac (22 vs 11 bits) */ /* !< ephemeris: polynomial clock correction coefficient [s/s], Note: parameters from ephemeris preferred vs almanac (16 vs 11 bits) */ /* !< ephemeris: polynomial clock correction coefficient [s/s^2] */ /* !< ephemeris: group delay differential between L1 and L2 [s] */ /* !< ephemeris: mean anomaly at reference time [rad] */ /* !< ephemeris: mean motion difference from computed value [rad/s] */ /* !< ephemeris: eccentricity [] */ /* !< ephemeris: square root of the semi-major axis [m^(1/2)] */ /* !< ephemeris: longitude of ascending node of orbit plane at weekly epoch [rad] */ /* !< ephemeris: inclination angle at reference time [rad] */ /* !< ephemeris: argument of perigee [rad] */ /* !< ephemeris: rate of right ascension [rad/s] */ /* !< ephemeris: rate of inclination angle [rad/s] */ /* !< ephemeris: amplitude of the cosine harmonic correction term to the argument of latitude [rad] */ /* !< ephemeris: amplitude of the sine harmonic correction term to the argument of latitude [rad] */ /* !< ephemeris: amplitude of the cosine harmonic correction term to the orbit radius [m] */ /* !< ephemeris: amplitude of the sine harmonic correction term to the orbit radius [m] */ /* !< ephemeris: amplitude of the cosine harmonic correction term to the angle of inclination [rad] */ /* !< ephemeris: amplitude of the sine harmonic correction term to the angle of inclination [rad] */ /* !< clock correction for this satellite for this epoch [m] */ /* !< clock drift correction for this satellite for this epoch [m/s] */ /* !< satellite X position WGS84 ECEF [m] */ /* !< satellite Y position WGS84 ECEF [m] */ /* !< satellite Z position WGS84 ECEF [m] */ /* !< satellite X velocity WGS84 ECEF [m/s] */ /* !< satellite Y velocity WGS84 ECEF [m/s] */ /* !< satellite Z velocity WGS84 ECEF [m/s] */ /* !< satelilte azimuth [rad] */ /* !< satelilte elevation [rad] */ /* !< satellite doppler with respect to the user position [m/s], Note: User must convert to Hz */ { double dz; double dy; double dx; double vz; double vy; double vx; double range_rate; double range; double tow; uint32_t i1; uint32_t week; if (toe==0UL) ++ephem_week; /*WrStr(" GPS toe="); WrCard(toe,1); WrStr(" week="); WrCard(ephem_week,1); WrStr(" "); */ *satX = 0.0; *satY = 0.0; *satZ = 0.0; vx = 0.0; vy = 0.0; vz = 0.0; ClockCorrDrift(gpsweek, gpstow, ephem_week, toe, toc, af0, af1, af2, ecc, sqrta, delta_n, m0, tgd, 0UL, clock_correction, clock_drift); /* adjust for week rollover */ week = gpsweek; tow = gpstow+ *clock_correction*3.3356409519815E-9; if (tow<0.0) { tow = tow+6.048E+5; --week; } if (tow>6.048E+5) { tow = tow-6.048E+5; ++week; } /*iterate to include the Sagnac correction since the range is unknown, an approximate of 70 ms is good enough to start the iterations so that 2 iterations are enough for sub mm accuracy */ range = 2.098547206E+7; range_rate = 0.0; for (i1 = 0UL; i1<=1UL; i1++) { SatPosVelocity(week, tow, ephem_week, toe, m0, delta_n, ecc, sqrta, omega0, i0, w, omegadot, idot, cuc, cus, crc, crs, cic, cis, range, range_rate, satX, satY, satZ, &vx, &vy, &vz); dx = userX-*satX; dy = userY-*satY; dz = userZ-*satZ; range = sqrt(dx*dx+dy*dy+dz*dz); range_rate = X2C_DIVL(vx*dx+vy*dy+vz*dz,range); /* this method uses the NovAtel style sign convention! */ } /* end for */ azelxyzxyz(userX, userY, userZ, *satX, *satY, *satZ, azimuth, elevation); *satVx = vx; *satVy = vy; *satVz = vz; *doppler = range_rate; } /* end SatPos() */ /*-- make median (over desired beacon intervall) of pseudo distance from all sat to all other */ #define gpssdr_H 4.294967296E+9 /* 2^32 */ #define gpssdr_HH 2.147483648E+9 static void medranges(void) { uint32_t i0; double r; double b; struct SAT * anonym; if (medcnt==0UL) { for (i0 = 0UL; i0<=32UL; i0++) { sat[i0].prangem = 0.0; sat[i0].pmcnt = 0UL; } /* end for */ } b = (-1.0); for (i0 = 0UL; i0<=32UL; i0++) { { /* with */ struct SAT * anonym = &sat[i0]; if (anonym->insyn && anonym->datasyn) { if (b<0.0) b = anonym->prange; else { r = anonym->prange-b; if (r>2.147483648E+9) r = r-4.294967296E+9; else if (r<(-2.147483648E+9)) r = r+4.294967296E+9; anonym->prangem = anonym->prangem+r; } ++anonym->pmcnt; } } } /* end for */ } /* end medranges() */ /*--in ephemeris announced sat error index to meters */ static float urai(uint32_t idx) { if (idx<=6UL) return (float)pow(2.0, (double)(1.0f+(float)idx*0.5f)); return (float)pow(2.0, (double)(float)(idx-2UL)); } /* end urai() */ /*-----2 or 3d fix */ static double angleofsats(double x0, double y00, double z0, double x1, double y1, double z1, double x2, double y2, double z2) { double d2; double d1; x1 = x1-x0; y1 = y1-y00; z1 = z1-z0; d1 = sqrt(sqrl(x1)+sqrl(y1)+sqrl(z1)); if (d1==0.0) return 0.0; d1 = X2C_DIVL(1.0,d1); x2 = x2-x0; y2 = y2-y00; z2 = z2-z0; d2 = sqrt(sqrl(x2)+sqrl(y2)+sqrl(z2)); if (d2==0.0) return 0.0; d2 = X2C_DIVL(1.0,d2); d1 = 0.5*sqrt(sqrl(x2*d2-x1*d1)+sqrl(y2*d2-y1*d1)+sqrl(z2*d2-z1*d1)); if (fabs(d1)>=1.0) return 3.1415926535898; return asin(d1)*2.0; } /* end angleofsats() */ static float dil(const struct SATPOS s1, const struct SATPOS s2, const struct POS upos) { double mz; double my; double mx; if (upos.lat!=0.0 || upos.long0!=0.0) wgs84(upos.lat, upos.long0, upos.alt, &mx, &my, &mz); else { mx = 0.0; my = 0.0; mz = 0.0; } return (float)(1.5707963267949-fabs(fabs(angleofsats(mx, my, mz, s1.x, s1.y, s1.z, s2.x, s2.y, s2.z))-1.5707963267949)); } /* end dil() */ static void calcdop(uint32_t us, const struct POS upos) { uint32_t k; /* x0,y0,z0,x1,y1,z1,x2,y2,z2:LONGREAL; */ uint32_t j; uint32_t i0; struct BESTDIL h1; struct BESTDIL h; /* wgs84(userpos.lat, userpos.long, userpos.alt, x0, y0, z0); */ memset((char *)bestdils,(char)0,sizeof(struct BESTDIL [50])); if (verb) osi_WrStr("dops:", 6ul); i0 = us; while (i0<=32UL) { j = sat[i0].next; while (j<=32UL) { h.d = dil(sat[i0].satpos, sat[j].satpos, upos); if (verb) { osic_WrFixed(h.d, 2L, 1UL); osi_WrStr(" ", 2ul); } /* h.d:=dist(sat[i].satpos.x, sat[i].satpos.y, sat[i].satpos.z, sat[j].satpos.x, sat[j].satpos.y, sat[j].satpos.z); */ /*IF verb THEN (* WrInt(i+1,1);WrStr(",");WrInt(j+1,1);WrStr(",");*) WrFixed(h.d*0.000001,1,1); WrStr(" "); END; */ if (h.d>0.0f) { k = 0UL; while (h.d0.5f)) { /* remove bad if min. 4 good and let one 0.0 at end */ h1 = bestdils[k]; bestdils[k] = h; ++k; h = h1; } } j = sat[j].next; } i0 = sat[i0].next; } if (verb) { osi_WrStr("/sort:", 7ul); i0 = 0UL; while (bestdils[i0].d>0.0f) { osic_WrFixed(bestdils[i0].d, 2L, 1UL); osi_WrStr(" ", 2ul); ++i0; } osi_WrStrLn("", 1ul); } } /* end calcdop() */ /*-- use nearest sats pos as startup position (time sample arrived first of all sat) */ static void guesspos(struct POSL * p) { uint32_t i0; double minr; double alt; memset((char *)p,(char)0,sizeof(struct POSL)); minr = (double)X2C_max_real; for (i0 = 0UL; i0<=32UL; i0++) { if (((sat[i0].insyn && sat[i0].datasyn) && sat[i0].satok) && sat[i0].rangeclat, &p->long0, &alt); } } /* end for */ if (verb && minr<(double)X2C_max_real) { osi_WrStr(" guess:[", 9ul); osic_WrFixed((float)(p->lat*5.7295779513082E+1), 5L, 1UL); osi_WrStr(",", 2ul); osic_WrFixed((float)(p->long0*5.7295779513082E+1), 5L, 1UL); osi_WrStrLn("]", 2ul); } } /* end guesspos() */ /*-- sum range errors between all sat pairs */ static double check(const struct POSL p) { double z1; double y1; double x1; double sum0; uint32_t i0; struct SATPOS sp1; struct SATPOS sp0; wgs84(p.lat, p.long0, p.alt, &x1, &y1, &z1); sum0 = 0.0; i0 = 0UL; while (bestdils[i0].d>0.0f) { sp0 = sat[bestdils[i0].s0].satpos; sp1 = sat[bestdils[i0].s1].satpos; sum0 = sum0+fabs((dist(sp0.x, sp0.y, sp0.z, x1, y1, z1)-sat[bestdils[i0].s0].range)-(dist(sp1.x, sp1.y, sp1.z, x1, y1, z1)-sat[bestdils[i0].s1].range)); ++i0; } if (i0==0UL) return (double)X2C_max_real; return X2C_DIVL(sum0,(double)i0); /* normalize to 1 pair */ } /* end check() */ /*--- go along best direction to minimum range difference to all sats */ #define gpssdr_DIRS 8 static double aquisith(struct POSL * p, double resol) { double best; double w; double o; uint32_t i0; uint32_t dir; struct POSL p1; p1 = *p; best = (double)X2C_max_real; o = 0.0; i0 = 0UL; for (;;) { w = (double)i0*7.8539816339745E-1; o = o*4.E-8; p->lat = p1.lat+cos(w)*o; p->long0 = p1.long0+sin(w)*o; if (p->long0>3.1415926535898) p->long0 = p->long0-6.2831853071796; else if (p->long0<(-3.1415926535898)) p->long0 = p->long0+6.2831853071796; if (fabs(p->lat)>1.5707963267949) break; ++posfixc; o = check(*p); if (o=4UL) { p.lat = up.lat; p.long0 = up.long0; p.alt = up.alt; wgs84(p.lat, p.long0, p.alt, &x, &y, &z); i0 = us; while (i0<=32UL) { { /* with */ struct SAT * anonym = &sat[i0]; anonym->range = dist(anonym->satpos.x, anonym->satpos.y, anonym->satpos.z, x, y, z); } i0 = sat[i0].next; } p.alt = p.alt+100.0; if (!fixalt) nmeavdil = X2C_DIVR(100.0f,maxr((float)aquisith(&p, 0.01), 0.1f)); p.lat = up.lat+1.5707963267949E-5; p.long0 = up.long0; p.alt = up.alt; e = X2C_DIVR(100.0f,maxr((float)check(p), 0.001f)); /*WrStr(" e="); WrFixed(e,2,1); WrStr(" "); */ p.lat = up.lat; p.long0 = up.long0+(double)(X2C_DIVR(1.5707963267949E-5f,maxr((float)cos(up.long0), 0.1f))); if (p.long0>3.1415926535898) p.long0 = p.long0-6.2831853071796; nmeahdil = maxr(X2C_DIVR(100.0f,maxr((float)check(p), 0.001f)), e); } } /* end calcdil() */ static void finetuneranges(uint32_t us, const struct POS p, char moving) { uint32_t nearest; uint32_t j; uint32_t i0; double z0; double y00; double x0; double n; double m; struct SAT * anonym; struct SAT * anonym0; /* corrone:=corrone+(mydist-m-corrone)*0.1; */ wgs84(p.lat, p.long0, p.alt, &x0, &y00, &z0); m = 0.0; j = 0UL; i0 = us; n = (double)X2C_max_real; while (i0<=32UL) { { /* with */ struct SAT * anonym = &sat[i0]; anonym->mydist = dist(anonym->satpos.x, anonym->satpos.y, anonym->satpos.z, x0, y00, z0)-anonym->rangec; m = m+anonym->mydist; if (anonym->rangecrangec; nearest = i0; } i0 = anonym->next; } ++j; } if (j>=4UL) { m = X2C_DIVL(m,(double)j); i0 = us; if (verb) osi_WrStr("corr:", 6ul); while (i0<=32UL) { { /* with */ struct SAT * anonym0 = &sat[i0]; anonym0->corrone = anonym0->corrone*0.95; if (!moving) { anonym0->corrone = anonym0->corrone+(anonym0->mydist-m)*0.045; if (anonym0->corrone>30.0) anonym0->corrone = 30.0; else if (anonym0->corrone<(-30.0)) anonym0->corrone = (-30.0); } /* IF i=nearest THEN corrone:=0.0 END; */ if (verb) { osic_WrINT32(i0+1UL, 1UL); osi_WrStr(":", 2ul); osic_WrFixed((float)anonym0->corrone, 1L, 1UL); osi_WrStr(" ", 2ul); } i0 = anonym0->next; } } if (verb) osi_WrStrLn("", 1ul); } } /* end finetuneranges() */ #define gpssdr_CHECKSTEP0 200.0 static float checkfix(struct POSL * po) { float dir; float e2; float e1; float e0; struct POSL ph; dir = 10.0f; for (;;) { ph = *po; e0 = (float)aquisith(&ph, 0.01); ph = *po; ph.alt = ph.alt+200.0; e1 = (float)aquisith(&ph, 0.01); ph = *po; ph.alt = ph.alt-200.0; e2 = (float)aquisith(&ph, 0.01); if (verb2) { osi_WrStr(" cf:[", 6ul); osic_WrFixed((float)(po->lat*5.7295779513082E+1), 5L, 1UL); osi_WrStr(",", 2ul); osic_WrFixed((float)(po->long0*5.7295779513082E+1), 5L, 1UL); osi_WrStr(" ", 2ul); osic_WrFixed((float)po->alt, 1L, 1UL); osi_WrStr(" ret=", 6ul); osic_WrFixed(maxr(e0, X2C_DIVR(200.0f,maxr(0.01f, (e1+e2)-e0*2.0f))), 1L, 1UL); osi_WrStr(" e0=", 5ul); osic_WrFixed(e0, 2L, 1UL); osi_WrStr(" e1=", 5ul); osic_WrFixed(e1, 2L, 1UL); osi_WrStr(" e2=", 5ul); osic_WrFixed(e2, 2L, 1UL); osi_WrStr(" dir=", 6ul); osic_WrFixed(dir, 2L, 1UL); osi_WrStr("] ", 3ul); } if ((float)fabs(dir)<0.25f || (float)fabs(e1-e2)<0.25f) break; if ((dir<0.0f && po->alt<(-700.0) || dir>=0.0f && po->alt>(double)maxalt) || e1>e2==dir>=0.0f) { dir = dir*(-0.5f); } ph = *po; e0 = (float)aquisith(po, 0.01); po->alt = ph.alt+(double)dir; } return maxr(e0, X2C_DIVR(200.0f,maxr(0.01f, (e1+e2)-e0*2.0f))); } /* end checkfix() */ /*-- make position and speed by try and error, makes more stable result as equation resolv */ /* dd:SET32; */ static void d23fix(uint32_t medcnt0, struct POS * pstart, float * offs, uint32_t * us, uint32_t * satc, char d3ok) { double med; uint32_t i0; struct POSL p; struct SAT * anonym; med = X2C_DIVL(1.4652562986591E+2,(double)medcnt0); /* dd:=SET32{}; */ *satc = 0UL; *us = X2C_max_longcard; for (i0 = 0UL; i0<=32UL; i0++) { { /* with */ struct SAT * anonym = &sat[i0]; if ((((anonym->insyn && anonym->datasyn) && anonym->satok) && anonym->bert==0UL) && anonym->pmcnt==medcnt0) { anonym->rangec = anonym->prangem*med+anonym->satpos.clkcorr; /* + corrone*/ anonym->range = anonym->rangec+anonym->corrone; anonym->next = *us; *us = i0; /* INCL(dd, i); */ ++*satc; } } } /* end for */ calcdop(*us, *pstart); p.lat = pstart->lat; p.long0 = pstart->long0; p.alt = pstart->alt; if (*satc>=4UL-(uint32_t)(fixalt || !noauto23d && d3ok)) { /* if we have altitude let it as it is and make pos with 3 sat */ if (p.alt<=(-1.E+4)) { if (p.lat==0.0 && p.long0==0.0) guesspos(&p); p.alt = 0.0; /* start alt from zero */ } if (*satc>=4UL) { if (fixalt) *offs = (float)aquisith(&p, 0.01); else *offs = checkfix(&p); last3dfix = *offs<=6.0f; } else if (last3dfix || fixalt) *offs = (float)aquisith(&p, 0.01); else *offs = (-1.0f); pstart->lat = p.lat; pstart->long0 = p.long0; pstart->alt = p.alt; } else *offs = (-1.0f); } /* end d23fix() */ static void speeds(uint32_t satc, uint32_t us, struct POS * pstart) { struct POSL ps0; struct POSL p; uint32_t i0; struct POS pl; double msmin; double msmax; double ms; double dir; double best; double e; double z0; double y00; double x0; struct SAT * anonym; if (satc>=4UL-(uint32_t)(fixalt || !noauto23d)) { p.lat = pstart->lat; p.long0 = pstart->long0; p.alt = pstart->alt; wgs84(p.lat, p.long0, p.alt, &x0, &y00, &z0); msmin = (double)X2C_max_real; msmax = (double)X2C_min_real; i0 = us; /*WrStr(" spd:"); */ while (i0<=32UL) { { /* with */ struct SAT * anonym = &sat[i0]; ms = 1.9029367279836E-1*anonym->mfreq-anonym->satpos.doppler; /* user speed doppler direction to sat in m/s */ anonym->range = dist(anonym->satpos.x, anonym->satpos.y, anonym->satpos.z, x0, y00, z0)+ms; ms = fabs(ms); /*WrFixed(ms,1,1); WrStr(","); */ if (ms>msmax) msmax = ms; if (ms=4UL) dir = ((msmax-msmin)+5.0)*4.0; else dir = 0.0; if (verb2) osi_WrStrLn("speeds", 7ul); best = (double)X2C_max_real; for (;;) { ps0 = p; ps0.alt = ps0.alt+dir; e = aquisith(&ps0, 0.01); if (espeed = (float)shortdist(*pstart, pl); /* fixed position - shifted by doppler */ pstart->dir = shortdir(*pstart, pl); if (pstart->dir<0.0f) pstart->dir = pstart->dir+6.2831853071796f; if (!fixalt && satc>=4UL) pstart->clb = (float)(pstart->alt-p.alt); else pstart->clb = 0.0f; finetuneranges(us, *pstart, pstart->speed>0.5f); calcdil(*pstart, us, satc); } } /* end speeds() */ /*-------2 or 3d fix */ static void noisefilter(struct POS * p, double timef) { double spd; double posstrength; double altstrength; double lowpass; double direrr; double dt; posstrength = (double)(1.0f-X2C_DIVR(1.0f,kaldat.strength)); altstrength = (double)(1.0f-X2C_DIVR(2.0f,kaldat.strength)); dt = timef-kaldat.time1; spd = (double)p->speed; if (spd>(double)(10.0f*kaldat.pos.speed)) spd = (double)kaldat.pos.speed; if (dt>5.0) dt = 5.0; if (kaldat.time1>0.0 && dt>0.1) { direrr = angdiff((double)p->dir, (double)shortdir(*p, kaldat.pos)); /* pos move dir - doppler dir */ lowpass = X2C_DIVL(posstrength,(double)(X2C_DIVR(sqr((float)spd)*0.1f, sqr((float)direrr)*50.0f+1.0f)+1.0f)); p->lat = p->lat*(1.0-lowpass)+kaldat.pos.lat*lowpass; p->long0 = p->long0*(1.0-lowpass)+kaldat.pos.long0*lowpass; if (verb) { osi_WrStr("kal dt=", 8ul); osic_WrFixed((float)dt, 1L, 1UL); osi_WrStr(" lp=", 5ul); osic_WrFixed((float)lowpass, 3L, 1UL); } lowpass = X2C_DIVL(fabs((p->alt-kaldat.pos.alt)-(double)p->clb*dt),fabs((double)p->clb*dt)+1.0); if (lowpass>altstrength) lowpass = altstrength; p->alt = p->alt*(1.0-lowpass)+(kaldat.pos.alt+(double)p->clb*dt)*lowpass; if (verb) { osi_WrStr(" alt=", 6ul); osic_WrFixed((float)p->alt, 1L, 1UL); osi_WrStr(" alto=", 7ul); osic_WrFixed((float)kaldat.pos.alt, 1L, 1UL); osi_WrStr(" clb=", 6ul); osic_WrFixed(p->clb, 3L, 1UL); osi_WrStr(" lpa=", 6ul); osic_WrFixed((float)lowpass, 3L, 1UL); osi_WrStrLn("", 1ul); } } else if (verb) { osi_WrStr("timejump=", 10ul); osic_WrFixed((float)dt, 1L, 1UL); osi_WrStrLn("", 1ul); } kaldat.pos = *p; p->speed = (float)spd; kaldat.time1 = timef; } /* end noisefilter() */ static void initpos(void) { memset((char *) &userpos,(char)0,sizeof(struct POS)); d3wasok = 0; posok = 0; falselocks = 0UL; userpos.alt = (-1.E+4); } /* end initpos() */ static void satposspeeds(double * timef, const struct POS upos) { uint32_t timec; uint32_t wnn; uint32_t sn; double tow1; double myz; double myy; double myx; struct SATPOS sp; struct POS satwgs; struct EPHEMERIS * anonym; if (upos.lat!=0.0 || upos.long0!=0.0) wgs84(upos.lat, upos.long0, upos.alt, &myx, &myy, &myz); else { myx = 0.0; myy = 0.0; myz = 0.0; } for (sn = 0UL; sn<=32UL; sn++) { if (sat[sn].insyn && sat[sn].datasyn) { memset((char *) &sp,(char)0,sizeof(struct SATPOS)); if (sat[sn].freqmedc>0UL) { sat[sn].mfreq = (double)(X2C_DIVR(sat[sn].freqmed,(float)sat[sn].freqmedc)); sat[sn].freqmed = 0.0f; sat[sn].freqmedc = 0UL; } { /* with */ struct EPHEMERIS * anonym = &almanach.ephem[sn]; *timef = ((double)(anonym->wncorr*604800UL+anonym->tow*6UL)+((double)(sampc-sat[sn].timesamp) +(double)sat[sn].timesampfrac*1.5625E-2)*4.8875855327468E-7)-(double)medcnt*0.01; /* shift time to middle of prn rounding intervall */ wnn = (uint32_t)X2C_TRUNCC( *timef*1.6534391534392E-6,0UL,X2C_max_longcard); tow1 = *timef-(double)(wnn*604800UL); wnn = wnn&1023UL; timec = (uint32_t)X2C_TRUNCC(*timef,0UL,X2C_max_longcard); if (((!(~anonym->done&0xEU) && (healthignore || anonym->health==0UL)) && anonym->ura<15UL) && anonym->wncorr*604800UL+anonym->tow*6UL<=twnwrap(anonym->wncorr, anonym->tow, anonym->toe)) { SatPos(myx, myy, myz, wnn&1023UL, tow1, anonym->wn, anonym->toe, anonym->toc, anonym->af0a, anonym->af1a, anonym->af2a, anonym->tgd, anonym->m0*3.1415926535898, anonym->deltan*3.1415926535898, anonym->ecc, anonym->roota, anonym->omega0*3.1415926535898, anonym->i0*3.1415926535898, anonym->w*3.1415926535898, anonym->omegadot*3.1415926535898, anonym->idot*3.1415926535898, anonym->cuc, anonym->cus, anonym->crc, anonym->crs, anonym->cic, anonym->cis, &sp.clkcorr, &sp.clkdrift, &sp.x, &sp.y, &sp.z, &sp.vx, &sp.vy, &sp.vz, &sp.azimuth, &sp.elevation, &sp.doppler); sp.azel = posok; sat[sn].satpos = sp; sat[sn].satok = 1; if (verb) { wgs84r(sp.x, sp.y, sp.z, &satwgs.lat, &satwgs.long0, &satwgs.alt); osi_WrStr("prn:", 5ul); osic_WrINT32(sn+1UL, 2UL); osi_WrStr(" ", 2ul); WrDate(timec/604800UL, timec%604800UL); osi_WrStr(" po:", 5ul); osic_WrFixed((float)(X2C_DIVL(satwgs.lat,1.7453292519943E-2)), 6L, 1UL); osi_WrStr("/", 2ul); osic_WrFixed((float)(X2C_DIVL(satwgs.long0,1.7453292519943E-2)), 6L, 1UL); osi_WrStr("/", 2ul); osic_WrFixed((float)(satwgs.alt*0.001), 1L, 1UL); if (posok) { osi_WrStr(" az:", 5ul); osic_WrFixed((float)(X2C_DIVL(sp.azimuth,1.7453292519943E-2)), 4L, 1UL); osi_WrStr(" el:", 5ul); osic_WrFixed((float)(X2C_DIVL(sp.elevation,1.7453292519943E-2)), 4L, 1UL); osi_WrStr(" d:", 4ul); osic_WrFixed((float)dist(myx, myy, myz, sp.x, sp.y, sp.z), 0L, 1UL); osi_WrStr(" dop:", 6ul); osic_WrFixed((float)(sp.doppler*5.2550354685707), 1L, 1UL); osi_WrStr("(", 2ul); osic_WrFixed((float)(sat[sn].mfreq-sp.doppler*5.2550354685707), 1L, 1UL); osi_WrStr(") ", 3ul); } osi_WrStr(" pd:", 5ul); osic_WrFixed((float)(sat[sn].prndoppler*1.203125E+4), 1L, 1UL); osi_WrStr(" +- ", 5ul); osic_WrINT32(sat[sn].plusc, 1UL); osi_WrStr(" ", 2ul); osic_WrINT32(sat[sn].minusc, 1UL); sat[sn].minusc = 0UL; sat[sn].plusc = 0UL; osi_WrStr(" sig:", 6ul); osic_WrFixed(sat[sn].sig, 0L, 1UL); osi_WrStr(" pn:", 5ul); osic_WrFixed(sat[sn].prnnois, 2L, 1UL); /* WrStr(" mp:"); WrFixed(sat[sn].multipath,2,1); */ osi_WrStr(" ber:", 6ul); osic_WrINT32(sat[sn].bert, 1UL); osi_WrStrLn("", 1ul); } } else sat[sn].satok = 0; } } else sat[sn].satok = 0; } /* end for */ } /* end satposspeeds() */ /*-- set of pseudoranges ready to make position and speeds */ static void navigate(void) { uint32_t usedsats; uint32_t utime; uint32_t satc; double timef; float d2ok; char eok; medranges(); ++medcnt; if (medcnt>=nmeaintervall) { /* we want a beacon */ if (verb) { osic_WrINT32(medcnt, 1UL); osi_WrStr(" ", 2ul); osic_WrINT32((sampc-sampnavi)/40920UL, 1UL); osi_WrStrLn("--nav", 6ul); } d2ok = (-1.0f); sampnavi = sampc; if (fixall) { userpos = fixpos; posok = 1; } else if (fixalt) userpos.alt = fixpos.alt; satposspeeds(&timef, userpos); utime = (uint32_t)X2C_TRUNCC(timef,0UL,X2C_max_longcard); d23fix(medcnt, &userpos, &d2ok, &usedsats, &satc, d3wasok); if (d2ok>=0.0f) { if (!fixall) { if (!posok) { satposspeeds(&timef, userpos); /* doppler to user known if latest user pos known */ } speeds(satc, usedsats, &userpos); } if (d2ok<6.0f) { d3wasok = 1; posok = 1; falselocks = 0UL; } else if (d2ok<1.E+5f) falselocks = 0UL; else { ++falselocks; if (falselocks>10UL) initpos(); } if ((kaldat.strength>0.0f && d3wasok) && d2ok<15.0f) noisefilter(&userpos, timef); if (verb) { if (!d3wasok || d2ok>=15.0f) { ++nofixc; osi_WrStr("no good fix now ", 17ul); } if (satc<4UL) osi_WrStr("2dfix ", 7ul); osi_WrStr(" d23:[res:", 11ul); osic_WrFixed(d2ok, 1L, 1UL); osi_WrStr(" ", 2ul); osic_WrFixed((float)(userpos.lat*5.7295779513082E+1), 5L, 1UL); osi_WrStr(",", 2ul); osic_WrFixed((float)(userpos.long0*5.7295779513082E+1), 5L, 1UL); osi_WrStr(",", 2ul); osic_WrFixed((float)userpos.alt, 1L, 1UL); osi_WrStrLn("]", 2ul); errsum = errsum+(double)d2ok; } } else { posok = 0; if (verb) { ++nofixc; osi_WrStr("too less sync sat now ", 23ul); } } if (verb) { osi_WrStr(" u:[", 5ul); osic_WrFixed((float)(userpos.lat*5.7295779513082E+1), 5L, 1UL); osi_WrStr(",", 2ul); osic_WrFixed((float)(userpos.long0*5.7295779513082E+1), 5L, 1UL); osi_WrStr(",", 2ul); osic_WrFixed((float)userpos.alt, 0L, 1UL); osi_WrStr(",", 2ul); osic_WrFixed(userpos.speed*3.6f, 2L, 1UL); osi_WrStr("km/h,", 6ul); osic_WrFixed(userpos.dir*5.7295779513082E+1f, 1L, 1UL); osi_WrStr("deg,", 5ul); osic_WrFixed(userpos.clb, 2L, 1UL); osi_WrStr("m/s", 4ul); osi_WrStr("]", 2ul); osi_WrStr(" resum:", 8ul); osic_WrFixed((float)errsum, 1L, 1UL); osi_WrStr(" posfixc:", 10ul); osic_WrINT32(posfixc, 1UL); osi_WrStr(" nofixc:", 9ul); osic_WrINT32(nofixc, 1UL); /* IF manpos THEN WrStr(" medd:"); WrFixed(meddist,1,1); WrStr(" meda:"); WrFixed(medalt,1,1); END; */ osi_WrStrLn("", 1ul); } if (d2ok>=0.0f && egmfn[0]) { egmmeter = egm96((float)userpos.lat, (float)userpos.long0, &eok); if (!eok) { osi_WrStrLn(" egm file fail", 15ul); egmfn[0] = 0; } } nmea((utime+zerotime)-(uint32_t)almanach.tls, userpos, (posok && d3wasok) && d2ok<15.0f, noauto23d, satc, osic_sqrt(sqr(nmeahdil)+sqr(nmeavdil)), nmeahdil, nmeavdil, egmmeter); medcnt = 0UL; } } /* end navigate() */ /*-------- navigation */ /*--------------- almanach */ static double ctolf(uint32_t c, int32_t bits, double scale) { double r; r = (double)c; if ((bits<0L && bits>=-32L) && X2C_IN(labs(bits)-1L,32,(uint32_t)c)) { r = (double)(int32_t)((uint32_t)c|X2C_LSH(0xFFFFFFFFUL,32,labs(bits))); } return r*scale; } /* end ctolf() */ /* PROCEDURE ctolf(c:CARDINAL; bits:INTEGER; scale:INTEGER):LONGREAL; BEGIN IF (bits<0) & (bits>-32) & (ABS(bits)-1 IN CAST(SET32,c)) THEN RETURN VAL(LONGREAL, VAL(INTEGER,CAST(SET32,c)+SHIFT(SET32{0..31},ABS(bits))))*(2.0**scale) END; --WrStr(" hs=");WrFixed(VAL(LONGREAL, c)*(2.0**scale),20,1); RETURN VAL(LONGREAL, c)*(2.0**scale); END ctolf; */ static uint32_t btoc(const uint32_t b[], uint32_t b_len, uint32_t start, uint32_t bits) /*VAR s:INTEGER; */ { return (uint32_t)(X2C_LSH(b[start/30UL],32,(int32_t)(bits+start%30UL)-30L)&X2C_LSH(0xFFFFFFFFUL,32, (int32_t)bits-32L)); } /* end btoc() */ static uint32_t btoc32(const uint32_t b[], uint32_t b_len, uint32_t start) { return (btoc(b, b_len, start, 8UL)<<24)+btoc(b, b_len, start+14UL, 24UL); } /* end btoc32() */ static uint32_t btoc24(const uint32_t b[], uint32_t b_len, uint32_t start) { return btoc(b, b_len, start, 24UL); } /* end btoc24() */ static uint32_t btoc16(const uint32_t b[], uint32_t b_len, uint32_t start) { return btoc(b, b_len, start, 16UL); } /* end btoc16() */ /* PROCEDURE modwn(w10,w8:CARDINAL):CARDINAL; VAR r:CARDINAL; d:INTEGER; BEGIN r:=w8+w10 DIV 256*256; d:=VAL(INTEGER,r)-VAL(INTEGER,w10); IF d>127 THEN r:=(r+(1024-256)) MOD 1024; ELSIF d<-127 THEN r:=(r+256) MOD 1024; END; RETURN r END modwn; */ /*--- write ephemerides in rinex format file */ #define gpssdr_LF0 "\012" static void rinexfile(void) { uint32_t i0; int32_t f; char hh[2000]; char h[2000]; char new0; struct EPHEMERIS * anonym; if (rinexfn[0U]==0) return; for (i0 = 0UL; i0<=31UL; i0++) { f = -1L; { /* with */ struct EPHEMERIS * anonym = &almanach.ephem[i0]; if ((((!(~anonym->done&0xEU) && anonym->IODE2==anonym->IODE3) && anonym->IODE2==(anonym->IODC&255UL)) && almanach.page18ok) && almanach.printed[i0]!=anonym->IODE3+32768UL) { almanach.printed[i0] = anonym->IODE3+32768UL; new0 = 0; if (rinexfn[0U]) { f = osi_OpenAppend(rinexfn, 1024ul); if (f<0L) { f = osi_OpenWrite(rinexfn, 1024ul); new0 = 1; } } if (f<0L) { osi_WrStr(hh, 2000ul); osi_WrStrLn(" almanach file wite error", 26ul); return; } h[0] = 0; /*header */ if (new0) { aprsstr_Append(h, 2000ul, " 4.02 N: GNSS NAV DATA M: RINEX VERSION / TY\ PE\015\012", 83ul); aprsstr_Append(h, 2000ul, "GPSSDR V0.1 DXL ", 41ul); GpsDate(anonym->wn, anonym->tow*6UL, hh, 2000ul); hh[4U] = hh[5U]; hh[5U] = hh[6U]; hh[6U] = hh[8U]; hh[7U] = hh[9U]; hh[8U] = ' '; hh[9U] = hh[11U]; hh[10U] = hh[12U]; hh[11U] = hh[14U]; hh[12U] = hh[15U]; hh[13U] = hh[17U]; hh[14U] = hh[18U]; hh[15U] = 0; aprsstr_Append(h, 2000ul, hh, 2000ul); aprsstr_Append(h, 2000ul, " UTC PGM / RUN BY / DATE\015\012", 27ul); /* Append(h, "GPS EPHEMERIDES TO RINEX"+NL); */ aprsstr_Append(h, 2000ul, " ", 5ul); rinexint(almanach.tls, 6UL, hh, 2000ul); aprsstr_Append(h, 2000ul, hh, 2000ul); rinexint(almanach.tlsf, 4UL, hh, 2000ul); aprsstr_Append(h, 2000ul, hh, 2000ul); rinexint((int32_t)almanach.wnlsf, 9UL, hh, 2000ul); aprsstr_Append(h, 2000ul, hh, 2000ul); rinexint((int32_t)(anonym->tow/14400UL), 1UL, hh, 2000ul); aprsstr_Append(h, 2000ul, hh, 2000ul); aprsstr_Append(h, 2000ul, " LEAP SECONDS\015\012", 51ul); aprsstr_Append(h, 2000ul, " END OF HEADER\015\01\ 2", 76ul); } /*line 0 */ aprsstr_Append(h, 2000ul, "> EPH G", 8ul); hh[0U] = (char)((i0+1UL)/10UL+48UL); hh[1U] = (char)((i0+1UL)%10UL+48UL); hh[2U] = 0; aprsstr_Append(h, 2000ul, hh, 2000ul); aprsstr_Append(h, 2000ul, " LNAV\015\012", 8ul); /*line 1 */ aprsstr_Append(h, 2000ul, "G", 2ul); aprsstr_Append(h, 2000ul, hh, 2000ul); aprsstr_Append(h, 2000ul, " ", 2ul); GpsDate(anonym->wn, anonym->tow*6UL, hh, 2000ul); hh[4U] = ' '; hh[7U] = ' '; hh[13U] = ' '; hh[16U] = ' '; aprsstr_Append(h, 2000ul, hh, 2000ul); rinexfloat(anonym->af0a, hh, 2000ul); aprsstr_Append(h, 2000ul, hh, 2000ul); rinexfloat(anonym->af1a, hh, 2000ul); aprsstr_Append(h, 2000ul, hh, 2000ul); rinexfloat(anonym->af2a, hh, 2000ul); aprsstr_Append(h, 2000ul, hh, 2000ul); aprsstr_Append(h, 2000ul, "\015\012", 3ul); /*-line 2 */ aprsstr_Append(h, 2000ul, " ", 5ul); rinexfloat((double)anonym->IODE2, hh, 2000ul); aprsstr_Append(h, 2000ul, hh, 2000ul); rinexfloat(anonym->crs, hh, 2000ul); aprsstr_Append(h, 2000ul, hh, 2000ul); rinexfloat(anonym->deltan*3.1415926535898, hh, 2000ul); aprsstr_Append(h, 2000ul, hh, 2000ul); rinexfloat(anonym->m0*3.1415926535898, hh, 2000ul); aprsstr_Append(h, 2000ul, hh, 2000ul); aprsstr_Append(h, 2000ul, "\015\012", 3ul); /*-line 3 */ aprsstr_Append(h, 2000ul, " ", 5ul); rinexfloat(anonym->cuc, hh, 2000ul); aprsstr_Append(h, 2000ul, hh, 2000ul); rinexfloat(anonym->ecc, hh, 2000ul); aprsstr_Append(h, 2000ul, hh, 2000ul); rinexfloat(anonym->cus, hh, 2000ul); aprsstr_Append(h, 2000ul, hh, 2000ul); rinexfloat(anonym->roota, hh, 2000ul); aprsstr_Append(h, 2000ul, hh, 2000ul); aprsstr_Append(h, 2000ul, "\015\012", 3ul); /*-line 4 */ aprsstr_Append(h, 2000ul, " ", 5ul); rinexfloat((double)anonym->toe, hh, 2000ul); aprsstr_Append(h, 2000ul, hh, 2000ul); rinexfloat(anonym->cic, hh, 2000ul); aprsstr_Append(h, 2000ul, hh, 2000ul); rinexfloat(anonym->omega0*3.1415926535898, hh, 2000ul); aprsstr_Append(h, 2000ul, hh, 2000ul); rinexfloat(anonym->cis, hh, 2000ul); aprsstr_Append(h, 2000ul, hh, 2000ul); aprsstr_Append(h, 2000ul, "\015\012", 3ul); /*-line 5 */ aprsstr_Append(h, 2000ul, " ", 5ul); rinexfloat(anonym->i0*3.1415926535898, hh, 2000ul); aprsstr_Append(h, 2000ul, hh, 2000ul); rinexfloat(anonym->crc, hh, 2000ul); aprsstr_Append(h, 2000ul, hh, 2000ul); rinexfloat(anonym->w*3.1415926535898, hh, 2000ul); aprsstr_Append(h, 2000ul, hh, 2000ul); rinexfloat(anonym->omegadot*3.1415926535898, hh, 2000ul); aprsstr_Append(h, 2000ul, hh, 2000ul); aprsstr_Append(h, 2000ul, "\015\012", 3ul); /*-line 6 */ aprsstr_Append(h, 2000ul, " ", 5ul); rinexfloat(anonym->idot*3.1415926535898, hh, 2000ul); aprsstr_Append(h, 2000ul, hh, 2000ul); rinexfloat(0.0, hh, 2000ul); aprsstr_Append(h, 2000ul, hh, 2000ul); rinexfloat((double)almanach.wnt, hh, 2000ul); aprsstr_Append(h, 2000ul, hh, 2000ul); rinexfloat(0.0, hh, 2000ul); aprsstr_Append(h, 2000ul, hh, 2000ul); aprsstr_Append(h, 2000ul, "\015\012", 3ul); /*-line 7 */ aprsstr_Append(h, 2000ul, " ", 5ul); rinexfloat((double)urai(anonym->ura), hh, 2000ul); aprsstr_Append(h, 2000ul, hh, 2000ul); rinexfloat((double)anonym->health, hh, 2000ul); aprsstr_Append(h, 2000ul, hh, 2000ul); rinexfloat(anonym->tgd, hh, 2000ul); aprsstr_Append(h, 2000ul, hh, 2000ul); rinexfloat((double)anonym->IODC, hh, 2000ul); aprsstr_Append(h, 2000ul, hh, 2000ul); aprsstr_Append(h, 2000ul, "\015\012", 3ul); /*-line 8 */ aprsstr_Append(h, 2000ul, " ", 5ul); rinexfloat((double)(anonym->tow*6UL), hh, 2000ul); aprsstr_Append(h, 2000ul, hh, 2000ul); aprsstr_Append(h, 2000ul, "\015\012", 3ul); } } if (f>=0L) { osi_WrBin(f, (char *)h, 2000u/1u, aprsstr_Length(h, 2000ul)); osic_Close(f); } } /* end for */ } /* end rinexfile() */ static void warmbootfile(char wr) { int32_t fd; int32_t res; if (warmbootfn[0]) { if (wr) fd = osi_OpenWrite(warmbootfn, 1024ul); else fd = osi_OpenRead(warmbootfn, 1024ul); if (fd>=0L) { if (wr) { osi_WrBin(fd, (char *) &almanach, sizeof(struct ALMANACH)/1u, sizeof(struct ALMANACH)); } else { res = osi_RdBin(fd, (char *) &almanach, sizeof(struct ALMANACH)/1u, sizeof(struct ALMANACH)); } osic_Close(fd); } } } /* end warmbootfile() */ /*--- 300 bit frame ready */ static char frame300(uint32_t s, const FRP300 frame, float ifase) { uint32_t j; uint32_t i0; uint32_t page; uint32_t subframeid; char h[100]; pSATDEMOD ps0; struct EPHEMERIS * anonym; struct EPHEMERIS * anonym0; struct EPHEMERIS * anonym1; struct EPHEMERIS * anonym2; almanach.ephtmp[s].tow = btoc(frame, 10ul, 30UL, 17UL); almanach.ephem[s].tow = almanach.ephtmp[s].tow; if (almanach.ephtmp[s].tow==0UL) ++almanach.ephtmp[s].wncorr; subframeid = btoc(frame, 10ul, 49UL, 3UL); sat[s].timesamp = sampc; sat[s].timesampfrac = ifase; if (verb) { osic_WrINT32(s+1UL, 2UL); osi_WrStr(":", 2ul); WrDate(almanach.ephtmp[s].wncorr, almanach.ephtmp[s].tow*6UL); osi_WrStr(" ls=", 5ul); osic_WrINT32((uint32_t)almanach.tls, 1UL); /*WrStr(" df="); WrFixed(sat[s].freqmed,1,1); */ /* WrStr(" do="); WrFixed(sat[s].prndoppler,4,1); */ osi_WrStr(" sig=", 6ul); osic_WrFixed(sat[s].sig, 1L, 1UL); osi_WrStr(" subf=", 7ul); osic_WrINT32(subframeid, 1UL); osi_WrStr(" tow=", 6ul); osic_WrINT32(almanach.ephtmp[s].tow, 1UL); osi_WrStr(" ", 2ul); } almanach.ephtmp[s].done |= (1U<wn = btoc(frame, 10ul, 60UL, 10UL); anonym->wncorr = anonym->wn; anonym->IODC = btoc(frame, 10ul, 210UL, 8UL)+btoc(frame, 10ul, 82UL, 2UL)*256UL; anonym->af2a = ctolf(btoc(frame, 10ul, 240UL, 8UL), -8L, 2.7755575615629E-17); anonym->af1a = ctolf(btoc16(frame, 10ul, 248UL), -16L, 1.1368683772162E-13); /* 2^-43 */ anonym->af0a = ctolf(btoc(frame, 10ul, 270UL, 22UL), -22L, 4.6566128730774E-10); anonym->toc = btoc16(frame, 10ul, 218UL)*16UL; anonym->tgd = ctolf(btoc(frame, 10ul, 196UL, 8UL), -8L, 4.6566128730774E-10); anonym->health = btoc(frame, 10ul, 76UL, 6UL); anonym->ura = btoc(frame, 10ul, 72UL, 4UL); if (verb) { osi_WrStr(" wnc=", 6ul); osic_WrINT32(anonym->wncorr, 1UL); osi_WrStr(" ", 2ul); osi_WrStr(" ura=", 6ul); osic_WrINT32(anonym->ura, 1UL); osi_WrStr(" ", 2ul); osi_WrStr(" health=", 9ul); osic_WrINT32(btoc(frame, 10ul, 76UL, 6UL), 1UL); osi_WrStr(" ", 2ul); } } } else if (subframeid==2UL) { { /* with */ struct EPHEMERIS * anonym0 = &almanach.ephtmp[s]; anonym0->AODO = btoc(frame, 10ul, 286UL, 5UL); anonym0->toe = btoc16(frame, 10ul, 270UL)*16UL; /* Reference Time Ephemeris */ anonym0->roota = ctolf(btoc32(frame, 10ul, 226UL), 32L, 1.9073486328125E-6); anonym0->cus = ctolf(btoc16(frame, 10ul, 210UL), -16L, 1.862645149231E-9); /* Amplitude of the Sine Harmonic Correction Term to the Argument of Latitude */ anonym0->ecc = ctolf(btoc32(frame, 10ul, 166UL), 32L, 1.1641532182693E-10); anonym0->cuc = ctolf(btoc16(frame, 10ul, 150UL), -16L, 1.862645149231E-9); /* Amplitude of the Cosine Harmonic Correction Term to the Argument of Latitude */ anonym0->m0 = ctolf(btoc32(frame, 10ul, 106UL), -32L, 4.6566128730774E-10); anonym0->deltan = ctolf(btoc16(frame, 10ul, 90UL), -16L, 1.1368683772162E-13); anonym0->crs = ctolf(btoc16(frame, 10ul, 68UL), -16L, 0.03125); /* Amplitude of the Sine Harmonic Correction Term to the Orbit Radius */ anonym0->IODE2 = btoc(frame, 10ul, 60UL, 8UL); } } else if (subframeid==3UL) { /*IF verb THEN WrStr(" toe=");WrInt(toe,1); WrStr(" "); WrStr(" "); END; */ { /* with */ struct EPHEMERIS * anonym1 = &almanach.ephtmp[s]; anonym1->idot = ctolf(btoc(frame, 10ul, 278UL, 14UL), -14L, 1.1368683772162E-13); anonym1->IODE3 = btoc(frame, 10ul, 270UL, 8UL); anonym1->omegadot = ctolf(btoc24(frame, 10ul, 240UL), -24L, 1.1368683772162E-13); anonym1->w = ctolf(btoc32(frame, 10ul, 196UL), -32L, 4.6566128730774E-10); anonym1->crc = ctolf(btoc16(frame, 10ul, 180UL), -16L, 0.03125); /* Amplitude of the Cosine Harmonic Correction Term to the Orbit Radius */ anonym1->i0 = ctolf(btoc32(frame, 10ul, 136UL), -32L, 4.6566128730774E-10); /* Inclination Angle at Reference Time */ anonym1->cis = ctolf(btoc16(frame, 10ul, 120UL), -16L, 1.862645149231E-9); /* Amplitude of the Sine Harmonic Correction Term to the Angle of Inclination */ anonym1->cic = ctolf(btoc16(frame, 10ul, 60UL), -16L, 1.862645149231E-9); /* Amplitude of the Cosine Harmonic Correction Term to the Angle of Inclination */ anonym1->omega0 = ctolf(btoc32(frame, 10ul, 76UL), -32L, 4.6566128730774E-10); } rinexfile(); warmbootfile(1); dopdone = 0UL; } else if (subframeid==4UL) { page = btoc(frame, 10ul, 62UL, 6UL); if (verb) { osi_WrStr(" page=", 7ul); osic_WrINT32(page, 1UL); osi_WrStr(" ", 2ul); } if (page==56UL) { /* page=18 */ almanach.tls = (int32_t)(signed char)btoc(frame, 10ul, 240UL, 8UL); almanach.a0 = ctolf(btoc32(frame, 10ul, 240UL), -32L, 9.3132257461548E-10); almanach.a1 = ctolf(btoc24(frame, 10ul, 150UL), -24L, 8.673617379884E-19); almanach.tot = btoc(frame, 10ul, 218UL, 8UL)*4096UL; almanach.wnt = btoc(frame, 10ul, 226UL, 8UL); almanach.wnlsf = btoc(frame, 10ul, 248UL, 8UL); almanach.tlsf = (int32_t)(signed char)btoc(frame, 10ul, 270UL, 8UL); /* signed */ almanach.page18ok = 1; if (verb) { osi_WrStr(" tls=", 6ul); osic_WrINT32((uint32_t)almanach.tls, 1UL); osi_WrStr(" ", 2ul); osi_WrStr(" tot=", 6ul); osic_WrINT32(almanach.tot, 1UL); osi_WrStr(" ", 2ul); osi_WrStr(" wnt=", 6ul); osic_WrINT32(almanach.wnt, 1UL); osi_WrStr(" ", 2ul); osi_WrStr(" tlsf=", 7ul); osic_WrINT32((uint32_t)almanach.tlsf, 1UL); osi_WrStr(" ", 2ul); } } else if (page==55UL) { /* page 17(55) special messages */ j = btoc16(frame, 10ul, 68UL); h[0U] = (char)(j&255UL); h[1U] = (char)(j/256UL); for (i0 = 0UL; i0<=5UL; i0++) { j = btoc24(frame, 10ul, 90UL+i0*30UL); h[2UL+i0*3UL] = (char)(j&255UL); h[3UL+i0*3UL] = (char)(j/256UL&255UL); h[4UL+i0*3UL] = (char)(j/65536UL); } /* end for */ j = btoc16(frame, 10ul, 270UL); h[20U] = (char)(j&255UL); h[21U] = (char)(j/256UL); if (verb) { osi_WrStr("Special Message:", 17ul); for (i0 = 0UL; i0<=21UL; i0++) { osi_WrStr((char *) &"???????????????????????????????? ?\"????\'???+?-./0123456789:??????ABCDEFGHIJKLM\ NOPQRSTUVWXYZ???????????????????????????????????????????????????????????????????????????????????????????????????????????\ ??????????????????????????????????????????????????o???????"[(uint8_t)h[i0]], 1u/1u); } /* end for */ } } } else if (subframeid==5UL) { page = btoc(frame, 10ul, 62UL, 6UL); if (verb) { osi_WrStr(" page=", 7ul); osic_WrINT32(btoc(frame, 10ul, 62UL, 6UL), 1UL); osi_WrStr(" ", 2ul); } } else { /* not existing subframe number */ if (verb) { osi_WrStr("FALSE LOCK subf=", 17ul); osic_WrINT32(subframeid, 1UL); osi_WrStrLn("", 1ul); } return 0; } { /* with */ struct EPHEMERIS * anonym2 = &almanach.ephtmp[s]; if ((!(~anonym2->done&0xEU) && anonym2->IODE2==anonym2->IODE3) && anonym2->IODE2==(anonym2->IODC&255UL)) { almanach.ephem[s] = almanach.ephtmp[s]; } else if (verb) { osi_WrStr("---IODE-missmatch ", 19ul); osic_WrINT32(anonym2->IODC&255UL, 1UL); osi_WrStr(" ", 2ul); osic_WrINT32(anonym2->IODE3, 1UL); osi_WrStr(" ", 2ul); osic_WrINT32(anonym2->IODE2, 1UL); osi_WrStr(" ", 2ul); } } if (verb) { osi_WrStr(" wnc=", 6ul); osic_WrINT32(almanach.ephem[s].wncorr, 1UL); osi_WrStr(" ", 2ul); osi_WrStr(" sq", 4ul); ps0 = psat; do { if (ps0->insync==gpssdr_TRACE) { osic_WrINT32(ps0->prn+1UL, 1UL); osi_WrStr(":", 2ul); osic_WrINT32((uint32_t)(int32_t)X2C_TRUNCI(ps0->squelch,X2C_min_longint,X2C_max_longint), 1UL); osi_WrStr(" ", 2ul); } ps0 = ps0->next; } while (ps0); osi_WrStrLn("", 1ul); } return 1; } /* end frame300() */ /*-------------almanach */ /*-- hamming code used for (fast) check of correct frame start and polarity */ static uint32_t rot(uint32_t s, int32_t n) { return X2C_LSH(s,32,n)^X2C_LSH(s,32,n-32L); } /* end rot() */ static char hamm(uint32_t * w, uint32_t wo) { uint32_t h; *w = *w&0x3FFFFFFFUL|X2C_LSH(wo,32,30); if ((0x40000000UL & *w)) *w = *w^0x3FFFFFC0UL; h = *w&0xFBFFBF00UL^rot(*w, 1L)&0x7FFBF01UL^rot(*w, 2L)&0xFC0F8100UL^rot(*w, 3L)&0xF81FFE02UL^rot(*w, 4L)&0xFC00000EUL^rot(*w, 5L)&0x7F00001UL^rot(*w, 6L)&0x3000UL; return ((*w^h^rot(h, 6L)^rot(h, 12L)^rot(h, 18L)^rot(h, 24L))&0x3FUL)==0UL; } /* end hamm() */ /*-- navigation data bits (polarisation unknown) 50bit/s and sample time of sat clock yet */ #define gpssdr_FRAMELEN 30 static void bit50(uint32_t s, char b, uint32_t ber, float samper, float freq, float noiselev, float prnn, float ifase, float level) { uint32_t i0; uint32_t wh; uint32_t w; struct SAT * anonym; { /* with */ struct SAT * anonym = &sat[s]; anonym->insyn = 1; anonym->freqmed = anonym->freqmed+freq; ++anonym->freqmedc; anonym->prndoppler = (double)samper; anonym->snr = noiselev; anonym->sig = level; anonym->bert = ber; anonym->prnnois = prnn; /* multipath:=echo; */ anonym->prange = (double)sampc+(double)ifase*1.5625E-2; anonym->bitc = anonym->fsyn; w = X2C_LSH(anonym->frame[anonym->framep],32,1)&0x3FFFFFFFUL; if (b) w |= 0x1UL; anonym->frame[anonym->framep] = w; ++anonym->fsyn; if (anonym->fsyn>=30UL) { /* wbit(s, 0, "?", w); */ if (anonym->framep==0UL) { wh = w&0x3FC00000UL; /* preamble mask */ if (wh==0x22C00000UL) { /* preamble normal lock */ anonym->fsyn = 0UL; anonym->invers = 0; if (verb2) wbit(s, 0UL, "^", 2ul, anonym->frame[0U]); } else if (wh==0x1D000000UL) { /* preamble invers lock */ anonym->invers = 1; anonym->frame[0U] = anonym->frame[0U]^0x3FFFFFFFUL; anonym->fsyn = 0UL; if (verb2) wbit(s, 0UL, "v", 2ul, anonym->frame[0U]); } else anonym->datasyn = 0; if (anonym->fsyn==0UL && hamm(&anonym->frame[anonym->framep], 0UL)) { anonym->framep = 1UL; /* found 300 bit block start */ } } else { anonym->fsyn = 0UL; if (anonym->invers) { anonym->frame[anonym->framep] = anonym->frame[anonym->framep]^0x3FFFFFFFUL; } if (hamm(&anonym->frame[anonym->framep], anonym->frame[anonym->framep-1UL])) { if (verb2) { wbit(s, anonym->framep, "+", 2ul, anonym->frame[anonym->framep]); } ++anonym->framep; if (anonym->framep>=10UL) { anonym->datasyn = frame300(s, anonym->frame, ifase); anonym->framep = 0UL; } } else { anonym->framep = 0UL; anonym->datasyn = 0; if (verb2) wbit(s, anonym->framep, "-", 2ul, w); } } } /*- find set of sat in same 50bit/s data sample */ /*WrStr(" p"); WrInt(s+1,1);WrStr(" ");WrInt(bitc,1);WrStr(":"); */ if (anonym->datasyn) { /*& (bert=0)*/ i0 = 0UL; for (;;) { if (sat[i0].datasyn && sat[i0].bitc!=anonym->bitc) { /* & (sat[i].bert=0)*/ break; /* not all sat in same 20ms periode */ } ++i0; if (i0>32UL) { /* todo: bad sat exclusion set no datasyn */ /*WrStr("(n)"); */ navigate(); break; } } } } } /* end bit50() */ static void resetsat(uint32_t prn) { sat[prn].insyn = 0; sat[prn].datasyn = 0; sat[prn].satok = 0; sat[prn].fsyn = 0UL; sat[prn].framep = 0UL; } /* end resetsat() */ /*--- demodulated 1000bit/s stream bits find center of change every 20 bits */ #define gpssdr_MED 0.01 static void bit1000(pSATDEMOD ps0, float b) { uint32_t m; uint32_t i0; float max0; float r; char chg; struct SATDEMOD * anonym; { /* with */ struct SATDEMOD * anonym = ps0; chg = anonym->lastb!=b>=0.0f; anonym->lastb = b>=0.0f; max0 = (-1.0f); /*WrStr(" {"); */ for (i0 = 0UL; i0<=19UL; i0++) { r = anonym->chhist[i0]; /*WrFixed(r,3,1); WrStr(" "); */ if (r>max0) { max0 = r; m = i0; } } /* end for */ /*WrStrLn("}"); */ anonym->chhist[anonym->histc] = anonym->chhist[anonym->histc]*0.99f; /* where is bit change in the 20 chirps for a databit*/ if (chg) { anonym->chhist[anonym->histc] = anonym->chhist[anonym->histc]+0.01f; if (m!=anonym->histc) { anonym->ber = 20UL; /* timestamp not sync to median 50baud bit change */ } } anonym->bitsum = anonym->bitsum+b; /* sum 20 chip bits to a databit */ anonym->freqsum = anonym->freqsum+anonym->freq; ++anonym->freqsumcnt; if (m==anonym->histc) { if (anonym->ber>0UL) --anonym->ber; if (verb3) osi_WrStrLn("", 1ul); bit50(ps0->prn, anonym->bitsum>=0.0f, anonym->ber, anonym->prndoppler, (float)(X2C_DIVL((double)anonym->freqsum, 4.1984040039101E+3*(double)(float)anonym->freqsumcnt)), anonym->squelch, anonym->prnnoise, anonym->ifase, anonym->level); anonym->freqsumcnt = 0UL; anonym->freqsum = 0.0f; anonym->bitsum = 0.0f; } anonym->histc = (anonym->histc+1UL)%20UL; } if (verb3) osic_WrINT32((uint32_t)(b>=0.0f), 1UL); } /* end bit1000() */ /*--- shedule search with unused channels and prefer just lost sats */ static void nextsat(pSATDEMOD ps0) { uint32_t o; pSATDEMOD s; o = scansat; for (;;) { s = psat; while ((s && s->insync) && s->prn!=scansat) s = s->next; if (s==0 || s->insync==gpssdr_UNUSED) { ps0->prn = scansat; if (verb2) { osi_WrStr("start scan prn:", 16ul); osic_WrUINT32(scansat+1UL, 1UL); osi_WrStrLn("", 1ul); } break; } scansat = scansat+1UL&31UL; if (o==scansat) break; } } /* end nextsat() */ /*--- find sats by random sliding spread code and then fft peak search in 500hz steps */ static char search(pSATDEMOD ps0, struct Complex b[], uint32_t b_len, float ii, float iq) { uint32_t i0; float e; float max0; float d; int32_t m; struct SATDEMOD * anonym; uint32_t tmp; { /* with */ struct SATDEMOD * anonym = ps0; if (GOLD[anonym->prn][anonym->goldp]) { b[anonym->wp].Re = -ii; b[anonym->wp].Im = -iq; } else { b[anonym->wp].Re = ii; b[anonym->wp].Im = iq; } ++anonym->goldp; if (anonym->goldp>1023UL) anonym->goldp = 1UL; ++anonym->wp; if (anonym->wp<=b_len-1) return 0; anonym->wp = 0UL; Transform(b, b_len); max0 = (-1.0f); e = 0.0f; tmp = b_len-1; i0 = 0UL; if (i0<=tmp) for (;; i0++) { /* find peak in spectrum search range */ if (i0<=searchkhz || i0>(b_len-1)-searchkhz) { d = CABSQ(b[i0].Re, b[i0].Re); e = e+d; if (d>max0) { max0 = d; m = (int32_t)i0; } } if (i0==tmp) break; } /* end for */ if (max0>e*anonym->peakthres) { /* optimize to find all sats in fft */ anonym->peakthres = (X2C_DIVR(max0,e))*1.4f; if (m>(int32_t)((b_len-1)/2UL)) { m -= (int32_t)((b_len-1)+1UL); /* make signed freq around zero */ } anonym->freq = (float)(2.099202001955E+6*(double)(float) -m); anonym->leadlag = anonym->freq; /* preset slow part of pll loop filter */ anonym->squelch = 0.0f; anonym->msok = 0UL; if (verb) { osic_WrINT32(anonym->prn+1UL, 2UL); osi_WrStr(":fftpeak:", 10ul); osic_WrFixed((float)(X2C_DIVL((double)anonym->freq,4.1984040039101E+3)), 1L, 1UL); osi_WrStr("Hz,lev:", 8ul); osic_WrFixed(X2C_DIVR(max0,e), 2L, 1UL); osi_WrStrLn("", 1ul); } return 1; } anonym->peakthres = anonym->peakthres*0.9995f; anonym->goldp = 1UL; if (!anonym->fixprn && sampc-anonym->lastsearch>4200000UL) { /* search intervall over */ anonym->lastsearch = sampc; if (sampc-anonym->lastsync>613800000UL) anonym->scan = 1; if (anonym->scan) nextsat(ps0); } } return 0; } /* end search() */ static void trace(pSATDEMOD ps0, float si, float sq) { uint32_t d; float dq; float di; float dp; float df; float hi; struct SATDEMOD * anonym; { /* with */ struct SATDEMOD * anonym = ps0; /*-- split spread spectrum into baseband channels */ if ((anonym->wp&1)) { /* half bit for data */ anonym->dds += (uint32_t)anonym->freqi; d = (uint32_t)X2C_LSH((uint32_t)anonym->dds,32,-18); di = DDS[d]; dq = DDS[d+4096UL&16383UL]; if (GOLD[anonym->prn][anonym->wp>>1]) { anonym->sumi = anonym->sumi+anonym->sio; anonym->sumq = anonym->sumq+anonym->sqo; anonym->sumqco = anonym->sumqco+anonym->sqc0; anonym->sqc0 = anonym->sic*dq+anonym->sqc*di; anonym->sumqc = anonym->sumqc+anonym->sqc0; } else { anonym->sumi = anonym->sumi-anonym->sio; anonym->sumq = anonym->sumq-anonym->sqo; anonym->sumqco = anonym->sumqco-anonym->sqc0; anonym->sqc0 = anonym->sic*dq+anonym->sqc*di; anonym->sumqc = anonym->sumqc-anonym->sqc0; } anonym->sio = si*di-sq*dq; anonym->sqo = si*dq+sq*di; } else { /* half bit for clock sync */ anonym->sic = si; anonym->sqc = sq; } ++anonym->wp; if (anonym->wp>=2047UL) { /*--chip ready, 1 iq sample 1000hz per sat */ if (anonym->msok>1000UL) bit1000(ps0, anonym->sumq); if (soundfd>=0L) soundout(ps0); /*--interpolate 1mhz/300m resolution with constant groop delay pll lowpass */ if (anonym->sumq!=0.0f) { hi = X2C_DIVR(anonym->sumqc-anonym->sumqco,anonym->sumq); if (verb) { if (hi<0.0f) ++sat[anonym->prn].minusc; else ++sat[anonym->prn].plusc; } anonym->prnnoise = anonym->prnnoise+((float)fabs(hi)-anonym->prnnoise)*0.01f; /* multipath:=multipath+((sumqc+sumqco)/sumq-multipath)*0.005; */ if (hi>1.0f) hi = 1.0f; else if (hi<(-1.0f)) hi = (-1.0f); } else hi = 0.0f; if (anonym->msok>1000UL) { /* locked, so slow pll */ anonym->ifase = anonym->ifase+hi*0.1f; /* 0.2 on 32 size ifirfine */ anonym->prndoppler = anonym->prndoppler+hi*0.0001f; /* 0.0002 on 32 size ifirfine */ } else { /* new sat so fast prn pll*/ anonym->ifase = anonym->ifase+hi; /* 1.0 on 32 size ifirfine */ anonym->prndoppler = anonym->prndoppler+(hi-anonym->prndoppler)*0.1f; } anonym->ifase = anonym->ifase+anonym->prndoppler; /* pll with no phase delay avoid pseudorange bias on high doppler sats */ anonym->level = anonym->level+((float)fabs(anonym->sumq)-anonym->level)*0.02f; /*--- carrier plland squelch */ df = fastatang2(anonym->sumi, anonym->sumq); dp = df-anonym->lastph; if (dp>3.1415926535898f) dp = dp-6.2831853071796f; if (dp<(-3.1415926535898f)) dp = dp+6.2831853071796f; if ((float)fabs(dp)<1.5707963267949f) { anonym->leadlag = (float)((double)anonym->leadlag+(double)dp*4.1984040039101E+3*10.0); } anonym->lastph = df; if (df<0.0f) df = 1.5707963267949f+df; else df = df-1.5707963267949f; anonym->squelch = anonym->squelch*0.995f+(float)fabs(df); df = 30000.0f*df; anonym->freq = anonym->freq+df; anonym->leadlag = anonym->leadlag+(anonym->freq-anonym->leadlag)*0.09f; anonym->freq = anonym->freq+(anonym->leadlag-anonym->freq)*0.15f; anonym->freqi = (int32_t)X2C_TRUNCI(anonym->freq,X2C_min_longint,X2C_max_longint); /* save time */ /*----carrier pll */ /*- shift sample time */ anonym->wp = 1UL; if (anonym->ifase<0.0f) { /*WrStr(" P++++ "); */ anonym->wp = 2UL; anonym->ifase = 63.0f; } else if (anonym->ifase>63.0f) { /*WrStr(" P---- "); */ anonym->wp = 0UL; anonym->ifase = 0.0f; } anonym->ifasei = (uint32_t)X2C_TRUNCC(anonym->ifase,0UL,X2C_max_longcard); /*- shift sample time */ anonym->sumi = 0.0f; anonym->sumq = 0.0f; anonym->sumqc = 0.0f; anonym->sumqco = 0.0f; if (anonym->msok>=1000UL) { if (anonym->squelch>120.0f) { /* sat lost */ resetsat(anonym->prn); if (verb) { osic_WrINT32(anonym->prn+1UL, 2UL); if (anonym->msok>1000UL) osi_WrStrLn(": sync-lost", 12ul); else { osi_WrStr(":no sync found on ", 19ul); osic_WrFixed((float)(X2C_DIVL((double)anonym->freq,4.1984040039101E+3)), 0L, 1UL); osi_WrStrLn("Hz", 3ul); } } anonym->insync = gpssdr_AQUISIT; } else if (anonym->squelch<80.0f) { anonym->lastsync = sampc; anonym->scan = 0; if (anonym->msok==1000UL) { if (verb) { osic_WrINT32(anonym->prn+1UL, 2UL); osi_WrStr(":+++SYNC OK on ", 16ul); osic_WrFixed((float)(X2C_DIVL((double)anonym->freq,4.1984040039101E+3)), 0L, 1UL); osi_WrStrLn("Hz", 3ul); } ++anonym->msok; } } } else ++anonym->msok; } } } /* end trace() */ /*-- read different iq formats */ union _3; union _3 { struct Complex c[4096]; short i0[16384]; uint8_t b[32768]; }; static uint32_t inreform(float b[], uint32_t b_len) { uint32_t wp; uint32_t rs; uint32_t bs; uint32_t i0; int32_t res; union _3 ib; char * p; uint32_t tmp; bs = 8192UL; if (8192UL>((b_len-1)+1UL)*2UL) bs = ((b_len-1)+1UL)*2UL; rs = 0UL; do { p = (char *) &ib.b[rs]; res = osi_RdBin(iqfd, p, 65536ul, bs-rs); if (res<=0L) return 0UL; rs += (uint32_t)res; } while (rs>1; } else { X2C_MOVE((char *) &ib,(char *)b,rs); wp = rs>>2; } return wp; } /* end inreform() */ /*-- iq samplerate conversation and interpolation */ static void doifir(uint32_t fase, float * ui, float * uq) { uint32_t e; uint32_t j; uint32_t i0; float t; i0 = 0UL; e = 5UL; if (fase>=64UL) { i0 = 2UL; e = 7UL; fase -= 64UL; } *ui = 0.0f; *uq = 0.0f; j = fase*5UL; do { t = IFIRTAB[j]; ++j; *ui = *ui+ifir[i0]*t; ++i0; *uq = *uq+ifir[i0]*t; ++i0; } while (i0insync==gpssdr_TRACE) { doifir(ps0->ifasei+phase, &ui, &uq); trace(ps0, ui, uq); } else if ((sampc&1UL)==0UL) { doifir(phase, &ui, &uq); if (search(ps0, ps0->fb, 2048ul, ui, uq)) { /* maybe sat found */ ps0->ifase = 0.0f; ps0->insync = gpssdr_TRACE; ps0->msok = 0UL; ps0->wp = 4UL; } } ps0 = ps0->next; } while (ps0); ++sampc; } /* end allsat() */ static uint32_t insampfine; static uint32_t insampstep; static uint32_t pinb; static uint32_t sinb; static uint32_t oldf; static uint32_t i; static uint32_t il; static pSATDEMOD ps; static char getinsamp(void) { if (pinb>=sinb) { sinb = inreform(iqbuf, 8192ul); if (sinb<2UL) return 0; pinb = 0UL; } X2C_MOVE((char *) &ifir[2U],(char *) &ifir[0U],sizeof(float [12])-sizeof(float)*2UL); ifir[10U] = iqbuf[pinb]; ++pinb; ifir[11U] = iqbuf[pinb]; ++pinb; return 1; } /* end getinsamp() */ X2C_STACK_LIMIT(8000000l) extern int main(int argc, char **argv) { uint32_t tmp; X2C_BEGIN(&argc,argv,1,20000000l,32000000l); if (sizeof(FRP300)!=40) X2C_ASSERT(0); aprsstr_BEGIN(); osi_BEGIN(); goldcode(); MakeDDS(DDS, 16384ul); memset((char *)sat,(char)0,sizeof(struct SAT [33])); memset((char *) &almanach,(char)0,sizeof(struct ALMANACH)); almfn[0] = 0; warmbootfn[0] = 0; maxalt = 50000.0f; errsum = 0.0; Parms(); warmbootfile(0); initpos(); genrev(2048UL); psat = 0; tmp = maxsat-1UL; i = 0UL; if (i<=tmp) for (;; i++) { osic_alloc((char * *) &ps, sizeof(struct SATDEMOD)); if (ps==0) Error("out of memory", 14ul); ps->next = psat; psat = ps; ps->insync = gpssdr_AQUISIT; ps->scan = 1; ps->lastsearch = 0x0FFBFE9BFUL; for (il = 0UL; il<=32UL; il++) { if (X2C_IN(il,32,fixsat)) { ps->fixprn = 1; ps->prn = il; fixsat &= ~(1UL<insamp; if (upsample) { insampstep = X2C_max_longcard-(uint32_t)X2C_TRUNCC((1.0f-X2C_DIVR((float)insamp,2.046E+6f))*4.294967295E+9f, 0UL,X2C_max_longcard); } else { insampstep = X2C_max_longcard-(uint32_t)X2C_TRUNCC((1.0f-X2C_DIVR(2.046E+6f,(float)insamp))*4.294967295E+9f, 0UL,X2C_max_longcard); } if (upsample) { for (;;) { oldf = insampfine; insampfine += insampstep; if (insampfine<=oldf && !getinsamp()) break; allsat(insampfine/67108864UL); } } else { while (getinsamp()) { oldf = insampfine; insampfine -= insampstep; if (insampfine>=oldf) allsat(insampfine/67108864UL); } } X2C_EXIT(); return 0; } X2C_MAIN_DEFINITION