/********************************************************************
//  tcm2.c  : Nov 2008
//  control of tcm2 compass
//  for the Spray 2008 CF2 controller board
//
//==== Future Expansion =======================================================
//		last update: Jan2009
//
//	1.
//
//******************************************************************/

#include	<cfxbios.h>		// Persistor BIOS and I/O Definitions
#include	<cfxpico.h>		// Persistor PicoDOS Definitions

#include	<assert.h>
#include	<ctype.h>
#include	<errno.h>
#include	<float.h>
#include	<limits.h>
#include	<locale.h>
#include	<math.h>
#include	<setjmp.h>
#include	<signal.h>
#include	<stdarg.h>
#include	<stddef.h>
#include	<stdio.h>
#include	<stdlib.h>
#include	<string.h>
#include	<time.h>

#include    "cf2_qsm332.h"
#include    "spi_cmd.h"
#include    "tcm2.h"
#include    "pitch_roll.h"
#include    "gpio_mux.h"
#include    "setup.h"

// globals
extern char   Verbose;  // switch for displaying more info
extern char   IRQ_Flag; // interrupt flag: says what caused the interrupt
extern short  iparam [ MAX_PARAM ]; // global parameter settings
extern struct all_param all;



float gmx, gmy, gmz, ghh; // global values from tcm2: used in get_tcm2 & cal
//=============================================================================


short  tcm2_on(  void ) //*****************************************************
{  // power up the tcm2 compass
   short ierr = 0;
   struct spi_param *ss;
   
      ss = all.sspi; // points to the spi comms struct
      ss->pcs = CS_GPIO;   // command is for the GPIO chip
      init_qsm( CS_GPIO ); 
      init_spi();

  ierr = spi_aux_pwr( AUX_ON_COMP, ss ); // compass now has power
  
  ierr = spi_mux( 1, SER_COMPASS, ss ); // turn on rs232 & configure mux
  
  return ( ierr );
} //***************************************************************************

short  tcm2_off( void ) //*****************************************************
{  // power up the tcm2 compass
   short ierr = 0;
   struct spi_param *ss;
   char sleep[] = "sleep";
   TUPort    *tup;
   
      ss = all.sspi; // points to the spi comms struct
      ss->pcs = CS_GPIO;   // command is for the GPIO chip
      init_qsm( CS_GPIO ); 
      init_spi();

    tup = all.tu_port[TU_COMP].tup;  // correct tpu uart port pointer
    tputs( tup, sleep);  // send the sleep command
    DelayMilliSecs(100);  //** wait to go to sleep
    
    ierr = spi_aux_pwr( -AUX_ON_COMP, ss );
    DelayMilliSecs(10);  //** wait 
  
    ierr = spi_mux( 0, SER_COMPASS, ss ); // turn off rs232 

  return ( ierr );
} //***************************************************************************


//*****************************************************************************
short send_tcm2( TUPort *tup, char str[], char sget[]) 
{ // send str to compass & get the reply
  // returns the # of bytes actually read
   short nget, found;  // = num char read
   
   TURxFlush(tup);   //  flush the tpu port
   tputs       ( tup, str);  //* send string
   nget = tgets( tup, sget, 80, 1, '\n', &found); //* read up to 80 char
   
   return ( nget );
} //***************************************************************************


// ****************************************************************************
short get_tcm2(  short on_off )
{ // gets the latest [heading,pitch,roll] scan
  // will cycle the power on/off if on_off = true
  
  // returns 0=no error
  //         1=scanf error
  //         2=no reply
  
  short n, ierr=0, nval, i, j; 
  char sget[80];  // = reply
  struct spi_param *ss;
  struct compass_param *comp;
  float mx, my, mz, pp, rr;
  float cp, sp, cr, sr, xx, yy, h;
  TUPort    *tup;

      ss = all.sspi; // points to the spi comms struct
      ss->pcs = CS_GPIO;   // command is for the GPIO chip
      init_qsm( CS_GPIO ); 
      init_spi();

  tup = all.tu_port[TU_COMP].tup;  // correct tpu uart port pointer

  comp = all.comp;  // point to the subset
  sget[0] = 0; // set to null length
  
  if (on_off)
  { // we are cycling the power
      tcm2_on(  );    // turn on the compass
      DelayMilliSecs( 800 ); // wait 0.8 s
  }
  else
  { // still should set up the MUX no matter what AUG13
      spi_mux( 1, SER_COMPASS, ss ); // turn on rs232 & configure mux
  }
  
  n = send_tcm2(tup, "s?", sget); // n = # of char read
  if (on_off) tcm2_off(  ); // turn off compass
  
  if (n) // true if got a reply -------------------------
  {   j=0;
      while ( (j<n) && (sget[j] != 'E') )
            j++; // look for an 'E'...marks an error flag
      sget[j] = '\0';  // =end of string to read in
      // if above isn't done, sscanf parses the E as an exponent value
            
      //oct06, updated for reading in magnetometers
      nval = sscanf(sget,"$C%fP%fR%fX%fY%fZ%f",&ghh,&pp,&rr,
             &gmx, &gmy, &gmz );
      //printf("ghh = %5.1f %s\n", ghh, sget);

      if (nval != 6) 
      { ierr = 1;  // error=1 = sscanf problem
        cprintf("tcm2 scanf err on str %s\n",sget);
      }
  } // end if n ------------------------------------------
  else ierr = 2;  // set flag that nothing was read in
  
  comp->err = ierr; // save the error code: 0=values below are valid
  if (ierr>0  ) // then an error
  {  // set output to default values
     comp->head = 359;
     comp->pitch =  0;
     comp->roll  =  0;
     all.exc->serr[4] &= ierr; //set err flag that gets sent back
     return(ierr);
  } // end if error 
  // else, OK, now process
  
  
  // For Spray mounting config, both pitch & roll need opposite signs
   pp   = -pp;
   rr   = -rr;

  if ( iparam [ IA_use_moff ]>0  )  //----------------------------------
  { // then we want to use our own calibration offsets
     
     // pp = pitch angle: angle btwn tcm2 long axis & horizon
     cp   = cos_find( pp ); // cos(pitch)
     sp   = sin_find( pp ); // sin(pitch)
  
     // rr = roll angle for sequential rotation
     sr   = sin_find( rr ); // sin(roll)
     cr   = cos_find( rr );
  
     // compute the magnetometer components in the x-y plane  
     // note TCM2 defines My = Left-hand rule
     // remove the offsets before correcting
     mx = gmx;
     my =-gmy;
     mz = gmz;
     
     my = -(gmy + iparam [ IA_moff_y ]*0.1);
     mz =   gmz + iparam [ IA_moff_z ]*0.1;
     mx =   gmx + iparam [ IA_moff_x ]*0.1;
     
     xx = cp*mx   - sp*sr *my - cr*sp *mz;
     yy =           cr    *my - sr    *mz; // just effected by the roll
  
     h = atan_find(yy,xx); // returns +/-180 range
     if (h<0) h += 360;
     // with any sort of luck, h now agrees with compass reading hh
     // printf("tcm2 h=%6.1f, derived = %6.1f \n",hh, h);
     // testing shows the above returns the right answers
  }  // end if ee_use_moff==1 -----------------------------------------
  else // we're just using the tcm2 compass value
  {  h = ghh; } // set h = tcm2 value
    
  // for clearance reasons, the tcm2 is mounted 180 out..
  h += 180; // add 180
  if (h>360) h -=360;
  
  if ( iparam [ IA_use_moff ]==2  )  //================================
  { // then apply the correction table
    if (comp->dh>0) //-----------------------------------------
    { // legal dh value, keep going
      i = h/ comp->dh; // input index
      if ( i>=0 && i< comp->num ) //iiiiiiiiiiiii
      { // then it is a legal index
         j = 1; //pitch angle index: 1=level
         if      ( pp < -5 ) j=0; // pitch down
         else if ( pp >  5 ) j=2; // pitch up
         xx = comp->hcal[i][j] *0.1; // correction value
         h +=xx; // apply the correction
         h = limit360( h ); // keep 0<x<360
      } // end if i is legal iiiiiiiiiiiiiiiiiiii
    } //-------------------------------------------------------
    
  } //=================================================================
  
  //  save values: error is already saved
  comp->head  = h;
  comp->pitch = pp;
  comp->roll  = rr;
   
  return ( ierr );
} 
// ****************************************************************************

void get_compass( void ) //****************************************************
{ // get the compass heading, pitch, and roll & display
  short ierr;
  struct compass_param *comp;
  
  comp = all.comp;

  ierr = get_tcm2( 1 );
  printf(" compass = %6.1f , roll = %5.1f ,"
         " pitch = %5.1f error =%d\n",
           comp->head, comp->roll, comp->pitch, comp->err );
  if (ierr) cprintf(" TCM2 error = %d \n",ierr);
  
  return;
} //***************************************************************************


float avg_tcm2(  short n, short type)  //**************************************
{ // take n samples of TCM2 sensor, and return the average
  // sensor is dependent upon type = ANG_ROLL, ANG_PITCH, ANG_HEAD
  float avg, x=0;
  short i, j, ierr;
  
  j=0; avg=0; // zero out averaging params
  if (n>10) n=10; // keep to reasonable number
  
  for (i=0;i<n;i++)  // do n times
  { 
    ierr = get_tcm2( 1 );
    if (ierr==0) // then no error
    { // average value
      j++; 
      switch(type) { //---------------------------
         case ANG_ROLL   : x = all.comp->roll;  break;
         case ANG_PITCH  : x = all.comp->pitch; break;
         case ANG_HEAD   : x = all.comp->head;  break;
         default : x=0; break; // not specified, return 0
      } // end type ------------------------------
      avg += x;
    }
    DelayMilliSecs(500); // wait 0.5 s
  }
  
  if (j>0) avg /= j;  // compute average value
  printf("Avg tcm%1d = %6.1f\n",type, avg);
  
  return(avg);
} //***************************************************************************

void  config_tcm2 ( void ) //**************************************************
{ // configure the compass
  short n; 
  char ch=' ',sget[80];  // = reply
  TUPort    *tup;

  tup = all.tu_port[TU_COMP].tup;  // correct tpu uart port pointer

  sget[0]=' ';
  tcm2_on(  );  // turn on compass
  DelayMilliSecs( 800 ); // wait 0.8 s

  // enable magnetometer output
  n = send_tcm2( tup, "em=e", sget); //enable
 
  n = send_tcm2( tup, "save", sget); //save the setting
  // save is needed for <2.5 versions, and ignored by newer versions

  return;
} //***************************************************************************

void lastcal_tcm2( void ) //***************************************************
{ // get the last calibration #'s
  short n; 
  char ch=' ',sget[80];  // = reply
  TUPort    *tup;

  tup = all.tu_port[TU_COMP].tup;  // correct tpu uart port pointer

  sget[0]=' ';
  tcm2_on(  );  // turn on compass
  DelayMilliSecs( 800 ); // wait 0.8 s

  // get the last calibration values
  n = send_tcm2( tup, "lc?", sget); //get the last calibration values
  if (n>0) cprintf("Last Cal Values = %s\n",sget);
  else { cprintf("TCM2 is not responding\n");}
 
   tcm2_off(  ); // turn off compass

  return;
} //***************************************************************************


short calibrate_tcm2( void ) //************************************************
{ // calibrate the compass
  // return 1=error, 0=OK
  short n, found, j, nval, cksum, cc; 
  char ch=' ',sget[80];  // = reply
  float pp, rr;
  TUPort    *tup;

  tup = all.tu_port[TU_COMP].tup;  // correct tpu uart port pointer

  sget[0]=' ';
  tcm2_on(  );  // turn on compass
  DelayMilliSecs( 800 ); // wait 0.8 s

  // get the last calibration values
  n = send_tcm2( tup, "lc?", sget); //get the last calibration values
  if (n>0) cprintf("Last Cal Values = %s\n",sget);
  else return(1);
 
  // clear the calibration
  n = send_tcm2( tup, "cc", sget); 
  if (n>0) cprintf("Cleared Cal Values = %s\n",sget);
  else return(1);

  // enable multi-point calibration
  n = send_tcm2( tup, "mpcal=e", sget); 
  if (n>0) cprintf("mpcal=e = %s\n",sget);

  // enable multi-point calibration
  n = send_tcm2( tup, "go", sget); 
  if (n>0) cprintf("go = %s\n",sget);
  cprintf("Do the multi-rotation Now\n"
         "When finished, plug back in and type 'H'\n");
  
  SerInFlush();
  do //==============================================================
  {  // look for response from TCM2
     n = tgets( tup, sget, 60,1, '\n', &found); //* read up to 80 char
     // 10jun09, do further error-checking for correct string
     if (n>10 && sget[0] =='$') // possibly good reply ------
     {   j=1; cc = 0;
         while ( (j<n) && ( sget[j] != 'E' ) 
                       && ( sget[j] != '*' )
                       && ( sget[j] != '$' ) ) //$=start new line
         { // compute the checksum
            cc ^= sget[j]; // XOR checksum
            j++; // point to the next char
         }
         
         if ( sget[j] == '*' ) //,,,,,,,,,,,,,,,,,,,,,,
         { // then found the checksum marker (not an error),
           j +=3; // the next 2 char are the checksum
           sget[j] = '\0';  // only read in to here
           cc = cc & 0xff; // keep lsb
           
           //try to read in the params
           nval = sscanf(sget,"$C%fP%fR%fX%fY%fZ%f*%x",&ghh,&pp,&rr,
                &gmx, &gmy, &gmz, &cksum );
           if (nval == 7   && cksum == cc ) 
           { // everything read in correctly, display!
             cprintf("%s\n",sget );
           }
           // else, bad string, don't display...
         } //,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
     } // end if n ------------------------------------------

     ch = SCIRxGetCharWithTimeout( 80 ); // get a character

  }
  while ( ch != 'H'  && ch != 'h' ); //==============================

  // stop the calibration
  n = send_tcm2( tup, "h", sget); //halt the calibration

  // enable multi-point calibration
  n = send_tcm2( tup, "mpcal=d", sget); 
  if (n>0) cprintf("mpcal=d = %s\n",sget);

  // get the last calibration values
  n = send_tcm2( tup, "lc?", sget); //get the last calibration values
  if (n>0) cprintf("New Cal Values = %s\n",sget);
  else return(1);
 
  return(0);
} //***************************************************************************

void tcm2_user_cal( void  ) //*************************************************
{  // spit out values for user calibration

   short ierr, i=0;
   float ht, h, r, p;
   char ch= ' ';

    config_tcm2(  );
    tcm2_on(  );
    cprintf("Record the following #s to file, spin compass\n"
          "Type 'Q' to exit.\n");
    cprintf(" : H(tcm2), Pitch, Roll, MX, MY, MZ H(user) dH \n");
  
  SerInFlush();  // flush any characters
  
  do //==================================================================
  {  // do until reach limit or a character detected
     ierr = get_tcm2( 0);
     
     if ( ierr==0)
     {  // print out the values
        p = all.comp->pitch;
        r = all.comp->roll;
        h = all.comp->head;
        
        ht = ghh -180; // ghh=tcm2 compass, uncorrected for orientation
        if (ht<0) ht=ht+360;
        
        printf(" %5.1f %5.1f %5.1f   %5.1f %5.1f %5.1f  %5.1f  %5.1f\n",
        ht, p, r, gmx, gmy, gmz, h, h-ht );
     }

     ch = SCIRxGetCharWithTimeout(200 ); // get a character
     ch = ch_l2u( ch );
     //if (ch>' ' && ch<'}') cprintf("%c",ch);
     
     //printf("\n");
  } while (i++<1000 && ch != 'Q'); //====================================
  
  tcm2_off(  );
  
  cprintf("Get cals from PC program & manually download to eeprom\n");
  
  return;
} //***************************************************************************

    
short  read_hcal ( void ) //***************************************************
{ // read the compass correction table from the file hcalXXXX.txt
  
  // returns error ( 0=no error )
  // if an error occurred, it sets the table to all zeros.
  short err = 0, i, j;
  short sn;
  FILE *fp;
  char name[20];
  struct compass_param *comp;
  
  comp = all.comp;
  
      sn = (short) VEEFetchLong( "SERNO", NO_VEE_VAL );
      
      if (sn == NO_VEE_VAL) //------------------------------------
      { // then NOT found !!
          sn = 999; // set to default
          cprintf("Illegal s/n, setting to default = %d", sn);
      } //-------------------------------------------------------
  
  // compose the config name ------------------------------------
  { sprintf(name,"hcal%04d.txt",sn); }
  
  //--- open the file -------------------------------------------
  fp = fopen(name, "r"); // read
  if (fp) //-----------------------------------------------------
  { // then it is valid, we can read in
    err = rd_hcal( fp  ); // read in all lines
  }
  else 
  {
    cprintf("File %s could not be opened \n",name);
    err=1; // open err
  }
  
  fclose( fp );
  
  if (err) //====================================================
  { // set the hcal to all zeros
    cprintf("ERROR reading HCAL file = %d\n", err);
    for (i=0; i<MAX_HCAL; i++ )
    {  for (j=0;j<3; j++)  comp->hcal[i][j] = 0;
    }
  } //===========================================================
   
  return ( err );
} //***************************************************************************
    
short  rd_hcal ( FILE *fp  ) //************************************************
{ // read in from file until no more lines

  // returns 0 if OK, else error status
  // err=1 = too many points in file to fit into hcal[]
  // err=2 = columns are out of order
  // err=3 = dh*n !=360: wrong number entries or wrong spacing
  // err=4 = duplicate 'C' lines
  // err=5 = illegal 'C' line
  // err=6 = 'c' line with no 'C' line yet
  // err=7 = first heading entry was not 0.
  // err=8 = too many rows
  // err=9 = bad dh between rows
  
  short err = 0, n, num, Cfound = 0, i=0;
  short nrow, dh=0, pi1, pi2, pi3;
  short h=0, hlast=0, diff;
  float e1, e2, e3;
  char str[80];
  struct compass_param *comp;
  
  comp = all.comp;
  
  do //====================================================================
  {  // read until EOF
    n = fget_line( fp, str, 80 ); // read up to 80 char
    
    if (n>6 && str[0] == 'C' ) //++++++++++++++++++++++++++++++++
    { // then this is the parameter line
      
      if (Cfound) return (4); // 2nd time a C was found
      Cfound = TRUE;
      
      num = sscanf(str,"C%d %d %d %d %d",&nrow, &dh, &pi1, &pi2, &pi3 );
      
      if (num==5) //5555555555555555555555555555555555555
      { // then read in correct # of arguments
        if ( nrow>MAX_HCAL ) return( 1 ); // too many entries!
        if ( pi1>=0 || pi3<= 0 ) return ( 2 ); //not correct order
        if ( dh*nrow !=360 ) return ( 3 ); // dh doesn't match n
        hlast = -dh; // initialize so first diff should = dh
        comp->dh = dh; //save the dh between the rows.
        comp->num= nrow; // save #rows
      }  
      else return(5); //555555555555555555555555555555555
      
    } //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    
    if (n>6 && str[0] == 'c' ) //++++++++++++++++++++++++++++++++
    { // then data line
      if (!Cfound) return(6); // data before parameter line!
      
      num = sscanf(str,"c%d %f %f %f", &h, &e1, &e2, &e3 );
      if (num==4) //4444444444444444444444444444444444444
      { // then right #arguments
        if (i==0 && h !=0 ) return(7);
        if (i>=nrow ) return(8); // too many rows!
        diff = h - hlast;
        if (diff != dh) return(9); // row spacing is wrong!
        // else OK...save the values
          comp->hcal[i][0] = ( short) (e1*10);  // keep to deci-degrees
          comp->hcal[i][1] = ( short) (e2*10);
          comp->hcal[i][2] = ( short) (e3*10);
          i++; // point to the next one
          hlast = h;
      } //44444444444444444444444444444444444444444444444
      
        
    } //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    
  } while (n>=0); //=======================================================
  
  return ( err );
} //***************************************************************************

void   display_hcal ( void ) //************************************************
{ // display the heading calibration table
  // assumes that it has already been read in
  short i, j, n, dh, h=0;
  float x;
  struct compass_param *comp;
  
  comp = all.comp;
  dh   = comp->dh;
  if (dh<1) 
  { cprintf("Illegal DH value of %d\n", dh);
    return;
  }
  n    = 360/dh; // number of entries
  if (n > MAX_HCAL )
  { cprintf("Too many entries in the table. n=%d\n",n);
    return;
  }
  // else display the results
  for (i=0; i<n; i++ ) //iiiiiiiiiiiiii
  {  // i=row
     printf("\n%3d <=H< %3d (-,0,+) corr= ",h, h+dh);
     for ( j=0; j<3; j++ )
     { // j=column
       x = comp->hcal[i][j]*0.1; //correction factor
       printf("%5.1f ",x);
     } //jjjjjjjjjjjjjjjjj
     h += dh;
  } //iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii
  printf("\n");
  
  return;
} //***************************************************************************

void menu_tcm2(void);
//*****************************************************************************
void  test_compass  (   void  )  
{ char ch=' ', str[80],sget[80];
  short nget, n, x, t, tmo=0;
  float avg;
  TUPort    *tup;

  tup = all.tu_port[TU_COMP].tup;  // correct tpu uart port pointer

  cprintf("              Test of Compass : %s \n", __DATE__);
  menu_tcm2();
  while ( ch !='Q') //=======================================================
  {
	SerInFlush();  // flush any characters

        if (ch !=' ' && ch>0 ) printf("C1>\n"); // display directory prompt
	    ch = -1; // illegal value - means it timed out
	    ch = SCIRxGetCharWithTimeout( 1000 ); // get a new character
	    tmo = check_tmo ( &ch, tmo );
	    // increments the tmo counter if ch<0, and
	    // goes to sleep mode after max_tmo.  Returns *ch as upper-case

    switch (ch) { // call the desired function ++++++++++++++++++++++++++++
        case 'Q' : break;  // will quit the program
        case '?' : break;  // displays the directory prompt
        case 'U' : menu_tcm2(); break;
        case  -1 :  break; // wait for another character
	    case '+' :  toggle_verbose(); // toggle verbose mode
				    break;

        case 'W' : 
		    tcm2_on(   );  
		    cprintf("Compass is on\n");
		    break;  
        case 'O' : 
    	    tcm2_off(  ); 
    	    cprintf("Compass is off\n");
    	    break;  

        case 'A' :  // average roll specified #times
				cprintf("   give # of points to average >\n");
				n = get_num(&x);
				printf("   enter 0=roll, 1=pitch, 2=head >\n");
				n = get_num(&t);
				if (n==1) //then a legal read of value
				{
				  avg = avg_tcm2( x, t);
				}
		    break;  // get avg tcm2 value

        case 'C' : tcm2_user_cal(  ); break;

        case 'D' : display_hcal(  ); break;

        case 'G' : get_compass(  ); break;

        case 'L' : lastcal_tcm2(  ); break;
        
        case 'M' : config_tcm2(  ); break;
        
        case 'R' : read_hcal (  ); break;

        case 'S' : // send tcm2 a string
            printf(" type line to send out to TCM2 >\n");
            SerInFlush(); // flush input
            gets(str);
            nget = send_tcm2( tup, str, sget);  //send str & get reply
            if (nget) cprintf("\n%s\n", sget);  // nget = #char in reply
            else      cprintf(" Received NO reply \n");
            break;
        /**/
        case '1' : 
                   cprintf("COMPASS CALIBRATION: This will erase the old setting\n");
                   cprintf("Do you really want to calibrate (y/n)? >\n");
                   if (YesNo() ) 
                   {   n = calibrate_tcm2(  ); 
                       tcm2_off(  ); // turn off
                       if (n) cprintf("Calibrate Error\n"); 
                   } break;

        default  : cprintf(" input unknown \n");
    } // end switch +++++++++++++++++++++++++++++++++++++++++++++++++++++++
    
  }  //=== end while ========================================================

   tcm2_off(  );  // make sure tcm2 is off
   return;
}  //**************************************************************************

void menu_tcm2(void) //********************************************************
{ //print out menu selections 
 cprintf("                Compass Menu\n"
 		 "Q.uit TCM2 test :   U.pdate menu   :   W.ake up TCM2  \n"
		 "O.ff TCM2       :   S.end string   :   G.et TCM2 reading \n"
		 "A.vg tcm        :   C.alibrate TCM2:   L.ast Cal #s \n"
		 "M.ag enable     :   1.old cal TCM2\n"
		 "D.isplay Err Table, R.ead HCAL file\n");
   switch ( iparam [ IA_use_moff ] )
   { // display the status of what is being used to correct
     case 0 : cprintf("TCM2 internal cal is the only correction\n"); break;
     case 2 : cprintf("HCALxxxx.txt correction file is used PLUS\n");
     case 1 : cprintf("In-House magnetometer offsets are used\n"); break;
     default : cprintf("IA_use_moff setting is UNKNOWN\n");
   }
   
 return;
} //***************************************************************************

//*** end *********************************************************************