/**
* SHT7x Library for 3.3V
*
* Copyright 2013 Ben Sumlin
* Based on the SHT7x library by Jonathan Oxer <jon@oxer.com.au> / <www.practicalarduino.com>
* In turn based on previous work by:
*    Maurice Ribble: <www.glacialwanderer.com/hobbyrobotics/?p=5>
*    Wayne ?: <ragingreality.blogspot.com/2008/01/ardunio-and-sht15.html>
*
* Manages communication with SHT7x series (SHT7x)
* temperature / humidity sensors from Sensirion (www.sensirion.com).
*/
#if (ARDUINO >= 100)
#include <Arduino.h>
#else
#include <WProgram.h>
#endif

#include "SHT7x.h"

	SHT7x::SHT7x(int dataPin, int clockPin)
	{
		_dataPin = dataPin;
		_clockPin = clockPin;
	}


	/* ================  Public methods ================ */

	/**
	* Reads the current temperature in degrees Celsius
	*/
	float SHT7x::readTemperatureC()
	{
		int _val;                // Raw value returned from sensor
		float _temperature;      // Temperature derived from raw value

		// Conversion coefficients from SHT15 datasheet
		const float D1 = -39.8;  // for 14 Bit @ 3.3V
		const float D2 =   0.01; // for 14 Bit DEGC

		// Fetch raw value
		_val = readTemperatureRaw();

		// Convert raw value to degrees Celsius
		_temperature = (_val * D2) + D1;

		return (_temperature);
	}

	/**
	* Reads the current temperature in degrees Fahrenheit
	*/
	float SHT7x::readTemperatureF()
	{
		int _val;                 // Raw value returned from sensor
		float _temperature;       // Temperature derived from raw value

		// Conversion coefficients from SHT15 datasheet
		const float D1 = -39.4;   // for 14 Bit @ 3.3V
		const float D2 =   0.018; // for 14 Bit DEGF

		// Fetch raw value
		_val = readTemperatureRaw();

		// Convert raw value to degrees Fahrenheit
		_temperature = (_val * D2) + D1;

		return (_temperature);
	}

	/**
	* Reads current temperature-corrected relative humidity
	*/
	float SHT7x::readHumidity()
	{
		int _val;                    // Raw humidity value returned from sensor
		float _linearHumidity;       // Humidity with linear correction applied
		float _correctedHumidity;    // Temperature-corrected humidity
		float _temperature;          // Raw temperature value

		// Conversion coefficients from SHT15 datasheet
		const float C1 = -2.0468;       // for 12 Bit
		const float C2 =  0.0367;       // for 12 Bit
		const float C3 = -0.0000015955; // for 12 Bit
		const float T1 =  0.01;         // for 14 Bit
		const float T2 =  0.00008;      // for 14 Bit

		// Command to send to the SHT7x to request humidity
		int _gHumidCmd = 0b00000101;

		// Fetch the value from the sensor
		sendCommandSHT(_gHumidCmd, _dataPin, _clockPin);
		waitForResultSHT(_dataPin);
		_val = getData16SHT(_dataPin, _clockPin);
		skipCrcSHT(_dataPin, _clockPin);

		// Apply linear conversion to raw value
		_linearHumidity = C1 + C2 * _val + C3 * _val * _val;

		// Get current temperature for humidity correction
		_temperature = readTemperatureC();

		// Correct humidity value for current temperature
		_correctedHumidity = (_temperature - 25.0 ) * (T1 + T2 * _val) + _linearHumidity;

		return (_correctedHumidity);
	}


	/* ================  Private methods ================ */

	/**
	* Reads the current raw temperature value
	*/
	float SHT7x::readTemperatureRaw()
	{
		int _val;

		// Command to send to the SHT7x to request Temperature
		int _gTempCmd  = 0b00000011;

		sendCommandSHT(_gTempCmd, _dataPin, _clockPin);
		waitForResultSHT(_dataPin);
		_val = getData16SHT(_dataPin, _clockPin);
		skipCrcSHT(_dataPin, _clockPin);

		return (_val);
	}

	/**
	*/
	int SHT7x::shiftIn(int _dataPin, int _clockPin, int _numBits)
	{
		int ret = 0;
		int i;

		for (i=0; i<_numBits; ++i)
		{
			digitalWrite(_clockPin, HIGH);
			delay(10);  // I don't know why I need this, but without it I don't get my 8 lsb of temp
			ret = ret*2 + digitalRead(_dataPin);
			digitalWrite(_clockPin, LOW);
		}

		return(ret);
	}

	/**
	*/
	void SHT7x::sendCommandSHT(int _command, int _dataPin, int _clockPin)
	{
		int ack;

		// Transmission Start
		pinMode(_dataPin, OUTPUT);
		pinMode(_clockPin, OUTPUT);
		digitalWrite(_dataPin, HIGH);
		digitalWrite(_clockPin, HIGH);
		digitalWrite(_dataPin, LOW);
		digitalWrite(_clockPin, LOW);
		digitalWrite(_clockPin, HIGH);
		digitalWrite(_dataPin, HIGH);
		digitalWrite(_clockPin, LOW);

		// The command (3 msb are address and must be 000, and last 5 bits are command)
		shiftOut(_dataPin, _clockPin, MSBFIRST, _command);

		// Verify we get the correct ack
		digitalWrite(_clockPin, HIGH);
		pinMode(_dataPin, INPUT);
		ack = digitalRead(_dataPin);
		if (ack != LOW) {
			//Serial.println("Ack Error 0");
		}
		digitalWrite(_clockPin, LOW);
		ack = digitalRead(_dataPin);
		if (ack != HIGH) {
			//Serial.println("Ack Error 1");
		}
	}

	/**
	*/
	void SHT7x::waitForResultSHT(int _dataPin)
	{
		int i;
		int ack;

		pinMode(_dataPin, INPUT);

		for(i= 0; i < 100; ++i)
		{
			delay(10);
			ack = digitalRead(_dataPin);

			if (ack == LOW) {
				break;
			}
		}

		if (ack == HIGH) {
			//Serial.println("Ack Error 2"); // Can't do serial stuff here, need another way of reporting errors
		}
	}

	/**
	*/
	int SHT7x::getData16SHT(int _dataPin, int _clockPin)
	{
		int val;

		// Get the most significant bits
		pinMode(_dataPin, INPUT);
		pinMode(_clockPin, OUTPUT);
		val = shiftIn(_dataPin, _clockPin, 8);
		val *= 256;

		// Send the required ack
		pinMode(_dataPin, OUTPUT);
		digitalWrite(_dataPin, HIGH);
		digitalWrite(_dataPin, LOW);
		digitalWrite(_clockPin, HIGH);
		digitalWrite(_clockPin, LOW);

		// Get the least significant bits
		pinMode(_dataPin, INPUT);
		val |= shiftIn(_dataPin, _clockPin, 8);

		return val;
	}

	/**
	*/
	void SHT7x::skipCrcSHT(int _dataPin, int _clockPin)
	{
		// Skip acknowledge to end trans (no CRC)
		pinMode(_dataPin, OUTPUT);
		pinMode(_clockPin, OUTPUT);

		digitalWrite(_dataPin, HIGH);
		digitalWrite(_clockPin, HIGH);
		digitalWrite(_clockPin, LOW);
	}
