#ifndef TG_TSL25911_H
#define TG_TSL25911_H

#include <Wire.h>


#define TSL25911_ADDRESS (0x29)

#define SENSOR_DATA_LENGTH 4

//////////////////////////////////////////////////////////////////
/// TSL25911 - Driver class for TSL25911 sensor
///
/// Based on the data sheet provided
///
class TSL25911{
  public:

    typedef enum {
        TSL25911_FULL = 0x0,
        TSL25911_IR = 0x1,
        TSL25911_VIS = 0x2,
    } tls25911_mode_t;

    typedef enum {
        TSL2591_INTEGRATIONTIME_100MS = 0x00, // 100 millis
        TSL2591_INTEGRATIONTIME_200MS = 0x01, // 200 millis
        TSL2591_INTEGRATIONTIME_300MS = 0x02, // 300 millis
        TSL2591_INTEGRATIONTIME_400MS = 0x03, // 400 millis
        TSL2591_INTEGRATIONTIME_500MS = 0x04, // 500 millis
        TSL2591_INTEGRATIONTIME_600MS = 0x05, // 600 millis
    } tsl2591IntegrationTime_t;

    /// Enumeration for the persistance filter (for interrupts)
    typedef enum {//  bit 7:4: 0
        TSL2591_PERSIST_EVERY = 0x00, // Every ALS cycle generates an interrupt
        TSL2591_PERSIST_ANY = 0x01,   // Any value outside of threshold range
        TSL2591_PERSIST_2 = 0x02,     // 2 consecutive values out of range
        TSL2591_PERSIST_3 = 0x03,     // 3 consecutive values out of range
        TSL2591_PERSIST_5 = 0x04,     // 5 consecutive values out of range
        TSL2591_PERSIST_10 = 0x05,    // 10 consecutive values out of range
        TSL2591_PERSIST_15 = 0x06,    // 15 consecutive values out of range
        TSL2591_PERSIST_20 = 0x07,    // 20 consecutive values out of range
        TSL2591_PERSIST_25 = 0x08,    // 25 consecutive values out of range
        TSL2591_PERSIST_30 = 0x09,    // 30 consecutive values out of range
        TSL2591_PERSIST_35 = 0x0A,    // 35 consecutive values out of range
        TSL2591_PERSIST_40 = 0x0B,    // 40 consecutive values out of range
        TSL2591_PERSIST_45 = 0x0C,    // 45 consecutive values out of range
        TSL2591_PERSIST_50 = 0x0D,    // 50 consecutive values out of range
        TSL2591_PERSIST_55 = 0x0E,    // 55 consecutive values out of range
        TSL2591_PERSIST_60 = 0x0F,    // 60 consecutive values out of range
    } tsl2591Persist_t;

    /// Enumeration for the sensor gain
    typedef enum {
        TSL2591_GAIN_LOW = 0x00,  /// low gain (1x)
        TSL2591_GAIN_MED = 0x10,  /// medium gain (25x)
        TSL2591_GAIN_HIGH = 0x20, /// medium gain (428x)
        TSL2591_GAIN_MAX = 0x30,  /// max gain (9876x)
    } tsl2591Gain_t;

   enum ChipModel{
        ChipModel_UNKNOWN = 0,
        ChipModel_TSL25911_REV0 = 0x50
   };


    TSL25911(TwoWire* i2c): m_initialized(false), gain(TSL2591_GAIN_MED), integration(TSL2591_INTEGRATIONTIME_500MS),i2c(i2c){}
    TSL25911(TwoWire* i2c, tsl2591Gain_t _gain,tsl2591IntegrationTime_t _integration) : m_initialized(false),gain(_gain),integration(_integration),i2c(i2c) {}

    ChipModel chipModel();

    bool begin();
    bool reset();

    uint16_t lumV();
    uint16_t lumIR();
    uint16_t lumF();
    float lumLux();
    void read(uint16_t& v, uint16_t& ir, uint16_t& f, float& lux);


protected:
    bool Initialize();


private:
    bool m_initialized;
    ChipModel m_chip_model;
    TwoWire* i2c;
    tsl2591Gain_t gain;
    tsl2591IntegrationTime_t integration;

    static const uint8_t REG_ENABLE = 0xA0 | 0x00;
    static const uint8_t REG_CTRL   = 0xA0 | 0x01;

    static const uint8_t PID_ADDR    = 0xA0 | 0x11;
    static const uint8_t ID_ADDR     = 0xA0 | 0x12;

    static const uint8_t DEVICE_STATUS = 0xA0 | 0x13;  // Internal Status
    static const uint8_t CHAN0_LOW = 0xA0 | 0x14;      // Channel 0 data, low byte
    static const uint8_t CHAN0_HIGH = 0xA0 | 0x15;     // Channel 0 data, high byte
    static const uint8_t CHAN1_LOW = 0xA0 | 0x16;      // Channel 1 data, low byte
    static const uint8_t CHAN1_HIGH = 0xA0 | 0x17;     // Channel 1 data, high byte


    float again();
    float atime();


    bool ReadChipID();

    bool ReadRegister(uint8_t addr,uint8_t data[],uint8_t length);
    bool ReadData(uint32_t data[SENSOR_DATA_LENGTH]);

    void WriteSettings();
    bool WriteRegister(uint8_t addr,uint8_t data);

};

#endif