/************************************************************************/
/*                                                                      */
/* Program PCPORTA.C for reading of pressure, temperature and           */
/* calibration data of MS5534. Displays compensated Temperature and     */
/* Pressure + Altitude using approximation of standard atmosphere       */
/*                                                                      */
/* Date: 18.12.97  This version includes the quadratic Term             */
/*                 for the temperature calculation                      */
/*                                                                      */
/* Last update: 18.05.00   (added comments)                             */
/************************************************************************/

/*

This program runs under MSDOS or Windows NT4.0 (in MSDOS Window)
The frequency at SCLK is defined to approx 1ms in the subroutine
del(int time). To have it faster delete the line delay(1) and
use the for(..) loop. Adjust with the constants del_hi and del_lo.

Basic routines are in the beginning, top level routines at the
end of the Source Code.
Therefore when reading the program please begin at the end
of the source code.

*/


#include <stdio.h>
#include <dos.h>
#include <conio.h>
#include <stdlib.h>

#define  L 1500

typedef unsigned int WORD;
int base = 956;
int datin[L];
int sclk = 0;
int sdi = 0;
int rest = 0xfc;
long dut,c1,c2,c3,c4,c5,c6;


const del_hi = 120/30;
const del_lo = 320/30;

del(int time);
oport(void);
int  iport(void);
sclklo(void);
sclkhi(void);
sdilo(void);
sdihi(void);
send_hi(void);
send_lo(void);
reset(void);
calib_req(long word);
d1_req(void);
d2_req(void);
long adc_read(void);
long d1_read(void);
long d2_read(void);
long cali_read(long word);
coeff(void);
long press(void);
long temp(void);
float alti_calc(float pres);


/********************* Subroutines ***************************/

/*************** Delay Time **********************************/

del(int time)
  {
  int i;
  delay(1);
  /*
  for (i = 0; i < (time << 5); i++)
    i = i;
  */
  };

/********** Output State of sdi and sclk to Port *************/

oport()
  {
  int outb;
  outb = sclk + (sdi << 1) + rest;
  outportb(base, outb);
  };

/***************** Read State of DIN from Port ***************/

int iport()
  {
  return((inportb(base + 1) & 32) >> 5);
  };


sdihi()
{
  sdi = 1;      oport();        del(del_hi);
}

sdilo()
{
  sdi = 0;      oport();        del(del_lo);
}
sclkhi()
{
  sclk = 1;     oport();        del(del_hi);
}

sclklo()
{
  sclk = 0;     oport();        del(del_lo);
}

send_hi()
  {
  sdihi();      /* Set DIN to High                   */
  sclkhi();     /* Clock-In DIN with the rising edge */
  sdilo();      /* Set DIN back to Low               */
  sclklo();     /* take clock back to Low            */
  };

send_lo()
  {
  sdilo();      /* Set DIN to Low                    */
  sclkhi();     /* Clock-In DIN with the rising edge */
  sclklo();     /* take clock back to Low            */
  };

/******* Sends the Reset Sequence to the MS5534 ******/

reset()
  {
  int i = 0;
  for(i = 0; i < 9; i++)
    {
    send_hi();
    send_lo();
    };
  for(i = 0; i < 3; i++)
    {
    send_lo();
    };
  };


/**** Trigger Calibration Data Readout Sequence ******/

calib_req(long word)
  {
  int i;
  for(i = 0; i < 3; i++) send_hi();
  send_lo();    send_hi();
  if (word == 1)
  {
     send_lo();  send_hi();  send_lo();  send_hi();
  }
  if (word == 2)
  {
     send_lo();  send_hi();  send_hi();  send_lo();
  }
  if (word == 3)
  {
     send_hi();  send_lo();  send_lo();  send_hi();
  }
  if (word == 4)
  {
     send_hi();  send_lo();  send_hi();  send_lo();
  }

  for(i = 0; i < 4; i++) send_lo();

  };

/*************** Trigger Readout of D1 ***************/

d1_req()
  {
  int i;
  for(i = 0; i < 3; i++) send_hi();
  send_hi();    send_lo();
  send_hi();    send_lo();
  for(i = 0; i < 5; i++) send_lo();
  };

/*************** Trigger Readout of D2 ***************/

d2_req()
  {
  int i;
  for(i = 0; i < 3; i++) send_hi();
  send_hi();    send_lo();
  send_lo();    send_hi();
  for(i = 0; i < 5; i++) send_lo();
  };

/*************** Readout of 16 Bit Result ************/

long adc_read()
  {
  int i = 0;
  long di = 0;
  long adc_val = 0;

  send_lo();
  delay(1);
  for(i = 0; i < 16; i++)
    {
    di = (long) iport();
    di = di << (15 - i);
    adc_val += di;
    send_lo();
    delay(1);
    };
  return(adc_val);
  };

/**********************************************************/
/* The following 3 routines read D1,D2 or Word1...Word4   */
/**********************************************************/

long d1_read()
  {
  d1_req();                     /* Start D1 conversion    */
  delay(1);
  do
   if(kbhit()) break;
  while ( iport() != 0);        /* Wait until DOUT = 0    */

  return(adc_read());           /* Read 16 Bit Result     */
  };

long d2_read()
  {
  d2_req();                     /* Start D2 conversion    */
  delay(1);
  do                            /* Wait until DOUT=0      */
   if(kbhit()) break;
  while ( iport() != 0);

  return(adc_read());           /* Read 16 Bit Result     */
  };

long cali_read(long word)
  {
  calib_req(word);              /* Instruction for reading*/
  delay(1);                     /* Calibration Words      */
  return(adc_read());           /* Read 16 Bit Result     */
  };

/**********************************************************/
/* Calculation of Calibration coefficients C1..C6         */
/* out of calibration words 1..4                          */
/* required once at program start                         */
/**********************************************************/


coeff()
  {
  long word1,word2,word3,word4;

  word1=cali_read(1);
  word2=cali_read(2);
  word3=cali_read(3);
  word4=cali_read(4);

  word1=0xac10;
  word2=0xa123;
  word3=0x9d1f;
  word4=0xc080;

  c1 = word1>>1;
  c2 = word3 & 0x3f;
  c2 <<= 6;
  c2 |= (word4 & 0x3f);
  c3 = word4>>6;
  c4 = word3>>6;
  c5 = word1<<10;
  c5 &= 0x400;
  c5 += word2>>6;
  c6 = word2&0x3f;
  }


/**********************************************************/
/* Calculation of pressure <p> out of D1,D2 and           */
/* calibration coefficients C1...C5                       */
/**********************************************************/


long press()
  {
     long d1,d2,ut1,off,sens,x,p;

     d1 = d1_read();            /* read pressure value    */
     d2 = d2_read();            /* read temperature value */

          d1=0x4689;
          d2=0x6160;

          ut1  = 8*c5+20224;
     dut  = d2-ut1;             /* dut=0 for T=20 degrC   */
                                /* can be positive or neg */

     /* if negative then use quadratic term for better    */
     /* accuracy for temperatures below 20degr C          */

     if (dut<0) dut -= (dut/128*dut/128)/4;
     off  = (c2+((c4-512)*dut/16384))*4;
     sens = c1+(c3*dut)/1024+24576;
     x    = (sens*(d1-7168))/16384-off;

     p    = x*100/32+250*100;   /* pressure in 0.01 mbar  */


     return(p);
  }

/**********************************************************/
/* Calculation of Temperature in degr Celsius             */
/* Input variable is <dut> and the coefficient C6         */
/* Output variable is <temp> in the 1/10 of degr Celsius  */
/**********************************************************/

long temp()
{
  long temp;

  temp = 200+(dut*(c6+50))/1024;
  return(temp);
}

/**********************************************************/
/* Approximation of 1976 US Standard Atmosphere           */
/* piecewise linear approximation in the form of          */
/* alti = 10*j-pres*i                                     */
/* Input variable is <pres> which is the pressure in mbar */
/* Output variable is <alti> which is the altitude in m   */
/**********************************************************/

float alti_calc(float pres)
{
   long i,j;
   float alti;

   if(pres<349)
   {
      i=210;
      j=15464;
   }
   else if(pres<400.5)
   {
      i=186;
      j=14626;
   }
   else if(pres<450)
   {
      i=168;
      j=13905;
   }
   else if(pres<499)
   {
      i=154;
      j=13275;
   }
   else if(pres<549)
   {
      i=142;
      j=12676;
   }
   else if(pres<600)
   {
      i=132;
      j=12127;
   }
   else if(pres<650)
   {
      i=123;
      j=11587;
   }
   else if(pres<700)
   {
      i=116;
      j=11132;
   }
   else if(pres<748)
   {
      i=109;
      j=10642;
   }
   else if(pres<800)
   {
      i=104;
      j=10268;
   }
   else if(pres<850)
   {
      i=98;
      j=9788;
   }
   else if(pres<897.5)
   {
      i=94;
      j=9448;
   }
   else if(pres<947.5)
   {
      i=90;
      j=9089;
   }
   else if(pres<1006)
   {
      i=86;
      j=8710;
   }
   else if(pres<1100)
   {
      i=81;
      j=8207;
   }
   alti = 10*j-pres*i;
   return(alti/10);
}

/************************************************************************/
/* (Pins Configuration on LPT1 port)                                    */
/* Pin 1  - ws    open                                                  */
/* Pin 2  - gb  - SCLK  data 1                                          */
/* Pin 3  - org - SDI   data 2                                          */
/* Pin 4  - gn  - VDD   data 4                                          */
/* Pin 10 - rt  - open  data 64                                         */
/* Pin 11 - br  - open  data x128                                       */
/* Pin 12 - bl  - SDO   data 32                                         */
/* Pin 25 - sw  - GND                                                   */
/************************************************************************/

main()
{

/***********************  Variables und Constants ***********************/

int i, j, k;
long p,t;
float p_fil,t_fil,alti;
FILE *dat_pointer;

base = *(WORD far *) MK_FP(0x0040, 8);

/************************ Main Program **********************************/

reset();                               /* Send Reset sequence to MS5534 */
coeff();                               /* Read and calculate C1...C6    */
clrscr();

p = press();
t = temp();
p_fil = p;                            /* Preset filtered Pressure value */

gotoxy(10,8);
printf("---------------------------------------------------------");
gotoxy(10,14);
printf("---------------------------------------------------------");

for(;;)
  {

  p = press();
  t = temp();

  if ((p>30000) && (p<110000))               /* Pressure 300...1100mb ? */
  {
  p_fil = (32*p_fil+(p-p_fil))/32;           /* Simple Low Pass Filter  */
  t_fil = t;                                 /* no filter for Temp      */
  alti = alti_calc(p_fil/100);               /* mbar -> altitude conv.  */
  }
  gotoxy(12,10);
  printf("Temperature %.2f øC    Pressure %.2f mbar\n", t_fil/10,p_fil/100);
  printf("\n");
  printf("                       Altitude %.1f m         \n",alti);
  if (kbhit()) break;
  };
}