Luminosity sensor by Texas Advanced Optoelectronic Solutions Inc.. Device combines one broadband photodiode (visible plus infrared) and one infrared-responding photodiode. Sets Gain x1 and 402mS as default.

Dependents:   MusicBoxForFathersDay FTHR_SensorHub Affich_Lum_Moist Projetv0 ... more

Revision:
5:5b1b625fda6f
Parent:
4:05d322353720
--- a/TSL2561.cpp	Tue Feb 20 10:52:41 2018 +0000
+++ b/TSL2561.cpp	Fri Sep 21 22:57:07 2018 +0000
@@ -1,47 +1,169 @@
-/*
- * mbed library program
- *  Luminosity sensor -- LIGHT-TO-DIGITAL CONVERTER (light intensity to a digital signal output)
- *  TSL2561 by Texas Advanced Optoelectronic Solutions Inc.
+/*!
+ * @file Adafruit_TSL2561_U.cpp
+ *
+ * @mainpage Adafruit TSL2561 Light/Lux sensor driver
+ *
+ * @section intro_sec Introduction
+ *
+ * This is the documentation for Adafruit's TSL2561 driver for the
+ * Arduino platform.  It is designed specifically to work with the
+ * Adafruit TSL2561 breakout: http://www.adafruit.com/products/439
+ *
+ * These sensors use I2C to communicate, 2 pins (SCL+SDA) are required
+ * to interface with the breakout.
+ *
+ * Adafruit invests time and resources providing this open source code,
+ * please support Adafruit and open-source hardware by purchasing
+ * products from Adafruit!
+ *
+ * @section dependencies Dependencies
+ *
+ * This library depends on
+ *  <a href="https://github.com/adafruit/Adafruit_Sensor">
+ * Adafruit_Sensor</a> being present on your system. Please make sure you have
+ * installed the latest version before using this library.
+ *
+ * @section author Author
+ *
+ * Written by Kevin "KTOWN" Townsend for Adafruit Industries.
  *
- * Copyright (c) 2015,'17,'18 Kenji Arai / JH1PJL
- *  http://www.page.sannet.ne.jp/kenjia/index.html
- *  http://mbed.org/users/kenjiArai/
- *      Created: Feburary   21st, 2015
- *      Revised: August     23rd, 2017
- *      Revised: Feburary   20th, 2018   bug fix -> read_ID() & who_am_i()
- *                                       Thanks PARK JAICHANG
- */
+ * @section license License
+ *
+ * BSD license, all text here must be included in any redistribution.
+ *
+ *   @section  HISTORY
+ *
+ *   v2.0 - Rewrote driver for Adafruit_Sensor and Auto-Gain support, and
+ *          added lux clipping check (returns 0 lux on sensor saturation)
+ *   v1.0 - First release (previously TSL2561)
+*/
+/**************************************************************************/
+
+//------- Modified by ----------------------------------------------------------
+//  Kenji Arai / JH1PJL
+//  http://www.page.sannet.ne.jp/kenjia/index.html
+//  http://mbed.org/users/kenjiArai/
+//      Created: Feburary   21st, 2015
+//      Revised: August     23rd, 2017
+//      Revised: Feburary   20th, 2018   bug fix -> read_ID() & who_am_i()
+//                                       Thanks PARK JAICHANG
+//      Revised: March      31st, 2018   Added "Auto Range mode"
+//                                       Use Adafruit library
+//
+// Original information     https://www.adafruit.com/product/439
+// Original source files    https://github.com/adafruit/TSL2561-Arduino-Library
+//                          https://github.com/adafruit/Adafruit_TSL2561
+// Change for Mbed platform
+//    modified -> all related files
+//------------------------------------------------------------------------------
 
 #include "TSL2561.h"
 
+// T, FN and CL package values
+#define TSL2561_LUX_K1T           (0x0040)  ///< 0.125 * 2^RATIO_SCALE
+#define TSL2561_LUX_B1T           (0x01f2)  ///< 0.0304 * 2^LUX_SCALE
+#define TSL2561_LUX_M1T           (0x01be)  ///< 0.0272 * 2^LUX_SCALE
+#define TSL2561_LUX_K2T           (0x0080)  ///< 0.250 * 2^RATIO_SCALE
+#define TSL2561_LUX_B2T           (0x0214)  ///< 0.0325 * 2^LUX_SCALE
+#define TSL2561_LUX_M2T           (0x02d1)  ///< 0.0440 * 2^LUX_SCALE
+#define TSL2561_LUX_K3T           (0x00c0)  ///< 0.375 * 2^RATIO_SCALE
+#define TSL2561_LUX_B3T           (0x023f)  ///< 0.0351 * 2^LUX_SCALE
+#define TSL2561_LUX_M3T           (0x037b)  ///< 0.0544 * 2^LUX_SCALE
+#define TSL2561_LUX_K4T           (0x0100)  ///< 0.50 * 2^RATIO_SCALE
+#define TSL2561_LUX_B4T           (0x0270)  ///< 0.0381 * 2^LUX_SCALE
+#define TSL2561_LUX_M4T           (0x03fe)  ///< 0.0624 * 2^LUX_SCALE
+#define TSL2561_LUX_K5T           (0x0138)  ///< 0.61 * 2^RATIO_SCALE
+#define TSL2561_LUX_B5T           (0x016f)  ///< 0.0224 * 2^LUX_SCALE
+#define TSL2561_LUX_M5T           (0x01fc)  ///< 0.0310 * 2^LUX_SCALE
+#define TSL2561_LUX_K6T           (0x019a)  ///< 0.80 * 2^RATIO_SCALE
+#define TSL2561_LUX_B6T           (0x00d2)  ///< 0.0128 * 2^LUX_SCALE
+#define TSL2561_LUX_M6T           (0x00fb)  ///< 0.0153 * 2^LUX_SCALE
+#define TSL2561_LUX_K7T           (0x029a)  ///< 1.3 * 2^RATIO_SCALE
+#define TSL2561_LUX_B7T           (0x0018)  ///< 0.00146 * 2^LUX_SCALE
+#define TSL2561_LUX_M7T           (0x0012)  ///< 0.00112 * 2^LUX_SCALE
+#define TSL2561_LUX_K8T           (0x029a)  ///< 1.3 * 2^RATIO_SCALE
+#define TSL2561_LUX_B8T           (0x0000)  ///< 0.000 * 2^LUX_SCALE
+#define TSL2561_LUX_M8T           (0x0000)  ///< 0.000 * 2^LUX_SCALE
+
+// CS package values
+#define TSL2561_LUX_K1C           (0x0043)  ///< 0.130 * 2^RATIO_SCALE
+#define TSL2561_LUX_B1C           (0x0204)  ///< 0.0315 * 2^LUX_SCALE
+#define TSL2561_LUX_M1C           (0x01ad)  ///< 0.0262 * 2^LUX_SCALE
+#define TSL2561_LUX_K2C           (0x0085)  ///< 0.260 * 2^RATIO_SCALE
+#define TSL2561_LUX_B2C           (0x0228)  ///< 0.0337 * 2^LUX_SCALE
+#define TSL2561_LUX_M2C           (0x02c1)  ///< 0.0430 * 2^LUX_SCALE
+#define TSL2561_LUX_K3C           (0x00c8)  ///< 0.390 * 2^RATIO_SCALE
+#define TSL2561_LUX_B3C           (0x0253)  ///< 0.0363 * 2^LUX_SCALE
+#define TSL2561_LUX_M3C           (0x0363)  ///< 0.0529 * 2^LUX_SCALE
+#define TSL2561_LUX_K4C           (0x010a)  ///< 0.520 * 2^RATIO_SCALE
+#define TSL2561_LUX_B4C           (0x0282)  ///< 0.0392 * 2^LUX_SCALE
+#define TSL2561_LUX_M4C           (0x03df)  ///< 0.0605 * 2^LUX_SCALE
+#define TSL2561_LUX_K5C           (0x014d)  ///< 0.65 * 2^RATIO_SCALE
+#define TSL2561_LUX_B5C           (0x0177)  ///< 0.0229 * 2^LUX_SCALE
+#define TSL2561_LUX_M5C           (0x01dd)  ///< 0.0291 * 2^LUX_SCALE
+#define TSL2561_LUX_K6C           (0x019a)  ///< 0.80 * 2^RATIO_SCALE
+#define TSL2561_LUX_B6C           (0x0101)  ///< 0.0157 * 2^LUX_SCALE
+#define TSL2561_LUX_M6C           (0x0127)  ///< 0.0180 * 2^LUX_SCALE
+#define TSL2561_LUX_K7C           (0x029a)  ///< 1.3 * 2^RATIO_SCALE
+#define TSL2561_LUX_B7C           (0x0037)  ///< 0.00338 * 2^LUX_SCALE
+#define TSL2561_LUX_M7C           (0x002b)  ///< 0.00260 * 2^LUX_SCALE
+#define TSL2561_LUX_K8C           (0x029a)  ///< 1.3 * 2^RATIO_SCALE
+#define TSL2561_LUX_B8C           (0x0000)  ///< 0.000 * 2^LUX_SCALE
+#define TSL2561_LUX_M8C           (0x0000)  ///< 0.000 * 2^LUX_SCALE
+
+// Auto-gain thresholds
+#define TSL2561_AGC_THI_13MS      (4850)    ///< Max value at Ti 13ms = 5047
+#define TSL2561_AGC_TLO_13MS      (100)     ///< Min value at Ti 13ms = 100
+#define TSL2561_AGC_THI_101MS     (36000)   ///< Max value at Ti 101ms = 37177
+#define TSL2561_AGC_TLO_101MS     (200)     ///< Min value at Ti 101ms = 200
+#define TSL2561_AGC_THI_402MS     (63000)   ///< Max value at Ti 402ms = 65535
+#define TSL2561_AGC_TLO_402MS     (500)     ///< Min value at Ti 402ms = 500
+
+// Clipping thresholds  ///< # Counts that trigger a change in gain/integration
+#define TSL2561_CLIPPING_13MS     (4900)
+#define TSL2561_CLIPPING_101MS    (37000)
+#define TSL2561_CLIPPING_402MS    (65000)
+
+// Delay for integration times
+#define TSL2561_DELAY_INTTIME_13MS  (15)   ///< Wait 15ms for 13ms integration
+#define TSL2561_DELAY_INTTIME_101MS (120)  ///< Wait 120ms for 101ms integration
+#define TSL2561_DELAY_INTTIME_402MS (450)  ///< Wait 450ms for 402ms integration
+
+/*========================================================================*/
+/*                            CONSTRUCTORS                                */
+/*========================================================================*/
+
 TSL2561::TSL2561 (PinName p_sda, PinName p_scl)
- : _i2c_p(new I2C(p_sda, p_scl)), _i2c(*_i2c_p)
+    : _i2c_p(new I2C(p_sda, p_scl)), _i2c(*_i2c_p)
 {
-    TSL2561_addr = TSL2561_ADDRESS_GND;
+    _addr = TSL2561_ADDR_LOW;
     init();
 }
 
 TSL2561::TSL2561 (PinName p_sda, PinName p_scl, uint8_t addr)
- : _i2c_p(new I2C(p_sda, p_scl)), _i2c(*_i2c_p)
+    : _i2c_p(new I2C(p_sda, p_scl)), _i2c(*_i2c_p)
 {
-    TSL2561_addr = addr;
+    _addr = addr;
     init();
 }
 
 TSL2561::TSL2561 (I2C& p_i2c)
- : _i2c(p_i2c)
+    : _i2c(p_i2c)
 {
-    TSL2561_addr = TSL2561_ADDRESS_GND;
+    _addr = TSL2561_ADDR_LOW;
     init();
 }
 
 TSL2561::TSL2561 (I2C& p_i2c, uint8_t addr)
- : _i2c(p_i2c)
+    : _i2c(p_i2c)
 {
-    TSL2561_addr = addr;
+    _addr = addr;
     init();
 }
 
+/*========================================================================*/
+/*                           PUBLIC FUNCTIONS                             */
+/*========================================================================*/
 /////////////// Read Lux from sensor //////////////////////
 /*
 For 0    < CH1/CH0 < 0.50 Lux = 0.0304  x CH0-0.062  x CH0 x ((CH1/CH0)1.4)
@@ -56,25 +178,28 @@
     double ratio;
     double dlux;
 
-    dt[0] = CMD_MULTI + TSL2561_DATA0LOW;
-    _i2c.write((int)TSL2561_addr, (char *)dt, 1, true);
-    _i2c.read(TSL2561_addr, (char *)dt, 2, false);
-    ch0 = dt[1] << 8 | dt[0];
-    dt[0] = CMD_MULTI + TSL2561_DATA1LOW;
-    _i2c.write((int)TSL2561_addr, (char *)dt, 1, true);
-    _i2c.read(TSL2561_addr, (char *)dt, 2, false);
-    ch1 = dt[1] << 8 | dt[0];
-    if (ch0 == 0xFFFF) {
-        return 2500.0;
-    }
+    _TSL2561AutoGain = false;
+    _TSL2561IntegrationTime = TSL2561_INTEGRATIONTIME_13MS;
+    _TSL2561Gain = TSL2561_GAIN_1X;
+    /* Set default integration time and gain */
+    setIntegrationTime(_TSL2561IntegrationTime);
+    setGain(_TSL2561Gain);
+    uint16_t x0, x1;
+    getLuminosity(&x0, &x1);
+    ch0 = x0;
+    ch1 = x1;
+    //printf("ch0 = %d, ch1 = %d\r\n", ch0, ch1);
+    //printf("Integ. Time = %d, Gain %d\r\n",
+    //     _TSL2561IntegrationTime, _TSL2561Gain);
     lux0 = (double)ch0;
     lux1 = (double)ch1;
     ratio = lux1 / lux0;
     read_timing_reg();
-    lux0 *= (402.0/integ_time);
-    lux1 *= (402.0/integ_time);
+    lux0 *= (402.0/(double)integ_time);
+    lux1 *= (402.0/(double)integ_time);
     lux0 /= gain;
     lux1 /= gain;
+    //printf("Integ. Time = %f, Gain %d\r\n", integ_time, gain);
     if (ratio <= 0.5) {
         dlux = 0.03040 * lux0 - 0.06200 * lux0 * pow(ratio,1.4);
     } else if (ratio <= 0.61) {
@@ -86,54 +211,528 @@
     } else {
         dlux = 0;
     }
+    disable();
     return (float)dlux;
 }
 
-/////////////// Initialize ////////////////////////////////
-void TSL2561::init()
+float TSL2561::lux_auto(void)
+{
+    uint32_t data;
+
+    enableAutoRange(true);
+    getEvent(&data);
+    //printf("line:%d\r\n", __LINE__);
+    return (float)data;
+}
+
+/**************************************************************************/
+/*!
+    @brief  Initializes I2C connection and settings.
+    Attempts to determine if the sensor is contactable, then sets up a default
+    integration time and gain. Then powers down the chip.
+    @returns True if sensor is found and initialized, false otherwise.
+*/
+/**************************************************************************/
+bool TSL2561::init()
+{
+    _TSL2561Initialised = false;
+    _TSL2561AutoGain = false;
+    _TSL2561IntegrationTime = TSL2561_INTEGRATIONTIME_13MS;
+    _TSL2561Gain = TSL2561_GAIN_1X;
+
+    /* Make sure we're actually connected */
+    uint8_t x = read8(TSL2561_COMMAND_BIT | TSL2561_REGISTER_ID);
+    if (x & 0xF0 != 0x50) { // ID code for TSL2561
+        //printf("initialize error!\r\n");
+        return false;
+    }
+    //printf("ID=0x%02x\r\n", x);
+    _TSL2561Initialised = true;
+
+    /* Set default integration time and gain */
+    setIntegrationTime(_TSL2561IntegrationTime);
+    setGain(_TSL2561Gain);
+    read_timing_reg();
+
+    /* Note: by default, the device is in power down mode on bootup */
+    disable();
+
+    t.reset();
+    t.start();
+    //printf("Integ. Time = %d, Gain %d\r\n",
+    //         _TSL2561IntegrationTime, _TSL2561Gain);
+    //printf("initialize finished!\r\n");
+    x = read8(TSL2561_COMMAND_BIT | TSL2561_REGISTER_TIMING);
+    //printf("TIMING REG=0x%02x\r\n", x);
+    return true;
+}
+
+/**************************************************************************/
+/*!
+    @brief  Enables or disables the auto-gain settings when reading
+            data from the sensor
+    @param enable Set to true to enable, False to disable
+*/
+/**************************************************************************/
+void TSL2561::enableAutoRange(bool enable)
+{
+    _TSL2561AutoGain = enable ? true : false;
+}
+
+/**************************************************************************/
+/*!
+    @brief      Sets the integration time for the TSL2561. Higher time means
+                more light captured (better for low light conditions) but will
+        take longer to run readings.
+    @param time The amount of time we'd like to add up values
+*/
+/**************************************************************************/
+void TSL2561::setIntegrationTime(TSL2561IntegrationTime_t time)
+{
+    /* Enable the device by setting the control bit to 0x03 */
+    enable();
+    /* Update the timing register */
+    write8(TSL2561_COMMAND_BIT | TSL2561_REGISTER_TIMING, time | _TSL2561Gain);
+    /* Update value placeholders */
+    _TSL2561IntegrationTime = time;
+    /* Turn the device off to save power */
+    disable();
+}
+
+/**************************************************************************/
+/*!
+    @brief  Adjusts the gain on the TSL2561 (adjusts the sensitivity to light)
+    @param gain The value we'd like to set the gain to
+*/
+/**************************************************************************/
+void TSL2561::setGain(TSL2561Gain_t gain)
+{
+    /* Enable the device by setting the control bit to 0x03 */
+    enable();
+    /* Update the timing register */
+    write8(TSL2561_COMMAND_BIT | TSL2561_REGISTER_TIMING, _TSL2561IntegrationTime | gain);
+    /* Update value placeholders */
+    _TSL2561Gain = gain;
+    /* Turn the device off to save power */
+    disable();
+}
+
+/**************************************************************************/
+/*!
+    @brief  Gets the broadband (mixed lighting) and IR only values from
+            the TSL2561, adjusting gain if auto-gain is enabled
+    @param  broadband Pointer to a uint16_t we will fill with a sensor
+                      reading from the IR+visible light diode.
+    @param  ir Pointer to a uint16_t we will fill with a sensor the
+               IR-only light diode.
+*/
+/**************************************************************************/
+void TSL2561::getLuminosity (uint16_t *broadband, uint16_t *ir)
+{
+    bool valid = false;
+
+    /* If Auto gain disabled get a single reading and continue */
+    if(!_TSL2561AutoGain) {
+        //printf("Get data without Auto gain\r\n");
+        getData (broadband, ir);
+        return;
+    }
+    //printf("Get data with Auto gain\r\n");
+    /* Read data until we find a valid range */
+    bool _agcCheck = false;
+    do {
+        uint16_t _b, _ir;
+        uint16_t _hi, _lo;
+        TSL2561IntegrationTime_t _it = _TSL2561IntegrationTime;
+
+        /* Get the hi/low threshold for the current integration time */
+        switch(_it) {
+            case TSL2561_INTEGRATIONTIME_13MS:
+                _hi = TSL2561_AGC_THI_13MS;
+                _lo = TSL2561_AGC_TLO_13MS;
+                break;
+            case TSL2561_INTEGRATIONTIME_101MS:
+                _hi = TSL2561_AGC_THI_101MS;
+                _lo = TSL2561_AGC_TLO_101MS;
+                break;
+            default:
+                _hi = TSL2561_AGC_THI_402MS;
+                _lo = TSL2561_AGC_TLO_402MS;
+                break;
+        }
+
+        getData(&_b, &_ir);
+
+        /* Run an auto-gain check if we haven't already done so ... */
+        if (!_agcCheck) {
+            if ((_b < _lo) && (_TSL2561Gain == TSL2561_GAIN_1X)) {
+                /* Increase the gain and try again */
+                setGain(TSL2561_GAIN_16X);
+                /* Drop the previous conversion results */
+                getData(&_b, &_ir);
+                /* Set a flag to indicate we've adjusted the gain */
+                _agcCheck = true;
+            } else if ((_b > _hi) && (_TSL2561Gain == TSL2561_GAIN_16X)) {
+                /* Drop gain to 1x and try again */
+                setGain(TSL2561_GAIN_1X);
+                /* Drop the previous conversion results */
+                getData(&_b, &_ir);
+                /* Set a flag to indicate we've adjusted the gain */
+                _agcCheck = true;
+            } else {
+                /* Nothing to look at here, keep moving ....
+                   Reading is either valid, or we're already at the chips limits */
+                *broadband = _b;
+                *ir = _ir;
+                valid = true;
+            }
+        } else {
+            /* If we've already adjusted the gain once, just return the new results.
+               This avoids endless loops where a value is at one extreme pre-gain,
+               and the the other extreme post-gain */
+            *broadband = _b;
+            *ir = _ir;
+            valid = true;
+        }
+    } while (!valid);
+}
+
+/**************************************************************************/
+/*!
+    Enables the device
+*/
+/**************************************************************************/
+void TSL2561::enable(void)
+{
+    /* Enable the device by setting the control bit to 0x03 */
+    write8(TSL2561_COMMAND_BIT | TSL2561_REGISTER_CONTROL, TSL2561_CONTROL_POWERON);
+}
+
+/**************************************************************************/
+/*!
+    Disables the device (putting it in lower power sleep mode)
+*/
+/**************************************************************************/
+void TSL2561::disable(void)
+{
+    /* Turn the device off to save power */
+    write8(TSL2561_COMMAND_BIT | TSL2561_REGISTER_CONTROL, TSL2561_CONTROL_POWEROFF);
+}
+
+/**************************************************************************/
+/*!
+    Private function to read luminosity on both channels
+*/
+/**************************************************************************/
+void TSL2561::getData (uint16_t *broadband, uint16_t *ir)
 {
-    _i2c.frequency(100000);
-    power_up();
-    set_timing_reg(TIMING_DEFAULT);
+    /* Enable the device by setting the control bit to 0x03 */
+    enable();
+
+    /* Wait x ms for ADC to complete */
+    switch (_TSL2561IntegrationTime) {
+        case TSL2561_INTEGRATIONTIME_13MS:
+            wait_ms(TSL2561_DELAY_INTTIME_13MS);
+            break;
+        case TSL2561_INTEGRATIONTIME_101MS:
+            wait_ms(TSL2561_DELAY_INTTIME_101MS);
+            break;
+        default:
+            wait_ms(TSL2561_DELAY_INTTIME_402MS);
+            break;
+    }
+
+    /* Reads a two byte value from channel 0 (visible + infrared) */
+    *broadband = read16(TSL2561_COMMAND_BIT | TSL2561_WORD_BIT | TSL2561_REGISTER_CHAN0_LOW);
+
+    /* Reads a two byte value from channel 1 (infrared) */
+    *ir = read16(TSL2561_COMMAND_BIT | TSL2561_WORD_BIT | TSL2561_REGISTER_CHAN1_LOW);
+
+    /* Turn the device off to save power */
+    disable();
 }
 
+/**************************************************************************/
+/*!
+    @brief  Converts the raw sensor values to the standard SI lux equivalent.
+    @param  broadband The 16-bit sensor reading from the IR+visible light diode.
+    @param  ir The 16-bit sensor reading from the IR-only light diode.
+    @returns The integer Lux value we calcuated.
+             Returns 0 if the sensor is saturated and the values are
+             unreliable, or 65536 if the sensor is saturated.
+*/
+/**************************************************************************/
+/**************************************************************************/
+/*!
+
+    Returns
+*/
+/**************************************************************************/
+uint32_t TSL2561::calculateLux(uint16_t broadband, uint16_t ir)
+{
+    unsigned long chScale;
+    unsigned long channel1;
+    unsigned long channel0;
+
+    //printf("line:%d\r\n", __LINE__);
+    /* Make sure the sensor isn't saturated! */
+    uint16_t clipThreshold;
+    //printf("_TSL2561IntegrationTime=%d\r\n", _TSL2561IntegrationTime);
+    switch (_TSL2561IntegrationTime) {
+        case TSL2561_INTEGRATIONTIME_13MS:
+            clipThreshold = TSL2561_CLIPPING_13MS;
+            chScale = TSL2561_LUX_CHSCALE_TINT0;
+            //printf("line:%d\r\n", __LINE__);
+            break;
+        case TSL2561_INTEGRATIONTIME_101MS:
+            clipThreshold = TSL2561_CLIPPING_101MS;
+            chScale = TSL2561_LUX_CHSCALE_TINT1;
+            break;
+        default:
+            clipThreshold = TSL2561_CLIPPING_402MS;
+            chScale = (1 << TSL2561_LUX_CHSCALE);
+            break;
+    }
+    //printf("clipThreshold=%d\r\n", clipThreshold);
+    /* Return 65536 lux if the sensor is saturated */
+    if ((broadband > clipThreshold) || (ir > clipThreshold)) {
+        //printf("line:%d\r\n", __LINE__);
+        return 65536;
+    }
+
+    //printf("line:%d\r\n", __LINE__);
+    //printf("chScale=%d\r\n", chScale);
+    /* Scale for gain (1x or 16x) */
+    if (!_TSL2561Gain) {
+        chScale = chScale << 4;
+    }
+    //printf("chScale=%d\r\n", chScale);
+    /* Scale the channel values */
+    channel0 = (broadband * chScale) >> TSL2561_LUX_CHSCALE;
+    channel1 = (ir * chScale) >> TSL2561_LUX_CHSCALE;
+    //printf("channel0=%d, channel1=%d\r\n", channel0, channel1);
+
+    /* Find the ratio of the channel values (Channel1/Channel0) */
+    unsigned long ratio1 = 0;
+    if (channel0 != 0) {
+        ratio1 = (channel1 << (TSL2561_LUX_RATIOSCALE+1)) / channel0;
+    }
+
+    /* round the ratio value */
+    long ratio = (ratio1 + 1) >> 1;
+    //printf("ratio1=%d, ratio=%d\r\n", ratio1, ratio);
+    unsigned int b, m;
+
+#ifdef TSL2561_PACKAGE_CS
+    //printf("line:%d\r\n", __LINE__);
+    if ((ratio >= 0) && (ratio <= TSL2561_LUX_K1C)) {
+        b=TSL2561_LUX_B1C;
+        m=TSL2561_LUX_M1C;
+    } else if (ratio <= TSL2561_LUX_K2C) {
+        b=TSL2561_LUX_B2C;
+        m=TSL2561_LUX_M2C;
+    } else if (ratio <= TSL2561_LUX_K3C) {
+        b=TSL2561_LUX_B3C;
+        m=TSL2561_LUX_M3C;
+    } else if (ratio <= TSL2561_LUX_K4C) {
+        b=TSL2561_LUX_B4C;
+        m=TSL2561_LUX_M4C;
+    } else if (ratio <= TSL2561_LUX_K5C) {
+        b=TSL2561_LUX_B5C;
+        m=TSL2561_LUX_M5C;
+    } else if (ratio <= TSL2561_LUX_K6C) {
+        b=TSL2561_LUX_B6C;
+        m=TSL2561_LUX_M6C;
+    } else if (ratio <= TSL2561_LUX_K7C) {
+        b=TSL2561_LUX_B7C;
+        m=TSL2561_LUX_M7C;
+    } else if (ratio > TSL2561_LUX_K8C) {
+        b=TSL2561_LUX_B8C;
+        m=TSL2561_LUX_M8C;
+    }
+#else
+    //printf("line:%d\r\n", __LINE__);
+    if ((ratio >= 0) && (ratio <= TSL2561_LUX_K1T)) {
+        b=TSL2561_LUX_B1T;
+        m=TSL2561_LUX_M1T;
+    } else if (ratio <= TSL2561_LUX_K2T) {
+        b=TSL2561_LUX_B2T;
+        m=TSL2561_LUX_M2T;
+    } else if (ratio <= TSL2561_LUX_K3T) {
+        b=TSL2561_LUX_B3T;
+        m=TSL2561_LUX_M3T;
+    } else if (ratio <= TSL2561_LUX_K4T) {
+        b=TSL2561_LUX_B4T;
+        m=TSL2561_LUX_M4T;
+    } else if (ratio <= TSL2561_LUX_K5T) {
+        b=TSL2561_LUX_B5T;
+        m=TSL2561_LUX_M5T;
+    } else if (ratio <= TSL2561_LUX_K6T) {
+        b=TSL2561_LUX_B6T;
+        m=TSL2561_LUX_M6T;
+    } else if (ratio <= TSL2561_LUX_K7T) {
+        b=TSL2561_LUX_B7T;
+        m=TSL2561_LUX_M7T;
+    } else if (ratio > TSL2561_LUX_K8T) {
+        b=TSL2561_LUX_B8T;
+        m=TSL2561_LUX_M8T;
+    }
+#endif
+
+    long temp;
+    temp = ((channel0 * b) - (channel1 * m));
+
+    /* Do not allow negative lux value */
+    if (temp < 0L) {
+        temp = 0;
+    }
+    //printf("line:%d\r\n", __LINE__);
+    /* Round lsb (2^(LUX_SCALE-1)) */
+    temp += (1 << (TSL2561_LUX_LUXSCALE-1));
+
+    /* Strip off fractional portion */
+    uint32_t lux = temp >> TSL2561_LUX_LUXSCALE;
+
+    /* Signal I2C had no errors */
+    //printf("Lux=%d\r\n", lux);
+    return lux;
+}
+
+/**************************************************************************/
+/*!
+    @brief  Gets the most recent sensor event
+    @param  event Pointer to a sensor_event_t type that will be filled
+                  with the lux value, timestamp, data type and sensor ID.
+    @returns True if sensor reading is between 0 and 65535 lux,
+             false if sensor is saturated
+*/
+/**************************************************************************/
+bool TSL2561::getEvent(uint32_t *event)
+{
+    uint16_t broadband, ir;
+
+    /* Calculate the actual lux value */
+    getLuminosity(&broadband, &ir);
+    //printf("broadband=%d, ir=%d\r\n", broadband, ir);
+    *event = calculateLux(broadband, ir);
+    //printf("LUX=%f\r\n", event->light);
+    //printf("LUX=%d\r\n", *event);
+    //printf("line:%d\r\n", __LINE__);
+    if (*event == 65536) {
+        //printf("line:%d\r\n", __LINE__);
+        return false;
+    }
+    //printf("line:%d\r\n", __LINE__);
+    return true;
+}
+
+/**************************************************************************/
+/*!
+    @brief  Gets the sensor_t data
+    @param  sensor A pointer to a sensor_t structure that we will fill with
+                   details about the TSL2561 and its capabilities
+*/
+/**************************************************************************/
+void TSL2561::getSensor(sensor_t *sensor)
+{
+    /* Insert the sensor name in the fixed length char array */
+    //sensor->version     = 1;
+    sensor->min_delay   = 0;
+    sensor->max_value   = 17000.0;  /* Based on trial and error ... confirm! */
+    sensor->min_value   = 1.0;
+    sensor->resolution  = 1.0;
+}
+
+/*========================================================================*/
+/*                          PRIVATE FUNCTIONS                             */
+/*========================================================================*/
+
+/**************************************************************************/
+/*!
+    @brief  Writes a register and an 8 bit value over I2C
+    @param  reg I2C register to write the value to
+    @param  value The 8-bit value we're writing to the register
+*/
+/**************************************************************************/
+void TSL2561::write8 (uint8_t reg, uint8_t value)
+{
+    dt[0] = reg;
+    dt[1] = value;
+    _i2c.write((int)_addr, (char *)dt, 2, false);
+}
+
+/**************************************************************************/
+/*!
+    @brief  Reads an 8 bit value over I2C
+    @param  reg I2C register to read from
+    @returns 8-bit value containing single byte data read
+*/
+/**************************************************************************/
+uint8_t TSL2561::read8(uint8_t reg)
+{
+    dt[0] = reg;
+    _i2c.write((int)_addr, (char *)dt, 1, true);
+    _i2c.read(_addr, (char *)dt, 1, false);
+    return dt[0];
+}
+
+/**************************************************************************/
+/*!
+    @brief  Reads a 16 bit values over I2C
+    @param  reg I2C register to read from
+    @returns 16-bit value containing 2-byte data read
+*/
+/**************************************************************************/
+uint16_t TSL2561::read16(uint8_t reg)
+{
+    dt[0] = reg;
+    _i2c.write((int)_addr, (char *)dt, 1, true);
+    _i2c.read(_addr, (char *)dt, 2, false);
+    uint16_t data = ((uint16_t)dt[1] << 8) + dt[0];
+    return data;
+}
+
+/*========================================================================*/
+/*   JH1PJL Original Functions  -> Keep compacibility for older revision  */
+/*========================================================================*/
+
 /////////////// Timing Register ///////////////////////////
 uint8_t TSL2561::set_timing_reg(uint8_t parameter)
 {
-    dt[0] = CMD_SINGLE + TSL2561_TIMING;
-    dt[1] = parameter;
-    _i2c.write((int)TSL2561_addr, (char *)dt, 2, false);
-    dt[0] = CMD_SINGLE + TSL2561_TIMING;
-    _i2c.write((int)TSL2561_addr, (char *)dt, 1, true);
-    _i2c.read(TSL2561_addr, (char *)dt, 1, false);
-    return dt[0];
+    enable();
+    write8(TSL2561_COMMAND_BIT | TSL2561_REGISTER_TIMING, parameter);
+    return read8(TSL2561_COMMAND_BIT | TSL2561_REGISTER_TIMING);
 }
 
 uint8_t TSL2561::read_timing_reg(void)
 {
-    uint8_t i;
+    uint8_t i, data;
 
-    dt[0] = CMD_SINGLE + TSL2561_TIMING;
-    _i2c.write((int)TSL2561_addr, (char *)dt, 1, true);
-    _i2c.read(TSL2561_addr, (char *)dt, 1, false);
-    if (dt[0] & TIMING_GAIN_16){
+    data = read8(TSL2561_COMMAND_BIT | TSL2561_REGISTER_TIMING);
+    if (data & TSL2561_GAIN_16X) {
         gain = 16;
+        _TSL2561Gain = TSL2561_GAIN_16X;
     } else {
         gain = 1;
+        _TSL2561Gain = TSL2561_GAIN_1X;
     }
-    i = dt[0] & 0x3;
+    i = data & 0x3;
     switch (i) {
         case 0:
             integ_time = 13.7;
+            _TSL2561IntegrationTime = TSL2561_INTEGRATIONTIME_13MS;
             break;
         case 1:
             integ_time = 101.0;
+            _TSL2561IntegrationTime = TSL2561_INTEGRATIONTIME_101MS;
             break;
         case 2:
             integ_time = 402.0;
+            _TSL2561IntegrationTime = TSL2561_INTEGRATIONTIME_402MS;
             break;
         default:
             integ_time = 0;
+            _TSL2561IntegrationTime = TSL2561_INTEGRATIONTIME_13MS;
             break;
     }
     return dt[0];
@@ -142,10 +741,7 @@
 /////////////// ID ////////////////////////////////////////
 uint8_t TSL2561::read_ID()
 {
-    dt[0] = CMD_SINGLE + TSL2561_ID;
-    _i2c.write((int)TSL2561_addr, (char *)dt, 1, true);
-    _i2c.read(TSL2561_addr, (char *)dt, 2, false);
-    id_number = dt[0];
+    id_number = read8(TSL2561_COMMAND_BIT | TSL2561_REGISTER_ID);
     return id_number;
 }
 
@@ -164,16 +760,12 @@
 /////////////// Power ON/OFF //////////////////////////////
 void TSL2561::power_up()
 {
-    dt[0] = CMD_SINGLE + TSL2561_CONTROL;
-    dt[1] = 3;
-    _i2c.write((int)TSL2561_addr, (char *)dt, 2, false);
+    enable();
 }
 
 void TSL2561::power_down()
 {
-    dt[0] = CMD_SINGLE + TSL2561_CONTROL;
-    dt[1] = 0;
-    _i2c.write((int)TSL2561_addr, (char *)dt, 2, false);
+    disable();
 }
 
 /////////////// I2C Freq. /////////////////////////////////
@@ -181,4 +773,3 @@
 {
     _i2c.frequency(hz);
 }
-