/*SKETCH FOR THE Teensy 3.2 Nephelometer card used only for thermodynamics and GPS sampling.
Used for ATMS 360 Class and others.
Each header file needs to be specifically defined on around lines 93 and 94 below.
Each analog pressure sensor is indivually calibrated and numbers are in lines 119 below.
This mesurement device uses: Teensy 3.2; Analog to digital convertor ADS1115; microSD card; NOKIA 5110 LCD screen;
Real time clock; UP501 GPS.
***************THE HARDWARE CONNECTIONS:***********************************
***************SHT75 T and RH sensor******
Pin on chip              Pins on Teensy
1 SCK                    7
2 VDD                    3.3 volts
3 GND                    GND
4 DATA                   6  Pulled up with 10kOhm resistor
*****************LCD*********************
NOKIA 5100
Pins on card:                        Pins on Teensy
1.RST -----reset                     2
2.CE----chip selection               3 
3.DC----data/commands                4
4.DIN---serial data line/out MOSI    5
5.CLK---serial clock speed   SLCK    8
6.3.3v---VCC.
7.LIGHT----backlight control terminal; bring to VCC to light it.
8.GND--power negative
*****************SD **************************
SD :bob-00544
Library:SD.h
Pins:
CD  ----unconneted,GND, this connetction comes built in
DO-----SPI MISO pin 12
GND-----GND
SCK-------SPI SCLK pin13
VCC--------Vout 3.3V, dont use 5V, 5V power will damage the SD card
DI -----SPI MOSI pin11
CS -----pin 4 ,pin 10 is also reserved

*****************16 bit ADC 1115 ADAFRUIT breakout board **************************
Device Pin Names                          Pins on Teensy
1  VDD---------                           3.3V
2  GND--------                            GND
3  SCL-------                             pin 19 A5
4  SDA-------A4                           pin 18 A4
5  ADDR----(0x48 (1001000) ADR -> GND
6  0x49 (1001001) ADR -> VDD              Using this address for the Nephelometer
7  0x4A (1001010) ADR -> SDA
8  0x4B (1001011) ADR -> SCL)
9  ALRT
10 A0                                    
11 A1
12 A2
13 A3
************** RTC ****************************************************************
SCL-------Analog Pin 16 (ALSO SOLDERED ON THE TEENSY TO PIN 19)
SDA-------Anolog Pin 17 (ALSO SOLDERED ON THE TEENSY TO PIN 18) 
**************** UP501 GPS ********************************************************
*** This device simply uses standard NMEA format data,
*** and serial port communication.
*** USE CHRONODOT TO SET THE TIME AND DATE SEPARATELY FROM THIS PROGRAM ****
Device Pin Names    Pins on Teensy
1 TX                0 RX
2 RX                1 TX
3 GND               GND
4 VDD               3.3 V
5 VDDbackup         3.3 V                                  
*/
/************** LIBRARIES ****************/
#include <Adafruit_ADS1X15.h>  /* ADC library     */
#include <Adafruit_GFX.h>      /* For the display */
#include <Adafruit_PCD8544.h>  /* For the display */
#include <Wire.h>              /* For the RTC     */
#include <TinyGPS.h>           /* For the GPS     */
#include <SPI.h>
#include <SD.h>                /* SD library      */
#include <Sensirion.h>         /* For the SHT75 T and RH sensor */

/******************** TEENSY PIN ASSIGNMENTS ********************/
/* Pins used for the Sensirion SHT75 sensor. */
const uint8_t dataPin  =  6; // These are the digital pins 6 and 7 on the Teensy.
const uint8_t clockPin =  7;

/******************  Set up the devices  ******************/
// OLD Adafruit_ADS1115 ads0(0x49);   /* For the 16 bit ADS1115 analog to digital convertor */
Adafruit_ADS1115 ads0;   /* For the 16 bit ADS1115 analog to digital convertor */
Adafruit_PCD8544 display = Adafruit_PCD8544(8, 5, 4, 3, 2); // For the LCD display

Sensirion tempSensor = Sensirion(dataPin, clockPin);

/**** This code uses a TinyGPS object, for the GPS. *****/
TinyGPS gps;
// HardwareSerial Uart = HardwareSerial();
HardwareSerial &Uart = Serial1; 
void gpsdump(TinyGPS &gps);
void printFloat(double f, int digits = 2); 

File mySensorData;
char fheader[]= "header11.csv"; //write the header to SD card
char fsensor[]="Sensor11.csv";  //write the sensor data  to SD card
String topOfFile;
int ChipSelect = 10;


/**************************** GLOBAL VARIABLES **************************/
/* Variable Name Protocol:  xxxYY where xxx is the sensor, and YY is the 1st two letters of variable */

/* Variable from the ADC1115 analog to digital convertor */
int gain ; /* Global variable used in the function getADS1115 to send gain back and forth to the main loop.*/
int gainSC=0 ; /* Scattering sensor initial gain value */
int gainLA=0 ; /* Laser power intial gain value */

/* Variables from Sensirion sht75. */
float shtTE, shtHU, shtDE ;  /* temperature, RH, and dewpoint */

/* Variables from the ads1115 analog to digital converter. */
float adsPR, adsVO ; /* Pressure, and Vcc=5 volts */
float premeas ; /* Temporary variable used for preliminary measurement with A/D to adapt to channel changes. */
int numAve  ; /* Number of averages made during each measurement. */
/* Variables calculated from the ads measurements */
float pressure                    ; /* Ambient Pressure from Analag sensor */
// float poffset=105.6            ; /* Nominal offset for pressure sensor, different for each */
//   float poffset=105.6 + 3.4      ; /* Pressure sensor offset serial 10 */
   float poffset=105.6 + 8.8      ; /* Pressure sensor offset serial 11 */
//   float poffset=105.6 + 2.0      ; /* Pressure sensor offset serial 12 */
//   float poffset=105.6 + 6.7      ; /* Pressure sensor offset serial 13 */


unsigned long int avetime = 2000UL;        /* Averaging time in milliseconds                                           */
unsigned long int Recycle = 4294957295UL;  /* Check to see if averaging routine needs recycled                         */
unsigned long int endtime ;                /* Time in milliseconds for averaging interval                              */
unsigned long int elatime ;                /* Total elapsed time since program started in ms. resets periodically.     */

int ii=0;
int jj=0;
int iDis =1;
int i ;

/**************************************** RTC VALUES ****************************************/
// These are global variables, available to all functions and procedures.
int seconds;  //  00-59 
int minutes;  //  00-59 
int hours;    //  1-12 - 00-23 
int days;     //  1-7 assuming Sunday is day 1.
int date;     //  01-31
int months;   //  01-12
int years;    //  0-99 

/******************** GPS VALUES, start with defaults ***************************************/
float gpslat=-99.99          ; /* decimal degrees */
float gpslon=-99.99          ; /* decimal degrees */
float gpsalt=-99.99          ; /* meters */
float gpsspeed=-99.99        ; /* kilometers / hour */
float gpscourse=-99.99       ; /* degrees */
int   gpsyear=-99              ; /* e.g. 2016 */
int   gpsmon=99                ; /* 1 thru 12 UTC */
int   gpsday=99                ; /* 1 thru 31 UTC */
int   gpshour=99               ; /* 0 thru 59 UTC */
int   gpsmin=99                ; /* 0 thru 59 UTC */
int   gpssec=99                ; /* 0 thru 59 UTC */

/************************************** END GLOBAL VARIABLES ********************************/

void setup()
{
/***************** Write header for the top of the file and the serial port ********/        ;
topOfFile="UTC_RTC_Date,UTC_RTC_Time,UTC_GPS_Date,UTC_GPS_Time,"                             ;
topOfFile.concat("PressSens_mV,VO_mV,Pressure_mb,numberAverages,Temperature_C,RH_%,")  ;
topOfFile.concat("DewTemp_C,Latitude,Longitude,Altitude_m,Speed_kph,Course_degrees")         ;

/*******************display LCD***********************/
// display.invertDisplay(true); // try this
 display.begin();
 display.setContrast(60);
 display.setTextSize(1);
 display.setTextColor(BLACK);

/*************** Start up the USB to serial output of the Teensy to monitor it if needed************/
Serial.begin(230400);     // Turn on the Teensy serial port output.
Serial.println(topOfFile);

/*************Set up the Teensy analog to digital conversion*********************************/ 
/* Teensy analog to digital ports are currently not used */
 analogReadAveraging(1024);  // Do 1024 measurements and average them for every analog input measurement.
 analogReadResolution(12); // Do 12 bit analog read resolution on the Teensy for the AUX channels.
 
/*********************** SD **************/
// pinMode(ChipSelect,OUTPUT); //This is the CS of SD module
// SD.begin(ChipSelect);//initilize the sd card with CS
//if (!SD.begin(ChipSelect))
//  {
//  }

// mySensorData = SD.open(fheader, FILE_WRITE);//Open SD File, Append if the file is already exist
// mySensorData.println(topOfFile); //the file header
// mySensorData.close();
pinMode(ChipSelect, OUTPUT); 
if (!SD.begin(ChipSelect)) {
  Serial.println("ERROR: SD Card Initialization Failed!");
} else {
  mySensorData = SD.open(fheader, FILE_WRITE);
  if (mySensorData) {
    mySensorData.println(topOfFile); 
    mySensorData.close();
  } else {
    Serial.println("ERROR: Could not open header file.");
  }
}
/*********************** ADC Part **************/
ads0.setGain(GAIN_TWOTHIRDS);    // 2/3x gain +/- 6.144V  1 bit = 3mV      0.1875mV (default)
ads0.begin(0x49);                    // Initialize ads1115
gain=0 ; /* Set the gain variable to the starting value */

// Set up the I2C connection for the RTC clock.
Wire.begin();


/***************** GPS STARTUP *****************/
Uart.begin(9600);

} /* Finished setting up. */


/********************* LOOP *****************************/
/**************** Program repeats on this ***************/
void loop() 
{


/*******  Do the temperature, humidity, and dewpoint measurements using the SHT75 sensor. *********/
tempSensor.measure(&shtTE, &shtHU, &shtDE);

/* Do the time averaged measurements, being careful to restart the millis timer if it over runs */

unsigned long int elatime = millis();
if (elatime >= Recycle) /* check to see if the millisecond timer is about to recycle to 0, and if so, wait. */
{
  delay(15000);        /* Allow the millisecond timer to return to 0 and start over */
  elatime = millis() ; /* second call is needed in case Recycle has happened */
}

  endtime = elatime+avetime;

/*************** DO THE VOLTAGE SOURCE, AND PRESSURE MEASUREMENTS */
/* Initialize the variables for averaging */
adsPR=0.0; adsVO=0.0 ;  i=0;
 do
{  
  i=i+1;
  /* Get the pressure sensor and power supply voltages, using fixed gain of zero */
  adsPR+=getADS1115(2,true,0) ;
  adsVO+=getADS1115(3,true,0) ; 


 } while (millis() <= endtime);

  numAve=i ; 
  float den = (float)i ;
  
  pressure=1111.11*adsPR/adsVO + poffset ; /* Calculation of pressure in mb */
  adsPR=adsPR/den               ;
  adsVO=adsVO/den               ;
 
/***************** Get the actual time now, from the real time clock ******************/
/*  Variables are filled due to the global definitions of variable types. */
get_time();
get_date();

/******************* Get the GPS data *********************************************/
bool newdata = false             ;
unsigned long startup = millis() ;
while (millis() - startup < 1000L) {
 if (Uart.available()) {
    char c = Uart.read();
    if (gps.encode(c)) { 
      newdata = true    ;
      break             ; /* Obtained data, bail out of the while loop */
    }
 }
}
 
if (newdata) gpsdump(gps);

/************ Write the data to the serial port to look at it. *****************/

  digitalClockDisplay()     ; /* Writes the time and date from the RTC */
  digitalClockDisplayGPS()  ; /* Writes the time and date from the GPS */
  Serial.print(adsPR,4); 
  Serial.print(",");
  Serial.print(adsVO,4); 
  Serial.print(",");
  Serial.print(pressure,5); 
  Serial.print(",");
  Serial.print(numAve);
  Serial.print(",");
  Serial.print(shtTE); 
  Serial.print(",");
  Serial.print(shtHU); 
  Serial.print(",");
  Serial.print(shtDE);  
  Serial.print(",");
  Serial.print(gpslat,5);  
  Serial.print(",");
  Serial.print(gpslon,5);  
  Serial.print(",");
  Serial.print(gpsalt);  
  Serial.print(",");
  Serial.print(gpsspeed);  
  Serial.print(",");
  Serial.println(gpscourse);  
/************************* WRITE DATA TO THE SD CARD NOW **********************************/
  mySensorData = SD.open(fsensor, FILE_WRITE); /* Open SD File, Append if the file is already exist. */
  digitalClockDisplaySD()     ; /* Writes the time and date from the RTC */
  digitalClockDisplaySDGPS()  ; /* Writes the time and date from the GPS */
  mySensorData.print(adsPR,4); 
  mySensorData.print(",");
  mySensorData.print(adsVO,4); 
  mySensorData.print(",");
  mySensorData.print(pressure,5); 
  mySensorData.print(",");
  mySensorData.print(numAve);
  mySensorData.print(",");
  mySensorData.print(shtTE); 
  mySensorData.print(",");
  mySensorData.print(shtHU); 
  mySensorData.print(",");
  mySensorData.print(shtDE);  
  mySensorData.print(",");
  mySensorData.print(gpslat,5);  
  mySensorData.print(",");
  mySensorData.print(gpslon,5);  
  mySensorData.print(",");
  mySensorData.print(gpsalt);  
  mySensorData.print(",");
  mySensorData.print(gpsspeed);  
  mySensorData.print(",");
  mySensorData.println(gpscourse); 
  mySensorData.close();
  
/************  Write to LCD display *******************/
  display.clearDisplay();  //For the display
  display.setCursor(0,0);  //For the display
      if (iDis==1)
           {
            display.print("Pres=");
            display.println(pressure,4);
            display.print("Temp=");
            display.println(shtTE);
            display.print("Tdew=");
            display.println(shtDE);
            display.print("Lat=");
            display.println(gpslat,4);
            display.print("Lon=");
            display.println(gpslon,4);
            display.print("Alt=");
            display.println(gpsalt);
            display.display();
            iDis=2;  
           }
     else if (iDis==2)
           {
            display.print("kph=");
            display.println(gpsspeed);           
            display.print("dir=");
            display.println(gpscourse);
            /* print date in mon/day/year format */
            if (gpsmon <= 9) {  display.print("0") ; display.print(gpsmon) ; }
               else display.print(gpsmon); display.print("/");
            if (gpsday <= 9) {  display.print("0") ; display.print(gpsday) ; }
               else display.print(gpsday); display.print("/");
            display.println(gpsyear);
            /* print hh:mm:ss */
            if (gpshour <= 9) {  display.print("0") ; display.print(gpshour) ; }
               else display.print(gpshour); display.print(":");
            if (gpsmin <= 9) {  display.print("0") ; display.print(gpsmin) ; }
               else display.print(gpsmin); display.print(":");
           if (gpssec <= 9) {  display.print("0") ; display.println(gpssec) ; }
               else display.println(gpssec); 
            digitalClockDisplayNOKIA() ; 
            display.display();
            iDis=1;  
           }
   
}  /* void loop() */

/*********************** SUBROUTINES *****************************/

/*  SD card printing of actual time and date.
*   Write the digital clock output to the SD card writer. */
void digitalClockDisplaySD(){
  SDPrintDigits(months) ;
  mySensorData.print("/");
  SDPrintDigits(date) ; 
  mySensorData.print("/20") ;
  SDPrintDigits(years) ;
  mySensorData.print(",") ;
  SDPrintDigits(hours) ;
  mySensorData.print(":") ;
  SDPrintDigits(minutes) ;
  mySensorData.print(":") ;
  SDPrintDigits(seconds) ;
  mySensorData.print(",") ;
}
void SDPrintDigits(int digits){
  if(digits < 10) mySensorData.print("0") ; 
  mySensorData.print(digits) ;
}
void digitalClockDisplay()
{
  SerialPrintDigits(months) ;
  Serial.print("/");
  SerialPrintDigits(date) ; 
  Serial.print("/20") ;
  SerialPrintDigits(years) ;
  Serial.print(",") ;
  SerialPrintDigits(hours) ;
  Serial.print(":") ;
  SerialPrintDigits(minutes) ;
  Serial.print(":") ;
  SerialPrintDigits(seconds) ;
  Serial.print(",") ;
} 

void SerialPrintDigits(int digits)
{
  if(digits < 10) Serial.print("0") ; 
  Serial.print(digits) ;
}

/*  NOKIA 5110 displaying of actual time and date.
*   Write the digital clock output to the Nokia 5110 screen. */
void digitalClockDisplayNOKIA(){
  display.print("RC ");
  NOKPrintDigits(months) ;
  display.print("/");
  NOKPrintDigits(date) ; 
  display.print("/20") ;
  NOKPrintDigits(years) ;
  display.println("") ;
  display.print("RC ");
  NOKPrintDigits(hours) ;
  display.print(":") ;
  NOKPrintDigits(minutes) ;
  display.print(":") ;
  NOKPrintDigits(seconds) ;
  display.println("") ;
}
void NOKPrintDigits(int digits){
  if(digits < 10) display.print("0") ; 
  display.print(digits) ;
}


void get_date()
{
  Wire.beginTransmission(104); 
  Wire.write(3);//set register to 3 (day)
  Wire.endTransmission();
  Wire.requestFrom(104, 4); //get 5 bytes(day,date,month,year,control);
  days   = bcdToDec(Wire.read()); 
  date  =  bcdToDec(Wire.read());   
  months = bcdToDec(Wire.read()); 
  years  = bcdToDec(Wire.read());  
}

void get_time()
{
  Wire.beginTransmission(104); 
  Wire.write(0);//set register to 0
  Wire.endTransmission();
  Wire.requestFrom(104, 3);//get 3 bytes (seconds,minutes,hours);
  seconds = bcdToDec(Wire.read() & 0x7f);
  minutes = bcdToDec(Wire.read());
  hours   = bcdToDec(Wire.read() & 0x3f);
}
   
byte decToBcd(byte val)
{
  return ( (val/10*16) + (val%10) );
}

byte bcdToDec(byte val)
{
  return ( (val/16*10) + (val%16) );
}


/*********************************************** GPS PROCEDURES ************************************/
/***************************************** GPS GlOBAL VALUES ***************************************/
/******************** GPS VALUES, start with defaults, from global declaration**********************/
// float gpslat=-99.99          ; /* decimal degrees */
// float gpslon=-99.99          ; /* decimal degrees */
// float gpsalt=-99.99          ; /* meters */
// float gpsspeed=-99.99        ; /* kilometers / hour */
// float gpscourse=-99.99       ; /* degrees */
// int gpsyear=-99              ; /* e.g. 2016 */
// int gpsmon=99                ; /* 1 thru 12 UTC */
// int gpsday=99                ; /* 1 thru 31 UTC */
// int gpshour=99               ; /* 0 thru 59 UTC */
// int gpsmin=99                ; /* 0 thru 59 UTC */
// int gpssec=99                ; /* 0 thru 59 UTC */

void gpsdump(TinyGPS &gps)
{
  long lat, lon;
  float flat, flon;
  unsigned long age, date, time, chars;
  int year;
  byte month, day, hour, minute, second, hundredths;
  unsigned short sentences, failed;

    gps.get_position(&lat, &lon, &age);
//  Serial.print("Lat/Long(10^-5 deg): "); Serial.print(lat); Serial.print(", "); Serial.print(lon); 
//  Serial.print(" Fix age: "); Serial.print(age); Serial.println("ms.");

  gps.f_get_position(&flat, &flon, &age);
//  Serial.print("Lat/Long(float): "); printFloat(flat, 5); Serial.print(", "); printFloat(flon, 5);
//  Serial.print(" Fix age: "); Serial.print(age); Serial.println("ms.");

    gps.get_datetime(&date, &time, &age);
//  Serial.print("Date(ddmmyy): "); Serial.print(date); Serial.print(" Time(hhmmsscc): ");
//    Serial.print(time);
//  Serial.print(" Fix age: "); Serial.print(age); Serial.println("ms.");

  gps.crack_datetime(&year, &month, &day, &hour, &minute, &second, &hundredths, &age);
//  Serial.print("Date: "); Serial.print(static_cast<int>(month)); Serial.print("/"); 
//    Serial.print(static_cast<int>(day)); Serial.print("/"); Serial.print(year);
//  Serial.print("  Time: "); Serial.print(static_cast<int>(hour)); Serial.print(":"); 
//    Serial.print(static_cast<int>(minute)); Serial.print(":"); Serial.print(static_cast<int>(second));
//    Serial.print("."); Serial.print(static_cast<int>(hundredths));
//  Serial.print("  Fix age: ");  Serial.print(age); Serial.println("ms.");

  gpslat=flat                                   ; 
  gpslon=flon                                   ;
  gpsalt   =gps.f_altitude()                    ;
  gpsspeed=gps.f_speed_kmph()                   ;
  gpscourse =gps.f_course()                     ;
  gpsyear   = year                              ;
  gpsmon    = static_cast<int>(month)           ;
  gpsday    = static_cast<int>(day)             ;
  gpshour   = static_cast<int>(hour)            ;
  gpsmin    = static_cast<int>(minute)          ;
  gpssec    = static_cast<int>(second)          ;

/*
    Serial.print("Alt(cm): "); Serial.print(gps.altitude()); Serial.print(" Course(10^-2 deg): ");
    Serial.print(gps.course()); Serial.print(" Speed(10^-2 knots): "); Serial.println(gps.speed());
    Serial.print("Alt(float): "); printFloat(gps.f_altitude()); Serial.print(" Course(float): ");
    printFloat(gps.f_course()); Serial.println();
    Serial.print("Speed(knots): "); printFloat(gps.f_speed_knots()); Serial.print(" (mph): ");
      printFloat(gps.f_speed_mph());
    Serial.print(" (mps): "); printFloat(gps.f_speed_mps()); Serial.print(" (kmph): ");
      printFloat(gps.f_speed_kmph()); Serial.println();
*/

  gps.stats(&chars, &sentences, &failed);
//  Serial.print("Stats: characters: "); Serial.print(chars); Serial.print(" sentences: ");
//  Serial.print(sentences); Serial.print(" failed checksum: "); Serial.println(failed);
}

void printFloat(double number, int digits)
{
  // Handle negative numbers
  if (number < 0.0) {
     Serial.print('-');
     number = -number;
  }

  // Round correctly so that print(1.999, 2) prints as "2.00"
  double rounding = 0.5;
  for (uint8_t i=0; i<digits; ++i)
    rounding /= 10.0;
  
  number += rounding;

  // Extract the integer part of the number and print it
  unsigned long int_part = (unsigned long)number;
  double remainder = number - (double)int_part;
  Serial.print(int_part);

  // Print the decimal point, but only if there are digits beyond
  if (digits > 0)
    Serial.print("."); 

  // Extract digits from the remainder one at a time
  while (digits-- > 0) {
    remainder *= 10.0;
    int toPrint = int(remainder);
    Serial.print(toPrint);
    remainder -= toPrint;
  }
}

/****************** Print a comma to the serial port ************************/
void c()  {
  Serial.print(",") ;
}

/*  SD card printing of actual time and date.
*   Write the digital clock output to the SD card writer. */
void digitalClockDisplaySDGPS(){
  SDPrintDigits(gpsmon) ;
  mySensorData.print("/");
  SDPrintDigits(gpsday) ; 
  mySensorData.print("/") ;
  SDPrintDigits(gpsyear) ;
  mySensorData.print(",") ;
  SDPrintDigits(gpshour) ;
  mySensorData.print(":") ;
  SDPrintDigits(gpsmin) ;
  mySensorData.print(":") ;
  SDPrintDigits(gpssec) ;
  mySensorData.print(",") ;
}

void digitalClockDisplayGPS()
{
  SerialPrintDigits(gpsmon) ;
  Serial.print("/");
  SerialPrintDigits(gpsday) ; 
  Serial.print("/") ;
  SerialPrintDigits(gpsyear) ;
  Serial.print(",") ;
  SerialPrintDigits(gpshour) ;
  Serial.print(":") ;
  SerialPrintDigits(gpsmin) ;
  Serial.print(":") ;
  SerialPrintDigits(gpssec) ;
  Serial.print(",") ;
} 

/**************** Function to obtain data from the ADS1115 sensor ****************/
/**************** It makes use of the global variable integer named gain *********/
/***  Inputs:  */
/* int channel = channel 0 to 3 to acquire data for. */
/* bool setGain=true, just acquire data; else autogain to find best gain and then acquire data ******/
/* int startGain = value of gain to use for either acquiring data directly, or starting autogain. */
/* At the end of the routine, the global variable is filled with the startGain value. */
/***  Outputs: */
/* measuredMilliVolts */
/* GAIN DEFINITIONS: */
/* gain=0 ads.setGain(GAIN_TWOTHIRDS);  // 2/3x gain +/- 6.144V  1 bit = 0.1875mV (default) */
/* gain=1 ads.setGain(GAIN_ONE);        // 1x gain   +/- 4.096V  1 bit = 0.125mV */
/* gain=2 ads.setGain(GAIN_TWO);        // 2x gain   +/- 2.048V  1 bit = 0.0625mV */
/* gain=3 ads.setGain(GAIN_FOUR);       // 4x gain   +/- 1.024V  1 bit = 0.03125mV */
/* gain=4 ads.setGain(GAIN_EIGHT);      // 8x gain   +/- 0.512V  1 bit = 0.015625mV */
/* gain=5 ads.setGain(GAIN_SIXTEEN);    // 16x gain  +/- 0.256V  1 bit = 0.0078125mV */
float getADS1115(int channel, bool setGain, int startGain) 
{
float conv[6]={0.1875,0.125,0.0625,0.03125,0.015625,0.0078125} ; /* mVolts / bit conversion factors */
uint16_t adc0 ;
uint16_t target=10000 ; /* Make a/d counts greater than this value if possible with autogain employed */ 
uint16_t over=32760   ; /* Peak allowed value of a/d counts during autozero.*/

if (setGain) {
  ADSsetGain(0) ; /* pre read the channel, pointing the ADS to this channel with minimal gain */
  adc0=ads0.readADC_SingleEnded(channel) ;
  ADSsetGain(startGain);
  adc0=ads0.readADC_SingleEnded(channel) ;
  gain=startGain ; 
  return conv[startGain]*(float)adc0 ;
  }
else{  /* Must find the autogain that makes sense */
  ADSsetGain(0) ; /* pre read the channel, pointing the ADS to this channel with minimal gain */
  adc0=ads0.readADC_SingleEnded(channel) ;
  bool failed=true ;
  int tries=0 ;
  do
  {
  tries++;
  ADSsetGain(startGain) ;
  adc0=ads0.readADC_SingleEnded(channel) ;
  if (adc0 > target && adc0 < over ) { /* the current gain value is good if true */
    gain=startGain ; 
    failed=false ;
    return conv[startGain]*(float)adc0 ;
  }
  else if (adc0 < target && startGain <5) {
    startGain++ ; /* Increase the gain */
    gain=startGain;
  }
  else if (adc0 > over && startGain > 0)   {
    startGain-- ; /* Decrease the gain */
    gain=startGain;
  }
  else if (tries > 5) {
    gain=startGain ; 
    failed=false ;
    return conv[startGain]*(float)adc0 ;
  }
  } while (failed) ;
}
return conv[startGain]*(float)adc0 ;
}

/* Subroutine to set gain on the preamp */
void ADSsetGain(int g) {
   if (g == 0) {
      ads0.setGain(GAIN_TWOTHIRDS);
   }
   else if (g==1) {
          ads0.setGain(GAIN_ONE);
   }
   else if (g==2) {
          ads0.setGain(GAIN_TWO);
   }
   else if (g==3) {
          ads0.setGain(GAIN_FOUR);
   }
   else if (g==4) {
          ads0.setGain(GAIN_EIGHT);
   }
   else if (g==5) {
          ads0.setGain(GAIN_SIXTEEN);
   }
   else { /* coerce the value to the safest value */
          ads0.setGain(GAIN_TWOTHIRDS);
   }
}

/*** Subroutine to calculate the thermistor temperature from its measured resistance. ***/
/* Uses the Stein Hart equation, with coefficients from the BR11KA152M thermistor. */
/* Resistance R is in Ohms */

  float Thermistor(float R) {
  float rat = log(R) ; 
  float a=1.051740553E-03   ; 
  float b=3.04251503400E-04 ;
  float c=1.9741958170E-07  ;
  float Ttherm = a + b*rat + c*rat*rat*rat  ;
  Ttherm = 1.0/Ttherm - 273.15  ; // Thermistor temperature in Celcius.
  return Ttherm ;
} 
