//============================================================================
//Copyright © 2012, open source hardware engineering
// 
//This application is free software; you can redistribute it and/or
//modify it under the terms of the GNU Lesser General Public
//License as published by the Free Software Foundation; either
//version 3 of the License, or (at your option) any later version.
//
//This application is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR When PARTICULAR PURPOSE. See the GNU
//Lesser General Public License for more details.
//
//You should have received a copy of the GNU Lesser General Public
//License along with this library; if not, see <http://www.gnu.org/licenses/>
//
//=============================================================================

#include <WxSpi.h>
#include <LoadCell.h>
#include <math.h>

bool hdwrOkay;
long counter;
long gain;
long offset;
double gsum;
double gsumsqr;
long nstat;
int navg;
bool useAveraging;
bool useFir;
int calAvg = 25;

const double loadCellFs = 25.0;          // lbs
const double loadCellGain = 3.23581e-3;  // volts/volt at full scale
const double loadCellExcitation = 2.500; // volts
const double adcRange = 10e-3;
const double adcFullScale = 8388608.0;

const double fsTweak  = 1.00000;     // unitless

double overallCalFactor;  // units are pounds per ADC count

void setup()
{
  Serial.begin(57600);
  
  Serial.println("* 25-lb Electronic Scale version 1.0");
  
  hdwrOkay = LoadCell.init();
  Serial.println(hdwrOkay ? "* Self Test OK" : "* Hardware Failure");
 
  overallCalFactor = adcRange * loadCellFs / (loadCellGain * loadCellExcitation * adcFullScale);
  overallCalFactor *= fsTweak;
  
  // LoadCell.setUnipolar(false);  
 
  LoadCell.calibrate(1, calAvg, 30, &gain, &offset);

  counter = 0L;
  nstat = 100L;
  navg=100;
  useAveraging = false;
  useFir = false;
}

void loop()
{    
  if (Serial.available() > 0)
  {
    int c = Serial.read();
    switch (c)
    {
      case 't':
      case 'T':
        LoadCell.tare(1,calAvg,30,&offset);
        gsum = gsumsqr = 0.0;
        counter = 0;
        break;
      break;
      case 'c':
      case 'C':
        LoadCell.calibrate(1,calAvg,30,&gain,&offset);
        gsum = gsumsqr = 0.0;
        counter = 0;
      break;
      case 'a':
      case 'A':
        useAveraging = !useAveraging;
        gsum = gsumsqr = 0.0;
        counter = 0;
        Serial.print("* Averaging is "); Serial.println(useAveraging ? "enabled" : "disabled");
        break;
      case 'f':
      case 'F':
          useFir = !useFir;
          gsum = gsumsqr = 0.0;
          counter = 0;
          Serial.print("* FIR "); Serial.println(useFir ? "enabled" : "disabled");
          break;
        case 'r':
        case 'R':
          gsum = gsumsqr = 0.0;
          counter = 0;
          Serial.println('* Statistics Reset');
          break;
      default:
      break;
    }
  }
  
  long force;

  if (useAveraging)  
  { 
    force = LoadCell.measureAverage(1,RNG_10_MV, navg, useFir);
  }
  else
  {
    force = LoadCell.measure(1,RNG_10_MV);
  }
  
  double forceLbs = ((double)force - 8388608.0) * overallCalFactor; // 3.9736e-6 * fsCalFactor;
  int wholeLbs = (int)forceLbs;
  double ozs = 16.0 * (forceLbs - wholeLbs);
  double forceGm = forceLbs * 454;
  
  #if 0
  Serial.print(useAveraging ? (useFir ? "FIR Force = " : "Avg Force = ") : "Force = ");
  Serial.print(wholeLbs);
  Serial.print("# ");
  Serial.print(ozs,2);
  Serial.print("oz = ");
  #endif
  
  Serial.println(forceGm,3);
  
  gsum += forceGm;
  gsumsqr += forceGm * forceGm;
  counter++;
  
  if (false) //counter >= nstat)
  {
    double mean = gsum / counter;
    double var = gsumsqr / counter - mean * mean;
    Serial.print("* Mean = "); Serial.print(mean,2);
    Serial.print("g, Stdev = "); Serial.print(sqrt(var),3); Serial.println("g");
    counter = 0;
    gsum = 0.0;
    gsumsqr = 0.0;
  }
}

