//
//    FILE: Max44009.cpp
//  AUTHOR: Rob Tillaart
// VERSION: 0.1.9
// PURPOSE: library for MAX44009 lux sensor Arduino
//     URL: https://github.com/RobTillaart/Arduino/tree/master/libraries
//
// Released to the public domain
//
// 0.1.9  - 2018-07-01 issue #108 Fix shift math
//          (thanks Roland vandecook)
// 0.1.8  - 2018-05-13 issue #105 Fix read register
//          (thanks morxGrillmeister)
// 0.1.7  - 2018-04-02 issue #98 extend constructor for ESP8266
// 0.1.6  - 2017-07-26 revert double to float 
// 0.1.5  - updated history
// 0.1.4  - added setAutomaticMode() to max44009.h (thanks debsahu)
// 0.1.03 - added configuration
// 0.1.02 - added threshold code
// 0.1.01 - added interrupt code
// 0.1.00 - initial version

#include "Max44009.h"


Max44009::Max44009(const uint8_t address, const uint8_t dataPin, const uint8_t clockPin)
{
    _address = address;
#ifdef ESP8266
        Wire.begin(dataPin, clockPin);
#else  // other platforms
        Wire.begin();
#endif
    // TWBR = 12; // Wire.setClock(400000);
    _data = 0;
    _error = 0;
}

Max44009::Max44009(const uint8_t address, bool continuousMode)
{
	_address = address;
	Wire.begin();
	// TWBR = 12; // Wire.setClock(400000);
	_data = 0;
	_error = 0;
	if (continuousMode)
	{
		setContinuousMode();
	}
	else
	{
		setAutomaticMode();
	}
}

float Max44009::getLux(void)
{
    uint8_t dhi = read(MAX44009_LUX_READING_HIGH);
    uint8_t dlo = read(MAX44009_LUX_READING_LOW);
    uint8_t e = dhi >> 4;
    uint32_t m = ((dhi & 0x0F) << 4) + (dlo & 0x0F);
    m <<= e;
    float val = m * 0.045;
    return val;
}

int Max44009::getError()
{
    int e = _error;
    _error = 0;
    return e;
}

void Max44009::setHighThreshold(const float value)
{
    setThreshold(MAX44009_THRESHOLD_HIGH, value);
}

float Max44009::getHighThreshold(void)
{
    return getThreshold(MAX44009_THRESHOLD_HIGH);
}

void Max44009::setLowThreshold(const float value)
{
    setThreshold(MAX44009_THRESHOLD_LOW, value);
}

float Max44009::getLowThreshold(void)
{
    return getThreshold(MAX44009_THRESHOLD_LOW);
}

void Max44009::setThresholdTimer(const uint8_t value)
{
    write(MAX44009_THRESHOLD_TIMER, value);
}

uint8_t Max44009::getThresholdTimer()
{
    return read(MAX44009_THRESHOLD_TIMER);
}

void Max44009::setConfiguration(const uint8_t value)
{
    write(MAX44009_CONFIGURATION, value);
}

uint8_t Max44009::getConfiguration()
{
    return read(MAX44009_CONFIGURATION);
}

void Max44009::setAutomaticMode()
{
    uint8_t config = read(MAX44009_CONFIGURATION);
    config &= ~MAX44009_CFG_CONTINUOUS; // off
    config &= ~MAX44009_CFG_MANUAL;     // off
    write(MAX44009_CONFIGURATION, config);
}

void Max44009::setContinuousMode()
{
    uint8_t config = read(MAX44009_CONFIGURATION);
    config |= MAX44009_CFG_CONTINUOUS; // on
    config &= ~MAX44009_CFG_MANUAL;    // off
    write(MAX44009_CONFIGURATION, config);
}

void Max44009::setManualMode(uint8_t CDR, uint8_t TIM)
{
    if (CDR !=0) CDR = 1;
    if (TIM > 7) TIM = 7;
    uint8_t config = read(MAX44009_CONFIGURATION);
    config &= ~MAX44009_CFG_CONTINUOUS; // off
    config |= MAX44009_CFG_MANUAL;      // on
    config &= 0xF0; // clear CDR & TIM bits
    config |= CDR << 3 | TIM;
    write(MAX44009_CONFIGURATION, config);
}

///////////////////////////////////////////////////////////
//
// PRIVATE
//
void Max44009::setThreshold(const uint8_t reg, const float value)
{
    // TODO CHECK RANGE
    uint32_t m = round(value / 0.045);  // mulitply * 22.22222222 is faster.
    uint8_t e = 0;
    while (m > 255)
    {
        m >>= 1;
        e++;
    };
    m = (m >> 4) & 0x0F;
    e <<= 4;
    write(reg, e | m);
}

float Max44009::getThreshold(uint8_t reg)
{
    uint8_t data = read(reg);
    uint8_t e = (data & 0xF0) >> 4;
    uint32_t m = ((data & 0x0F) << 4) + 0x0F;
    m <<= e;
    float val = m * 0.045;
    return val;
}

uint8_t Max44009::read(uint8_t reg)
{
    Wire.beginTransmission(_address);
    Wire.write(reg);
    _error = Wire.endTransmission();
    if (_error != 0)
    {
        return _data; // last value
    }
    if (Wire.requestFrom(_address, (uint8_t) 1) != 1)
    {
        _error = 10;
        return _data; // last value
    }
#if (ARDUINO <  100)
    _data = Wire.receive();
#else
    _data = Wire.read();
#endif
    return _data;
}

void Max44009::write(uint8_t reg, uint8_t value)
{
    Wire.beginTransmission(_address);
    Wire.write(reg);
    Wire.write(value);
    _error = Wire.endTransmission();
}

// --- END OF FILE ---