www.pudn.com > opengpssim.zip > ogslibrary.c


/* ************************************************************************ 
   *                                                                      *
   *                          GPS Simulation                              *
   *                                                                      *
   * -------------------------------------------------------------------- *
   *                                                                      *
   *    Module:   ogslibrary.cpp                                          *
   *                                                                      *
   *   Version:   0.1                                                     *
   *                                                                      *
   *      Date:   02.03.02                                                *
   *                                                                      *
   *    Author:   G. Beyerle                                              *
   *                                                                      *
   * -------------------------------------------------------------------- *
   *                                                                      *
   * Copyright (C) 2002  Georg Beyerle                                    *
   *                                                                      *
   * This program is free software; you can redistribute it and/or modify *
   * it under the terms of the GNU General Public License as published by *
   * the Free Software Foundation; either version 2 of the License, or    *
   * (at your option) any later version.                                  *
   *                                                                      *
   * This program is distributed in the hope that it will be useful,      *
   * but WITHOUT ANY WARRANTY; without even the implied warranty of       *
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        *
   * GNU General Public License for more details.                         *
   *                                                                      *
   * You should have received a copy of the GNU General Public License    *
   * along with this program; if not, write to the Free Software          *
   * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.            *
   *                                                                      *
   * -------------------------------------------------------------------- *
   *                                                                      *
   * The files 'gpsfuncs.cpp', 'gpsrcvr.cpp' and 'gp2021.cpp' are modi-   *
   * fied versions of the files with the same name from Clifford Kelley's * 
   * OpenSourceGPS distribution. The unmodified files can be obtained     *
   * from http://www.home.earthlink.net/~cwkelley                         *
   *                                                                      *
   * -------------------------------------------------------------------- *
   *                                                                      *
   *           Library routines for OpenSourceGPS GPS simulator           *
   *                                                                      *
   ************************************************************************ */

/* ******************************* changes ********************************

   dd.mm.yy -

   ************************************************************************ */

/* ------------------------------- includes ------------------------------- */

#include 
#include 
#include 
#include 
#include 

#ifdef unix
#include 
#endif

#define OSGLIBRY_H

#include "ogsdefine.h"
#include "ogsstructs.h"
#include "ogsextern.h"
#include "ogslibrary.h"

/* ------------------------------- defines -------------------------------- */

/* ------------------------------- globals -------------------------------- */

/* -------------------------- prototypes (global) ------------------------- */

static int exor_long( unsigned long x);

/* ------------------------------ procedures ------------------------------ */

//
//  read key:value pair from parameter file
//
int read_key_value_pair_double( char *tok, char pattern[], double *val, char sep[])
{
  char *token;
  int ret = 0;

  if ( strstr( tok, pattern))
  {
    token = strtok( NULL, sep);
    if ( token) 
    {
      sscanf( token, "%e", val);
      printf( "%s = %f\n", pattern, *val);
      ret = 1;
    }  
  }
  return (ret);
}  

//
//  read key:value pair from parameter file
//
int read_key_value_pair_float( char *tok, char pattern[], float *val, char sep[])
{
  char *token;
  int ret = 0;

  if ( strstr( tok, pattern))
  {
    token = strtok( NULL, sep);
    if ( token) 
    {
      sscanf( token, "%f", val);
      printf( "%s = %f\n", pattern, *val);
      ret = 1;
    }  
  }
  return (ret);
}  

int read_key_value_pair_int( char *tok, char pattern[], int *val, char sep[])
{
  char *token;
  int ret = 0;

  if ( strstr( tok, pattern))
  {
    token = strtok( NULL, sep);
    if ( token) 
    {
      sscanf( token, "%d", val);
      printf( "%s = %d\n", pattern, *val);
      ret = 1;
    }  
  }
  return (ret);
}  

int read_key_value_pair_uint( char *tok, char pattern[], unsigned int *val, char sep[])
{
  char *token;
  int ret = 0;

  if ( strstr( tok, pattern))
  {
    token = strtok( NULL, sep);
    if ( token) 
    {
      sscanf( token, "%d", val);
      printf( "%s = %d\n", pattern, *val);
      ret = 1;
    }  
  }
  return (ret);
}  

int read_key_value_pair_long( char *tok, char pattern[], long *val, char sep[])
{
  char *token;
  int ret = 0;

  if ( strstr( tok, pattern))
  {
    token = strtok( NULL, sep);
    if ( token) 
    {
      sscanf( token, "%d", val);
      printf( "%s = %d\n", pattern, *val);
      ret = 1;
    }  
  }
  return (ret);
}  


//
//  create C/A code and write to global variable CACODE[][]
//
//  adapted from MATLAB routine written by
//  Fredrik Johansson, Rahman Mollaei, Jonas Thor, Joergen Uusitalo
//  Lulea University of Technology, Sweden
//  http://www.sm.luth.se/csee/courses/sms/019/1998/navstar/navstar.html
//
void calc_cacode( void)
{
  int prn;    // 1,...,32 
  int s1, s2;
  int i, j, tmp;

  int tap[32][2] = 
    {{2,  6}, {3, 7}, {4, 8}, {5, 9}, {1, 9}, 
     {2, 10}, {1, 8}, {2, 9}, {3,10}, {2, 3},
     {3,  4}, {5, 6}, {6, 7}, {7, 8}, {8, 9}, 
     {9, 10}, {1, 4}, {2, 5}, {3, 6}, {4, 7}, 
     {5,  8}, {6, 9}, {1, 3}, {4, 6}, {5, 7}, 
     {6,  8}, {7, 9}, {8,10}, {1, 6}, {2, 7}, 
     {3,  8}, {4, 9}};

// loop over all PRNs
  for ( prn=1; prn<=NOFSAT; prn++)
  {

// initial state
    int g1[11] = {0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},  // we don't use first element
        g2[11] = {0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1};

// select taps for G2 delay
    s1 = tap[prn-1][0];
    s2 = tap[prn-1][1];
  
    for ( i=0; i1; j--)
        g1[j] = g1[j-1];
      g1[1] = tmp;
    
//  Generator 2 - shift reg 2  (1+X^2+X^3+X^6+X^8+X^9+X^10)
      tmp = g2[2]*g2[3]*g2[6]*g2[8]*g2[9]*g2[10];
      for ( j=10; j>1; j--)
        g2[j] = g2[j-1];
      g2[1] = tmp;
    }
  }
  return;
}

#if 0

//
//  encode navigation data to array sf2[][] and copy to message[1500] buffer
//
void encode_navmess( char prn, char ch, int i4satid, int i5satid, 
  IONODATA *iono, UTCDATA *utc)
{
  char                schar;
  short unsigned int  sint;
  short int           ssint;
  int                 k, j, sfr, word, isv;
  char                uchar;
  unsigned long       ulong;

//  clear subframe array
  for ( sfr=1; sfr<=5; sfr++)
  {
    for ( word=1; word<=10; word++)
    {
      sf2[sfr][word] = 0;
    }
  }

//
//  copy ephemeris & almanac data to subframe array sf2[][]
//

//
//  EPHEMERIS ENCODE  subframes 1 to 3
//
//  subframe 1
//
//  iodc = int(((sf2[1][3] & 0x3) <<8 ) | ((sf2[1][8] & 0xFF0000L) >> 16));

//  iweek               = int(sf2[1][3] >> 14);
//  gps_eph[prn].week   = iweek;
  ulong                 = gps_eph[prn].week & 0x3FF;  // 10 bits
  sf2[1][3]             = sf2[1][3] | (ulong << 14); 

//  iura                = int(( sf2[1][3] & 0xF00 ) >> 8);
//  gps_eph[prn].ura    = iura;
  ulong                 = gps_eph[prn].ura & 0xF;  // 4 bits
  sf2[1][3]             = sf2[1][3] | (ulong << 8); 

//  ihealth             = int(( sf2[1][3] & 0xFC ) >> 2);
//  gps_eph[prn].health = ihealth;
  ulong                 = gps_eph[prn].health & 0x3F;  // 6 bits
  sf2[1][3]             = sf2[1][3] | (ulong << 2); 

//  iodc = int(((sf2[1][3] & 0x3) << 8 ) | ((sf2[1][8] & 0xFF0000L) >> 16));
  ulong                 = gps_eph[prn].iodc & 0x300;  // 10 bits, 2 MSB
  sf2[1][3]             = sf2[1][3] | (ulong >> 8);
  ulong                 = gps_eph[prn].iodc & 0xFF;  // 10 bits, 8 LSB
  sf2[1][8]             = sf2[1][8] | (ulong << 16);

//  gps_eph[prn].iodc   = iodc;

//  itgd                = int( sf2[1][7] & 0xFF);
//  gps_eph[prn].tgd    = itgd*4.656612873e-10;
  schar                 = char( gps_eph[prn].tgd/4.656612873e-10);  // 8 bits, scale 2^-31
  ulong                 = long( schar) & 0xFF;
  sf2[1][7]             = sf2[1][7] | (ulong);

//  itoc                = int( sf2[1][8] & 0xFFFF);
//  gps_eph[prn].toc    = itoc*16.0;
  ulong                 = long( gps_eph[prn].toc/16.0) & 0xFFFF;  // 16 bits
  sf2[1][8]             = sf2[1][8] | (ulong);

//  iaf2                = int( sf2[1][9] >> 16);
//  gps_eph[prn].af2    = iaf2*2.775557562e-17;
  schar                 = char( gps_eph[prn].af2/2.775557562e-17);  // 8 bits, scale 2^-55
  ulong                 = long( schar) & 0xFF;
  sf2[1][9]             = sf2[1][9] | (ulong << 16);

//  iaf1                = int( sf2[1][9] & 0xFFFF);
//  gps_eph[prn].af1    = iaf1*1.136868377e-13;
  ssint                 = int( gps_eph[prn].af1/1.136868377e-13);  // 16 bits, scale 2^-43
  ulong                 = long( ssint) & 0xFFFF;
  sf2[1][9]             = sf2[1][9] | (ulong);

//  iaf0                = sf2[1][10] >> 2;
//  if ( bit_test_l( iaf0, 22)) 
//    iaf0 = iaf0 | 0xFFC00000L;
//  gps_eph[prn].af0    = iaf0*4.656612873e-10;
  ulong                 = long(gps_eph[prn].af0/4.656612873e-10) & 0x3FFFFF;  // 22 bits, scale 2^-31
  if ( ulong & (0x1L << (22-1)))  // test bit 22
    ulong = ulong | 0xFFC00000L;
  sf2[1][10]            = sf2[1][10] | (ulong << 2);

//
//   subframe 2
//

//  icrs = int(sf2[2][3] & 0xFFFF);
//  gps_eph[prn].crs    = icrs*.03125;
  ssint                 = int( gps_eph[prn].crs/.03125);  // 16 bits, scale 2^-5
  ulong                 = long( ssint) & 0xFFFF;
  sf2[2][3]             = sf2[2][3] | (ulong);

//  idn                 = int(sf2[2][4] >> 8);
//  gps_eph[prn].dn     = idn*1.136868377e-13*pi;
  ssint                 = int( gps_eph[prn].dn/(1.136868377e-13*pi));  // (Delta n) 16 bits, scale 2^-43, rad
  ulong                 = long( ssint) & 0xFFFF;
  sf2[2][4]             = sf2[2][4] | (ulong << 8);

//  im0                 = ((sf2[2][4] & 0xFF) << 24) | sf2[2][5];
//  gps_eph[prn].ma     = im0*4.656612873e-10*pi;
  ulong                 = long( gps_eph[prn].ma/(4.656612873e-10*pi));  // 32 bits, scale 2^-31, rad
  sf2[2][4]             = sf2[2][4] | ((ulong & 0xFF000000) >> 24);
  sf2[2][5]             = sf2[2][5] | (ulong & 0xFFFFFF);

//  icuc                = int(sf2[2][6] >> 8);
//  gps_eph[prn].cuc    = icuc*1.862645149e-9;
  ssint                 = int( gps_eph[prn].cuc/(1.862645149e-9));  // 16 bits, scale 2^-29
  ulong                 = long( ssint) & 0xFFFF;
  sf2[2][6]             = sf2[2][6] | (ulong << 8);

//  ie                  = ((sf2[2][6] & 0xFF) << 24) | sf2[2][7];
//  gps_eph[prn].ety    = ie*1.164153218e-10;
  ulong                 = long( gps_eph[prn].ety/(1.164153218e-10));  // 32 bits, scale 2^-33
  sf2[2][6]             = sf2[2][6] | ((ulong & 0xFF000000) >> 24);
  sf2[2][7]             = sf2[2][7] | (ulong & 0xFFFFFF);

//  icus                = int(sf2[2][8] >> 8);
//  gps_eph[prn].cus    = icus*1.862645149e-9;
  ssint                 = int( gps_eph[prn].cus/1.862645149e-9);  // 16 bits, scale 2^-29
  ulong                 = long( ssint) & 0xFFFF;
  sf2[2][8]             = sf2[2][8] | (ulong << 8);

//  isqra               = (((sf2[2][8] & 0xFF) << 24) | sf2[2][9]);
//  gps_eph[prn].sqra   = isqra*1.907348633e-6;
//  if (gps_eph[prn].sqra>0.0) 
//    gps_eph[prn].wm   = 19964981.84/pow(gps_eph[prn].sqra,3);
  ulong                 = long( gps_eph[prn].sqra/(1.907348633e-6));  // 32 bits, scale 2^-19
  sf2[2][8]             = sf2[2][8] | ((ulong & 0xFF000000) >> 24);
  sf2[2][9]             = sf2[2][9] | (ulong & 0xFFFFFF);

//  itoe                = int(sf2[2][10] >> 8);
//  gps_eph[prn].toe    = itoe*16.;
  ssint                 = int( gps_eph[prn].toe/16.);  // 16 bits, scale 2^4
  ulong                 = long( ssint) & 0xFFFF;
  sf2[2][10]            = sf2[2][10] | (ulong << 8);


//
// subframe 3
//
//  icic                = int(sf2[3][3] >> 8);
//  gps_eph[prn].cic    = icic*1.862645149e-9;
  ssint                 = int( gps_eph[prn].cic/1.862645149e-9);  // 16 bits, scale 2^-29
  ulong                 = long( ssint) & 0xFFFF;
  sf2[3][3]             = sf2[3][3] | (ulong << 8);

//  iomega0             = ((sf2[3][3] & 0xFF) << 24) | sf2[3][4];
//  gps_eph[prn].w0 = iomega0*4.656612873e-10*pi;
  ulong                 = long( gps_eph[prn].w0/(4.656612873e-10*pi));  // 32 bits, scale 2^-31, rad
  sf2[3][3]             = sf2[3][3] | ((ulong & 0xFF000000) >> 24);
  sf2[3][4]             = sf2[3][4] | (ulong & 0xFFFFFF);

//  icis                = int(sf2[3][5] >> 8);
//  gps_eph[prn].cis    = icis*1.862645149e-9;
  ssint                 = int( gps_eph[prn].cis/1.862645149e-9);  // 16 bits, scale 2^-29
  ulong                 = long( ssint) & 0xFFFF;
  sf2[3][5]             = sf2[3][5] | (ulong << 8);

//  inc0                = ((sf2[3][5] & 0xFF) << 24) | sf2[3][6];
//  gps_eph[prn].inc0   = inc0*4.656612873e-10*pi;
  ulong                 = long( gps_eph[prn].inc0/(4.656612873e-10*pi));  // 32 bits, scale 2^-31, rad
  sf2[3][5]             = sf2[3][5] | ((ulong & 0xFF000000) >> 24);
  sf2[3][6]             = sf2[3][6] | (ulong & 0xFFFFFF);

//  icrc                = int(sf2[3][7] >> 8);
//  gps_eph[prn].crc    = icrc*.03125;
  ssint                 = int( gps_eph[prn].crc/.03125);  // 16 bits, scale 2^-5
  ulong                 = long( ssint) & 0xFFFF;
  sf2[3][7]             = sf2[3][7] | (ulong << 8);

//  iw = ((sf2[3][7] & 0xFF) << 24) | sf2[3][8];
//  gps_eph[prn].w = iw*4.656612873e-10*pi;
  ulong                 = long( gps_eph[prn].w/(4.656612873e-10*pi));  // 32 bits, scale 2^-31, rad
  sf2[3][7]             = sf2[3][7] | ((ulong & 0xFF000000) >> 24);
  sf2[3][8]             = sf2[3][8] | (ulong & 0xFFFFFF);

//  iomegadot = sf2[3][9];
//  if (bit_test_l(iomegadot,24)) 
//    iomegadot           = iomegadot | 0xFF000000L;
//  gps_eph[prn].omegadot = iomegadot*1.136868377e-13*pi;
  ulong                 = long(gps_eph[prn].omegadot/(1.136868377e-13*pi)) & 0xFFFFFF;  // 24 bits, scale 2^-43, rad
  if ( ulong & (0x1L << (24-1)))  // test bit 24
    ulong = ulong | 0xFF000000L;
  sf2[3][9]             = sf2[3][9] | (ulong << 2);

//  idot=int((sf2[3][10] & 0xFFFC) >> 2);
//  if (bit_test_l(idot,14)) 
//    idot=idot | 0xC000;
//  gps_eph[prn].idot   = idot*1.136868377e-13*pi;
  ssint                 = int( gps_eph[prn].idot/(1.136868377e-13*pi));  // 14 bits, scale 2^-43, rad
  ulong                 = long( ssint) & 0x3FFF;
  sf2[3][10]            = sf2[3][10] | (ulong << 2);

//
//    ALMANAC ENCODE  subframes 4 and 5
//
//    SUBFRAME 4
//

//      i4p = int((sf2[4][3] & 0x3F0000L) >> 16);
//      if ( i4p != i4satid)
//      {
//        i4satid=i4p;
  ulong     = i4satid & 0x3F;
  sf2[4][3] = sf2[4][3] | (ulong << 16);

  if (i4satid > 24 && i4satid < 33)
  {
//
//  almanac data for satellite 25 thru 32 (frame 5, pages 2,3,4,5,7,8,9,10)
//
    isv = i4satid;

//    gps_alm[isv].week=gps_week;
//    iae=int(sf2[4][3] & 0x00FFFFL);
//    gps_alm[isv].ety=iae*4.768371582E-7;
    ssint     = int( gps_alm[isv].ety/(4.768371582E-7));  // 16 bits, scale 2^-21
    ulong     = long( ssint) & 0xFFFF;
    sf2[4][3] = sf2[4][3] | (ulong);

//    iatoa=int(sf2[4][4] >> 16);
//    gps_alm[isv].toa=iatoa*4096.0;
    schar     = char( gps_alm[isv].toa/4096.0);  // 8 bits, scale 2^12
    ulong     = long( schar) & 0xFF;
    sf2[4][4] = sf2[4][4] | (ulong << 16);

//    iadeli=sf2[4][4] & 0x00FFFFL;
//    if (bit_test_l(iadeli,16)) 
//      iadeli=iadeli | 0xFFFF0000L;
//    gps_alm[isv].inc=(iadeli*1.907348633E-6+0.3)*pi;
    ssint     = int( (gps_alm[isv].inc/pi-0.3)/1.907348633E-6);  // 16 bits, scale 2^-19
    ulong     = long( ssint) & 0xFFFF;
    sf2[4][4] = sf2[4][4] | (ulong);

//    iomegad=int(sf2[4][5] >> 8);
//    gps_alm[isv].rra=iomegad*3.637978807E-12*pi;
    ssint     = int( gps_alm[isv].rra/(3.637978807E-12*pi));  // 16 bits, scale 2^-38
    ulong     = long( ssint) & 0xFFFF;
    sf2[4][5] = sf2[4][5] | (ulong << 8);

//    gps_alm[isv].health=int(sf2[4][5] & 0x0000FF);
    ulong     = long( gps_alm[isv].health) & 0xFF;
    sf2[4][5] = sf2[4][5] | (ulong);

//    iasqr=sf2[4][6];
//    gps_alm[isv].sqa=iasqr*4.8828125E-4;
//    if (gps_alm[isv].sqa>0.0) 
//      gps_alm[isv].w=19964981.84/pow(gps_alm[isv].sqa,3);
    ssint     = int( gps_alm[isv].sqa/(4.8828125E-4));  // 16 bits, scale 2^-11
    ulong     = long( ssint) & 0xFFFF;
    sf2[4][6] = sf2[4][6] | (ulong);

//    iaomega0=sf2[4][7];
//    if (bit_test_l(iaomega0,24)) 
//      iaomega0=iaomega0 | 0xFF000000L;
//    gps_alm[isv].lan=iaomega0*1.192092896E-7*pi;
    ulong     = long( gps_alm[isv].lan/(1.192092896E-7*pi)) & 0xFFFFFF;  // 24 bits, scale 2^-23, rad
    if ( ulong & (0x1L << (24-1)))  // test bit 24
      ulong = ulong | 0xFF000000L;
    sf2[4][7] = sf2[4][7] | (ulong);

//    iaw=sf2[4][8];
//    if (bit_test_l(iaw,24)) 
//      iaw=iaw | 0xFF000000L;
//    gps_alm[isv].aop=iaw*1.192092896E-7*pi;
    ulong     = long( gps_alm[isv].aop/(1.192092896E-7*pi)) & 0xFFFFFF;  // 24 bits, scale 2^-23, rad
    if ( ulong & (0x1L << (24-1)))  // test bit 24
      ulong = ulong | 0xFF000000L;
    sf2[4][8] = sf2[4][8] | (ulong);

//    iam0=sf2[4][9];
//    if (bit_test_l(iam0,24)) 
//      iam0=iam0 | 0xFF000000L;  
//    gps_alm[isv].ma=iam0*1.192092896E-7*pi;
    ulong     = long( gps_alm[isv].ma/(1.192092896E-7*pi)) & 0xFFFFFF;  // 24 bits, scale 2^-23, rad
    if ( ulong & (0x1L << (24-1)))  // test bit 24
      ulong = ulong | 0xFF000000L;
    sf2[4][9] = sf2[4][9] | (ulong);

//    iaaf0=(sf2[4][10] >> 13) | (sf2[4][10] & 0x1C);
//    if ( bit_test_l( iaaf0, 11)) 
//      iaaf0=iaaf0 | 0xFFFFF800L;
//    gps_alm[isv].af0=iaaf0*9.536743164E-7;
    ulong     = long( gps_alm[isv].af0/(9.536743164E-7)) & 0x7FF;  // 11 bits, scale 2^-20
    if ( ulong & (0x1L << (11-1)))  // test bit 11
      ulong = ulong | 0xFFFFF800L;
    sf2[4][10] = sf2[4][10] | ((ulong & 0x7) << 2);
    sf2[4][10] = sf2[4][10] | ((ulong & 0x7F8) << 13);

//    iaaf1=(sf2[4][10] | 0xFFE0) >> 5;
//    if (bit_test_l(iaaf1,11)) 
//      iaaf1=iaaf1 | 0xFFFFF800L;
//    gps_alm[isv].af1=iaaf1*3.637978807E-12;
    ulong     = long( gps_alm[isv].af1/(3.637978807E-12)) & 0x7FF;  // 11 bits, scale 2^-38
    if ( ulong & (0x1L << (11-1)))  // test bit 11
      ulong = ulong | 0xFFFFF800L;
    sf2[4][10] = sf2[4][10] | (ulong << 5);
  }
  else if ( i4satid == 55)
  {
//
//  special messages (22 ASCII chars) (frame 4, page 17)
//
//    gps_alm[prn].text_message[0]=char((sf2[4][3] & 0x00FF00) >> 8);
    ulong = long( gps_alm[prn].text_message[0]) & 0xFF;  // 8 bits
    sf2[4][3] = sf2[4][3] | (ulong << 8);

//    gps_alm[prn].text_message[1]=char( sf2[4][3] & 0x0000FF);
    ulong = long( gps_alm[prn].text_message[1]) & 0xFF;  // 8 bits
    sf2[4][3] = sf2[4][3] | (ulong);

    for ( k=1; k<=7; k++)
    {
//      gps_alm[prn].text_message[3*k-1] = char(sf2[4][k+3] >> 16);
      ulong = long( gps_alm[prn].text_message[3*k-1]) & 0xFF;  // 8 bits
      sf2[4][k+3] = sf2[4][k+3] | (ulong << 16);
//      gps_alm[prn].text_message[3*k  ] = char((sf2[4][k+3] & 0x00FF00) >>  8);
      ulong = long( gps_alm[prn].text_message[3*k]) & 0xFF;  // 8 bits
      sf2[4][k+3] = sf2[4][k+3] | (ulong << 8);
//      gps_alm[prn].text_message[3*k+1] = char(sf2[4][k+3] & 0x0000FF);
      ulong = long( gps_alm[prn].text_message[3*k+1]) & 0xFF;  // 8 bits
      sf2[4][k+3] = sf2[4][k+3] | (ulong);
    }
  }
  else if ( i4satid == 56)
  {
//
//  ionospheric and UTC data (frame 4, page 18)
//
//          ial0=int((sf2[4][3] & 0x00FF00) >> 8);
//          al0=ial0*9.313225746e-10;
    schar     = char( iono->al0/(9.313225746e-10));  // 8 bits, scale 2^-30
    ulong     = long( schar) & 0xFF;
    sf2[4][3] = sf2[4][3] | (ulong << 8);

//          ial1= int(sf2[4][3] & 0x0000FF);
//          al1=ial1*7.4505806e-9;
    schar     = char( iono->al1/(7.4505806e-9));  // 8 bits, scale 2^-27
    ulong     = long( schar) & 0xFF;
    sf2[4][3] = sf2[4][3] | (ulong);

//          ial2= int(sf2[4][4] >> 16);
//          al2=ial2*5.960464478e-8;
    schar     = char( iono->al2/(5.960464478e-8));  // 8 bits, scale 2^-24
    ulong     = long( schar) & 0xFF;
    sf2[4][4] = sf2[4][4] | (ulong << 16);

//          ial3=int((sf2[4][4] & 0x00FF00) >> 8);
//          al3=ial3*5.960464478e-8;
    schar     = char( iono->al3/(5.960464478e-8));  // 8 bits, scale 2^-24
    ulong     = long( schar) & 0xFF;
    sf2[4][4] = sf2[4][4] | (ulong << 8);

//          ibt0= int(sf2[4][4] & 0x0000FF);
//          b0=ibt0*2048.;
    schar     = char( iono->b0/(2048.));  // 8 bits, scale 2^11
    ulong     = long( schar) & 0xFF;
    sf2[4][4] = sf2[4][4] | (ulong);

//          ibt1= int(sf2[4][5] >> 16);
//          b1=ibt1*16384.;
    schar     = char( iono->b1/(16384.));  // 8 bits, scale 2^14
    ulong     = long( schar) & 0xFF;
    sf2[4][5] = sf2[4][5] | (ulong << 16);

//          ibt2=int((sf2[4][5] & 0x00FF00) >> 8);
//          b2=ibt2*65536.;
    schar     = char( iono->b2/(65536.));  // 8 bits, scale 2^16
    ulong     = long( schar) & 0xFF;
    sf2[4][5] = sf2[4][5] | (ulong << 8);

//          ibt3= int(sf2[4][5] & 0x00FF);
//          b3=ibt3*65536.;
    schar     = char( iono->b3/(65536.));  // 8 bits, scale 2^16
    ulong     = long( schar) & 0xFF;
    sf2[4][5] = sf2[4][5] | (ulong);

//          ia1=   sf2[4][6];
//          if (bit_test_l(ia1,24)) ia1=ia1 | 0xFF000000L;
//          a1=ia1*8.881784197e-16;
    ulong     = long( utc->a1/(8.881784197e-16)) & 0xFFFFFF;  // 24 bits, scale 2^-50
    if ( ulong & (0x1L << (24-1)))  // test bit 24
      ulong = ulong | 0xFF000000L;
    sf2[4][6] = sf2[4][6] | (ulong);

//          ia0=  (sf2[4][7] << 8) | (sf2[4][8] >> 16);
//          a0=ia0*9.31322574615e-10;
    ulong     = long( utc->a0/(9.31322574615e-10));  // 32 bits, scale 2^-30
    sf2[4][7] = sf2[4][7] | ((ulong & 0xFFFFFF00) >> 8);
    sf2[4][8] = sf2[4][8] | ((ulong & 0xFF) << 16);

//          itot=  int((sf2[4][8] & 0x00FF00) >> 8);
//          tot=itot*4096;
    schar     = char( utc->tot/(4096.));  // 8 bits, scale 2^12
    ulong     = long( schar) & 0xFF;
    sf2[4][8] = sf2[4][8] | (ulong << 8);

//          iWNt=  int(sf2[4][8] & 0xFF);
//          WNt=iWNt;
    schar     = char( utc->WNt);  // 8 bits, scale 1
    ulong     = long( schar) & 0xFF;
    sf2[4][8] = sf2[4][8] | (ulong);

//          idtls=  int(sf2[4][9] >> 16);
//          if (idtls > 128) idtls = idtls |0xFF00;
//          dtls=idtls;
    schar     = char( utc->dtls);  // 8 bits, scale 1
    ulong     = long( schar) & 0xFF;
    sf2[4][9] = sf2[4][9] | (ulong);

//          iWNlsf=int((sf2[4][9] & 0x00FF00) >> 8);
//          WNlsf=iWNlsf;
    schar     = char( utc->WNlsf);  // 8 bits, scale 1
    ulong     = long( schar) & 0xFF;
    sf2[4][9] = sf2[4][9] | (ulong << 8);

//          iDN   = int(sf2[4][9] & 0x0000FF);
//          DN=iDN;
    schar     = char( utc->DN);  // 8 bits, scale 1
    ulong     = long( schar) & 0xFF;
    sf2[4][9] = sf2[4][9] | (ulong);

//          idtlsf= int(sf2[4][10] >> 16);
//          if (idtlsf >128) idtlsf=idtlsf |0xFF00;
//          dtlsf=idtlsf;
    schar     = char( utc->dtlsf);  // 8 bits, scale 1
    ulong     = long( schar) & 0xFF;
    sf2[4][9] = sf2[4][9] | (ulong << 16);
  }
  else if ( i4satid == 63 )
  {
//
//  satellite configuration for 32 satellites (frame 4, page 25)
//
//          ASV[1] = int((sf2[4][3] & 0x00F000) >>12);
//          ASV[2]= int((sf2[4][3] & 0x000F00) >>8);
//          ASV[3]= int((sf2[4][3] & 0x0000F0) >>4);
//          ASV[4]= int( sf2[4][3] & 0x00000F);
    for ( k=2; k<6; k++)
    {
      sf2[4][3] = sf2[4][3] | (long( ASV[-1+k]) << (20-(4*k)));
    }

//          ASV[5]= int( sf2[4][4] >> 20);
//          ASV[6]= int((sf2[4][4] & 0x0F0000L) >>16);
//          ASV[7]= int((sf2[4][4] & 0x00F000) >>12);
//          ASV[8]= int((sf2[4][4] & 0x000F00) >> 8);
//          ASV[9]= int((sf2[4][4] & 0x0000F0) >> 4);
//          ASV[10]=int(sf2[4][4] & 0x00000F);
    for ( k=0; k<6; k++)
    {
      sf2[4][4] = sf2[4][4] | (long( ASV[5+k]) << (20-(4*k)));
    }

//          ASV[11]=int(sf2[4][5] >>20);
//          ASV[12]=int((sf2[4][5] & 0x0F0000L) >>16);
//          ASV[13]=int((sf2[4][5] & 0x00F000) >>12);
//          ASV[14]=int((sf2[4][5] & 0x000F00) >> 8);
//          ASV[15]=int((sf2[4][5] & 0x0000F0) >> 4);
//          ASV[16]=int(sf2[4][5] & 0x00000F);
    for ( k=0; k<6; k++)
    {
      sf2[4][5] = sf2[4][5] | (long( ASV[11+k]) << (20-(4*k)));
    }

//          ASV[17]=int(sf2[4][6] >>20);
//          ASV[18]=int((sf2[4][6] & 0x0F0000L) >>16);
//          ASV[19]=int((sf2[4][6] & 0x00F000) >>12);
//          ASV[20]=int((sf2[4][6] & 0x000F00) >> 8);
//          ASV[21]=int((sf2[4][6] & 0x0000F0) >> 4);
//          ASV[22]=int(sf2[4][6] & 0x00000F);
    for ( k=0; k<6; k++)
    {
      sf2[4][6] = sf2[4][6] | (long( ASV[17+k]) << (20-(4*k)));
    }

//          ASV[23]=int(sf2[4][7] >>20);
//          ASV[24]=int((sf2[4][7] & 0x0F0000L) >>16);
//          ASV[25]=int((sf2[4][7] & 0x00F000) >>12);
//          ASV[26]=int((sf2[4][7] & 0x000F00) >> 8);
//          ASV[27]=int((sf2[4][7] & 0x0000F0) >> 4);
//          ASV[28]=int( sf2[4][7] & 0x00000F);
    for ( k=0; k<6; k++)
    {
      sf2[4][7] = sf2[4][7] | (long( ASV[23+k]) << (20-(4*k)));
    }

//          ASV[29]=int( sf2[4][8] >>20);
//          ASV[30]=int((sf2[4][8] & 0x0F0000L) >>16);
//          ASV[31]=int((sf2[4][8] & 0x00F000) >>12);
//          ASV[32]=int((sf2[4][8] & 0x000F00) >> 8);
    for ( k=0; k<4; k++)
    {
      sf2[4][8] = sf2[4][8] | (long( ASV[29+k]) << (20-(4*k)));
    }

//          SVh[25]=int(sf2[4][8] & 0x00003F);
//          if( SVh[25]==0x3f) gps_alm[25].inc=0.0;
    sf2[4][8] = sf2[4][8] | (long( SVh[25]));

//          SVh[26]=int(sf2[4][9] >>18);
//          if( SVh[26]==0x3f) gps_alm[26].inc=0.0;
    sf2[4][9] = sf2[4][9] | (long( SVh[26]) << 18);

//          SVh[27]=int((sf2[4][9] & 0x03F000L) >>12);
//          if( SVh[27]==0x3f) gps_alm[27].inc=0.0;
    sf2[4][9] = sf2[4][9] | (long( SVh[27]) << 12);

//          SVh[28]=int((sf2[4][9] & 0x000FC0) >>6);
//          if( SVh[28]==0x3f) gps_alm[28].inc=0.0;
    sf2[4][9] = sf2[4][9] | (long( SVh[28]) << 6);

//          SVh[29]= int(sf2[4][9] & 0x00003F);
//          if( SVh[29]==0x3f) gps_alm[29].inc=0.0;
    sf2[4][9] = sf2[4][9] | (long( SVh[29]));

//          SVh[30]= int(sf2[4][10] >>18);
//          if( SVh[30]==0x3f) gps_alm[30].inc=0.0;
    sf2[4][10] = sf2[4][10] | (long( SVh[30]) << 18);

//          SVh[31]=int((sf2[4][10]& 0x03F000L) >>12);
//          if( SVh[31]==0x3f) gps_alm[31].inc=0.0;
    sf2[4][10] = sf2[4][10] | (long( SVh[31]) << 12);

//          SVh[32]=int((sf2[4][10]& 0x000FC0) >>6);
//          if( SVh[32]==0x3f) gps_alm[32].inc=0.0;
    sf2[4][10] = sf2[4][10] | (long( SVh[32]) << 6);
  }

//
//    SUBFRAME 5
//

//      i5p = int((sf2[5][3] & 0x3F0000L) >> 16);
//      chan[ch].page5 = i5p;
//      if ( i5satid != i5p)
//      {
//        i5satid=i5p;

  if ( i5satid == 51 )
  {

//
//  satellite health data for sats 1 thru 24, almanac reference time,
//  and almanac reference week number (frame 5, page 25)
//

//       iatoa = int((sf2[5][3] & 0xFF00) >>8);
//       atoa = iatoa*4096;
//          SVh[1] = int(sf2[5][4] >>18);
//          if( SVh[1]==0x3f) gps_alm[1].inc=0.0;
//          SVh[2] = int((sf2[5][4] & 0x03F000L)>>12);
//          if( SVh[2]==0x3f) gps_alm[2].inc=0.0;
//          SVh[3] = int((sf2[5][4] & 0x000FC0)>>6);
//          if( SVh[3]==0x3f) gps_alm[3].inc=0.0;
//          SVh[4] = int(sf2[5][4] & 0x00003F);
//          if( SVh[4]==0x3f) gps_alm[4].inc=0.0;
    for ( k=0; k<4; k++)
    {
      sf2[5][4] = sf2[5][4] | (long( SVh[1+k]) << (18-(6*k)));
    }

//          SVh[5] = int(sf2[5][5] >>18);
//          if( SVh[5]==0x3f) gps_alm[5].inc=0.0;
//          SVh[6] = int((sf2[5][5] & 0x03F000L)>>12);
//          if( SVh[6]==0x3f) gps_alm[6].inc=0.0;
//          SVh[7] = int((sf2[5][5] & 0x000FC0)>>6);
//          if( SVh[7]==0x3f) gps_alm[7].inc=0.0;
//          SVh[8] = int(sf2[5][5] & 0x00003F);
//          if( SVh[8]==0x3f) gps_alm[8].inc=0.0;
    for ( k=0; k<4; k++)
    {
      sf2[5][5] = sf2[5][5] | (long( SVh[5+k]) << (18-(6*k)));
    }
//          SVh[9] = int(sf2[5][6] >> 18);
//          if( SVh[9]==0x3f) gps_alm[9].inc=0.0;
//          SVh[10] = int((sf2[5][6] & 0x03F000L)>>12);
//          if( SVh[10]==0x3f) gps_alm[10].inc=0.0;
//          SVh[11] = int((sf2[5][6] & 0x000FC0)>>6);
//          if( SVh[11]==0x3f) gps_alm[11].inc=0.0;
//          SVh[12] = int(sf2[5][6] & 0x00003F);
//          if( SVh[12]==0x3f) gps_alm[12].inc=0.0;
    for ( k=0; k<4; k++)
    {
      sf2[5][6] = sf2[5][6] | (long( SVh[9+k]) << (18-(6*k)));
    }
//          SVh[13] = int(sf2[5][7] >>18);
//          if( SVh[13]==0x3f) gps_alm[13].inc=0.0;
//          SVh[14] = int((sf2[5][7] & 0x03F000L)>>12);
//          if( SVh[14]==0x3f) gps_alm[14].inc=0.0;
//          SVh[15] = int((sf2[5][7] & 0x000FC0)>>6);
//          if( SVh[15]==0x3f) gps_alm[15].inc=0.0;
//          SVh[16] = int(sf2[5][7] & 0x00003F);
//          if( SVh[16]==0x3f) gps_alm[16].inc=0.0;
    for ( k=0; k<4; k++)
    {
      sf2[5][7] = sf2[5][7] | (long( SVh[13+k]) << (18-(6*k)));
    }
//          SVh[17] = int(sf2[5][8] >>18);
//          if( SVh[17]==0x3f) gps_alm[17].inc=0.0;
//          SVh[18] = int((sf2[5][8] & 0x03F000L)>>12);
//          if( SVh[18]==0x3f) gps_alm[18].inc=0.0;
//          SVh[19] = int((sf2[5][8] & 0x000FC0)>>6);
//          if( SVh[19]==0x3f) gps_alm[19].inc=0.0;
//          SVh[20] = int(sf2[5][8] & 0x00003F);
//          if( SVh[20]==0x3f) gps_alm[20].inc=0.0;
    for ( k=0; k<4; k++)
    {
      sf2[5][8] = sf2[5][8] | (long( SVh[17+k]) << (18-(6*k)));
    }
//          SVh[21] = int(sf2[5][9] >>18);
//          if( SVh[21]==0x3f) gps_alm[21].inc=0.0;
//          SVh[22] = int((sf2[5][9] & 0x03F000L)>>12);
//          if( SVh[22]==0x3f) gps_alm[22].inc=0.0;
//          SVh[23] = int((sf2[5][9] & 0x000FC0)>>6);
//          if( SVh[23]==0x3f) gps_alm[23].inc=0.0;
//          SVh[24] = int(sf2[5][9] & 0x00003F);
//          if( SVh[24]==0x3f) gps_alm[24].inc=0.0;
    for ( k=0; k<4; k++)
    {
      sf2[5][9] = sf2[5][9] | (long( SVh[21+k]) << (18-(6*k)));
    }
  }
  else
  {
//
//  almanac data for satellite 1 thru 24 (frame 5, pages 1-24)
//
    isv = i5satid;

//          gps_alm[isv].week=gps_week;
//          iae=int(sf2[5][3] & 0xFFFF);
//          gps_alm[isv].ety=iae*4.768371582E-7;
//          iatoa=int(sf2[5][4] >> 16);
//          gps_alm[isv].toa=iatoa*4096.0;
//          iadeli=int(sf2[5][4] & 0xFFFF);
//          gps_alm[isv].inc=(iadeli*1.907348633E-6+0.3)*pi;
//          iaomegad=int(sf2[5][5] >> 8);
//          gps_alm[isv].rra=iaomegad*3.637978807E-12*pi;
//          gps_alm[isv].health=int(sf2[5][5] & 0xFF);
//          iasqr=sf2[5][6];
//          gps_alm[isv].sqa=iasqr*4.8828125E-4;
//          if (gps_alm[isv].sqa>0.0) gps_alm[isv].w=19964981.84/pow(gps_alm[isv].sqa,3);
//          iaomega0=sf2[5][7];
//          if (bit_test_l(iaomega0,24)) iaomega0=iaomega0 | 0xFF000000L;
//          gps_alm[isv].lan=iaomega0*1.192092896E-7*pi;
//          iaw=sf2[5][8];
//          if (bit_test_l(iaw,24)) iaw=iaw | 0xFF000000L;
//          gps_alm[isv].aop=iaw*1.192092896E-7*pi;
//          iam0=sf2[5][9];
//          if (bit_test_l(iam0,24)) iam0=iam0 | 0xFF000000L;
//          gps_alm[isv].ma=iam0*1.192092896E-7*pi;
//          iaaf0=int((sf2[5][10] >> 13) | (sf2[5][10] & 0x1C));
//          if (bit_test_l(iaaf0,11)) iaaf0=iaaf0 | 0xF800;
//          gps_alm[isv].af0=iaaf0*9.536743164E-7;
//          iaaf1=int((sf2[5][10] & 0xFFE0) >> 5);
//          if (bit_test_l(iaaf1,11)) 
//            iaaf1=iaaf1 | 0xF800;
//          gps_alm[isv].af1=iaaf1*3.637978807E-12;

//
//  copied from subframe4, pages 1-24
//
    ssint     = int( gps_alm[isv].ety/(4.768371582E-7));  // 16 bits, scale 2^-21
    ulong     = long( ssint) & 0xFFFF;
    sf2[5][3] = sf2[5][3] | (ulong);

    schar     = char( gps_alm[isv].toa/4096.0);  // 8 bits, scale 2^12
    ulong     = long( schar) & 0xFF;
    sf2[5][4] = sf2[5][4] | (ulong << 16);

    ssint     = int( (gps_alm[isv].inc/pi-0.3)/1.907348633E-6);  // 16 bits, scale 2^-19
    ulong     = long( ssint) & 0xFFFF;
    sf2[5][4] = sf2[5][4] | (ulong);

    ssint     = int( gps_alm[isv].rra/(3.637978807E-12*pi));  // 16 bits, scale 2^-38
    ulong     = long( ssint) & 0xFFFF;
    sf2[5][5] = sf2[5][5] | (ulong << 8);

    ulong     = long( gps_alm[isv].health) & 0xFF;
    sf2[5][5] = sf2[5][5] | (ulong);

    ssint     = int( gps_alm[isv].sqa/(4.8828125E-4));  // 16 bits, scale 2^-11
    ulong     = long( ssint) & 0xFFFF;
    sf2[5][6] = sf2[5][6] | (ulong);

    ulong     = long( gps_alm[isv].lan/(1.192092896E-7*pi)) & 0xFFFFFF;  // 24 bits, scale 2^-23, rad
    if ( ulong & (0x1L << (24-1)))  // test bit 24
      ulong = ulong | 0xFF000000L;
    sf2[5][7] = sf2[5][7] | (ulong);

    ulong     = long( gps_alm[isv].aop/(1.192092896E-7*pi)) & 0xFFFFFF;  // 24 bits, scale 2^-23, rad
    if ( ulong & (0x1L << (24-1)))  // test bit 24
      ulong = ulong | 0xFF000000L;
    sf2[5][8] = sf2[5][8] | (ulong);

    ulong     = long( gps_alm[isv].ma/(1.192092896E-7*pi)) & 0xFFFFFF;  // 24 bits, scale 2^-23, rad
    if ( ulong & (0x1L << (24-1)))  // test bit 24
      ulong = ulong | 0xFF000000L;
    sf2[5][9] = sf2[5][9] | (ulong);

    ulong     = long( gps_alm[isv].af0/(9.536743164E-7)) & 0x7FF;  // 11 bits, scale 2^-20
    if ( ulong & (0x1L << (11-1)))  // test bit 11
      ulong = ulong | 0xFFFFF800L;
    sf2[5][10] = sf2[5][10] | ((ulong & 0x7) << 2);
    sf2[5][10] = sf2[5][10] | ((ulong & 0x7F8) << 13);

    ulong     = long( gps_alm[isv].af1/(3.637978807E-12)) & 0x7FF;  // 11 bits, scale 2^-38
    if ( ulong & (0x1L << (11-1)))  // test bit 11
      ulong = ulong | 0xFFFFF800L;
    sf2[5][10] = sf2[5][10] | (ulong << 5);
  }

//
//  add to each 24 bit word 6 parity bits
//
  add_parity_bits();

//
//  5 subframe a 300 bits; 10 words a 30 bits
// 

//  copy from sf2[][] to chan[ch].message[1500] buffer
  unsigned long scale;

  j=0;
  for ( sfr=1; sfr<=5; sfr++)
  {
    for ( word=1; word<=10; word++)
    {
//      scale = 536870912L;                // 536870912L = 2^29
      scale = 0x1L << 29;
//      sf2[sfr][word] = 0;
      for ( k=0; k<=29; k++)
      {
//        if ( chan[ch].message[(j+chan[ch].offset)%1500] == 1)
//          sf2[sfr][word] += scale;
        if ( sf2[sfr][word] & scale)
          chan[ch].message[(j+chan[ch].offset)%1500] = 1;
        else 
          chan[ch].message[(j+chan[ch].offset)%1500] = -1;
        scale = scale >> 1;
        j++;
      }
    }
  } // --- for ( sfr=1; sfr<=5; sfr++) ---

  return;
}


//
//  add 6 parity bits to sf2[][]
//
//  based on gpsrcvr.cpp/parity_check()
//  Clifford Kelley cwkelley@earthlink.net
//  Copyright (c) 1996-2001 Clifford Kelley
//
void add_parity_bits( void)
{
  unsigned long x;
  int  parity;
  char d29=1, d30=1, // assume that last 2 bits from last frame are one
       sfm, word, 
       b1, b2, b3, b4, b5, b6;
  long mask1 = 0xEC7CD2L, 
       mask2 = 0x763E69L, 
       mask3 = 0xBB1F34L,
       mask4 = 0x5D8F9AL, 
       mask5 = 0xAEC7CDL, 
       mask6 = 0x2DEA27L;

  for ( sfm = 1; sfm <= 5; sfm++)
  {
    for ( word=1; word<=10; word++)
    {
      x   = (sf2[sfm][word] & mask1) | (d29 << 31);  // bit 31 of sf2[][] is unused
      b1 = exor_long( x) << 5;
      x   = (sf2[sfm][word] & mask2) | (d30 << 31);  // bit 31 of sf2[][] is unused
      b2 = exor_long( x) << 4;
      x   = (sf2[sfm][word] & mask3) | (d29 << 31);  // bit 31 of sf2[][] is unused
      b3 = exor_long( x) << 3;
      x   = (sf2[sfm][word] & mask4) | (d30 << 31);  // bit 31 of sf2[][] is unused
      b4 = exor_long( x) << 2;
      x   = (sf2[sfm][word] & mask5) | (d30 << 31);  // bit 31 of sf2[][] is unused
      b5 = exor_long( x) << 1;
      x   = (sf2[sfm][word] & mask6) | (d29 << 31);  // bit 31 of sf2[][] is unused
      b6 = exor_long( x);

      parity = b1 + b2 + b3 + b4 + b5 + b6;

      if ( d30 == 1) 
        sf2[sfm][word] = ~sf2[sfm][word] & 0x03fffffc0L;

//  add 6 parity bits
      sf2[sfm][word] = (sf2[sfm][word] << 6) | (parity & 0x3F);

// update d29/d30 bits
      d29 = (parity & 0x2) >> 1;
      d30 = parity & 0x1;
    }
  }
}

//
//  xor all 32 bits in a long variable (b31^b30^b29^...^b2^b1^b0)
//
static int exor_long( unsigned long x)
{
  char i;
  int res = 0;

  for ( i=0; i<32; i++)
  {
    res = res ^ (x & 0x1);
    x = x >> 1;
  }
  return res;
}

inline double frem( double x, double y)
{
  double res;

  if ( x >= 0.0)
    res = fmod( x, y);
  else
    res = -fmod( -x, y);    
  return res;
}

#endif



/*******************************************************************************
FUNCTION bit_test_long()
RETURNS  int

PARAMETERS
    Data
    bit_n

PURPOSE
  This function returns a 1 if bit number bit_n of long Data is set
  else it returns a 0
  NOTE: bit_n = 1,...,32

WRITTEN BY
  Clifford Kelley

*******************************************************************************/

int bit_test_long( unsigned long data, int bit_n)
{
  return ( data & (0x1L << (bit_n-1)));
}

/*******************************************************************************
FUNCTION parity_exor_7to30( int bit, long parity)
RETURNS  
  GPS parity

PARAMETERS 
  parity : long word to be processed

PURPOSE
  xor bits 7 to 30 in nav msg word
  and xor result with parameter 'bit'
  
WRITTEN BY
  Clifford Kelley

*******************************************************************************/
int parity_exor_7to30( int bit, long parity)
{
  int i;
  int res = 0;

  for ( i=7; i<=30; i++)
  {
    if ( bit_test_long( parity, i)) 
      res++;
  }
//  res = res % 2;
  res = (bit^res) & 0x1;

  return (res);
}

//
//  controlled malloc()
//
char *conmalloc( size_t len)
{
  char *ptr;
  
  ptr = (char*) malloc( len);
  if ( !ptr)
  {
    printf( "malloc() failed!\n");
    exit(-1);
  }

  return (ptr);
}

#define DIRBUFLEN 512

//
//  extract position of 'bin' and 'data' dir and write to global variable
//
void set_directories( char *ptr)
{
  char *ptr2, *ptr3;

#ifdef unix
//  if relative pathname we need to add current working dir
  if ( ptr[0] != '/')
  {
    char workdir[DIRBUFLEN];
    ptr2 = getcwd( workdir, DIRBUFLEN);
    if ( !ptr2 || strlen( workdir)+strlen( ptr) > DIRBUFLEN-1)
    {
      printf( "Increase dir buffer size!\n");
      exit(-1);
    }
    strcat( workdir, "/");
    strcat( workdir, ptr);
    ptr = workdir;
  }
#endif

//  printf(">%s<\n", ptr);
//  getchar();

  OGSBinDir  = (char*) conmalloc( strlen( ptr) + 1);
  OGSDataDir = (char*) conmalloc( strlen( ptr) + 1);

  strcpy( OGSBinDir, ptr);

//  printf("%s\n", OGSBinDir);

#ifdef __TURBOC__
  ptr2 = OGSBinDir;
  while ( *ptr2)
  {
    if (*ptr2 == '\\')
      *ptr2 = '/';
    ptr2++;  
  }
#endif

//  printf( "%s\n", OGSBinDir);

  ptr2 = strrchr( OGSBinDir, '/');
  if ( !ptr2)
  {
    printf( "invalid OGS directory structure! (%s)\n", OGSBinDir);
    exit(-1);
  }
  *ptr2 = '\0';

  strcpy( OGSDataDir, OGSBinDir);

  ptr2 = strrchr( OGSDataDir, '/');
  if ( !ptr2)
  {
    printf( "invalid OGS directory structure! (%s)\n", OGSBinDir);
    exit(-1);
  }
  *ptr2 = '\0';

  strcat( OGSBinDir, "/");
  strcat( OGSDataDir, "/data/");

//  printf("%s\n", OGSBinDir);
//  printf("%s\n", OGSDataDir);
//  getchar();

  return;
}



#ifndef __TURBOC__

void clrscr( void)
{
  printf( "\x1B[2J\x1B[0d\x1B[0G");
  return;
}

void gotoxy( int x, int y)
{
  printf( "\x1B[%dd \x1B[%dG", y, x);
  return;
}

//  don't know how to do these...
#ifdef linux

//
// from kbhit.c, WROX book "Beginning LINUX Programming" (www.wrox.com)
//
#include 
#include 
#include 
#include 

static struct termios   initial_settings, 
                        new_settings;
static int              peek_character = -1;

void init_keyboard( void)
{
  tcgetattr( 0, &initial_settings);
  new_settings = initial_settings;
  new_settings.c_lflag &= ~ICANON;
  new_settings.c_lflag &= ~ECHO;
  new_settings.c_lflag &= ~ISIG;
  new_settings.c_cc[VMIN] = 1;
  new_settings.c_cc[VTIME] = 0;
  tcsetattr( 0, TCSANOW, &new_settings);
}

void close_keyboard( void)
{
  tcsetattr(0, TCSANOW, &initial_settings);
}

int kbhit( void)
{
  char ch;
  int nread;

  if ( peek_character != -1)
    return 1;
  new_settings.c_cc[VMIN]=0;
  tcsetattr( 0, TCSANOW, &new_settings);
  nread = read(0,&ch,1);
  new_settings.c_cc[VMIN]=1;
  tcsetattr( 0, TCSANOW, &new_settings);

  if ( nread == 1) 
  {
    peek_character = ch;
    return 1;
  }
  return 0;
}

int readch( void)
{
  char ch;

  if ( peek_character != -1) 
  {
    ch = peek_character;
    peek_character = -1;
    return ch;
  }
  read( 0, &ch, 1);
  return ch;
}

#else
// not linux

int kbhit( void)
{
  return 0;
}

char getch( void)
{
  return '0';
}

#endif

#endif

/* ------------------------------ end of file ----------------------------- */