/****************************************************
pHmtero - CoSensores (Sensores Comunitarios) 
*****************************************************
Adaptación del codigo de DFRobot Gravity: Analog pH Sensor / Meter Kit V2, SKU:SEN0161-V2
https://wiki.dfrobot.com/Gravity__Analog_pH_Sensor_Meter_Kit_V2_SKU_SEN0161-V2
https://github.com/DFRobot/DFRobot_PH 
*****************************************************/


#if ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif

#include "DFRobot_PH.h"
#include <EEPROM.h>

#define EEPROM_write(address, p) {int i = 0; byte *pp = (byte*)&(p);for(; i < sizeof(p); i++) EEPROM.write(address+i, pp[i]);}
#define EEPROM_read(address, p)  {int i = 0; byte *pp = (byte*)&(p);for(; i < sizeof(p); i++) pp[i]=EEPROM.read(address+i);}

#define PHVALUEADDR 0x00    //parametros iniciales de calibracio'n guardados en el EEPROM


DFRobot_PH::DFRobot_PH()
{
    this->_temperature    = 25.0;
    this->_phValue        = 7;
    this->_acidVoltage    = 3830.0;    //buffer pH=4.01 a 25^C
    this->_neutralVoltage = 3305.0;     //buffer pH=6.86 a 25^C
    this->_voltage        = 1500.0;
}

DFRobot_PH::~DFRobot_PH()
{

}

void DFRobot_PH::begin()
{
    EEPROM_read(PHVALUEADDR, this->_neutralVoltage);  //carga el voltaje correspondiente al pH neutro en el EEPROM (pH = 6.86)
    //Serial.print("_neutralVoltage:");
    //Serial.println(this->_neutralVoltage);
    if(EEPROM.read(PHVALUEADDR)==0xFF && EEPROM.read(PHVALUEADDR+1)==0xFF && EEPROM.read(PHVALUEADDR+2)==0xFF && EEPROM.read(PHVALUEADDR+3)==0xFF){
        this->_neutralVoltage = 3305.0;  //nuevo EEPROM
        EEPROM_write(PHVALUEADDR, this->_neutralVoltage);
    }
    EEPROM_read(PHVALUEADDR+4, this->_acidVoltage);//carga el voltaje correspondiente al pH acido en el EEPROM (pH = 4.01)
    //Serial.print("_acidVoltage:");
    //Serial.println(this->_acidVoltage);
    if(EEPROM.read(PHVALUEADDR+4)==0xFF && EEPROM.read(PHVALUEADDR+5)==0xFF && EEPROM.read(PHVALUEADDR+6)==0xFF && EEPROM.read(PHVALUEADDR+7)==0xFF){
        this->_acidVoltage = 3830.0;  //nuevo EEPROM
        EEPROM_write(PHVALUEADDR+4, this->_acidVoltage);
    }
}

float DFRobot_PH::readPH(float voltage, float temperature)
{
    float slope = (6.86-4.01)/((this->_neutralVoltage-1500.0)/3.0 - (this->_acidVoltage-1500.0)/3.0);  // calibracio'n de dos puntos:_neutralVoltage,6.86 y _acidVoltage,4.01
    float intercept =  6.86 - slope*(this->_neutralVoltage-1500.0)/3.0;
    
    Serial.print(voltage,0);
    Serial.print("mV ");
    Serial.print("A:");
    Serial.print(slope,4);
    Serial.print(" B:");
    Serial.println(intercept);
    Serial.println();
   
    
    this->_phValue = slope*(voltage-1500.0)/3.0+intercept;  //pH = A*voltaje + B
    return _phValue;
    
}


void DFRobot_PH::calibration(float voltage, float temperature,char* cmd)
{
    this->_voltage = voltage;
    this->_temperature = temperature;
    strupr(cmd);
    phCalibration(cmdParse(cmd));  // si recibe el CMD por el monitor serial entra al modo calibracio'n
    
}

void DFRobot_PH::calibration(float voltage, float temperature)
{
    this->_voltage = voltage;
    this->_temperature = temperature;
    if(cmdSerialDataAvailable() > 0){
        phCalibration(cmdParse());  // si recibe el CMD por el monitor serial entra al modo calibracio'n
    }
}


boolean DFRobot_PH::cmdSerialDataAvailable()
{
    char cmdReceivedChar;
    static unsigned long cmdReceivedTimeOut = millis();
    while(Serial.available()>0){
        if(millis() - cmdReceivedTimeOut > 500U){
            this->_cmdReceivedBufferIndex = 0;
            memset(this->_cmdReceivedBuffer,0,(ReceivedBufferLength));                
        }
        cmdReceivedTimeOut = millis();
        cmdReceivedChar = Serial.read();
        if (cmdReceivedChar == '\n' || this->_cmdReceivedBufferIndex==ReceivedBufferLength-1){
            this->_cmdReceivedBufferIndex = 0;
            strupr(this->_cmdReceivedBuffer);
            return true;
            
        }else{
            this->_cmdReceivedBuffer[this->_cmdReceivedBufferIndex] = cmdReceivedChar;
            this->_cmdReceivedBufferIndex++;
            
        }
    }
    return false;
}

byte DFRobot_PH::cmdParse(const char* cmd)
{
    byte modeIndex = 0;
    if(strstr(cmd, "CALIBRAR")      != NULL){
        modeIndex = 1;
    }else if(strstr(cmd, "SALIR") != NULL){
        modeIndex = 3;
    }else if(strstr(cmd, "PHCAL")  != NULL){
        modeIndex = 2;
    }
    return modeIndex;
}

byte DFRobot_PH::cmdParse()
{
    byte modeIndex = 0;
    if(strstr(this->_cmdReceivedBuffer, "CALIBRAR")      != NULL){
        modeIndex = 1;
    }else if(strstr(this->_cmdReceivedBuffer, "SALIR") != NULL){
        modeIndex = 3;
    }else if(strstr(this->_cmdReceivedBuffer, "PHCAL")  != NULL){
        modeIndex = 2;
    }
    return modeIndex;
}

void DFRobot_PH::phCalibration(byte mode)
{
    char *receivedBufferPtr;
    static boolean phCalibrationFinish  = 0;
    static boolean enterCalibrationFlag = 0;
    
    switch(mode){
      
        case 0:
        if(enterCalibrationFlag){
            Serial.println(F(">>>error<<<"));
        }
        break;

        case 1:
        enterCalibrationFlag = 1;
        phCalibrationFinish  = 0;
        Serial.println();
        //Serial.println(F(">>>calibrando<<<"));
        Serial.println(F("buffer 4.01 o 6.86"));
        Serial.println();
        Serial.println();
        Serial.println();
        break;
        
        case 2:
        if(enterCalibrationFlag){
            if((this->_voltage>3000)&&(this->_voltage<3500)){        // buffer solution:6.86{
                Serial.println();
                Serial.print(F("buffer 6.86"));
                this->_neutralVoltage =  this->_voltage;
                //Serial.println(F(",SALIR para guardar y salir<<<"));
                Serial.println();
                Serial.println();
                Serial.println();
                phCalibrationFinish = 1;
            }else if((this->_voltage>3501)&&(this->_voltage<4000)){  //buffer solution:4.01
                Serial.println();
                Serial.print(F("buffer 4.01"));
                this->_acidVoltage =  this->_voltage;
                //Serial.println(F(",SALIR para guardar y salir<<<")); 
                Serial.println();
                Serial.println();
                Serial.println();
                phCalibrationFinish = 1;
            }else{
                Serial.println();
                Serial.print(F(">>>error<<<"));
                Serial.println();                // not buffer solution or faulty operation
                Serial.println();
                Serial.println();
                phCalibrationFinish = 0;
            }
        }
        break;

        case 3:
        if(enterCalibrationFlag){
            Serial.println();
            if(phCalibrationFinish){
                if((this->_voltage>3000)&&(this->_voltage<3500)){
                    EEPROM_write(PHVALUEADDR, this->_neutralVoltage);
                }else if((this->_voltage>3501)&&(this->_voltage<4000)){
                    EEPROM_write(PHVALUEADDR+4, this->_acidVoltage);
                }
                Serial.print(F(">>>calibrado"));
            }else{
                Serial.print(F(">>>fallo"));
            }
            Serial.println(F(",salir<<<"));
            Serial.println();
            Serial.println();
            Serial.println();
            phCalibrationFinish  = 0;
            enterCalibrationFlag = 0;
        }
        break;
    }
}
