From be334245ffe4f76404f98745e1eb9698ed6ff037 Mon Sep 17 00:00:00 2001 From: Florian Eitel Date: Sun, 4 Aug 2019 11:56:18 +0200 Subject: [PATCH] Refactor sensor interface with extra files and function pointer That makes it easier to enable/disable sensors. Also added support for APDS9930 --- firmware/config_user.h.example | 6 +- firmware/firmware.ino | 105 +- .../libraries/APDS9930-master/.gitattributes | 22 + firmware/libraries/APDS9930-master/.gitignore | 192 +++ firmware/libraries/APDS9930-master/LICENSE | 22 + firmware/libraries/APDS9930-master/README.md | 92 ++ .../AmbientLightInterrupt.ino | 180 +++ .../AmbientLightLED/AmbientLightLED.ino | 113 ++ .../AmbientLightSensor/AmbientLightSensor.ino | 120 ++ .../AmbientLightToneAC/AmbientLightToneAC.ino | 108 ++ .../ProximityInterrupt/ProximityInterrupt.ino | 157 +++ .../examples/ProximityLED/ProximityLED.ino | 131 ++ .../ProximitySensor/ProximitySensor.ino | 113 ++ .../libraries/APDS9930-master/keywords.txt | 0 .../APDS9930-master/library.properties | 9 + .../APDS9930-master/src/APDS9930.cpp | 1147 +++++++++++++++++ .../libraries/APDS9930-master/src/APDS9930.h | 231 ++++ firmware/sensor_apds9930.ino | 23 + firmware/sensor_apds9960.ino | 27 + firmware/sensor_battery.ino | 48 + firmware/sensor_bme280.ino | 24 + firmware/sensor_wind.ino | 23 + firmware/sensors.ino | 75 -- firmware/webUpdater.ino | 2 +- 24 files changed, 2832 insertions(+), 138 deletions(-) create mode 100644 firmware/libraries/APDS9930-master/.gitattributes create mode 100644 firmware/libraries/APDS9930-master/.gitignore create mode 100644 firmware/libraries/APDS9930-master/LICENSE create mode 100644 firmware/libraries/APDS9930-master/README.md create mode 100644 firmware/libraries/APDS9930-master/examples/AmbientLightInterrupt/AmbientLightInterrupt.ino create mode 100644 firmware/libraries/APDS9930-master/examples/AmbientLightLED/AmbientLightLED.ino create mode 100644 firmware/libraries/APDS9930-master/examples/AmbientLightSensor/AmbientLightSensor.ino create mode 100644 firmware/libraries/APDS9930-master/examples/AmbientLightToneAC/AmbientLightToneAC.ino create mode 100644 firmware/libraries/APDS9930-master/examples/ProximityInterrupt/ProximityInterrupt.ino create mode 100644 firmware/libraries/APDS9930-master/examples/ProximityLED/ProximityLED.ino create mode 100644 firmware/libraries/APDS9930-master/examples/ProximitySensor/ProximitySensor.ino create mode 100644 firmware/libraries/APDS9930-master/keywords.txt create mode 100644 firmware/libraries/APDS9930-master/library.properties create mode 100644 firmware/libraries/APDS9930-master/src/APDS9930.cpp create mode 100644 firmware/libraries/APDS9930-master/src/APDS9930.h create mode 100644 firmware/sensor_apds9930.ino create mode 100644 firmware/sensor_apds9960.ino create mode 100644 firmware/sensor_battery.ino create mode 100644 firmware/sensor_bme280.ino create mode 100644 firmware/sensor_wind.ino delete mode 100644 firmware/sensors.ino diff --git a/firmware/config_user.h.example b/firmware/config_user.h.example index f3491b6..7bdc598 100644 --- a/firmware/config_user.h.example +++ b/firmware/config_user.h.example @@ -10,6 +10,11 @@ // Enable/Disable features //#define WEBUPDATER_FEATURE #define BATTERY_POWERED +#define SENSOR_WIND +#define SENSOR_APDS9960 +//#define SENSOR_APDS9930 +#define SENSOR_BME280 +#define SENSOR_BATTERY const float HUMIDITY_FACTOR = 1.0; const float LIGHT_FACTOR = 1.0; @@ -27,4 +32,3 @@ const char *INFLUXDB_PASS = "password"; String DEVICE_NAME = "devicename"; #endif - diff --git a/firmware/firmware.ino b/firmware/firmware.ino index e0475f4..3111d48 100644 --- a/firmware/firmware.ino +++ b/firmware/firmware.ino @@ -18,8 +18,6 @@ #include // WiFiClient #include // WiFiManager #include // https://github.com/hwwong/ESP8266Influxdb auchecken und den ordner in das arduino\library verzeichnis kopieren -#include // Adafruit APDS9960 - https://www.makerfabs.com/index.php?route=product/product&product_id=281 -#include // BME280 - https://www.roboter-bausatz.de/1704/bmp280-barometer-luftdrucksensor?gclid=EAIaIQobChMIlpumj8Hp2wIVFWYbCh01PgmFEAQYAyABEgIwBvD_BwE // Project includes #include "config.h" @@ -49,18 +47,15 @@ //*************************************************************************// -float currentSensorData[8] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; +const uint8_t VALUES = 8; +float currentSensorData[VALUES] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; +float (*sensors[VALUES])() = {}; uint16_t update_sensor_cnt = 0; uint16_t update_webserver_cnt = 0; -uint16_t energySavingIterations = 0; WiFiManager wifiManager; Influxdb influxdb(INFLUXDB_HOST, INFLUXDB_PORT); -Adafruit_APDS9960 apds; -Adafruit_BME280 bme; - -bool apds_connected = false; #ifdef WEBUPDATER_FEATURE String localIP = "127.0.0.1"; @@ -117,21 +112,36 @@ void setup() { influxdb.opendb(INFLUXDB_DB, INFLUXDB_USER, INFLUXDB_PASS); // Initialize and configure the sensors - //Light Sensor - if (apds.begin()) { - apds_connected = true; - apds.enableColor(true); +#ifdef SENSOR_APDS9930 + if (sensor_apds9930_begin()) { + sensors[SENSOR_LIGHT] = &apds9930_light; } +#endif - debug("APDS Connected!"); +#ifdef SENSOR_APDS9960 + if (sensor_apds9960_begin()) { + sensors[SENSOR_LIGHT] = &apds9930_light; + } +#endif +#ifdef SENSOR_BME280 //Temperature + pressure - bool status = bme.begin(BME_ADDRESS); - if (!status) { - debug("Could not find a valid BME280 sensor, check wiring!"); - //#warning TODO: FIXME while (1); + if (sensor_bme280_begin(BME_ADDRESS)) { + sensors[SENSOR_TEMPERATURE] = &bme280_temperature; + sensors[SENSOR_HUMIDITY] = &bme280_humidity; + sensors[SENSOR_PRESSURE] = &bme280_pressure; } - debug("BME Connected!"); +#endif + +#ifdef SENSOR_WIND + sensors[SENSOR_WINDSPEED] = &wind_speed; +#endif + +#ifdef SENSOR_BATTERY + sensors[SENSOR_BAT_VOLTAGE] = &battery_voltage; + sensors[SENSOR_BATCHARGESTATE] = &battery_charging; + sensors[SENSOR_ESAVEMODE] = &isEnergySavingMode; +#endif #ifdef WEBUPDATER_FEATURE #ifndef BATTERY_POWERED @@ -166,7 +176,7 @@ void setup() { #ifdef BATTERY_POWERED void criticalBatCheck() { - float volt = getBatteryVoltage(); + float volt = battery_voltage(); if (volt <= BAT_EMERGENCY_DEEPSLEEP_VOLTAGE) { debug("Bat Voltage: " + String(volt) + " V"); debug("Low battery, going into deep sleep."); @@ -177,26 +187,6 @@ void criticalBatCheck() { } #endif -#ifdef BATTERY_POWERED -int energySavingMode() { - // Give the solar panel some time to load the cell to prevent - // flapping. - if (energySavingIterations > 0) { - energySavingIterations--; - return 1; - } - - // Is the battery low? - if (currentSensorData[SENSOR_BAT_VOLTAGE] <= BAT_LOW_VOLTAGE) { - // Entering energy saving - energySavingIterations = ENERGY_SAVING_ITERATIONS; - - return 1; - } - - return 0; -} -#endif void loop() { #ifdef BATTERY_POWERED @@ -232,32 +222,25 @@ void _loop() { } #endif - update_sensor_cnt = 0; - currentSensorData[SENSOR_TEMPERATURE] = fetchTemperature(); - currentSensorData[SENSOR_HUMIDITY] = fetchHumidity(); - if (apds_connected) { - currentSensorData[SENSOR_LIGHT] = fetchLight(); - } - currentSensorData[SENSOR_PRESSURE] = fetchPressure(); -#ifdef BATTERY_POWERED - currentSensorData[SENSOR_BAT_VOLTAGE] = getBatteryVoltage(); - currentSensorData[SENSOR_BATCHARGESTATE] = isBatCharging(); -#else - currentSensorData[SENSOR_BAT_VOLTAGE] = 0xFFFFFFFF; - currentSensorData[SENSOR_BATCHARGESTATE] = 0xFFFFFFFF; -#endif -#ifdef BATTERY_POWERED + +#ifdef defined(BATTERY_POWERED) && defined(SENSOR_WIND) + if (energySavingMode() == 1) { // Disable expensive tasks - if (energySavingMode() == 0) { + sensors[SENSOR_WINDSPEED] = 0; + } else { + sensors[SENSOR_WINDSPEED] = &wind_speed; + } #endif - currentSensorData[SENSOR_WINDSPEED] = fetchWindspeed(); - currentSensorData[SENSOR_ESAVEMODE] = ENERGY_SAVE_MODE_DISABLED; -#ifdef BATTERY_POWERED + + update_sensor_cnt = 0; + + for (uint8_t i = 0; i < VALUES; i++) { + if (sensors[i]) { + currentSensorData[i] = sensors[i](); } else { - currentSensorData[SENSOR_WINDSPEED] = 0xFFFFFFFF; - currentSensorData[SENSOR_ESAVEMODE] = ENERGY_SAVE_MODE_ENABLED; + currentSensorData[i] = 0xFFFFFFFF; } -#endif + } debug(""); debug("Current readings:"); diff --git a/firmware/libraries/APDS9930-master/.gitattributes b/firmware/libraries/APDS9930-master/.gitattributes new file mode 100644 index 0000000..412eeda --- /dev/null +++ b/firmware/libraries/APDS9930-master/.gitattributes @@ -0,0 +1,22 @@ +# Auto detect text files and perform LF normalization +* text=auto + +# Custom for Visual Studio +*.cs diff=csharp +*.sln merge=union +*.csproj merge=union +*.vbproj merge=union +*.fsproj merge=union +*.dbproj merge=union + +# Standard to msysgit +*.doc diff=astextplain +*.DOC diff=astextplain +*.docx diff=astextplain +*.DOCX diff=astextplain +*.dot diff=astextplain +*.DOT diff=astextplain +*.pdf diff=astextplain +*.PDF diff=astextplain +*.rtf diff=astextplain +*.RTF diff=astextplain diff --git a/firmware/libraries/APDS9930-master/.gitignore b/firmware/libraries/APDS9930-master/.gitignore new file mode 100644 index 0000000..2778edb --- /dev/null +++ b/firmware/libraries/APDS9930-master/.gitignore @@ -0,0 +1,192 @@ +################# +## SparkFun Useful stuff +################# + +## AVR Development +*.eep +*.elf +*.lst +*.lss +*.sym +*.d +*.o +*.srec +*.map + +## Notepad++ backup files +*.bak + +## BOM files +*bom* + +################# +## Eclipse +################# + +*.pydevproject +.project +.metadata +bin/ +tmp/ +*.tmp +*.bak +*.swp +*~.nib +local.properties +.classpath +.settings/ +.loadpath + +# External tool builders +.externalToolBuilders/ + +# Locally stored "Eclipse launch configurations" +*.launch + +# CDT-specific +.cproject + +# PDT-specific +.buildpath + + +############# +## Eagle +############# + +# Ignore the board and schematic backup files +*.b#? +*.s#? + + +################# +## Visual Studio +################# + +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results +[Dd]ebug/ +[Rr]elease/ +*_i.c +*_p.c +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.vspscc +.builds +*.dotCover + +## TODO: If you have NuGet Package Restore enabled, uncomment this +#packages/ + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf + +# Visual Studio profiler +*.psess +*.vsp + +# ReSharper is a .NET coding add-in +_ReSharper* + +# Installshield output folder +[Ee]xpress + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish + +# Others +[Bb]in +[Oo]bj +sql +TestResults +*.Cache +ClientBin +stylecop.* +~$* +*.dbmdl +Generated_Code #added for RIA/Silverlight projects + +# Backup & report files from converting an old project file to a newer +# Visual Studio version. Backup files are not needed, because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML + + +############ +## Windows +############ + +# Windows image file caches +Thumbs.db + +# Folder config file +Desktop.ini + + +############# +## Python +############# + +*.py[co] + +# Packages +*.egg +*.egg-info +dist +build +eggs +parts +bin +var +sdist +develop-eggs +.installed.cfg + +# Installer logs +pip-log.txt + +# Unit test / coverage reports +.coverage +.tox + +#Translations +*.mo + +#Mr Developer +.mr.developer.cfg + +# Mac crap +.DS_Store diff --git a/firmware/libraries/APDS9930-master/LICENSE b/firmware/libraries/APDS9930-master/LICENSE new file mode 100644 index 0000000..9d6e5b5 --- /dev/null +++ b/firmware/libraries/APDS9930-master/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2015 Davide Depau + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/firmware/libraries/APDS9930-master/README.md b/firmware/libraries/APDS9930-master/README.md new file mode 100644 index 0000000..ce60370 --- /dev/null +++ b/firmware/libraries/APDS9930-master/README.md @@ -0,0 +1,92 @@ +APDS9930 Ambient Light and Proximity sensor +=========================================== + +This is a fork of the [library from Sparkfun for the APDS-9960 sensor](https://github.com/sparkfun/APDS-9960_RGB_and_Gesture_Sensor). It has been adapted to read values from this other model. + +[**Quick-start guide available here**](https://web.archive.org/web/20151224052223/http://davideddu.org/blog/posts/apds-9930-arduino-quickstart/) + +[**Purchase an Avago APDS-9930 Breakout Board here**](http://www.dx.com/p/384037?Utm_rid=14976370&Utm_source=affiliate) + + +# DO NOT EMAIL ME IF YOU HAVE AN ISSUE +It will be deleted without reading. If you have an issue, [create an issue](https://github.com/Depau/APDS9930/issues) here on GitHub. + +# Unmaintained +I'm not going to maintain this library any more. I will merge pull requests, though. Contributions are welcome. Just don't expect anything from me. + +![Avago APDS-9930 Breakout Board](http://img.dxcdn.com/productimages/sku_384037_1.jpg) + +**Note:** even though it says APDS-9960, it's an APDS-9930. That's how I ended up getting one of those. I wanted the RGB sensor. I found this crap in my mailbox. But I decided to write a library for it anyways ;) + +Getting Started +--------------- + +* Download the Git repository as a ZIP ("Download ZIP" button) +* Unzip +* Copy the entire library directory (APDS-9930) to +\/libraries +* Open the Arduino program +* Select File -> Examples -> APDS9930 -> GestureTest +* Plug in your Arduino and APDS-9930 with the following connections + +*-OR-* + +* Use the library manager + +| Arduino Pin | APDS-9930 Board | Function | +|---|---|---| +| 3.3V | VCC | Power | +| GND | GND | Ground | +| A4 | SDA | I²C Data | +| A5 | SCL | I²C Clock | +| 2 | INT | Interrupt | + +*P.S.: you already know you can't use this purple little thing with your 5V Arduino without a level shifter, right? :) In case you don't have a level shifter, you can detach the microcontroller from an Arduino Uno, reconnect the oscillator pins, the RX and TX pins, the reset and the LED/SCK pins back to the board with some jumper wires. You can then power the microcontroller from a 3.3V source (the 3V3 output on the board should work) and connect the sensor directly to the MCU. Look up "Arduino on Breadboard".* + +* Go to Tools -> Board and select your Arduino board +* Go to Tools -> Serial Port and select the COM port of your Arduino board +* Click "Upload" +* Go to Tools -> Serial Monitor +* Ensure the baud rate is set at 9600 baud +* Swipe your hand over the sensor in various directions! + +Repository Contents +------------------- + +* **/examples** - Example sketches for the library (.ino). Run these from the Arduino IDE. +* **/extras** - Additional documentation for the user. These files are ignored by the IDE. +* **/src** - Source files for the library (.cpp, .h). +* **keywords.txt** - Keywords from this library that will be highlighted in the Arduino IDE. +* **library.properties** - General library properties for the Arduino package manager. + +Documentation +-------------- + +* **[Quickstart Guide](https://web.archive.org/web/20151224052223/http://davideddu.org/blog/posts/apds-9930-arduino-quickstart/)** - Basic hookup guide for the sensor. +* **[Product Repository](https://github.com/Davideddu/APDS9930)** - Main repository (including hardware files) for the APDS9930 ambient light and proximity sensor. +* **[Installing an Arduino Library Guide](https://learn.sparkfun.com/tutorials/installing-an-arduino-library)** - Basic information on how to install an Arduino library. + + +Version History +--------------- +* master - Adapted for use with APDS-9930 +* [V_1.4.0](https://github.com/sparkfun/APDS-9960_RGB_and_Gesture_Sensor_Arduino_Library/tree/V_1.4.0) - Updated to new library structure +* V_1.3.0 - Implemented disableProximitySensor(). Thanks to jmg5150 for catching that! +* V_1.2.0 - Added pinMode line to GestureTest demo to fix interrupt bug with some Arduinos +* V_1.1.0 - Updated GestureTest demo to not freeze with fast swipes +* V_1.0.0: Initial release +* Ambient and RGB light sensing implemented +* Ambient light interrupts working +* Proximity sensing implemented +* Proximity interrupts working + +License Information +------------------- + +This product is _**open source**_! + +Please use, reuse, and modify these files as you see fit. Please maintain attribution to SparkFun Electronics and release anything derivative under the same license. + +Distributed as-is; no warranty is given. + +- Your friends at SparkFun. And Davide Depau :* diff --git a/firmware/libraries/APDS9930-master/examples/AmbientLightInterrupt/AmbientLightInterrupt.ino b/firmware/libraries/APDS9930-master/examples/AmbientLightInterrupt/AmbientLightInterrupt.ino new file mode 100644 index 0000000..2c44b52 --- /dev/null +++ b/firmware/libraries/APDS9930-master/examples/AmbientLightInterrupt/AmbientLightInterrupt.ino @@ -0,0 +1,180 @@ +/**************************************************************** +AmbientLightInterrupt.ino +APDS-9930 RGB and Gesture Sensor +Shawn Hymel @ SparkFun Electronics +October 24, 2014 +https://github.com/sparkfun/APDS-9930_RGB_and_Gesture_Sensor + +Tests the ambient light interrupt abilities of the APDS-9930. +Configures the APDS-9930 over I2C and waits for an external +interrupt based on high or low light conditions. Try covering +the sensor with your hand or bringing the sensor close to a +bright light source. You might need to adjust the LIGHT_INT_HIGH +and LIGHT_INT_LOW values to get the interrupt to work correctly. + +Hardware Connections: + +IMPORTANT: The APDS-9930 can only accept 3.3V! + + Arduino Pin APDS-9930 Board Function + + 3.3V VCC Power + GND GND Ground + A4 SDA I2C Data + A5 SCL I2C Clock + 2 INT Interrupt + 13 - LED + +Resources: +Include Wire.h and APDS9930.h + +Development environment specifics: +Written in Arduino 1.0.5 +Tested with SparkFun Arduino Pro Mini 3.3V + +This code is beerware; if you see me (or any other SparkFun +employee) at the local, and you've found our code helpful, please +buy us a round! + +Distributed as-is; no warranty is given. +****************************************************************/ + +#define DUMP_REGS + +#include +#include + +// Pins +#define APDS9930_INT 2 // Needs to be an interrupt pin +#define LED_PIN 13 // LED for showing interrupt + +// Constants +#define LIGHT_INT_HIGH 1000 // High light level for interrupt +#define LIGHT_INT_LOW 10 // Low light level for interrupt + +// Global variables +APDS9930 apds = APDS9930(); +float ambient_light = 0; +uint16_t ch0 = 0; +uint16_t ch1 = 1; +volatile bool isr_flag = false; +uint16_t threshold = 0; + +void setup() { + + // Set LED as output + pinMode(LED_PIN, OUTPUT); + pinMode(APDS9930_INT, INPUT); + + // Initialize Serial port + Serial.begin(9600); + Serial.println(); + Serial.println(F("----------------------------")); + Serial.println(F("APDS-9930 - Light Interrupts")); + Serial.println(F("----------------------------")); + + // Initialize interrupt service routine + attachInterrupt(0, interruptRoutine, FALLING); + + // Initialize APDS-9930 (configure I2C and initial values) + if ( apds.init() ) { + Serial.println(F("APDS-9930 initialization complete")); + } else { + Serial.println(F("Something went wrong during APDS-9930 init!")); + } + + // Set high and low interrupt thresholds + if ( !apds.setLightIntLowThreshold(LIGHT_INT_LOW) ) { + Serial.println(F("Error writing low threshold")); + } + if ( !apds.setLightIntHighThreshold(LIGHT_INT_HIGH) ) { + Serial.println(F("Error writing high threshold")); + } + + // Start running the APDS-9930 light sensor (no interrupts) + if ( apds.enableLightSensor(false) ) { + Serial.println(F("Light sensor is now running")); + } else { + Serial.println(F("Something went wrong during light sensor init!")); + } + + // Read high and low interrupt thresholds + if ( !apds.getLightIntLowThreshold(threshold) ) { + Serial.println(F("Error reading low threshold")); + } else { + Serial.print(F("Low Threshold: ")); + Serial.println(threshold); + } + if ( !apds.getLightIntHighThreshold(threshold) ) { + Serial.println(F("Error reading high threshold")); + } else { + Serial.print(F("High Threshold: ")); + Serial.println(threshold); + } + + // Enable interrupts + if ( !apds.setAmbientLightIntEnable(1) ) { + Serial.println(F("Error enabling interrupts")); + } + +#ifdef DUMP_REGS + /* Register dump */ + uint8_t reg; + uint8_t val; + + for(reg = 0x00; reg <= 0x19; reg++) { + if( (reg != 0x10) && \ + (reg != 0x11) ) + { + apds.wireReadDataByte(reg, val); + Serial.print(reg, HEX); + Serial.print(": 0x"); + Serial.println(val, HEX); + } + } + apds.wireReadDataByte(0x1E, val); + Serial.print(0x1E, HEX); + Serial.print(": 0x"); + Serial.println(val, HEX); +#endif + + // Wait for initialization and calibration to finish + delay(500); +} + +void loop() { + + // If interrupt occurs, print out the light levels + if ( isr_flag ) { + + // Read the light levels (ambient, red, green, blue) and print + if ( !apds.readAmbientLightLux(ambient_light) || + !apds.readCh0Light(ch0) || + !apds.readCh1Light(ch1) ) { + Serial.println("Error reading light values"); + } else { + Serial.print("Interrupt! Ambient: "); + Serial.print(ambient_light); + Serial.print(F(" Ch0: ")); + Serial.print(ch0); + Serial.print(F(" Ch1: ")); + Serial.println(ch1); + } + + // Turn on LED for a half a second + digitalWrite(LED_PIN, HIGH); + delay(500); + digitalWrite(LED_PIN, LOW); + + // Reset flag and clear APDS-9930 interrupt (IMPORTANT!) + isr_flag = false; + if ( !apds.clearAmbientLightInt() ) { + Serial.println("Error clearing interrupt"); + } + + } +} + +void interruptRoutine() { + isr_flag = true; +} \ No newline at end of file diff --git a/firmware/libraries/APDS9930-master/examples/AmbientLightLED/AmbientLightLED.ino b/firmware/libraries/APDS9930-master/examples/AmbientLightLED/AmbientLightLED.ino new file mode 100644 index 0000000..1cd8869 --- /dev/null +++ b/firmware/libraries/APDS9930-master/examples/AmbientLightLED/AmbientLightLED.ino @@ -0,0 +1,113 @@ +/**************************************************************** +AmbientLightLED.ino + +Tests the ambient light sensing abilities of the +APDS-9930. Configures APDS-9930 over I2C and polls the sensor for +ambient light levels, which are displayed over the +serial console. + +Hardware Connections: + +IMPORTANT: The APDS-9930 can only accept 3.3V! + + Arduino Pin APDS-9930 Board Function + + 3.3V VCC Power + GND GND Ground + A4 SDA I2C Data + A5 SCL I2C Clock + + 10 (pwm) LED anode + +Distributed as-is; no warranty is given. +****************************************************************/ + +#define PWM_LED_PIN 10 +#define DUMP_REGS + +#include +#include + +// Global Variables +APDS9930 apds = APDS9930(); +float ambient_light = 0; // can also be an unsigned long +uint16_t ch0 = 0; +uint16_t ch1 = 1; +float max_light = 0; + +void setup() { + //analogReference(EXTERNAL); + pinMode(PWM_LED_PIN, OUTPUT); + + // Initialize Serial port + Serial.begin(9600); + Serial.println(); + Serial.println(F("--------------------------------")); + Serial.println(F("APDS-9930 - Ambient light sensor")); + Serial.println(F("--------------------------------")); + + // Initialize APDS-9930 (configure I2C and initial values) + if ( apds.init() ) { + Serial.println(F("APDS-9930 initialization complete")); + } else { + Serial.println(F("Something went wrong during APDS-9930 init!")); + } + + // Start running the APDS-9930 light sensor (no interrupts) + if ( apds.enableLightSensor(false) ) { + Serial.println(F("Light sensor is now running")); + } else { + Serial.println(F("Something went wrong during light sensor init!")); + } + +#ifdef DUMP_REGS + /* Register dump */ + uint8_t reg; + uint8_t val; + + for(reg = 0x00; reg <= 0x19; reg++) { + if( (reg != 0x10) && \ + (reg != 0x11) ) + { + apds.wireReadDataByte(reg, val); + Serial.print(reg, HEX); + Serial.print(": 0x"); + Serial.println(val, HEX); + } + } + apds.wireReadDataByte(0x1E, val); + Serial.print(0x1E, HEX); + Serial.print(": 0x"); + Serial.println(val, HEX); +#endif + + // Wait for initialization and calibration to finish + delay(500); +} + +void loop() { + + // Read the light levels (ambient, red, green, blue) + if ( !apds.readAmbientLightLux(ambient_light) || + !apds.readCh0Light(ch0) || + !apds.readCh1Light(ch1) ) { + Serial.println(F("Error reading light values")); + } else { + Serial.print(F("Ambient: ")); + Serial.print(ambient_light); + Serial.print(F(" Ch0: ")); + Serial.print(ch0); + Serial.print(F(" Ch1: ")); + Serial.println(ch1); + + if ( ambient_light > max_light ) { + max_light = ambient_light; + } + ambient_light = map(ambient_light, 0, max_light, 0, 1023); + analogWrite(PWM_LED_PIN, ambient_light); + + } + + // Wait 1 second before next reading + delay(50); +} \ No newline at end of file diff --git a/firmware/libraries/APDS9930-master/examples/AmbientLightSensor/AmbientLightSensor.ino b/firmware/libraries/APDS9930-master/examples/AmbientLightSensor/AmbientLightSensor.ino new file mode 100644 index 0000000..9d390fe --- /dev/null +++ b/firmware/libraries/APDS9930-master/examples/AmbientLightSensor/AmbientLightSensor.ino @@ -0,0 +1,120 @@ +/**************************************************************** +AmbientLightSensor.ino +APDS-9930 Ambient light and proximity sensor +Davide Depau +December 11, 2015 +https://github.com/Davideddu/APDS9930 + +Shawn Hymel @ SparkFun Electronics +October 15, 2014 +https://github.com/sparkfun/APDS-9930_RGB_and_Gesture_Sensor + +Tests thembient light sensing abilities of the +APDS-9930. Configures APDS-9930 over I2C and polls the sensor for +ambient light levels, which are displayed over the +serial console. + +Hardware Connections: + +IMPORTANT: The APDS-9930 can only accept 3.3V! + + Arduino Pin APDS-9930 Board Function + + 3.3V VCC Power + GND GND Ground + A4 SDA I2C Data + A5 SCL I2C Clock + +Resources: +Include Wire.h and APDS-9930.h + +Development environment specifics: +Written in Arduino 1.6.5 +Tested with Arduino Uno and Mega. + +This code is beerware; if you see me (or any other SparkFun +employee) at the local, and you've found our code helpful, please +buy us a round! + +Distributed as-is; no warranty is given. +****************************************************************/ + +#define DUMP_REGS + +#include +#include + +// Global Variables +APDS9930 apds = APDS9930(); +float ambient_light = 0; // can also be an unsigned long +uint16_t ch0 = 0; +uint16_t ch1 = 1; + +void setup() { + //analogReference(EXTERNAL); + + // Initialize Serial port + Serial.begin(9600); + Serial.println(); + Serial.println(F("--------------------------------")); + Serial.println(F("APDS-9930 - Ambient light sensor")); + Serial.println(F("--------------------------------")); + + // Initialize APDS-9930 (configure I2C and initial values) + if ( apds.init() ) { + Serial.println(F("APDS-9930 initialization complete")); + } else { + Serial.println(F("Something went wrong during APDS-9930 init!")); + } + + // Start running the APDS-9930 light sensor (no interrupts) + if ( apds.enableLightSensor(false) ) { + Serial.println(F("Light sensor is now running")); + } else { + Serial.println(F("Something went wrong during light sensor init!")); + } + +#ifdef DUMP_REGS + /* Register dump */ + uint8_t reg; + uint8_t val; + + for(reg = 0x00; reg <= 0x19; reg++) { + if( (reg != 0x10) && \ + (reg != 0x11) ) + { + apds.wireReadDataByte(reg, val); + Serial.print(reg, HEX); + Serial.print(": 0x"); + Serial.println(val, HEX); + } + } + apds.wireReadDataByte(0x1E, val); + Serial.print(0x1E, HEX); + Serial.print(": 0x"); + Serial.println(val, HEX); +#endif + + // Wait for initialization and calibration to finish + delay(500); +} + +void loop() { + + // Read the light levels (ambient, red, green, blue) + if ( !apds.readAmbientLightLux(ambient_light) || + !apds.readCh0Light(ch0) || + !apds.readCh1Light(ch1) ) { + Serial.println(F("Error reading light values")); + } else { + Serial.print(F("Ambient: ")); + Serial.print(ambient_light); + Serial.print(F(" Ch0: ")); + Serial.print(ch0); + Serial.print(F(" Ch1: ")); + Serial.println(ch1); + } + + // Wait 1 second before next reading + delay(1000); +} \ No newline at end of file diff --git a/firmware/libraries/APDS9930-master/examples/AmbientLightToneAC/AmbientLightToneAC.ino b/firmware/libraries/APDS9930-master/examples/AmbientLightToneAC/AmbientLightToneAC.ino new file mode 100644 index 0000000..ff369b3 --- /dev/null +++ b/firmware/libraries/APDS9930-master/examples/AmbientLightToneAC/AmbientLightToneAC.ino @@ -0,0 +1,108 @@ +/**************************************************************** +AmbientLightToneAC.ino + +Tests the ambient light sensing abilities of the +APDS-9930. Configures APDS-9930 over I2C and polls the sensor for +ambient light levels, which are displayed over the +serial console. + +Hardware Connections: + +IMPORTANT: The APDS-9930 can only accept 3.3V! + + Arduino Pin APDS-9930 Board Function + + 3.3V VCC Power + GND GND Ground + A4 SDA I2C Data + A5 SCL I2C Clock + +Connect speakers to the correct pins. Check toneAC.h for more info. + +Distributed as-is; no warranty is given. +****************************************************************/ + +#define DUMP_REGS + +#include +#include +#include + +// Global Variables +APDS9930 apds = APDS9930(); +float ambient_light = 0; // can also be an unsigned long +uint16_t ch0 = 0; +uint16_t ch1 = 1; +float max_light = 0; + +void setup() { + //analogReference(EXTERNAL); + + // Initialize Serial port + Serial.begin(9600); + Serial.println(); + Serial.println(F("--------------------------------")); + Serial.println(F("APDS-9930 - Ambient light sensor")); + Serial.println(F("--------------------------------")); + + // Initialize APDS-9930 (configure I2C and initial values) + if ( apds.init() ) { + Serial.println(F("APDS-9930 initialization complete")); + } else { + Serial.println(F("Something went wrong during APDS-9930 init!")); + } + + // Start running the APDS-9930 light sensor (no interrupts) + if ( apds.enableLightSensor(false) ) { + Serial.println(F("Light sensor is now running")); + } else { + Serial.println(F("Something went wrong during light sensor init!")); + } + +#ifdef DUMP_REGS + /* Register dump */ + uint8_t reg; + uint8_t val; + + for(reg = 0x00; reg <= 0x19; reg++) { + if( (reg != 0x10) && \ + (reg != 0x11) ) + { + apds.wireReadDataByte(reg, val); + Serial.print(reg, HEX); + Serial.print(": 0x"); + Serial.println(val, HEX); + } + } + apds.wireReadDataByte(0x1E, val); + Serial.print(0x1E, HEX); + Serial.print(": 0x"); + Serial.println(val, HEX); +#endif + + // Wait for initialization and calibration to finish + delay(500); +} + +void loop() { + + // Read the light levels (ambient, red, green, blue) + if ( !apds.readAmbientLightLux(ambient_light) || + !apds.readCh0Light(ch0) || + !apds.readCh1Light(ch1) ) { + Serial.println(F("Error reading light values")); + } else { + Serial.print(F("Ambient: ")); + Serial.print(ambient_light); + Serial.print(F(" Ch0: ")); + Serial.print(ch0); + Serial.print(F(" Ch1: ")); + Serial.println(ch1); + + unsigned long freq = map(ch0, 0, 1024, 60, 16000); + toneAC(freq, 10, 50, true); + } + + // Wait 1 second before next reading + delay(50); +} \ No newline at end of file diff --git a/firmware/libraries/APDS9930-master/examples/ProximityInterrupt/ProximityInterrupt.ino b/firmware/libraries/APDS9930-master/examples/ProximityInterrupt/ProximityInterrupt.ino new file mode 100644 index 0000000..b93e914 --- /dev/null +++ b/firmware/libraries/APDS9930-master/examples/ProximityInterrupt/ProximityInterrupt.ino @@ -0,0 +1,157 @@ +/**************************************************************** +ProximityInterrupt.ino +APDS-9930 Ambient light and proximity sensor +Davide Depau +December 11, 2015 +https://github.com/Davideddu/APDS9930 + +Shawn Hymel @ SparkFun Electronics +October 24, 2014 +https://github.com/sparkfun/APDS-9930_RGB_and_Gesture_Sensor + +Tests the proximity interrupt abilities of the APDS-9930. +Configures the APDS-9930 over I2C and waits for an external +interrupt based on high or low proximity conditions. Move your +hand near the sensor and watch the LED on pin 13. + +Hardware Connections: + +IMPORTANT: The APDS-9930 can only accept 3.3V! + + Arduino Pin APDS-9930 Board Function + + 3.3V VCC Power + GND GND Ground + A4 SDA I2C Data + A5 SCL I2C Clock + 2 INT Interrupt + 13 - LED + +Resources: +Include Wire.h and APDS9930.h + +Development environment specifics: +Written in Arduino 1.6.5 +Tested with Arduino Uno and Mega + +This code is beerware; if you see me (or any other SparkFun +employee) at the local, and you've found our code helpful, please +buy us a round! + +Distributed as-is; no warranty is given. +****************************************************************/ + +#define DUMP_REGS + +#include +#include + +// Pins +#define APDS9930_INT 2 // Needs to be an interrupt pin +#define LED_PIN 13 // LED for showing interrupt + +// Constants +#define PROX_INT_HIGH 600 // Proximity level for interrupt +#define PROX_INT_LOW 0 // No far interrupt + +// Global variables +APDS9930 apds = APDS9930(); +uint16_t proximity_data = 0; +volatile bool isr_flag = false; + +void setup() { + + // Set LED as output + pinMode(LED_PIN, OUTPUT); + pinMode(APDS9930_INT, INPUT); + + // Initialize Serial port + Serial.begin(9600); + Serial.println(); + Serial.println(F("------------------------------")); + Serial.println(F("APDS-9930 - ProximityInterrupt")); + Serial.println(F("------------------------------")); + + // Initialize interrupt service routine + attachInterrupt(0, interruptRoutine, FALLING); + + // Initialize APDS-9930 (configure I2C and initial values) + if ( apds.init() ) { + Serial.println(F("APDS-9930 initialization complete")); + } else { + Serial.println(F("Something went wrong during APDS-9930 init!")); + } + + // Adjust the Proximity sensor gain + if ( !apds.setProximityGain(PGAIN_2X) ) { + Serial.println(F("Something went wrong trying to set PGAIN")); + } + + // Set proximity interrupt thresholds + if ( !apds.setProximityIntLowThreshold(PROX_INT_LOW) ) { + Serial.println(F("Error writing low threshold")); + } + if ( !apds.setProximityIntHighThreshold(PROX_INT_HIGH) ) { + Serial.println(F("Error writing high threshold")); + } + + // Start running the APDS-9930 proximity sensor (interrupts) + if ( apds.enableProximitySensor(true) ) { + Serial.println(F("Proximity sensor is now running")); + } else { + Serial.println(F("Something went wrong during sensor init!")); + } + +#ifdef DUMP_REGS + /* Register dump */ + uint8_t reg; + uint8_t val; + + for(reg = 0x00; reg <= 0x19; reg++) { + if( (reg != 0x10) && \ + (reg != 0x11) ) + { + apds.wireReadDataByte(reg, val); + Serial.print(reg, HEX); + Serial.print(": 0x"); + Serial.println(val, HEX); + } + } + apds.wireReadDataByte(0x1E, val); + Serial.print(0x1E, HEX); + Serial.print(": 0x"); + Serial.println(val, HEX); +#endif + +} + +void loop() { + + // If interrupt occurs, print out the proximity level + if ( isr_flag ) { + + // Read proximity level and print it out + if ( !apds.readProximity(proximity_data) ) { + Serial.println("Error reading proximity value"); + } else { + Serial.print("Proximity detected! Level: "); + Serial.println(proximity_data); + } + + // Turn on LED for a half a second + digitalWrite(LED_PIN, HIGH); + delay(500); + digitalWrite(LED_PIN, LOW); + + // Reset flag and clear APDS-9930 interrupt (IMPORTANT!) + isr_flag = false; + if ( !apds.clearProximityInt() ) { + Serial.println("Error clearing interrupt"); + } + + } +} + +void interruptRoutine() { + isr_flag = true; +} \ No newline at end of file diff --git a/firmware/libraries/APDS9930-master/examples/ProximityLED/ProximityLED.ino b/firmware/libraries/APDS9930-master/examples/ProximityLED/ProximityLED.ino new file mode 100644 index 0000000..1694b4e --- /dev/null +++ b/firmware/libraries/APDS9930-master/examples/ProximityLED/ProximityLED.ino @@ -0,0 +1,131 @@ +/**************************************************************** +ProximityLED.ino +Davide Depau +December 11, 2015 +https://github.com/Davideddu/APDS9930 + +https://github.com/sparkfun/APDS-9930_RGB_and_Gesture_Sensor + +Tests the proximity sensing abilities of the APDS-9930. +Configures the APDS-9930 over I2C and polls for the distance to +the object nearest the sensor, then turns on an LED accordingly. + +Hardware Connections: + +IMPORTANT: The APDS-9930 can only accept 3.3V! + + Arduino Pin APDS-9930 Board Function + + 3.3V VCC Power + GND GND Ground + A4 SDA I2C Data + A5 SCL I2C Clock + + 10 (PWM) LED Anode + +Resources: +Include Wire.h and APDS9930.h + +Development environment specifics: +Written in Sublime Text + Stino + Arduino 1.7.2 +Tested with Arduino Uno + level shifter + +This code is chocolateware; if you see me at the grocery store, +and you've found our code helpful, please buy us me a chocolate bar! :D + +Distributed as-is; no warranty is given. +****************************************************************/ + +#define DUMP_REGS +#define PWM_LED_PIN 10 + +#include +#include + +// Global Variables +APDS9930 apds = APDS9930(); +uint16_t proximity_data = 0; +int proximity_max = 0; + +void setup() { + //analogReference(EXTERNAL); + pinMode(PWM_LED_PIN, OUTPUT); + + // Initialize Serial port + Serial.begin(9600); + Serial.println(); + Serial.println(F("------------------------")); + Serial.println(F("APDS-9930 - ProximityLED")); + Serial.println(F("------------------------")); + + // Initialize APDS-9930 (configure I2C and initial values) + if ( apds.init() ) { + Serial.println(F("APDS-9930 initialization complete")); + } else { + Serial.println(F("Something went wrong during APDS-9930 init!")); + } + + // Adjust the Proximity sensor gain + if ( !apds.setProximityGain(PGAIN_1X) ) { + Serial.println(F("Something went wrong trying to set PGAIN")); + } + + // Start running the APDS-9930 proximity sensor (no interrupts) + if ( apds.enableProximitySensor(false) ) { + Serial.println(F("Proximity sensor is now running")); + } else { + Serial.println(F("Something went wrong during sensor init!")); + } + +#ifdef DUMP_REGS + /* Register dump */ + uint8_t reg; + uint8_t val; + + for(reg = 0x00; reg <= 0x19; reg++) { + if( (reg != 0x10) && \ + (reg != 0x11) ) + { + apds.wireReadDataByte(reg, val); + Serial.print(reg, HEX); + Serial.print(": 0x"); + Serial.println(val, HEX); + } + } + apds.wireReadDataByte(0x1E, val); + Serial.print(0x1E, HEX); + Serial.print(": 0x"); + Serial.println(val, HEX); +#endif +} + +void loop() { + + // Read the proximity value + if ( !apds.readProximity(proximity_data) ) { + Serial.println("Error reading proximity value"); + } else { + Serial.print("Proximity: "); + Serial.print(proximity_data); + + // This is an ugly hack to reduce sensor noise. + // You may want to adjust POFFSET instead. + /* + proximity_data -= 200; + if (proximity_data > 50000) { + proximity_data = 0; + } + if (proximity_data > proximity_max) { + proximity_max = proximity_data; + } + proximity_data = map(proximity_data, 0, proximity_max, 0, 1023); + */ + + Serial.print(F(" Remapped: ")); + Serial.println(proximity_data); + analogWrite(PWM_LED_PIN, proximity_data); + } + + // Wait 250 ms before next reading + delay(10); +} \ No newline at end of file diff --git a/firmware/libraries/APDS9930-master/examples/ProximitySensor/ProximitySensor.ino b/firmware/libraries/APDS9930-master/examples/ProximitySensor/ProximitySensor.ino new file mode 100644 index 0000000..1fe2054 --- /dev/null +++ b/firmware/libraries/APDS9930-master/examples/ProximitySensor/ProximitySensor.ino @@ -0,0 +1,113 @@ +/**************************************************************** +ProximitySensor.ino +APDS-9930 ambient light and proximity sensor +Davide Depau +December 11, 2015 +https://github.com/Davideddu/APDS9930 + +Shawn Hymel @ SparkFun Electronics +October 28, 2014 +https://github.com/sparkfun/APDS-9960_RGB_and_Gesture_Sensor + +Tests the proximity sensing abilities of the APDS-9930. +Configures the APDS-9930 over I2C and polls for the distance to +the object nearest the sensor. + +Hardware Connections: + +IMPORTANT: The APDS-9930 can only accept 3.3V! + + Arduino Pin APDS-9930 Board Function + + 3.3V VCC Power + GND GND Ground + A4 SDA I2C Data + A5 SCL I2C Clock + +Resources: +Include Wire.h and SparkFun_APDS-9930.h + +Development environment specifics: +Written in Arduino 1.0.5 +Tested with SparkFun Arduino Pro Mini 3.3V + +This code is beerware; if you see me (or any other SparkFun +employee) at the local, and you've found our code helpful, please +buy us a round! + +Distributed as-is; no warranty is given. +****************************************************************/ + +#define DUMP_REGS + +#include +#include + +// Global Variables +APDS9930 apds = APDS9930(); +uint16_t proximity_data = 0; + +void setup() { + //analogReference(EXTERNAL); + + // Initialize Serial port + Serial.begin(9600); + Serial.println(); + Serial.println(F("---------------------------")); + Serial.println(F("APDS-9930 - ProximitySensor")); + Serial.println(F("---------------------------")); + + // Initialize APDS-9930 (configure I2C and initial values) + if ( apds.init() ) { + Serial.println(F("APDS-9930 initialization complete")); + } else { + Serial.println(F("Something went wrong during APDS-9930 init!")); + } + + // // Adjust the Proximity sensor gain + // if ( !apds.setProximityGain(PGAIN_2X) ) { + // Serial.println(F("Something went wrong trying to set PGAIN")); + // } + + // Start running the APDS-9930 proximity sensor (no interrupts) + if ( apds.enableProximitySensor(false) ) { + Serial.println(F("Proximity sensor is now running")); + } else { + Serial.println(F("Something went wrong during sensor init!")); + } + +#ifdef DUMP_REGS + /* Register dump */ + uint8_t reg; + uint8_t val; + + for(reg = 0x00; reg <= 0x19; reg++) { + if( (reg != 0x10) && \ + (reg != 0x11) ) + { + apds.wireReadDataByte(reg, val); + Serial.print(reg, HEX); + Serial.print(": 0x"); + Serial.println(val, HEX); + } + } + apds.wireReadDataByte(0x1E, val); + Serial.print(0x1E, HEX); + Serial.print(": 0x"); + Serial.println(val, HEX); +#endif +} + +void loop() { + + // Read the proximity value + if ( !apds.readProximity(proximity_data) ) { + Serial.println("Error reading proximity value"); + } else { + Serial.print("Proximity: "); + Serial.println(proximity_data); + } + + // Wait 250 ms before next reading + delay(250); +} \ No newline at end of file diff --git a/firmware/libraries/APDS9930-master/keywords.txt b/firmware/libraries/APDS9930-master/keywords.txt new file mode 100644 index 0000000..e69de29 diff --git a/firmware/libraries/APDS9930-master/library.properties b/firmware/libraries/APDS9930-master/library.properties new file mode 100644 index 0000000..7487b16 --- /dev/null +++ b/firmware/libraries/APDS9930-master/library.properties @@ -0,0 +1,9 @@ +name=APDS-9930 Ambient Light and Proximity Sensor +version=1.5.1 +author=Davide Depau +maintainer=Davide Depau +sentence=Library for the Avago APDS-9930 sensor +paragraph=This library works with the breakout board for the Avago APDS-9930 proximity and light sensor +category=Sensors +url=https://github.com/Davideddu/APDS9930 +architectures=* diff --git a/firmware/libraries/APDS9930-master/src/APDS9930.cpp b/firmware/libraries/APDS9930-master/src/APDS9930.cpp new file mode 100644 index 0000000..ccfd0ff --- /dev/null +++ b/firmware/libraries/APDS9930-master/src/APDS9930.cpp @@ -0,0 +1,1147 @@ +/** + * @file APDS-9930.cpp + * @brief Library for the SparkFun APDS-9930 breakout board + * @author Shawn Hymel (SparkFun Electronics) + * + * @copyright This code is public domain but you buy me a beer if you use + * this and we meet someday (Beerware license). + * + * This library interfaces the Avago APDS-9930 to Arduino over I2C. The library + * relies on the Arduino Wire (I2C) library. to use the library, instantiate an + * APDS9930 object, call init(), and call the appropriate functions. + * + * APDS-9930 current draw tests (default parameters): + * Off: 1mA + * Waiting for gesture: 14mA + * Gesture in progress: 35mA + */ + + #include + #include + + #include "APDS9930.h" + +/** + * @brief Constructor - Instantiates APDS9930 object + */ +APDS9930::APDS9930() +{ + +} + +/** + * @brief Destructor + */ +APDS9930::~APDS9930() +{ + +} + +/** + * @brief Configures I2C communications and initializes registers to defaults + * + * @return True if initialized successfully. False otherwise. + */ +bool APDS9930::init() +{ + uint8_t id; + + /* Initialize I2C */ + Wire.begin(); + + /* Read ID register and check against known values for APDS-9930 */ + if( !wireReadDataByte(APDS9930_ID, id) ) { + Serial.println(F("ID read")); + return false; + } + if( !(id == APDS9930_ID_1 || id == APDS9930_ID_2) ) { + Serial.println(F("ID check")); + Serial.println(String("ID is ") + String(id, HEX)); + //return false; + } + + /* Set ENABLE register to 0 (disable all features) */ + if( !setMode(ALL, OFF) ) { + Serial.println(F("Regs off")); + return false; + } + + /* Set default values for ambient light and proximity registers */ + if( !wireWriteDataByte(APDS9930_ATIME, DEFAULT_ATIME) ) { + return false; + } + if( !wireWriteDataByte(APDS9930_WTIME, DEFAULT_WTIME) ) { + return false; + } + if( !wireWriteDataByte(APDS9930_PPULSE, DEFAULT_PPULSE) ) { + return false; + } + if( !wireWriteDataByte(APDS9930_POFFSET, DEFAULT_POFFSET) ) { + return false; + } + if( !wireWriteDataByte(APDS9930_CONFIG, DEFAULT_CONFIG) ) { + return false; + } + if( !setLEDDrive(DEFAULT_PDRIVE) ) { + return false; + } + if( !setProximityGain(DEFAULT_PGAIN) ) { + return false; + } + if( !setAmbientLightGain(DEFAULT_AGAIN) ) { + return false; + } + if( !setProximityDiode(DEFAULT_PDIODE) ) { + return false; + } + if( !setProximityIntLowThreshold(DEFAULT_PILT) ) { + return false; + } + if( !setProximityIntHighThreshold(DEFAULT_PIHT) ) { + return false; + } + if( !setLightIntLowThreshold(DEFAULT_AILT) ) { + return false; + } + if( !setLightIntHighThreshold(DEFAULT_AIHT) ) { + return false; + } + if( !wireWriteDataByte(APDS9930_PERS, DEFAULT_PERS) ) { + return false; + } + + return true; +} + +/******************************************************************************* + * Public methods for controlling the APDS-9930 + ******************************************************************************/ + +/** + * @brief Reads and returns the contents of the ENABLE register + * + * @return Contents of the ENABLE register. 0xFF if error. + */ +uint8_t APDS9930::getMode() +{ + uint8_t enable_value; + + /* Read current ENABLE register */ + if( !wireReadDataByte(APDS9930_ENABLE, enable_value) ) { + return ERROR; + } + + return enable_value; +} + +/** + * @brief Enables or disables a feature in the APDS-9930 + * + * @param[in] mode which feature to enable + * @param[in] enable ON (1) or OFF (0) + * @return True if operation success. False otherwise. + */ +bool APDS9930::setMode(uint8_t mode, uint8_t enable) +{ + uint8_t reg_val; + + /* Read current ENABLE register */ + reg_val = getMode(); + if( reg_val == ERROR ) { + return false; + } + + /* Change bit(s) in ENABLE register */ + enable = enable & 0x01; + if( mode >= 0 && mode <= 6 ) { + if (enable) { + reg_val |= (1 << mode); + } else { + reg_val &= ~(1 << mode); + } + } else if( mode == ALL ) { + if (enable) { + reg_val = 0x7F; + } else { + reg_val = 0x00; + } + } + + /* Write value back to ENABLE register */ + if( !wireWriteDataByte(APDS9930_ENABLE, reg_val) ) { + return false; + } + + return true; +} + +/** + * @brief Starts the light (Ambient/IR) sensor on the APDS-9930 + * + * @param[in] interrupts true to enable hardware interrupt on high or low light + * @return True if sensor enabled correctly. False on error. + */ +bool APDS9930::enableLightSensor(bool interrupts) +{ + + /* Set default gain, interrupts, enable power, and enable sensor */ + if( !setAmbientLightGain(DEFAULT_AGAIN) ) { + return false; + } + if( interrupts ) { + if( !setAmbientLightIntEnable(1) ) { + return false; + } + } else { + if( !setAmbientLightIntEnable(0) ) { + return false; + } + } + if( !enablePower() ){ + return false; + } + if( !setMode(AMBIENT_LIGHT, 1) ) { + return false; + } + + return true; + +} + +/** + * @brief Ends the light sensor on the APDS-9930 + * + * @return True if sensor disabled correctly. False on error. + */ +bool APDS9930::disableLightSensor() +{ + if( !setAmbientLightIntEnable(0) ) { + return false; + } + if( !setMode(AMBIENT_LIGHT, 0) ) { + return false; + } + + return true; +} + +/** + * @brief Starts the proximity sensor on the APDS-9930 + * + * @param[in] interrupts true to enable hardware external interrupt on proximity + * @return True if sensor enabled correctly. False on error. + */ +bool APDS9930::enableProximitySensor(bool interrupts) +{ + /* Set default gain, LED, interrupts, enable power, and enable sensor */ + if( !setProximityGain(DEFAULT_PGAIN) ) { + return false; + } + if( !setLEDDrive(DEFAULT_PDRIVE) ) { + return false; + } + if( interrupts ) { + if( !setProximityIntEnable(1) ) { + return false; + } + } else { + if( !setProximityIntEnable(0) ) { + return false; + } + } + if( !enablePower() ){ + return false; + } + if( !setMode(PROXIMITY, 1) ) { + return false; + } + + return true; +} + +/** + * @brief Ends the proximity sensor on the APDS-9930 + * + * @return True if sensor disabled correctly. False on error. + */ +bool APDS9930::disableProximitySensor() +{ + if( !setProximityIntEnable(0) ) { + return false; + } + if( !setMode(PROXIMITY, 0) ) { + return false; + } + + return true; +} + +/** + * Turn the APDS-9930 on + * + * @return True if operation successful. False otherwise. + */ +bool APDS9930::enablePower() +{ + if( !setMode(POWER, 1) ) { + return false; + } + + return true; +} + +/** + * Turn the APDS-9930 off + * + * @return True if operation successful. False otherwise. + */ +bool APDS9930::disablePower() +{ + if( !setMode(POWER, 0) ) { + return false; + } + + return true; +} + +/******************************************************************************* + * Ambient light sensor controls + ******************************************************************************/ + +/** + * @brief Reads the ambient (clear) light level as a 16-bit value + * + * @param[out] val value of the light sensor. + * @return True if operation successful. False otherwise. + */ +bool APDS9930::readAmbientLightLux(float &val) +{ + uint16_t Ch0; + uint16_t Ch1; + + /* Read value from channel 0 */ + if( !readCh0Light(Ch0) ) { + return false; + } + + /* Read value from channel 1 */ + if( !readCh1Light(Ch1) ) { + return false; + } + + val = floatAmbientToLux(Ch0, Ch1); + return true; +} + +bool APDS9930::readAmbientLightLux(unsigned long &val) +{ + uint16_t Ch0; + uint16_t Ch1; + + /* Read value from channel 0 */ + if( !readCh0Light(Ch0) ) { + return false; + } + + /* Read value from channel 1 */ + if( !readCh1Light(Ch1) ) { + return false; + } + + val = ulongAmbientToLux(Ch0, Ch1); + return true; +} + +float APDS9930::floatAmbientToLux(uint16_t Ch0, uint16_t Ch1) +{ + uint8_t x[4]={1,8,16,120}; + float ALSIT = 2.73 * (256 - DEFAULT_ATIME); + float iac = max(Ch0 - B * Ch1, C * Ch0 - D * Ch1); + if (iac < 0) iac = 0; + float lpc = GA * DF / (ALSIT * x[getAmbientLightGain()]); + return iac * lpc; +} + +unsigned long APDS9930::ulongAmbientToLux(uint16_t Ch0, uint16_t Ch1) +{ + uint8_t x[4]={1,8,16,120}; + unsigned long ALSIT = 2.73 * (256 - DEFAULT_ATIME); + unsigned long iac = max(Ch0 - B * Ch1, C * Ch0 - D * Ch1); + if (iac < 0) iac = 0; + unsigned long lpc = GA * DF / (ALSIT * x[getAmbientLightGain()]); + return iac * lpc; +} + +bool APDS9930::readCh0Light(uint16_t &val) +{ + uint8_t val_byte; + val = 0; + + /* Read value from channel 0 */ + if( !wireReadDataByte(APDS9930_Ch0DATAL, val_byte) ) { + return false; + } + val = val_byte; + if( !wireReadDataByte(APDS9930_Ch0DATAH, val_byte) ) { + return false; + } + val += ((uint16_t)val_byte << 8); + return true; +} + +bool APDS9930::readCh1Light(uint16_t &val) +{ + uint8_t val_byte; + val = 0; + + /* Read value from channel 0 */ + if( !wireReadDataByte(APDS9930_Ch1DATAL, val_byte) ) { + return false; + } + val = val_byte; + if( !wireReadDataByte(APDS9930_Ch1DATAH, val_byte) ) { + return false; + } + val += ((uint16_t)val_byte << 8); + return true; +} + +/******************************************************************************* + * Proximity sensor controls + ******************************************************************************/ + +/** + * @brief Reads the proximity level as an 8-bit value + * + * @param[out] val value of the proximity sensor. + * @return True if operation successful. False otherwise. + */ +bool APDS9930::readProximity(uint16_t &val) +{ + val = 0; + uint8_t val_byte; + + /* Read value from proximity data register */ + if( !wireReadDataByte(APDS9930_PDATAL, val_byte) ) { + return false; + } + val = val_byte; + if( !wireReadDataByte(APDS9930_PDATAH, val_byte) ) { + return false; + } + val += ((uint16_t)val_byte << 8); + + return true; +} + +/******************************************************************************* + * Getters and setters for register values + ******************************************************************************/ + +/** + * @brief Returns the lower threshold for proximity detection + * + * @return lower threshold + */ +uint16_t APDS9930::getProximityIntLowThreshold() +{ + uint16_t val; + uint8_t val_byte; + + /* Read value from PILT register */ + if( !wireReadDataByte(APDS9930_PILTL, val_byte) ) { + val = 0; + } + val = val_byte; + if( !wireReadDataByte(APDS9930_PILTH, val_byte) ) { + val = 0; + } + val |= ((uint16_t)val_byte << 8); + + return val; +} + +/** + * @brief Sets the lower threshold for proximity detection + * + * @param[in] threshold the lower proximity threshold + * @return True if operation successful. False otherwise. + */ +bool APDS9930::setProximityIntLowThreshold(uint16_t threshold) +{ + uint8_t lo; + uint8_t hi; + hi = threshold >> 8; + lo = threshold & 0x00FF; + + if( !wireWriteDataByte(APDS9930_PILTL, lo) ) { + return false; + } + if( !wireWriteDataByte(APDS9930_PILTH, hi) ) { + return false; + } + + return true; +} + +/** + * @brief Returns the high threshold for proximity detection + * + * @return high threshold + */ +uint16_t APDS9930::getProximityIntHighThreshold() +{ + uint16_t val; + uint8_t val_byte; + + /* Read value from PILT register */ + if( !wireReadDataByte(APDS9930_PIHTL, val_byte) ) { + val = 0; + } + val = val_byte; + if( !wireReadDataByte(APDS9930_PIHTH, val_byte) ) { + val = 0; + } + val |= ((uint16_t)val_byte << 8); + + return val; +} + +/** + * @brief Sets the high threshold for proximity detection + * + * @param[in] threshold the high proximity threshold + * @return True if operation successful. False otherwise. + */ +bool APDS9930::setProximityIntHighThreshold(uint16_t threshold) +{ + uint8_t lo; + uint8_t hi; + hi = threshold >> 8; + lo = threshold & 0x00FF; + + if( !wireWriteDataByte(APDS9930_PIHTL, lo) ) { + return false; + } + if( !wireWriteDataByte(APDS9930_PIHTH, hi) ) { + return false; + } + + return true; +} + +/** + * @brief Returns LED drive strength for proximity and ALS + * + * Value LED Current + * 0 100 mA + * 1 50 mA + * 2 25 mA + * 3 12.5 mA + * + * @return the value of the LED drive strength. 0xFF on failure. + */ +uint8_t APDS9930::getLEDDrive() +{ + uint8_t val; + + /* Read value from CONTROL register */ + if( !wireReadDataByte(APDS9930_CONTROL, val) ) { + return ERROR; + } + + /* Shift and mask out LED drive bits */ + val = (val >> 6) & 0b00000011; + + return val; +} + +/** + * @brief Sets the LED drive strength for proximity and ALS + * + * Value LED Current + * 0 100 mA + * 1 50 mA + * 2 25 mA + * 3 12.5 mA + * + * @param[in] drive the value (0-3) for the LED drive strength + * @return True if operation successful. False otherwise. + */ +bool APDS9930::setLEDDrive(uint8_t drive) +{ + uint8_t val; + + /* Read value from CONTROL register */ + if( !wireReadDataByte(APDS9930_CONTROL, val) ) { + return false; + } + + /* Set bits in register to given value */ + drive &= 0b00000011; + drive = drive << 6; + val &= 0b00111111; + val |= drive; + + /* Write register value back into CONTROL register */ + if( !wireWriteDataByte(APDS9930_CONTROL, val) ) { + return false; + } + + return true; +} + +/** + * @brief Returns receiver gain for proximity detection + * + * Value Gain + * 0 1x + * 1 2x + * 2 4x + * 3 8x + * + * @return the value of the proximity gain. 0xFF on failure. + */ +uint8_t APDS9930::getProximityGain() +{ + uint8_t val; + + /* Read value from CONTROL register */ + if( !wireReadDataByte(APDS9930_CONTROL, val) ) { + return ERROR; + } + + /* Shift and mask out PDRIVE bits */ + val = (val >> 2) & 0b00000011; + + return val; +} + +/** + * @brief Sets the receiver gain for proximity detection + * + * Value Gain + * 0 1x + * 1 2x + * 2 4x + * 3 8x + * + * @param[in] drive the value (0-3) for the gain + * @return True if operation successful. False otherwise. + */ +bool APDS9930::setProximityGain(uint8_t drive) +{ + uint8_t val; + + /* Read value from CONTROL register */ + if( !wireReadDataByte(APDS9930_CONTROL, val) ) { + return false; + } + + /* Set bits in register to given value */ + drive &= 0b00000011; + drive = drive << 2; + val &= 0b11110011; + val |= drive; + + /* Write register value back into CONTROL register */ + if( !wireWriteDataByte(APDS9930_CONTROL, val) ) { + return false; + } + + return true; +} + +/** + * @brief Returns the proximity diode + * + * Value Diode selection + * 0 Reserved + * 1 Reserved + * 2 Use Ch1 diode + * 3 Reserved + * + * @return the selected diode. 0xFF on failure. + */ +uint8_t APDS9930::getProximityDiode() +{ + uint8_t val; + + /* Read value from CONTROL register */ + if( !wireReadDataByte(APDS9930_CONTROL, val) ) { + return ERROR; + } + + /* Shift and mask out PDRIVE bits */ + val = (val >> 4) & 0b00000011; + + return val; +} + +/** + * @brief Selects the proximity diode + * + * Value Diode selection + * 0 Reserved + * 1 Reserved + * 2 Use Ch1 diode + * 3 Reserved + * + * @param[in] drive the value (0-3) for the diode + * @return True if operation successful. False otherwise. + */ +bool APDS9930::setProximityDiode(uint8_t drive) +{ + uint8_t val; + + /* Read value from CONTROL register */ + if( !wireReadDataByte(APDS9930_CONTROL, val) ) { + return false; + } + + /* Set bits in register to given value */ + drive &= 0b00000011; + drive = drive << 4; + val &= 0b11001111; + val |= drive; + + /* Write register value back into CONTROL register */ + if( !wireWriteDataByte(APDS9930_CONTROL, val) ) { + return false; + } + + return true; +} + +/** + * @brief Returns receiver gain for the ambient light sensor (ALS) + * + * Value Gain + * 0 1x + * 1 4x + * 2 16x + * 3 120x + * + * @return the value of the ALS gain. 0xFF on failure. + */ +uint8_t APDS9930::getAmbientLightGain() +{ + uint8_t val; + + /* Read value from CONTROL register */ + if( !wireReadDataByte(APDS9930_CONTROL, val) ) { + return ERROR; + } + + /* Shift and mask out ADRIVE bits */ + val &= 0b00000011; + + return val; +} + +/** + * @brief Sets the receiver gain for the ambient light sensor (ALS) + * + * Value Gain + * 0 1x + * 1 4x + * 2 16x + * 3 64x + * + * @param[in] drive the value (0-3) for the gain + * @return True if operation successful. False otherwise. + */ +bool APDS9930::setAmbientLightGain(uint8_t drive) +{ + uint8_t val; + + /* Read value from CONTROL register */ + if( !wireReadDataByte(APDS9930_CONTROL, val) ) { + return false; + } + + /* Set bits in register to given value */ + drive &= 0b00000011; + val &= 0b11111100; + val |= drive; + + /* Write register value back into CONTROL register */ + if( !wireWriteDataByte(APDS9930_CONTROL, val) ) { + return false; + } + + return true; +} + +/** + * @brief Gets the low threshold for ambient light interrupts + * + * @param[out] threshold current low threshold stored on the APDS-9930 + * @return True if operation successful. False otherwise. + */ +bool APDS9930::getLightIntLowThreshold(uint16_t &threshold) +{ + uint8_t val_byte; + threshold = 0; + + /* Read value from ambient light low threshold, low byte register */ + if( !wireReadDataByte(APDS9930_AILTL, val_byte) ) { + return false; + } + threshold = val_byte; + + /* Read value from ambient light low threshold, high byte register */ + if( !wireReadDataByte(APDS9930_AILTH, val_byte) ) { + return false; + } + threshold = threshold + ((uint16_t)val_byte << 8); + + return true; +} + +/** + * @brief Sets the low threshold for ambient light interrupts + * + * @param[in] threshold low threshold value for interrupt to trigger + * @return True if operation successful. False otherwise. + */ +bool APDS9930::setLightIntLowThreshold(uint16_t threshold) +{ + uint8_t val_low; + uint8_t val_high; + + /* Break 16-bit threshold into 2 8-bit values */ + val_low = threshold & 0x00FF; + val_high = (threshold & 0xFF00) >> 8; + + /* Write low byte */ + if( !wireWriteDataByte(APDS9930_AILTL, val_low) ) { + return false; + } + + /* Write high byte */ + if( !wireWriteDataByte(APDS9930_AILTH, val_high) ) { + return false; + } + + return true; +} + +/** + * @brief Gets the high threshold for ambient light interrupts + * + * @param[out] threshold current low threshold stored on the APDS-9930 + * @return True if operation successful. False otherwise. + */ +bool APDS9930::getLightIntHighThreshold(uint16_t &threshold) +{ + uint8_t val_byte; + threshold = 0; + + /* Read value from ambient light high threshold, low byte register */ + if( !wireReadDataByte(APDS9930_AIHTL, val_byte) ) { + return false; + } + threshold = val_byte; + + /* Read value from ambient light high threshold, high byte register */ + if( !wireReadDataByte(APDS9930_AIHTH, val_byte) ) { + return false; + } + threshold = threshold + ((uint16_t)val_byte << 8); + + return true; +} + +/** + * @brief Sets the high threshold for ambient light interrupts + * + * @param[in] threshold high threshold value for interrupt to trigger + * @return True if operation successful. False otherwise. + */ +bool APDS9930::setLightIntHighThreshold(uint16_t threshold) +{ + uint8_t val_low; + uint8_t val_high; + + /* Break 16-bit threshold into 2 8-bit values */ + val_low = threshold & 0x00FF; + val_high = (threshold & 0xFF00) >> 8; + + /* Write low byte */ + if( !wireWriteDataByte(APDS9930_AIHTL, val_low) ) { + return false; + } + + /* Write high byte */ + if( !wireWriteDataByte(APDS9930_AIHTH, val_high) ) { + return false; + } + + return true; +} + + +/** + * @brief Gets if ambient light interrupts are enabled or not + * + * @return 1 if interrupts are enabled, 0 if not. 0xFF on error. + */ +uint8_t APDS9930::getAmbientLightIntEnable() +{ + uint8_t val; + + /* Read value from ENABLE register */ + if( !wireReadDataByte(APDS9930_ENABLE, val) ) { + return ERROR; + } + + /* Shift and mask out AIEN bit */ + val = (val >> 4) & 0b00000001; + + return val; +} + +/** + * @brief Turns ambient light interrupts on or off + * + * @param[in] enable 1 to enable interrupts, 0 to turn them off + * @return True if operation successful. False otherwise. + */ +bool APDS9930::setAmbientLightIntEnable(uint8_t enable) +{ + uint8_t val; + + /* Read value from ENABLE register */ + if( !wireReadDataByte(APDS9930_ENABLE, val) ) { + return false; + } + + /* Set bits in register to given value */ + enable &= 0b00000001; + enable = enable << 4; + val &= 0b11101111; + val |= enable; + + /* Write register value back into ENABLE register */ + if( !wireWriteDataByte(APDS9930_ENABLE, val) ) { + return false; + } + + return true; +} + +/** + * @brief Gets if proximity interrupts are enabled or not + * + * @return 1 if interrupts are enabled, 0 if not. 0xFF on error. + */ +uint8_t APDS9930::getProximityIntEnable() +{ + uint8_t val; + + /* Read value from ENABLE register */ + if( !wireReadDataByte(APDS9930_ENABLE, val) ) { + return ERROR; + } + + /* Shift and mask out PIEN bit */ + val = (val >> 5) & 0b00000001; + + return val; +} + +/** + * @brief Turns proximity interrupts on or off + * + * @param[in] enable 1 to enable interrupts, 0 to turn them off + * @return True if operation successful. False otherwise. + */ +bool APDS9930::setProximityIntEnable(uint8_t enable) +{ + uint8_t val; + + /* Read value from ENABLE register */ + if( !wireReadDataByte(APDS9930_ENABLE, val) ) { + return false; + } + + /* Set bits in register to given value */ + enable &= 0b00000001; + enable = enable << 5; + val &= 0b11011111; + val |= enable; + + /* Write register value back into ENABLE register */ + if( !wireWriteDataByte(APDS9930_ENABLE, val) ) { + return false; + } + + return true; +} + +/** + * @brief Clears the ambient light interrupt + * + * @return True if operation completed successfully. False otherwise. + */ +bool APDS9930::clearAmbientLightInt() +{ + if( !wireWriteByte(CLEAR_ALS_INT) ) { + return false; + } + + return true; +} + +/** + * @brief Clears the proximity interrupt + * + * @return True if operation completed successfully. False otherwise. + */ +bool APDS9930::clearProximityInt() +{ + if( !wireWriteByte(CLEAR_PROX_INT) ) { + return false; + } + + return true; +} + +/** + * @brief Clears all interrupts + * + * @return True if operation completed successfully. False otherwise. + */ +bool APDS9930::clearAllInts() +{ + if( !wireWriteByte(CLEAR_ALL_INTS) ) { + return false; + } + + return true; +} + +/******************************************************************************* + * Raw I2C Reads and Writes + ******************************************************************************/ + +/** + * @brief Writes a single byte to the I2C device (no register) + * + * @param[in] val the 1-byte value to write to the I2C device + * @return True if successful write operation. False otherwise. + */ +bool APDS9930::wireWriteByte(uint8_t val) +{ + Wire.beginTransmission(APDS9930_I2C_ADDR); + Wire.write(val); + if( Wire.endTransmission() != 0 ) { + return false; + } + + return true; +} + +/** + * @brief Writes a single byte to the I2C device and specified register + * + * @param[in] reg the register in the I2C device to write to + * @param[in] val the 1-byte value to write to the I2C device + * @return True if successful write operation. False otherwise. + */ +bool APDS9930::wireWriteDataByte(uint8_t reg, uint8_t val) +{ + Wire.beginTransmission(APDS9930_I2C_ADDR); + Wire.write(reg | AUTO_INCREMENT); + Wire.write(val); + if( Wire.endTransmission() != 0 ) { + return false; + } + + return true; +} + +/** + * @brief Writes a block (array) of bytes to the I2C device and register + * + * @param[in] reg the register in the I2C device to write to + * @param[in] val pointer to the beginning of the data byte array + * @param[in] len the length (in bytes) of the data to write + * @return True if successful write operation. False otherwise. + */ +bool APDS9930::wireWriteDataBlock( uint8_t reg, + uint8_t *val, + unsigned int len) +{ + unsigned int i; + + Wire.beginTransmission(APDS9930_I2C_ADDR); + Wire.write(reg | AUTO_INCREMENT); + for(i = 0; i < len; i++) { + Wire.beginTransmission(APDS9930_I2C_ADDR); + Wire.write(val[i]); + } + if( Wire.endTransmission() != 0 ) { + return false; + } + + return true; +} + +/** + * @brief Reads a single byte from the I2C device and specified register + * + * @param[in] reg the register to read from + * @param[out] the value returned from the register + * @return True if successful read operation. False otherwise. + */ +bool APDS9930::wireReadDataByte(uint8_t reg, uint8_t &val) +{ + + /* Indicate which register we want to read from */ + if (!wireWriteByte(reg | AUTO_INCREMENT)) { + return false; + } + + /* Read from register */ + Wire.requestFrom(APDS9930_I2C_ADDR, 1); + while (Wire.available()) { + val = Wire.read(); + } + + return true; +} + + +/** + * @brief Reads a block (array) of bytes from the I2C device and register + * + * @param[in] reg the register to read from + * @param[out] val pointer to the beginning of the data + * @param[in] len number of bytes to read + * @return Number of bytes read. -1 on read error. + */ +int APDS9930::wireReadDataBlock( uint8_t reg, + uint8_t *val, + unsigned int len) +{ + unsigned char i = 0; + + /* Indicate which register we want to read from */ + if (!wireWriteByte(reg | AUTO_INCREMENT)) { + return -1; + } + + /* Read block data */ + Wire.requestFrom(APDS9930_I2C_ADDR, len); + while (Wire.available()) { + if (i >= len) { + return -1; + } + val[i] = Wire.read(); + i++; + } + + return i; +} \ No newline at end of file diff --git a/firmware/libraries/APDS9930-master/src/APDS9930.h b/firmware/libraries/APDS9930-master/src/APDS9930.h new file mode 100644 index 0000000..640544d --- /dev/null +++ b/firmware/libraries/APDS9930-master/src/APDS9930.h @@ -0,0 +1,231 @@ +/** + * @file APDS-9930.h + * @brief Library for the SparkFun APDS-9930 breakout board + * @author Shawn Hymel (SparkFun Electronics) + * + * @copyright This code is public domain but you buy me a beer if you use + * this and we meet someday (Beerware license). + * + * This library interfaces the Avago APDS-9930 to Arduino over I2C. The library + * relies on the Arduino Wire (I2C) library. to use the library, instantiate an + * APDS9930 object, call init(), and call the appropriate functions. + */ + +#ifndef APDS9930_H +#define APDS9930_H + +#include + +/* Debug */ +#define DEBUG 0 + +/* APDS-9930 I2C address */ +#define APDS9930_I2C_ADDR 0x39 + +/* Command register modes */ +#define REPEATED_BYTE 0x80 +#define AUTO_INCREMENT 0xA0 +#define SPECIAL_FN 0xE0 + +/* Error code for returned values */ +#define ERROR 0xFF + +/* Acceptable device IDs */ +#define APDS9930_ID_1 0x12 +#define APDS9930_ID_2 0x39 + +/* Misc parameters */ +#define FIFO_PAUSE_TIME 30 // Wait period (ms) between FIFO reads + +/* APDS-9930 register addresses */ +#define APDS9930_ENABLE 0x00 +#define APDS9930_ATIME 0x01 +#define APDS9930_PTIME 0x02 +#define APDS9930_WTIME 0x03 +#define APDS9930_AILTL 0x04 +#define APDS9930_AILTH 0x05 +#define APDS9930_AIHTL 0x06 +#define APDS9930_AIHTH 0x07 +#define APDS9930_PILTL 0x08 +#define APDS9930_PILTH 0x09 +#define APDS9930_PIHTL 0x0A +#define APDS9930_PIHTH 0x0B +#define APDS9930_PERS 0x0C +#define APDS9930_CONFIG 0x0D +#define APDS9930_PPULSE 0x0E +#define APDS9930_CONTROL 0x0F +#define APDS9930_ID 0x12 +#define APDS9930_STATUS 0x13 +#define APDS9930_Ch0DATAL 0x14 +#define APDS9930_Ch0DATAH 0x15 +#define APDS9930_Ch1DATAL 0x16 +#define APDS9930_Ch1DATAH 0x17 +#define APDS9930_PDATAL 0x18 +#define APDS9930_PDATAH 0x19 +#define APDS9930_POFFSET 0x1E + + +/* Bit fields */ +#define APDS9930_PON 0b00000001 +#define APDS9930_AEN 0b00000010 +#define APDS9930_PEN 0b00000100 +#define APDS9930_WEN 0b00001000 +#define APSD9930_AIEN 0b00010000 +#define APDS9930_PIEN 0b00100000 +#define APDS9930_SAI 0b01000000 + +/* On/Off definitions */ +#define OFF 0 +#define ON 1 + +/* Acceptable parameters for setMode */ +#define POWER 0 +#define AMBIENT_LIGHT 1 +#define PROXIMITY 2 +#define WAIT 3 +#define AMBIENT_LIGHT_INT 4 +#define PROXIMITY_INT 5 +#define SLEEP_AFTER_INT 6 +#define ALL 7 + +/* LED Drive values */ +#define LED_DRIVE_100MA 0 +#define LED_DRIVE_50MA 1 +#define LED_DRIVE_25MA 2 +#define LED_DRIVE_12_5MA 3 + +/* Proximity Gain (PGAIN) values */ +#define PGAIN_1X 0 +#define PGAIN_2X 1 +#define PGAIN_4X 2 +#define PGAIN_8X 3 + +/* ALS Gain (AGAIN) values */ +#define AGAIN_1X 0 +#define AGAIN_8X 1 +#define AGAIN_16X 2 +#define AGAIN_120X 3 + +/* Interrupt clear values */ +#define CLEAR_PROX_INT 0xE5 +#define CLEAR_ALS_INT 0xE6 +#define CLEAR_ALL_INTS 0xE7 + +/* Default values */ +#define DEFAULT_ATIME 0xED +#define DEFAULT_WTIME 0xFF +#define DEFAULT_PTIME 0xFF +#define DEFAULT_PPULSE 0x08 +#define DEFAULT_POFFSET 0 // 0 offset +#define DEFAULT_CONFIG 0 +#define DEFAULT_PDRIVE LED_DRIVE_100MA +#define DEFAULT_PDIODE 2 +#define DEFAULT_PGAIN PGAIN_8X +#define DEFAULT_AGAIN AGAIN_1X +#define DEFAULT_PILT 0 // Low proximity threshold +#define DEFAULT_PIHT 50 // High proximity threshold +#define DEFAULT_AILT 0xFFFF // Force interrupt for calibration +#define DEFAULT_AIHT 0 +#define DEFAULT_PERS 0x22 // 2 consecutive prox or ALS for int. + +/* ALS coefficients */ +#define DF 52 +#define GA 0.49 +#define B 1.862 +#define C 0.746 +#define D 1.291 + +/* State definitions */ +enum { + NOTAVAILABLE_STATE, + NEAR_STATE, + FAR_STATE, + ALL_STATE +}; + +#ifdef _AVR_IO_H_ + // Do not use this alias as it's deprecated + #define NA_STATE NOTAVAILABLE_STATE +#endif + +/* APDS9930 Class */ +class APDS9930 { +public: + + /* Initialization methods */ + APDS9930(); + ~APDS9930(); + bool init(); + uint8_t getMode(); + bool setMode(uint8_t mode, uint8_t enable); + + /* Turn the APDS-9930 on and off */ + bool enablePower(); + bool disablePower(); + + /* Enable or disable specific sensors */ + bool enableLightSensor(bool interrupts = false); + bool disableLightSensor(); + bool enableProximitySensor(bool interrupts = false); + bool disableProximitySensor(); + + /* LED drive strength control */ + uint8_t getLEDDrive(); + bool setLEDDrive(uint8_t drive); + // uint8_t getGestureLEDDrive(); + // bool setGestureLEDDrive(uint8_t drive); + + /* Gain control */ + uint8_t getAmbientLightGain(); + bool setAmbientLightGain(uint8_t gain); + uint8_t getProximityGain(); + bool setProximityGain(uint8_t gain); + bool setProximityDiode(uint8_t drive); + uint8_t getProximityDiode(); + + + /* Get and set light interrupt thresholds */ + bool getLightIntLowThreshold(uint16_t &threshold); + bool setLightIntLowThreshold(uint16_t threshold); + bool getLightIntHighThreshold(uint16_t &threshold); + bool setLightIntHighThreshold(uint16_t threshold); + + /* Get and set interrupt enables */ + uint8_t getAmbientLightIntEnable(); + bool setAmbientLightIntEnable(uint8_t enable); + uint8_t getProximityIntEnable(); + bool setProximityIntEnable(uint8_t enable); + + /* Clear interrupts */ + bool clearAmbientLightInt(); + bool clearProximityInt(); + bool clearAllInts(); + + /* Proximity methods */ + bool readProximity(uint16_t &val); + + /* Ambient light methods */ + bool readAmbientLightLux(float &val); + bool readAmbientLightLux(unsigned long &val); + float floatAmbientToLux(uint16_t Ch0, uint16_t Ch1); + unsigned long ulongAmbientToLux(uint16_t Ch0, uint16_t Ch1); + bool readCh0Light(uint16_t &val); + bool readCh1Light(uint16_t &val); + +//private: + + /* Proximity Interrupt Threshold */ + uint16_t getProximityIntLowThreshold(); + bool setProximityIntLowThreshold(uint16_t threshold); + uint16_t getProximityIntHighThreshold(); + bool setProximityIntHighThreshold(uint16_t threshold); + + /* Raw I2C Commands */ + bool wireWriteByte(uint8_t val); + bool wireWriteDataByte(uint8_t reg, uint8_t val); + bool wireWriteDataBlock(uint8_t reg, uint8_t *val, unsigned int len); + bool wireReadDataByte(uint8_t reg, uint8_t &val); + int wireReadDataBlock(uint8_t reg, uint8_t *val, unsigned int len); +}; + +#endif diff --git a/firmware/sensor_apds9930.ino b/firmware/sensor_apds9930.ino new file mode 100644 index 0000000..0917dd5 --- /dev/null +++ b/firmware/sensor_apds9930.ino @@ -0,0 +1,23 @@ +#include + +APDS9930 _sensor_apds9930 = APDS9930(); + +bool sensor_apds9930_begin() { + bool status = _sensor_apds9930.init(); + if (status) { + _sensor_apds9930.enableLightSensor(false); + debug("APDS9930 Connected"); + } else { + debug("Could not find a valid APDS9930 sensor, check wiring!"); + } + return status; +} + +float apds9930_light() { + float ambient_light = 0; + if (_sensor_apds9930.readAmbientLightLux(ambient_light)) { + return ambient_light; + } else { + return 0; + } +} diff --git a/firmware/sensor_apds9960.ino b/firmware/sensor_apds9960.ino new file mode 100644 index 0000000..b6ad2ab --- /dev/null +++ b/firmware/sensor_apds9960.ino @@ -0,0 +1,27 @@ +#include // Adafruit APDS9960 - https://www.makerfabs.com/index.php?route=product/product&product_id=281 + +Adafruit_APDS9960 _sensor_apds9960; + +bool sensor_apds9960_begin() { + bool status = _sensor_apds9960.begin(); + if (status) { + _sensor_apds9960.enableColor(true); + debug("APDS9960 Connected"); + } else { + debug("Could not find a valid APDS9960 sensor, check wiring!"); + } + return status; +} + +float apds9960_light() { + uint16_t red, green, blue, white, lux; + + while(!_sensor_apds9960.colorDataReady()) { + delay(5); + } + + _sensor_apds9960.getColorData(&red, &green, &blue, &white); + //calculate lux + lux = _sensor_apds9960.calculateLux(red, green, blue); + return lux * LIGHT_FACTOR; +} diff --git a/firmware/sensor_battery.ino b/firmware/sensor_battery.ino new file mode 100644 index 0000000..1a19a74 --- /dev/null +++ b/firmware/sensor_battery.ino @@ -0,0 +1,48 @@ +float _sensor_battery_saveMode = 0; +uint16_t energySavingIterations = 0; + +// Copied from https://arduinodiy.wordpress.com/2016/12/25/monitoring-lipo-battery-voltage-with-wemos-d1-minibattery-shield-and-thingspeak/ +float battery_voltage() { + // ESP8266 ADC pin input voltage range ist 0V .. 1V + // The Wemos D1 mini does already contain a voltage divider circuit: A0(Wemos PCB) -- [220kOhm] -- ADC (ESP8266)-- [100kOhm] -- GND + // The (+) pole of the battery is connected to the A0 pin of the Wemos board through a additional 100kOhm resistance. + // The battery voltage of 4.2V max is measured as 1.0V on ESP8266 ADC pin. + uint16_t raw = analogRead(A0); + float volt = raw / 1023.0; + return volt * 4.2; +} + +float battery_charging() { + if (LOW == digitalRead(BAT_CHARGING_PIN)) { + return BAT_CHARGE_STATE_CHARGING; + } else if (LOW == digitalRead(BAT_CHARGED_PIN)) { + return BAT_CHARGE_STATE_CHARGED; + } + + return BAT_CHARGE_STATE_NOTCHARGING; +} + +int energySavingMode() { + // Give the solar panel some time to load the cell to prevent + // flapping. + if (energySavingIterations > 0) { + energySavingIterations--; + _sensor_battery_saveMode = ENERGY_SAVE_MODE_ENABLED; + return 1; + } + + // Is the battery low? + if (currentSensorData[SENSOR_BAT_VOLTAGE] <= BAT_LOW_VOLTAGE) { + // Entering energy saving + energySavingIterations = ENERGY_SAVING_ITERATIONS; + _sensor_battery_saveMode = ENERGY_SAVE_MODE_ENABLED; + return 1; + } + + _sensor_battery_saveMode = ENERGY_SAVE_MODE_DISABLED; + return 0; +} + +float isEnergySavingMode() { + return _sensor_battery_saveMode; +} diff --git a/firmware/sensor_bme280.ino b/firmware/sensor_bme280.ino new file mode 100644 index 0000000..f288ead --- /dev/null +++ b/firmware/sensor_bme280.ino @@ -0,0 +1,24 @@ +#include // BME280 - https://www.roboter-bausatz.de/1704/bmp280-barometer-luftdrucksensor?gclid=EAIaIQobChMIlpumj8Hp2wIVFWYbCh01PgmFEAQYAyABEgIwBvD_BwE +#include "config_user.h" + +Adafruit_BME280 _sensor_bme280; + +bool sensor_bme280_begin(uint8_t addr) { + bool status = _sensor_bme280.begin(addr); + if (status) { + debug("BME280 Connected!"); + } else { + debug("Could not find a valid BME280 sensor, check wiring!"); + } + return status; +} + +float bme280_temperature() { + return _sensor_bme280.readTemperature(); +} +float bme280_pressure() { + return _sensor_bme280.readPressure() / 100.0F; +} +float bme280_humidity() { + return _sensor_bme280.readHumidity() * HUMIDITY_FACTOR; +} diff --git a/firmware/sensor_wind.ino b/firmware/sensor_wind.ino new file mode 100644 index 0000000..746a5f5 --- /dev/null +++ b/firmware/sensor_wind.ino @@ -0,0 +1,23 @@ +#include "config_user.h" + +int anemometerRotations = 0; +unsigned long currentTime = 0; + +ICACHE_RAM_ATTR void _anemometerInterrupt() { + anemometerRotations++; +#ifdef DEBUG + Serial.print("*"); +#endif +} + +float wind_speed() { + anemometerRotations = 0; + currentTime = millis(); + int interruptNumber = digitalPinToInterrupt(ANEMOMETER_PIN); + + attachInterrupt(interruptNumber, _anemometerInterrupt, RISING); + delay(1000 * 5); + detachInterrupt(interruptNumber); + + return (float)anemometerRotations / 5.0 * 2.4; +} diff --git a/firmware/sensors.ino b/firmware/sensors.ino deleted file mode 100644 index 8ed0291..0000000 --- a/firmware/sensors.ino +++ /dev/null @@ -1,75 +0,0 @@ -#include "config_user.h" - -int anemometerRotations = 0; -unsigned long currentTime = 0; - -float fetchTemperature() { - return bme.readTemperature(); -} - -float fetchPressure() { - return bme.readPressure() / 100.0F; -} - -float fetchHumidity() { - return bme.readHumidity() * HUMIDITY_FACTOR; -} - -float fetchLight() { - //TODO read values - uint16_t red, green, blue, white, lux; - - while(!apds.colorDataReady()) { - delay(5); - } - - apds.getColorData(&red, &green, &blue, &white); - //calculate lux - lux = apds.calculateLux(red, green, blue); - return lux * LIGHT_FACTOR; -} - -ICACHE_RAM_ATTR void _anemometerInterrupt() { - anemometerRotations++; -#ifdef DEBUG - Serial.print("*"); -#endif -} - -float fetchWindspeed() { - anemometerRotations = 0; - currentTime = millis(); - int interruptNumber = digitalPinToInterrupt(ANEMOMETER_PIN); - - attachInterrupt(interruptNumber, _anemometerInterrupt, RISING); - delay(1000 * 5); - detachInterrupt(interruptNumber); - - return (float)anemometerRotations / 5.0 * 2.4; -} - -// Copied from https://arduinodiy.wordpress.com/2016/12/25/monitoring-lipo-battery-voltage-with-wemos-d1-minibattery-shield-and-thingspeak/ -#ifdef BATTERY_POWERED -float getBatteryVoltage() { - // ESP8266 ADC pin input voltage range ist 0V .. 1V - // The Wemos D1 mini does already contain a voltage divider circuit: A0(Wemos PCB) -- [220kOhm] -- ADC (ESP8266)-- [100kOhm] -- GND - // The (+) pole of the battery is connected to the A0 pin of the Wemos board through a additional 100kOhm resistance. - // The battery voltage of 4.2V max is measured as 1.0V on ESP8266 ADC pin. - uint16_t raw = analogRead(A0); - float volt = raw / 1023.0; - return volt * 4.2; -} - -float isBatCharging() { - if (LOW == digitalRead(BAT_CHARGING_PIN)) - { - return BAT_CHARGE_STATE_CHARGING; - } else if (LOW == digitalRead(BAT_CHARGED_PIN)) - { - return BAT_CHARGE_STATE_CHARGED; - } - - return BAT_CHARGE_STATE_NOTCHARGING; -} - -#endif diff --git a/firmware/webUpdater.ino b/firmware/webUpdater.ino index 7c93097..2b1bb87 100644 --- a/firmware/webUpdater.ino +++ b/firmware/webUpdater.ino @@ -46,7 +46,7 @@ void doWebUpdater(void) void setSensorData(String device, String localip, float sensorValues[]) { dev = device; ip = localip; - for (uint8_t i = 0; i < 7; i++) + for (uint8_t i = 0; i < VALUES; i++) { sensValues[i] = sensorValues[i]; }