/*
 Author: Obrtac Tomas  
 Mail: obrtac.tomas@gmail.com
 2017
 */


#include <xc.h>
#include "Sensors_lib.h"

void Restart_Barometric(void)
{
    Send_I2C_StartBit();
    Send_I2C_Data(0b11101110); // Address of the sensor
    while (SSPCON2bits.ACKSTAT); // Wait for ACK
    Send_I2C_Data(0b00011110); // Send command
    while (SSPCON2bits.ACKSTAT);// Wait for ACK
    Send_I2C_StopBit(); // End transmit
    __delay_ms(10);
    __delay_ms(10);
    __delay_ms(10);
}

uint32_t MS5607_Read_Value_4096(uint8_t command)
{
    char uart[30];
    char addr_R,addr_W,command_A;
    addr_R = 0b11101111; // Address for writing
    addr_W = 0b11101110; // Address for reading
    uint32_t value; 
    Send_I2C_StartBit();
    Send_I2C_Data(addr_W); // Send ADD
    while (SSPCON2bits.ACKSTAT); //Wait for ACK
    Send_I2C_Data(command); // Write command
    while (SSPCON2bits.ACKSTAT); // Wait for ACK
    Send_I2C_StopBit(); 
    __delay_ms(20);
    __delay_ms(20);
    Send_I2C_StartBit();
    Send_I2C_Data(addr_W); // Sending ADD
    while (SSPCON2bits.ACKSTAT); // Wait for ACK
    Send_I2C_Data(0b00000000); // Write command
    while (SSPCON2bits.ACKSTAT); // Wait for ACK
    Send_I2C_StopBit();
    __delay_ms(20);
    __delay_ms(20);
    Send_I2C_StartBit();
    Send_I2C_Data(addr_R); // Send ADD
    while (SSPCON2bits.ACKSTAT); // Wait for ACK
    value = Read_I2C_Data(); // Read data
    value = value << 8; // Shift left
    Send_I2C_ACK(); // Send ACK
    value += Read_I2C_Data(); // Read data
    value = value << 8; // Shift left
    Send_I2C_ACK(); // Send ACK
    value += Read_I2C_Data(); // Read data
    Send_I2C_NAK(); // SendNAK
    Send_I2C_StopBit();
    return value;
}

uint16_t MS5607_Read_Constant(uint8_t command)
{   // Function for getting 16 bits constants
    char addr_R,addr_W;
    addr_R = 0b11101111; // Address for writing
    addr_W = 0b11101110; // Address for reading
    uint16_t value;
    Send_I2C_StartBit();
    Send_I2C_Data(addr_W); // Send ADD
    while (SSPCON2bits.ACKSTAT); // Wait for ACK
    Send_I2C_Data(command); // Send command
    while (SSPCON2bits.ACKSTAT); //  Wait for ACK
    Send_I2C_StopBit();
    Send_I2C_StartBit();
    Send_I2C_Data(addr_R); // Send ADD
    while (SSPCON2bits.ACKSTAT);
    value = Read_I2C_Data(); // Read value
    value = value << 8;
    Send_I2C_ACK(); //Send ACK
    value += Read_I2C_Data(); // Read value
    Send_I2C_NAK(); // Send NAk
    Send_I2C_StopBit();
    return value;
}


uint16_t *Return_Constans_MS5607(void)
{
    // Get required constants for the calculation of the value
    static uint16_t C1[7] ;
    Restart_Barometric();
    C1[1] = MS5607_Read_Constant(0b10100010); 
    C1[2] = MS5607_Read_Constant(0b10100100);
    C1[3] = MS5607_Read_Constant(0b10100110);
    C1[4] = MS5607_Read_Constant(0b10101000);
    C1[5] = MS5607_Read_Constant(0b10101010);
    C1[6] = MS5607_Read_Constant(0b10101110);
    return C1;
}

uint16_t *Return_Values_MS5607(uint16_t Konst[])
{
    /* This calculation is little bit complicated because the sensor require
     * calucating with 64 bits numbers and the MCU can handle max 32 bit values
     * See more info in datasheet
     * */
    uint32_t Pressure_unconverted, Pressure, Temperature_unconverted;
    int32_t Temperature,dT;
    uint32_t Helping;
    uint32_t OFF,Sens;
    static uint32_t Values[2];
    Pressure_unconverted = MS5607_Read_Value_4096(0b01001000); // Read the pressure
    Temperature_unconverted = MS5607_Read_Value_4096(0b01011000); // Read the temperature
    dT = Temperature_unconverted; // Calculate DT constant
    dT -=(long)Konst[5] << 8;
    Helping = (unsigned long)dT >> 10;
    Helping *= Konst[6];
    Helping = Helping >> 13;
    Temperature = 2000 + Helping;
    // Shift values to compute large numbers
    OFF = ((long)Konst[2] << 12) +((((long)Konst[4] >> 5)*(dT >>6))) ; 
    Sens = ((long)Konst[1] << 11)+(((long)Konst[3]>> 6)*(dT>>6));
    Pressure = (((Sens >> 11) * (Pressure_unconverted >> 10) - OFF) >> 10);
    Values[0] = Temperature;
    Values[1] = Pressure;
    return Values; 
}
    
void OPT3001_Configuration(char address)
{
    Send_I2C_StartBit();
    Send_I2C_Data(address); // Address of 
    while (SSPCON2bits.ACKSTAT); // Wait for ACK
    Send_I2C_Data(0b00000001); // Result register
    while (SSPCON2bits.ACKSTAT); // Wait for ACK
    Send_I2C_Data(0b11001011); // MSB
    while (SSPCON2bits.ACKSTAT); // Wait for ACK
    Send_I2C_Data(0b11111111); // LSB
    while (SSPCON2bits.ACKSTAT); // Wait for ACK
    Send_I2C_StopBit();
}

float OPT3001_Converted_Value(char address)
{
    OPT3001_Configuration(address); // Configure the sensor before reading
    uint16_t intensity;
    Send_I2C_StartBit();
    // Wake the sensor up from the sleep
    Send_I2C_Data(address); // Address of the sensor
    while (SSPCON2bits.ACKSTAT); // Wait for ACK
    Send_I2C_Data(0b00000000); // Result register
    while (SSPCON2bits.ACKSTAT); // Wait for ACK
    Send_I2C_StopBit();
    // Wait for value conversion, It takes about 800 ms
    int i;
    for (i = 0; i < 50; i++) __delay_ms(20);
    // Commands for reading value
    Send_I2C_StartBit();
    Send_I2C_Data(address+1); // Address of the sensor with "1" at the end for reading
    while (SSPCON2bits.ACKSTAT); // Wait for ACK
    intensity = Read_I2C_Data(); // Read the MSB
    intensity = intensity << 8; // Byteshift
    Send_I2C_ACK(); // Sending ACK
    intensity += Read_I2C_Data(); //Reading LSB
    Send_I2C_NAK(); // Sending NAK
    Send_I2C_StopBit();
    //float converted_value = (0.01 * pow(2,intenzita >> 12) *((intenzita << 4) >>4) );
    //return converted_value;
    return (0.01 * pow(2,intensity >> 12) *((intensity << 4) >>4) );
}

    float ADT7301_Converted_Value(void)
{
    uint16_t temperature;
    int i;
    SPI1ON = 0;
    ReceiveSPI(0b00000000); // Wake up ADT7301
    ReceiveSPI(0b00000000); 
    __delay_ms(5); // Waiting for conversion
    temperature = ReceiveSPI(0b00100000); // After finishing the transmission the ADT will go in to low power mode
    temperature = (temperature << 8); // Shifting MSB 
    temperature += ReceiveSPI(0b00000000);
    SPI1ON = 1;
    if ((0x2000 & temperature) == 0x2000) // Check sign bit for negative value.
    {
        return ((float)temperature - 16384)/32; // Conversion formula if negative temperature.
        }
    else
    {
        return ((float)temperature/32); // Conversion formula if positive temperature.
    } 
}

