├── .gitattributes ├── .gitignore ├── LICENSE.md ├── README.md ├── examples ├── AmbientLightInterrupt │ └── AmbientLightInterrupt.ino ├── ColorSensor │ └── ColorSensor.ino ├── GestureTest │ └── GestureTest.ino ├── ProximityInterrupt │ └── ProximityInterrupt.ino └── ProximitySensor │ └── ProximitySensor.ino ├── library.properties └── src ├── README.md ├── SparkFun_APDS9960.cpp └── SparkFun_APDS9960.h /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | *.sln merge=union 7 | *.csproj merge=union 8 | *.vbproj merge=union 9 | *.fsproj merge=union 10 | *.dbproj merge=union 11 | 12 | # Standard to msysgit 13 | *.doc diff=astextplain 14 | *.DOC diff=astextplain 15 | *.docx diff=astextplain 16 | *.DOCX diff=astextplain 17 | *.dot diff=astextplain 18 | *.DOT diff=astextplain 19 | *.pdf diff=astextplain 20 | *.PDF diff=astextplain 21 | *.rtf diff=astextplain 22 | *.RTF diff=astextplain 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ################# 2 | ## SparkFun Useful stuff 3 | ################# 4 | 5 | ## AVR Development 6 | *.eep 7 | *.elf 8 | *.lst 9 | *.lss 10 | *.sym 11 | *.d 12 | *.o 13 | *.srec 14 | *.map 15 | 16 | ## Notepad++ backup files 17 | *.bak 18 | 19 | ## BOM files 20 | *bom* 21 | 22 | ################# 23 | ## Eclipse 24 | ################# 25 | 26 | *.pydevproject 27 | .project 28 | .metadata 29 | bin/ 30 | tmp/ 31 | *.tmp 32 | *.bak 33 | *.swp 34 | *~.nib 35 | local.properties 36 | .classpath 37 | .settings/ 38 | .loadpath 39 | 40 | # External tool builders 41 | .externalToolBuilders/ 42 | 43 | # Locally stored "Eclipse launch configurations" 44 | *.launch 45 | 46 | # CDT-specific 47 | .cproject 48 | 49 | # PDT-specific 50 | .buildpath 51 | 52 | 53 | ############# 54 | ## Eagle 55 | ############# 56 | 57 | # Ignore the board and schematic backup files 58 | *.b#? 59 | *.s#? 60 | 61 | 62 | ################# 63 | ## Visual Studio 64 | ################# 65 | 66 | ## Ignore Visual Studio temporary files, build results, and 67 | ## files generated by popular Visual Studio add-ons. 68 | 69 | # User-specific files 70 | *.suo 71 | *.user 72 | *.sln.docstates 73 | 74 | # Build results 75 | [Dd]ebug/ 76 | [Rr]elease/ 77 | *_i.c 78 | *_p.c 79 | *.ilk 80 | *.meta 81 | *.obj 82 | *.pch 83 | *.pdb 84 | *.pgc 85 | *.pgd 86 | *.rsp 87 | *.sbr 88 | *.tlb 89 | *.tli 90 | *.tlh 91 | *.tmp 92 | *.vspscc 93 | .builds 94 | *.dotCover 95 | 96 | ## TODO: If you have NuGet Package Restore enabled, uncomment this 97 | #packages/ 98 | 99 | # Visual C++ cache files 100 | ipch/ 101 | *.aps 102 | *.ncb 103 | *.opensdf 104 | *.sdf 105 | 106 | # Visual Studio profiler 107 | *.psess 108 | *.vsp 109 | 110 | # ReSharper is a .NET coding add-in 111 | _ReSharper* 112 | 113 | # Installshield output folder 114 | [Ee]xpress 115 | 116 | # DocProject is a documentation generator add-in 117 | DocProject/buildhelp/ 118 | DocProject/Help/*.HxT 119 | DocProject/Help/*.HxC 120 | DocProject/Help/*.hhc 121 | DocProject/Help/*.hhk 122 | DocProject/Help/*.hhp 123 | DocProject/Help/Html2 124 | DocProject/Help/html 125 | 126 | # Click-Once directory 127 | publish 128 | 129 | # Others 130 | [Bb]in 131 | [Oo]bj 132 | sql 133 | TestResults 134 | *.Cache 135 | ClientBin 136 | stylecop.* 137 | ~$* 138 | *.dbmdl 139 | Generated_Code #added for RIA/Silverlight projects 140 | 141 | # Backup & report files from converting an old project file to a newer 142 | # Visual Studio version. Backup files are not needed, because we have git ;-) 143 | _UpgradeReport_Files/ 144 | Backup*/ 145 | UpgradeLog*.XML 146 | 147 | 148 | ############ 149 | ## Windows 150 | ############ 151 | 152 | # Windows image file caches 153 | Thumbs.db 154 | 155 | # Folder config file 156 | Desktop.ini 157 | 158 | 159 | ############# 160 | ## Python 161 | ############# 162 | 163 | *.py[co] 164 | 165 | # Packages 166 | *.egg 167 | *.egg-info 168 | dist 169 | build 170 | eggs 171 | parts 172 | bin 173 | var 174 | sdist 175 | develop-eggs 176 | .installed.cfg 177 | 178 | # Installer logs 179 | pip-log.txt 180 | 181 | # Unit test / coverage reports 182 | .coverage 183 | .tox 184 | 185 | #Translations 186 | *.mo 187 | 188 | #Mr Developer 189 | .mr.developer.cfg 190 | 191 | # Mac crap 192 | .DS_Store 193 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | 2 | License Information 3 | ------------------- 4 | 5 | The hardware is released under [Creative Commons Share-alike 3.0](http://creativecommons.org/licenses/by-sa/3.0/). 6 | 7 | All other code is open source so please feel free to do anything you want with it; you buy me a beer if you use this and we meet someday ([Beerware license](http://en.wikipedia.org/wiki/Beerware)). 8 | 9 | 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | SparkFun APDS9960 RGB and Gesture Sensor Arduino Library 2 | ========================================================= 3 | 4 | ![Avago APDS-9960 Breakout Board - SEN-12787 ](https://cdn.sparkfun.com/r/92-92/assets/parts/9/6/0/3/12787-01.jpg) 5 | 6 | [*Avago APDS-9960 Breakout Board (SEN-12787)*](https://www.sparkfun.com/products/12787) 7 | 8 | Getting Started 9 | --------------- 10 | 11 | * Download the Git repository as a ZIP ("Download ZIP" button) 12 | * Unzip 13 | * Copy the entire library directory (APDS-9960_RGB_and_Gesture_Sensor_Arduino_Library 14 | ) to \/libraries 15 | * Open the Arduino program 16 | * Select File -> Examples -> SparkFun_APDS9960 -> GestureTest 17 | * Plug in your Arduino and APDS-9960 with the following connections 18 | 19 | *-OR-* 20 | 21 | * Use the library manager 22 | 23 | | Arduino Pin | APDS-9960 Board | Function | 24 | |---|---|---| 25 | | 3.3V | VCC | Power | 26 | | GND | GND | Ground | 27 | | A4 | SDA | I2C Data | 28 | | A5 | SCL | I2C Clock | 29 | | 2 | INT | Interrupt | 30 | 31 | * Go to Tools -> Board and select your Arduino board 32 | * Go to Tools -> Serial Port and select the COM port of your Arduino board 33 | * Click "Upload" 34 | * Go to Tools -> Serial Monitor 35 | * Ensure the baud rate is set at 9600 baud 36 | * Swipe your hand over the sensor in various directions! 37 | 38 | Repository Contents 39 | ------------------- 40 | 41 | * **/examples** - Example sketches for the library (.ino). Run these from the Arduino IDE. 42 | * **/src** - Source files for the library (.cpp, .h). 43 | * **library.properties** - General library properties for the Arduino package manager. 44 | 45 | Documentation 46 | -------------- 47 | 48 | * **[Installing an Arduino Library Guide](https://learn.sparkfun.com/tutorials/installing-an-arduino-library)** - Basic information on how to install an Arduino library. 49 | * **[Product Repository](https://github.com/sparkfun/APDS-9960_RGB_and_Gesture_Sensor)** - Main repository (including hardware files) for the SparkFun_APDS9960 RGB and Gesture Sensor. 50 | * **[Hookup Guide](https://learn.sparkfun.com/tutorials/apds-9960-rgb-and-gesture-sensor-hookup-guide)** - Basic hookup guide for the sensor. 51 | 52 | Products that use this Library 53 | --------------------------------- 54 | 55 | * [SEN-12787](https://www.sparkfun.com/products/12787)- Avago APDS-9960 56 | 57 | Version History 58 | --------------- 59 | * [V_1.4.1](https://github.com/sparkfun/SparkFun_APDS-9960_Sensor_Arduino_Library/tree/V_1.4.1) - Removing blank files, updating library.properties file. 60 | * [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 61 | * V_1.3.0 - Implemented disableProximitySensor(). Thanks to jmg5150 for catching that! 62 | * V_1.2.0 - Added pinMode line to GestureTest demo to fix interrupt bug with some Arduinos 63 | * V_1.1.0 - Updated GestureTest demo to not freeze with fast swipes 64 | * V_1.0.0: Initial release 65 | * Ambient and RGB light sensing implemented 66 | * Ambient light interrupts working 67 | * Proximity sensing implemented 68 | * Proximity interrupts working 69 | * Gesture (UP, DOWN, LEFT, RIGHT, NEAR, FAR) sensing implemented 70 | 71 | License Information 72 | ------------------- 73 | 74 | This product is _**open source**_! 75 | 76 | The **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! 77 | 78 | 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. 79 | 80 | Distributed as-is; no warranty is given. 81 | 82 | - Your friends at SparkFun. 83 | -------------------------------------------------------------------------------- /examples/AmbientLightInterrupt/AmbientLightInterrupt.ino: -------------------------------------------------------------------------------- 1 | /**************************************************************** 2 | AmbientLightInterrupt.ino 3 | APDS-9960 RGB and Gesture Sensor 4 | Shawn Hymel @ SparkFun Electronics 5 | October 24, 2014 6 | https://github.com/sparkfun/APDS-9960_RGB_and_Gesture_Sensor 7 | 8 | Tests the ambient light interrupt abilities of the APDS-9960. 9 | Configures the APDS-9960 over I2C and waits for an external 10 | interrupt based on high or low light conditions. Try covering 11 | the sensor with your hand or bringing the sensor close to a 12 | bright light source. You might need to adjust the LIGHT_INT_HIGH 13 | and LIGHT_INT_LOW values to get the interrupt to work correctly. 14 | 15 | Hardware Connections: 16 | 17 | IMPORTANT: The APDS-9960 can only accept 3.3V! 18 | 19 | Arduino Pin APDS-9960 Board Function 20 | 21 | 3.3V VCC Power 22 | GND GND Ground 23 | A4 SDA I2C Data 24 | A5 SCL I2C Clock 25 | 2 INT Interrupt 26 | 13 - LED 27 | 28 | Resources: 29 | Include Wire.h and SparkFun_APDS-9960.h 30 | 31 | Development environment specifics: 32 | Written in Arduino 1.0.5 33 | Tested with SparkFun Arduino Pro Mini 3.3V 34 | 35 | This code is beerware; if you see me (or any other SparkFun 36 | employee) at the local, and you've found our code helpful, please 37 | buy us a round! 38 | 39 | Distributed as-is; no warranty is given. 40 | ****************************************************************/ 41 | 42 | #include 43 | #include 44 | 45 | // Pins 46 | #define APDS9960_INT 2 // Needs to be an interrupt pin 47 | #define LED_PIN 13 // LED for showing interrupt 48 | 49 | // Constants 50 | #define LIGHT_INT_HIGH 1000 // High light level for interrupt 51 | #define LIGHT_INT_LOW 10 // Low light level for interrupt 52 | 53 | // Global variables 54 | SparkFun_APDS9960 apds = SparkFun_APDS9960(); 55 | uint16_t ambient_light = 0; 56 | uint16_t red_light = 0; 57 | uint16_t green_light = 0; 58 | uint16_t blue_light = 0; 59 | int isr_flag = 0; 60 | uint16_t threshold = 0; 61 | 62 | void setup() { 63 | 64 | // Set LED as output 65 | pinMode(LED_PIN, OUTPUT); 66 | pinMode(APDS9960_INT, INPUT); 67 | 68 | // Initialize Serial port 69 | Serial.begin(9600); 70 | Serial.println(); 71 | Serial.println(F("-------------------------------------")); 72 | Serial.println(F("SparkFun APDS-9960 - Light Interrupts")); 73 | Serial.println(F("-------------------------------------")); 74 | 75 | // Initialize interrupt service routine 76 | attachInterrupt(0, interruptRoutine, FALLING); 77 | 78 | // Initialize APDS-9960 (configure I2C and initial values) 79 | if ( apds.init() ) { 80 | Serial.println(F("APDS-9960 initialization complete")); 81 | } else { 82 | Serial.println(F("Something went wrong during APDS-9960 init!")); 83 | } 84 | 85 | // Set high and low interrupt thresholds 86 | if ( !apds.setLightIntLowThreshold(LIGHT_INT_LOW) ) { 87 | Serial.println(F("Error writing low threshold")); 88 | } 89 | if ( !apds.setLightIntHighThreshold(LIGHT_INT_HIGH) ) { 90 | Serial.println(F("Error writing high threshold")); 91 | } 92 | 93 | // Start running the APDS-9960 light sensor (no interrupts) 94 | if ( apds.enableLightSensor(false) ) { 95 | Serial.println(F("Light sensor is now running")); 96 | } else { 97 | Serial.println(F("Something went wrong during light sensor init!")); 98 | } 99 | 100 | // Read high and low interrupt thresholds 101 | if ( !apds.getLightIntLowThreshold(threshold) ) { 102 | Serial.println(F("Error reading low threshold")); 103 | } else { 104 | Serial.print(F("Low Threshold: ")); 105 | Serial.println(threshold); 106 | } 107 | if ( !apds.getLightIntHighThreshold(threshold) ) { 108 | Serial.println(F("Error reading high threshold")); 109 | } else { 110 | Serial.print(F("High Threshold: ")); 111 | Serial.println(threshold); 112 | } 113 | 114 | // Enable interrupts 115 | if ( !apds.setAmbientLightIntEnable(1) ) { 116 | Serial.println(F("Error enabling interrupts")); 117 | } 118 | 119 | // Wait for initialization and calibration to finish 120 | delay(500); 121 | } 122 | 123 | void loop() { 124 | 125 | // If interrupt occurs, print out the light levels 126 | if ( isr_flag == 1 ) { 127 | 128 | // Read the light levels (ambient, red, green, blue) and print 129 | if ( !apds.readAmbientLight(ambient_light) || 130 | !apds.readRedLight(red_light) || 131 | !apds.readGreenLight(green_light) || 132 | !apds.readBlueLight(blue_light) ) { 133 | Serial.println("Error reading light values"); 134 | } else { 135 | Serial.print("Interrupt! Ambient: "); 136 | Serial.print(ambient_light); 137 | Serial.print(" R: "); 138 | Serial.print(red_light); 139 | Serial.print(" G: "); 140 | Serial.print(green_light); 141 | Serial.print(" B: "); 142 | Serial.println(blue_light); 143 | } 144 | 145 | // Turn on LED for a half a second 146 | digitalWrite(LED_PIN, HIGH); 147 | delay(500); 148 | digitalWrite(LED_PIN, LOW); 149 | 150 | // Reset flag and clear APDS-9960 interrupt (IMPORTANT!) 151 | isr_flag = 0; 152 | if ( !apds.clearAmbientLightInt() ) { 153 | Serial.println("Error clearing interrupt"); 154 | } 155 | 156 | } 157 | } 158 | 159 | void interruptRoutine() { 160 | isr_flag = 1; 161 | } -------------------------------------------------------------------------------- /examples/ColorSensor/ColorSensor.ino: -------------------------------------------------------------------------------- 1 | /**************************************************************** 2 | ColorSensor.ino 3 | APDS-9960 RGB and Gesture Sensor 4 | Shawn Hymel @ SparkFun Electronics 5 | October 15, 2014 6 | https://github.com/sparkfun/APDS-9960_RGB_and_Gesture_Sensor 7 | 8 | Tests the color and ambient light sensing abilities of the 9 | APDS-9960. Configures APDS-9960 over I2C and polls the sensor for 10 | ambient light and color levels, which are displayed over the 11 | serial console. 12 | 13 | Hardware Connections: 14 | 15 | IMPORTANT: The APDS-9960 can only accept 3.3V! 16 | 17 | Arduino Pin APDS-9960 Board Function 18 | 19 | 3.3V VCC Power 20 | GND GND Ground 21 | A4 SDA I2C Data 22 | A5 SCL I2C Clock 23 | 24 | Resources: 25 | Include Wire.h and SparkFun_APDS-9960.h 26 | 27 | Development environment specifics: 28 | Written in Arduino 1.0.5 29 | Tested with SparkFun Arduino Pro Mini 3.3V 30 | 31 | This code is beerware; if you see me (or any other SparkFun 32 | employee) at the local, and you've found our code helpful, please 33 | buy us a round! 34 | 35 | Distributed as-is; no warranty is given. 36 | ****************************************************************/ 37 | 38 | #include 39 | #include 40 | 41 | // Global Variables 42 | SparkFun_APDS9960 apds = SparkFun_APDS9960(); 43 | uint16_t ambient_light = 0; 44 | uint16_t red_light = 0; 45 | uint16_t green_light = 0; 46 | uint16_t blue_light = 0; 47 | 48 | void setup() { 49 | 50 | // Initialize Serial port 51 | Serial.begin(9600); 52 | Serial.println(); 53 | Serial.println(F("--------------------------------")); 54 | Serial.println(F("SparkFun APDS-9960 - ColorSensor")); 55 | Serial.println(F("--------------------------------")); 56 | 57 | // Initialize APDS-9960 (configure I2C and initial values) 58 | if ( apds.init() ) { 59 | Serial.println(F("APDS-9960 initialization complete")); 60 | } else { 61 | Serial.println(F("Something went wrong during APDS-9960 init!")); 62 | } 63 | 64 | // Start running the APDS-9960 light sensor (no interrupts) 65 | if ( apds.enableLightSensor(false) ) { 66 | Serial.println(F("Light sensor is now running")); 67 | } else { 68 | Serial.println(F("Something went wrong during light sensor init!")); 69 | } 70 | 71 | // Wait for initialization and calibration to finish 72 | delay(500); 73 | } 74 | 75 | void loop() { 76 | 77 | // Read the light levels (ambient, red, green, blue) 78 | if ( !apds.readAmbientLight(ambient_light) || 79 | !apds.readRedLight(red_light) || 80 | !apds.readGreenLight(green_light) || 81 | !apds.readBlueLight(blue_light) ) { 82 | Serial.println("Error reading light values"); 83 | } else { 84 | Serial.print("Ambient: "); 85 | Serial.print(ambient_light); 86 | Serial.print(" Red: "); 87 | Serial.print(red_light); 88 | Serial.print(" Green: "); 89 | Serial.print(green_light); 90 | Serial.print(" Blue: "); 91 | Serial.println(blue_light); 92 | } 93 | 94 | // Wait 1 second before next reading 95 | delay(1000); 96 | } -------------------------------------------------------------------------------- /examples/GestureTest/GestureTest.ino: -------------------------------------------------------------------------------- 1 | /**************************************************************** 2 | GestureTest.ino 3 | APDS-9960 RGB and Gesture Sensor 4 | Shawn Hymel @ SparkFun Electronics 5 | May 30, 2014 6 | https://github.com/sparkfun/APDS-9960_RGB_and_Gesture_Sensor 7 | 8 | Tests the gesture sensing abilities of the APDS-9960. Configures 9 | APDS-9960 over I2C and waits for gesture events. Calculates the 10 | direction of the swipe (up, down, left, right) and displays it 11 | on a serial console. 12 | 13 | To perform a NEAR gesture, hold your hand 14 | far above the sensor and move it close to the sensor (within 2 15 | inches). Hold your hand there for at least 1 second and move it 16 | away. 17 | 18 | To perform a FAR gesture, hold your hand within 2 inches of the 19 | sensor for at least 1 second and then move it above (out of 20 | range) of the sensor. 21 | 22 | Hardware Connections: 23 | 24 | IMPORTANT: The APDS-9960 can only accept 3.3V! 25 | 26 | Arduino Pin APDS-9960 Board Function 27 | 28 | 3.3V VCC Power 29 | GND GND Ground 30 | A4 SDA I2C Data 31 | A5 SCL I2C Clock 32 | 2 INT Interrupt 33 | 34 | Resources: 35 | Include Wire.h and SparkFun_APDS-9960.h 36 | 37 | Development environment specifics: 38 | Written in Arduino 1.0.5 39 | Tested with SparkFun Arduino Pro Mini 3.3V 40 | 41 | This code is beerware; if you see me (or any other SparkFun 42 | employee) at the local, and you've found our code helpful, please 43 | buy us a round! 44 | 45 | Distributed as-is; no warranty is given. 46 | ****************************************************************/ 47 | 48 | #include 49 | #include 50 | 51 | // Pins 52 | #define APDS9960_INT 2 // Needs to be an interrupt pin 53 | 54 | // Constants 55 | 56 | // Global Variables 57 | SparkFun_APDS9960 apds = SparkFun_APDS9960(); 58 | int isr_flag = 0; 59 | 60 | void setup() { 61 | 62 | // Set interrupt pin as input 63 | pinMode(APDS9960_INT, INPUT); 64 | 65 | // Initialize Serial port 66 | Serial.begin(9600); 67 | Serial.println(); 68 | Serial.println(F("--------------------------------")); 69 | Serial.println(F("SparkFun APDS-9960 - GestureTest")); 70 | Serial.println(F("--------------------------------")); 71 | 72 | // Initialize interrupt service routine 73 | attachInterrupt(0, interruptRoutine, FALLING); 74 | 75 | // Initialize APDS-9960 (configure I2C and initial values) 76 | if ( apds.init() ) { 77 | Serial.println(F("APDS-9960 initialization complete")); 78 | } else { 79 | Serial.println(F("Something went wrong during APDS-9960 init!")); 80 | } 81 | 82 | // Start running the APDS-9960 gesture sensor engine 83 | if ( apds.enableGestureSensor(true) ) { 84 | Serial.println(F("Gesture sensor is now running")); 85 | } else { 86 | Serial.println(F("Something went wrong during gesture sensor init!")); 87 | } 88 | } 89 | 90 | void loop() { 91 | if( isr_flag == 1 ) { 92 | detachInterrupt(0); 93 | handleGesture(); 94 | isr_flag = 0; 95 | attachInterrupt(0, interruptRoutine, FALLING); 96 | } 97 | } 98 | 99 | void interruptRoutine() { 100 | isr_flag = 1; 101 | } 102 | 103 | void handleGesture() { 104 | if ( apds.isGestureAvailable() ) { 105 | switch ( apds.readGesture() ) { 106 | case DIR_UP: 107 | Serial.println("UP"); 108 | break; 109 | case DIR_DOWN: 110 | Serial.println("DOWN"); 111 | break; 112 | case DIR_LEFT: 113 | Serial.println("LEFT"); 114 | break; 115 | case DIR_RIGHT: 116 | Serial.println("RIGHT"); 117 | break; 118 | case DIR_NEAR: 119 | Serial.println("NEAR"); 120 | break; 121 | case DIR_FAR: 122 | Serial.println("FAR"); 123 | break; 124 | default: 125 | Serial.println("NONE"); 126 | } 127 | } 128 | } -------------------------------------------------------------------------------- /examples/ProximityInterrupt/ProximityInterrupt.ino: -------------------------------------------------------------------------------- 1 | /**************************************************************** 2 | ProximityInterrupt.ino 3 | APDS-9960 RGB and Gesture Sensor 4 | Shawn Hymel @ SparkFun Electronics 5 | October 24, 2014 6 | https://github.com/sparkfun/APDS-9960_RGB_and_Gesture_Sensor 7 | 8 | Tests the proximity interrupt abilities of the APDS-9960. 9 | Configures the APDS-9960 over I2C and waits for an external 10 | interrupt based on high or low proximity conditions. Move your 11 | hand near the sensor and watch the LED on pin 13. 12 | 13 | Hardware Connections: 14 | 15 | IMPORTANT: The APDS-9960 can only accept 3.3V! 16 | 17 | Arduino Pin APDS-9960 Board Function 18 | 19 | 3.3V VCC Power 20 | GND GND Ground 21 | A4 SDA I2C Data 22 | A5 SCL I2C Clock 23 | 2 INT Interrupt 24 | 13 - LED 25 | 26 | Resources: 27 | Include Wire.h and SparkFun_APDS-9960.h 28 | 29 | Development environment specifics: 30 | Written in Arduino 1.0.5 31 | Tested with SparkFun Arduino Pro Mini 3.3V 32 | 33 | This code is beerware; if you see me (or any other SparkFun 34 | employee) at the local, and you've found our code helpful, please 35 | buy us a round! 36 | 37 | Distributed as-is; no warranty is given. 38 | ****************************************************************/ 39 | 40 | #include 41 | #include 42 | 43 | // Pins 44 | #define APDS9960_INT 2 // Needs to be an interrupt pin 45 | #define LED_PIN 13 // LED for showing interrupt 46 | 47 | // Constants 48 | #define PROX_INT_HIGH 50 // Proximity level for interrupt 49 | #define PROX_INT_LOW 0 // No far interrupt 50 | 51 | // Global variables 52 | SparkFun_APDS9960 apds = SparkFun_APDS9960(); 53 | uint8_t proximity_data = 0; 54 | int isr_flag = 0; 55 | 56 | void setup() { 57 | 58 | // Set LED as output 59 | pinMode(LED_PIN, OUTPUT); 60 | pinMode(APDS9960_INT, INPUT); 61 | 62 | // Initialize Serial port 63 | Serial.begin(9600); 64 | Serial.println(); 65 | Serial.println(F("---------------------------------------")); 66 | Serial.println(F("SparkFun APDS-9960 - ProximityInterrupt")); 67 | Serial.println(F("---------------------------------------")); 68 | 69 | // Initialize interrupt service routine 70 | attachInterrupt(0, interruptRoutine, FALLING); 71 | 72 | // Initialize APDS-9960 (configure I2C and initial values) 73 | if ( apds.init() ) { 74 | Serial.println(F("APDS-9960 initialization complete")); 75 | } else { 76 | Serial.println(F("Something went wrong during APDS-9960 init!")); 77 | } 78 | 79 | // Adjust the Proximity sensor gain 80 | if ( !apds.setProximityGain(PGAIN_2X) ) { 81 | Serial.println(F("Something went wrong trying to set PGAIN")); 82 | } 83 | 84 | // Set proximity interrupt thresholds 85 | if ( !apds.setProximityIntLowThreshold(PROX_INT_LOW) ) { 86 | Serial.println(F("Error writing low threshold")); 87 | } 88 | if ( !apds.setProximityIntHighThreshold(PROX_INT_HIGH) ) { 89 | Serial.println(F("Error writing high threshold")); 90 | } 91 | 92 | // Start running the APDS-9960 proximity sensor (interrupts) 93 | if ( apds.enableProximitySensor(true) ) { 94 | Serial.println(F("Proximity sensor is now running")); 95 | } else { 96 | Serial.println(F("Something went wrong during sensor init!")); 97 | } 98 | } 99 | 100 | void loop() { 101 | 102 | // If interrupt occurs, print out the proximity level 103 | if ( isr_flag == 1 ) { 104 | 105 | // Read proximity level and print it out 106 | if ( !apds.readProximity(proximity_data) ) { 107 | Serial.println("Error reading proximity value"); 108 | } else { 109 | Serial.print("Proximity detected! Level: "); 110 | Serial.println(proximity_data); 111 | } 112 | 113 | // Turn on LED for a half a second 114 | digitalWrite(LED_PIN, HIGH); 115 | delay(500); 116 | digitalWrite(LED_PIN, LOW); 117 | 118 | // Reset flag and clear APDS-9960 interrupt (IMPORTANT!) 119 | isr_flag = 0; 120 | if ( !apds.clearProximityInt() ) { 121 | Serial.println("Error clearing interrupt"); 122 | } 123 | 124 | } 125 | } 126 | 127 | void interruptRoutine() { 128 | isr_flag = 1; 129 | } -------------------------------------------------------------------------------- /examples/ProximitySensor/ProximitySensor.ino: -------------------------------------------------------------------------------- 1 | /**************************************************************** 2 | ProximityTest.ino 3 | APDS-9960 RGB and Gesture Sensor 4 | Shawn Hymel @ SparkFun Electronics 5 | October 28, 2014 6 | https://github.com/sparkfun/APDS-9960_RGB_and_Gesture_Sensor 7 | 8 | Tests the proximity sensing abilities of the APDS-9960. 9 | Configures the APDS-9960 over I2C and polls for the distance to 10 | the object nearest the sensor. 11 | 12 | Hardware Connections: 13 | 14 | IMPORTANT: The APDS-9960 can only accept 3.3V! 15 | 16 | Arduino Pin APDS-9960 Board Function 17 | 18 | 3.3V VCC Power 19 | GND GND Ground 20 | A4 SDA I2C Data 21 | A5 SCL I2C Clock 22 | 23 | Resources: 24 | Include Wire.h and SparkFun_APDS-9960.h 25 | 26 | Development environment specifics: 27 | Written in Arduino 1.0.5 28 | Tested with SparkFun Arduino Pro Mini 3.3V 29 | 30 | This code is beerware; if you see me (or any other SparkFun 31 | employee) at the local, and you've found our code helpful, please 32 | buy us a round! 33 | 34 | Distributed as-is; no warranty is given. 35 | ****************************************************************/ 36 | 37 | #include 38 | #include 39 | 40 | // Global Variables 41 | SparkFun_APDS9960 apds = SparkFun_APDS9960(); 42 | uint8_t proximity_data = 0; 43 | 44 | void setup() { 45 | 46 | // Initialize Serial port 47 | Serial.begin(9600); 48 | Serial.println(); 49 | Serial.println(F("------------------------------------")); 50 | Serial.println(F("SparkFun APDS-9960 - ProximitySensor")); 51 | Serial.println(F("------------------------------------")); 52 | 53 | // Initialize APDS-9960 (configure I2C and initial values) 54 | if ( apds.init() ) { 55 | Serial.println(F("APDS-9960 initialization complete")); 56 | } else { 57 | Serial.println(F("Something went wrong during APDS-9960 init!")); 58 | } 59 | 60 | // Adjust the Proximity sensor gain 61 | if ( !apds.setProximityGain(PGAIN_2X) ) { 62 | Serial.println(F("Something went wrong trying to set PGAIN")); 63 | } 64 | 65 | // Start running the APDS-9960 proximity sensor (no interrupts) 66 | if ( apds.enableProximitySensor(false) ) { 67 | Serial.println(F("Proximity sensor is now running")); 68 | } else { 69 | Serial.println(F("Something went wrong during sensor init!")); 70 | } 71 | } 72 | 73 | void loop() { 74 | 75 | // Read the proximity value 76 | if ( !apds.readProximity(proximity_data) ) { 77 | Serial.println("Error reading proximity value"); 78 | } else { 79 | Serial.print("Proximity: "); 80 | Serial.println(proximity_data); 81 | } 82 | 83 | // Wait 250 ms before next reading 84 | delay(250); 85 | } -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=SparkFun APDS9960 RGB and Gesture Sensor 2 | version=1.4.3 3 | author=SparkFun Electronics 4 | maintainer=SparkFun Electronics 5 | sentence=Library for the Avago APDS-9960 sensor 6 | paragraph=This library works with the SparkFun Breakout board for the Avago APDS-9960 proximity, light, RGB, and gesture sensor, made by SparkFun Electronics. 7 | category=Sensors 8 | url=https://github.com/sparkfun/SparkFun_APDS-9960_Sensor_Arduino_Library 9 | architectures=* 10 | -------------------------------------------------------------------------------- /src/README.md: -------------------------------------------------------------------------------- 1 | This folder should contain the .cpp and .h files for the library. 2 | 3 | If backward compatibility is needed, source code should be placed in the library root folder and in a "utilyt" folder. 4 | 5 | Check out the [library specification](https://github.com/arduino/Arduino/wiki/Arduino-IDE-1.5:-Library-specification) for more details. -------------------------------------------------------------------------------- /src/SparkFun_APDS9960.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @file SparkFun_APDS-9960.cpp 3 | * @brief Library for the SparkFun APDS-9960 breakout board 4 | * @author Shawn Hymel (SparkFun Electronics) 5 | * 6 | * @copyright This code is public domain but you buy me a beer if you use 7 | * this and we meet someday (Beerware license). 8 | * 9 | * This library interfaces the Avago APDS-9960 to Arduino over I2C. The library 10 | * relies on the Arduino Wire (I2C) library. to use the library, instantiate an 11 | * APDS9960 object, call init(), and call the appropriate functions. 12 | * 13 | * APDS-9960 current draw tests (default parameters): 14 | * Off: 1mA 15 | * Waiting for gesture: 14mA 16 | * Gesture in progress: 35mA 17 | */ 18 | 19 | #include 20 | #include 21 | 22 | #include "SparkFun_APDS9960.h" 23 | 24 | /** 25 | * @brief Constructor - Instantiates SparkFun_APDS9960 object 26 | */ 27 | SparkFun_APDS9960::SparkFun_APDS9960() 28 | { 29 | gesture_ud_delta_ = 0; 30 | gesture_lr_delta_ = 0; 31 | 32 | gesture_ud_count_ = 0; 33 | gesture_lr_count_ = 0; 34 | 35 | gesture_near_count_ = 0; 36 | gesture_far_count_ = 0; 37 | 38 | gesture_state_ = 0; 39 | gesture_motion_ = DIR_NONE; 40 | } 41 | 42 | /** 43 | * @brief Destructor 44 | */ 45 | SparkFun_APDS9960::~SparkFun_APDS9960() 46 | { 47 | 48 | } 49 | 50 | /** 51 | * @brief Configures I2C communications and initializes registers to defaults 52 | * 53 | * @return True if initialized successfully. False otherwise. 54 | */ 55 | bool SparkFun_APDS9960::init() 56 | { 57 | uint8_t id; 58 | 59 | /* Initialize I2C */ 60 | Wire.begin(); 61 | 62 | /* Read ID register and check against known values for APDS-9960 */ 63 | if( !wireReadDataByte(APDS9960_ID, id) ) { 64 | return false; 65 | } 66 | if( !(id == APDS9960_ID_1 || id == APDS9960_ID_2) ) { 67 | return false; 68 | } 69 | 70 | /* Set ENABLE register to 0 (disable all features) */ 71 | if( !setMode(ALL, OFF) ) { 72 | return false; 73 | } 74 | 75 | /* Set default values for ambient light and proximity registers */ 76 | if( !wireWriteDataByte(APDS9960_ATIME, DEFAULT_ATIME) ) { 77 | return false; 78 | } 79 | if( !wireWriteDataByte(APDS9960_WTIME, DEFAULT_WTIME) ) { 80 | return false; 81 | } 82 | if( !wireWriteDataByte(APDS9960_PPULSE, DEFAULT_PROX_PPULSE) ) { 83 | return false; 84 | } 85 | if( !wireWriteDataByte(APDS9960_POFFSET_UR, DEFAULT_POFFSET_UR) ) { 86 | return false; 87 | } 88 | if( !wireWriteDataByte(APDS9960_POFFSET_DL, DEFAULT_POFFSET_DL) ) { 89 | return false; 90 | } 91 | if( !wireWriteDataByte(APDS9960_CONFIG1, DEFAULT_CONFIG1) ) { 92 | return false; 93 | } 94 | if( !setLEDDrive(DEFAULT_LDRIVE) ) { 95 | return false; 96 | } 97 | if( !setProximityGain(DEFAULT_PGAIN) ) { 98 | return false; 99 | } 100 | if( !setAmbientLightGain(DEFAULT_AGAIN) ) { 101 | return false; 102 | } 103 | if( !setProxIntLowThresh(DEFAULT_PILT) ) { 104 | return false; 105 | } 106 | if( !setProxIntHighThresh(DEFAULT_PIHT) ) { 107 | return false; 108 | } 109 | if( !setLightIntLowThreshold(DEFAULT_AILT) ) { 110 | return false; 111 | } 112 | if( !setLightIntHighThreshold(DEFAULT_AIHT) ) { 113 | return false; 114 | } 115 | if( !wireWriteDataByte(APDS9960_PERS, DEFAULT_PERS) ) { 116 | return false; 117 | } 118 | if( !wireWriteDataByte(APDS9960_CONFIG2, DEFAULT_CONFIG2) ) { 119 | return false; 120 | } 121 | if( !wireWriteDataByte(APDS9960_CONFIG3, DEFAULT_CONFIG3) ) { 122 | return false; 123 | } 124 | 125 | /* Set default values for gesture sense registers */ 126 | if( !setGestureEnterThresh(DEFAULT_GPENTH) ) { 127 | return false; 128 | } 129 | if( !setGestureExitThresh(DEFAULT_GEXTH) ) { 130 | return false; 131 | } 132 | if( !wireWriteDataByte(APDS9960_GCONF1, DEFAULT_GCONF1) ) { 133 | return false; 134 | } 135 | if( !setGestureGain(DEFAULT_GGAIN) ) { 136 | return false; 137 | } 138 | if( !setGestureLEDDrive(DEFAULT_GLDRIVE) ) { 139 | return false; 140 | } 141 | if( !setGestureWaitTime(DEFAULT_GWTIME) ) { 142 | return false; 143 | } 144 | if( !wireWriteDataByte(APDS9960_GOFFSET_U, DEFAULT_GOFFSET) ) { 145 | return false; 146 | } 147 | if( !wireWriteDataByte(APDS9960_GOFFSET_D, DEFAULT_GOFFSET) ) { 148 | return false; 149 | } 150 | if( !wireWriteDataByte(APDS9960_GOFFSET_L, DEFAULT_GOFFSET) ) { 151 | return false; 152 | } 153 | if( !wireWriteDataByte(APDS9960_GOFFSET_R, DEFAULT_GOFFSET) ) { 154 | return false; 155 | } 156 | if( !wireWriteDataByte(APDS9960_GPULSE, DEFAULT_GPULSE) ) { 157 | return false; 158 | } 159 | if( !wireWriteDataByte(APDS9960_GCONF3, DEFAULT_GCONF3) ) { 160 | return false; 161 | } 162 | if( !setGestureIntEnable(DEFAULT_GIEN) ) { 163 | return false; 164 | } 165 | 166 | #if 0 167 | /* Gesture config register dump */ 168 | uint8_t reg; 169 | uint8_t val; 170 | 171 | for(reg = 0x80; reg <= 0xAF; reg++) { 172 | if( (reg != 0x82) && \ 173 | (reg != 0x8A) && \ 174 | (reg != 0x91) && \ 175 | (reg != 0xA8) && \ 176 | (reg != 0xAC) && \ 177 | (reg != 0xAD) ) 178 | { 179 | wireReadDataByte(reg, val); 180 | Serial.print(reg, HEX); 181 | Serial.print(": 0x"); 182 | Serial.println(val, HEX); 183 | } 184 | } 185 | 186 | for(reg = 0xE4; reg <= 0xE7; reg++) { 187 | wireReadDataByte(reg, val); 188 | Serial.print(reg, HEX); 189 | Serial.print(": 0x"); 190 | Serial.println(val, HEX); 191 | } 192 | #endif 193 | 194 | return true; 195 | } 196 | 197 | /******************************************************************************* 198 | * Public methods for controlling the APDS-9960 199 | ******************************************************************************/ 200 | 201 | /** 202 | * @brief Reads and returns the contents of the STATUS register 203 | * 204 | * @return Contents of the STATUS register. 0xFF if error. 205 | */ 206 | uint8_t SparkFun_APDS9960::getStatusRegister() 207 | { 208 | uint8_t status_value; 209 | 210 | /* Read current ENABLE register */ 211 | if(!wireReadDataByte(APDS9960_STATUS, status_value) ) { 212 | return ERROR; 213 | } 214 | 215 | return status_value; 216 | } 217 | 218 | /** 219 | * @brief Reads and returns the contents of the ENABLE register 220 | * 221 | * @return Contents of the ENABLE register. 0xFF if error. 222 | */ 223 | uint8_t SparkFun_APDS9960::getMode() 224 | { 225 | uint8_t enable_value; 226 | 227 | /* Read current ENABLE register */ 228 | if( !wireReadDataByte(APDS9960_ENABLE, enable_value) ) { 229 | return ERROR; 230 | } 231 | 232 | return enable_value; 233 | } 234 | 235 | /** 236 | * @brief Enables or disables a feature in the APDS-9960 237 | * 238 | * @param[in] mode which feature to enable 239 | * @param[in] enable ON (1) or OFF (0) 240 | * @return True if operation success. False otherwise. 241 | */ 242 | bool SparkFun_APDS9960::setMode(uint8_t mode, uint8_t enable) 243 | { 244 | uint8_t reg_val; 245 | 246 | /* Read current ENABLE register */ 247 | reg_val = getMode(); 248 | if( reg_val == ERROR ) { 249 | return false; 250 | } 251 | 252 | /* Change bit(s) in ENABLE register */ 253 | enable = enable & 0x01; 254 | if( mode >= 0 && mode <= 6 ) { 255 | if (enable) { 256 | reg_val |= (1 << mode); 257 | } else { 258 | reg_val &= ~(1 << mode); 259 | } 260 | } else if( mode == ALL ) { 261 | if (enable) { 262 | reg_val = 0x7F; 263 | } else { 264 | reg_val = 0x00; 265 | } 266 | } 267 | 268 | /* Write value back to ENABLE register */ 269 | if( !wireWriteDataByte(APDS9960_ENABLE, reg_val) ) { 270 | return false; 271 | } 272 | 273 | return true; 274 | } 275 | 276 | /** 277 | * @brief Starts the light (R/G/B/Ambient) sensor on the APDS-9960 278 | * 279 | * @param[in] interrupts true to enable hardware interrupt on high or low light 280 | * @return True if sensor enabled correctly. False on error. 281 | */ 282 | bool SparkFun_APDS9960::enableLightSensor(bool interrupts) 283 | { 284 | 285 | /* Set default gain, interrupts, enable power, and enable sensor */ 286 | if( !setAmbientLightGain(DEFAULT_AGAIN) ) { 287 | return false; 288 | } 289 | if( interrupts ) { 290 | if( !setAmbientLightIntEnable(1) ) { 291 | return false; 292 | } 293 | } else { 294 | if( !setAmbientLightIntEnable(0) ) { 295 | return false; 296 | } 297 | } 298 | if( !enablePower() ){ 299 | return false; 300 | } 301 | if( !setMode(AMBIENT_LIGHT, 1) ) { 302 | return false; 303 | } 304 | 305 | return true; 306 | 307 | } 308 | 309 | /** 310 | * @brief Ends the light sensor on the APDS-9960 311 | * 312 | * @return True if sensor disabled correctly. False on error. 313 | */ 314 | bool SparkFun_APDS9960::disableLightSensor() 315 | { 316 | if( !setAmbientLightIntEnable(0) ) { 317 | return false; 318 | } 319 | if( !setMode(AMBIENT_LIGHT, 0) ) { 320 | return false; 321 | } 322 | 323 | return true; 324 | } 325 | 326 | /** 327 | * @brief Starts the proximity sensor on the APDS-9960 328 | * 329 | * @param[in] interrupts true to enable hardware external interrupt on proximity 330 | * @return True if sensor enabled correctly. False on error. 331 | */ 332 | bool SparkFun_APDS9960::enableProximitySensor(bool interrupts) 333 | { 334 | /* Set default gain, LED, interrupts, enable power, and enable sensor */ 335 | if( !setProximityGain(DEFAULT_PGAIN) ) { 336 | return false; 337 | } 338 | if( !setLEDDrive(DEFAULT_LDRIVE) ) { 339 | return false; 340 | } 341 | if( interrupts ) { 342 | if( !setProximityIntEnable(1) ) { 343 | return false; 344 | } 345 | } else { 346 | if( !setProximityIntEnable(0) ) { 347 | return false; 348 | } 349 | } 350 | if( !enablePower() ){ 351 | return false; 352 | } 353 | if( !setMode(PROXIMITY, 1) ) { 354 | return false; 355 | } 356 | 357 | return true; 358 | } 359 | 360 | /** 361 | * @brief Ends the proximity sensor on the APDS-9960 362 | * 363 | * @return True if sensor disabled correctly. False on error. 364 | */ 365 | bool SparkFun_APDS9960::disableProximitySensor() 366 | { 367 | if( !setProximityIntEnable(0) ) { 368 | return false; 369 | } 370 | if( !setMode(PROXIMITY, 0) ) { 371 | return false; 372 | } 373 | 374 | return true; 375 | } 376 | 377 | /** 378 | * @brief Starts the gesture recognition engine on the APDS-9960 379 | * 380 | * @param[in] interrupts true to enable hardware external interrupt on gesture 381 | * @return True if engine enabled correctly. False on error. 382 | */ 383 | bool SparkFun_APDS9960::enableGestureSensor(bool interrupts) 384 | { 385 | 386 | /* Enable gesture mode 387 | Set ENABLE to 0 (power off) 388 | Set WTIME to 0xFF 389 | Set AUX to LED_BOOST_300 390 | Enable PON, WEN, PEN, GEN in ENABLE 391 | */ 392 | resetGestureParameters(); 393 | if( !wireWriteDataByte(APDS9960_WTIME, 0xFF) ) { 394 | return false; 395 | } 396 | if( !wireWriteDataByte(APDS9960_PPULSE, DEFAULT_GESTURE_PPULSE) ) { 397 | return false; 398 | } 399 | if( !setLEDBoost(LED_BOOST_300) ) { 400 | return false; 401 | } 402 | if( interrupts ) { 403 | if( !setGestureIntEnable(1) ) { 404 | return false; 405 | } 406 | } else { 407 | if( !setGestureIntEnable(0) ) { 408 | return false; 409 | } 410 | } 411 | if( !setGestureMode(1) ) { 412 | return false; 413 | } 414 | if( !enablePower() ){ 415 | return false; 416 | } 417 | if( !setMode(WAIT, 1) ) { 418 | return false; 419 | } 420 | if( !setMode(PROXIMITY, 1) ) { 421 | return false; 422 | } 423 | if( !setMode(GESTURE, 1) ) { 424 | return false; 425 | } 426 | 427 | return true; 428 | } 429 | 430 | /** 431 | * @brief Ends the gesture recognition engine on the APDS-9960 432 | * 433 | * @return True if engine disabled correctly. False on error. 434 | */ 435 | bool SparkFun_APDS9960::disableGestureSensor() 436 | { 437 | resetGestureParameters(); 438 | if( !setGestureIntEnable(0) ) { 439 | return false; 440 | } 441 | if( !setGestureMode(0) ) { 442 | return false; 443 | } 444 | if( !setMode(GESTURE, 0) ) { 445 | return false; 446 | } 447 | 448 | return true; 449 | } 450 | 451 | /** 452 | * @brief Determines if there is a gesture available for reading 453 | * 454 | * @return True if gesture available. False otherwise. 455 | */ 456 | bool SparkFun_APDS9960::isGestureAvailable() 457 | { 458 | uint8_t val; 459 | 460 | /* Read value from GSTATUS register */ 461 | if( !wireReadDataByte(APDS9960_GSTATUS, val) ) { 462 | return ERROR; 463 | } 464 | 465 | /* Shift and mask out GVALID bit */ 466 | val &= APDS9960_GVALID; 467 | 468 | /* Return true/false based on GVALID bit */ 469 | if( val == 1) { 470 | return true; 471 | } else { 472 | return false; 473 | } 474 | } 475 | 476 | /** 477 | * @brief Processes a gesture event and returns best guessed gesture 478 | * 479 | * @return Number corresponding to gesture. -1 on error. 480 | */ 481 | int SparkFun_APDS9960::readGesture() 482 | { 483 | uint8_t fifo_level = 0; 484 | uint8_t bytes_read = 0; 485 | uint8_t fifo_data[128]; 486 | uint8_t gstatus; 487 | int motion; 488 | int i; 489 | 490 | /* Make sure that power and gesture is on and data is valid */ 491 | if( !isGestureAvailable() || !(getMode() & 0b01000001) ) { 492 | return DIR_NONE; 493 | } 494 | 495 | /* Keep looping as long as gesture data is valid */ 496 | while(1) { 497 | 498 | /* Wait some time to collect next batch of FIFO data */ 499 | delay(FIFO_PAUSE_TIME); 500 | 501 | /* Get the contents of the STATUS register. Is data still valid? */ 502 | if( !wireReadDataByte(APDS9960_GSTATUS, gstatus) ) { 503 | return ERROR; 504 | } 505 | 506 | /* If we have valid data, read in FIFO */ 507 | if( (gstatus & APDS9960_GVALID) == APDS9960_GVALID ) { 508 | 509 | /* Read the current FIFO level */ 510 | if( !wireReadDataByte(APDS9960_GFLVL, fifo_level) ) { 511 | return ERROR; 512 | } 513 | 514 | #if DEBUG 515 | Serial.print("FIFO Level: "); 516 | Serial.println(fifo_level); 517 | #endif 518 | 519 | /* If there's stuff in the FIFO, read it into our data block */ 520 | if( fifo_level > 0) { 521 | bytes_read = wireReadDataBlock( APDS9960_GFIFO_U, 522 | (uint8_t*)fifo_data, 523 | (fifo_level * 4) ); 524 | if( bytes_read == -1 ) { 525 | return ERROR; 526 | } 527 | #if DEBUG 528 | Serial.print("FIFO Dump: "); 529 | for ( i = 0; i < bytes_read; i++ ) { 530 | Serial.print(fifo_data[i]); 531 | Serial.print(" "); 532 | } 533 | Serial.println(); 534 | #endif 535 | 536 | /* If at least 1 set of data, sort the data into U/D/L/R */ 537 | if( bytes_read >= 4 ) { 538 | for( i = 0; i < bytes_read; i += 4 ) { 539 | gesture_data_.u_data[gesture_data_.index] = \ 540 | fifo_data[i + 0]; 541 | gesture_data_.d_data[gesture_data_.index] = \ 542 | fifo_data[i + 1]; 543 | gesture_data_.l_data[gesture_data_.index] = \ 544 | fifo_data[i + 2]; 545 | gesture_data_.r_data[gesture_data_.index] = \ 546 | fifo_data[i + 3]; 547 | gesture_data_.index++; 548 | gesture_data_.total_gestures++; 549 | } 550 | 551 | #if DEBUG 552 | Serial.print("Up Data: "); 553 | for ( i = 0; i < gesture_data_.total_gestures; i++ ) { 554 | Serial.print(gesture_data_.u_data[i]); 555 | Serial.print(" "); 556 | } 557 | Serial.println(); 558 | #endif 559 | 560 | /* Filter and process gesture data. Decode near/far state */ 561 | if( processGestureData() ) { 562 | if( decodeGesture() ) { 563 | //***TODO: U-Turn Gestures 564 | #if DEBUG 565 | //Serial.println(gesture_motion_); 566 | #endif 567 | } 568 | } 569 | 570 | /* Reset data */ 571 | gesture_data_.index = 0; 572 | gesture_data_.total_gestures = 0; 573 | } 574 | } 575 | } else { 576 | 577 | /* Determine best guessed gesture and clean up */ 578 | delay(FIFO_PAUSE_TIME); 579 | decodeGesture(); 580 | motion = gesture_motion_; 581 | #if DEBUG 582 | Serial.print("END: "); 583 | Serial.println(gesture_motion_); 584 | #endif 585 | resetGestureParameters(); 586 | return motion; 587 | } 588 | } 589 | } 590 | 591 | /** 592 | * Turn the APDS-9960 on 593 | * 594 | * @return True if operation successful. False otherwise. 595 | */ 596 | bool SparkFun_APDS9960::enablePower() 597 | { 598 | if( !setMode(POWER, 1) ) { 599 | return false; 600 | } 601 | 602 | return true; 603 | } 604 | 605 | /** 606 | * Turn the APDS-9960 off 607 | * 608 | * @return True if operation successful. False otherwise. 609 | */ 610 | bool SparkFun_APDS9960::disablePower() 611 | { 612 | if( !setMode(POWER, 0) ) { 613 | return false; 614 | } 615 | 616 | return true; 617 | } 618 | 619 | /******************************************************************************* 620 | * Ambient light and color sensor controls 621 | ******************************************************************************/ 622 | 623 | /** 624 | * @brief Reads the ambient (clear) light level as a 16-bit value 625 | * 626 | * @param[out] val value of the light sensor. 627 | * @return True if operation successful. False otherwise. 628 | */ 629 | bool SparkFun_APDS9960::readAmbientLight(uint16_t &val) 630 | { 631 | uint8_t val_byte; 632 | val = 0; 633 | 634 | /* Read value from clear channel, low byte register */ 635 | if( !wireReadDataByte(APDS9960_CDATAL, val_byte) ) { 636 | return false; 637 | } 638 | val = val_byte; 639 | 640 | /* Read value from clear channel, high byte register */ 641 | if( !wireReadDataByte(APDS9960_CDATAH, val_byte) ) { 642 | return false; 643 | } 644 | val = val + ((uint16_t)val_byte << 8); 645 | 646 | return true; 647 | } 648 | 649 | /** 650 | * @brief Reads the red light level as a 16-bit value 651 | * 652 | * @param[out] val value of the light sensor. 653 | * @return True if operation successful. False otherwise. 654 | */ 655 | bool SparkFun_APDS9960::readRedLight(uint16_t &val) 656 | { 657 | uint8_t val_byte; 658 | val = 0; 659 | 660 | /* Read value from clear channel, low byte register */ 661 | if( !wireReadDataByte(APDS9960_RDATAL, val_byte) ) { 662 | return false; 663 | } 664 | val = val_byte; 665 | 666 | /* Read value from clear channel, high byte register */ 667 | if( !wireReadDataByte(APDS9960_RDATAH, val_byte) ) { 668 | return false; 669 | } 670 | val = val + ((uint16_t)val_byte << 8); 671 | 672 | return true; 673 | } 674 | 675 | /** 676 | * @brief Reads the green light level as a 16-bit value 677 | * 678 | * @param[out] val value of the light sensor. 679 | * @return True if operation successful. False otherwise. 680 | */ 681 | bool SparkFun_APDS9960::readGreenLight(uint16_t &val) 682 | { 683 | uint8_t val_byte; 684 | val = 0; 685 | 686 | /* Read value from clear channel, low byte register */ 687 | if( !wireReadDataByte(APDS9960_GDATAL, val_byte) ) { 688 | return false; 689 | } 690 | val = val_byte; 691 | 692 | /* Read value from clear channel, high byte register */ 693 | if( !wireReadDataByte(APDS9960_GDATAH, val_byte) ) { 694 | return false; 695 | } 696 | val = val + ((uint16_t)val_byte << 8); 697 | 698 | return true; 699 | } 700 | 701 | /** 702 | * @brief Reads the red light level as a 16-bit value 703 | * 704 | * @param[out] val value of the light sensor. 705 | * @return True if operation successful. False otherwise. 706 | */ 707 | bool SparkFun_APDS9960::readBlueLight(uint16_t &val) 708 | { 709 | uint8_t val_byte; 710 | val = 0; 711 | 712 | /* Read value from clear channel, low byte register */ 713 | if( !wireReadDataByte(APDS9960_BDATAL, val_byte) ) { 714 | return false; 715 | } 716 | val = val_byte; 717 | 718 | /* Read value from clear channel, high byte register */ 719 | if( !wireReadDataByte(APDS9960_BDATAH, val_byte) ) { 720 | return false; 721 | } 722 | val = val + ((uint16_t)val_byte << 8); 723 | 724 | return true; 725 | } 726 | 727 | /******************************************************************************* 728 | * Proximity sensor controls 729 | ******************************************************************************/ 730 | 731 | /** 732 | * @brief Reads the proximity level as an 8-bit value 733 | * 734 | * @param[out] val value of the proximity sensor. 735 | * @return True if operation successful. False otherwise. 736 | */ 737 | bool SparkFun_APDS9960::readProximity(uint8_t &val) 738 | { 739 | val = 0; 740 | 741 | /* Read value from proximity data register */ 742 | if( !wireReadDataByte(APDS9960_PDATA, val) ) { 743 | return false; 744 | } 745 | 746 | return true; 747 | } 748 | 749 | /******************************************************************************* 750 | * High-level gesture controls 751 | ******************************************************************************/ 752 | 753 | /** 754 | * @brief Resets all the parameters in the gesture data member 755 | */ 756 | void SparkFun_APDS9960::resetGestureParameters() 757 | { 758 | gesture_data_.index = 0; 759 | gesture_data_.total_gestures = 0; 760 | 761 | gesture_ud_delta_ = 0; 762 | gesture_lr_delta_ = 0; 763 | 764 | gesture_ud_count_ = 0; 765 | gesture_lr_count_ = 0; 766 | 767 | gesture_near_count_ = 0; 768 | gesture_far_count_ = 0; 769 | 770 | gesture_state_ = 0; 771 | gesture_motion_ = DIR_NONE; 772 | } 773 | 774 | /** 775 | * @brief Processes the raw gesture data to determine swipe direction 776 | * 777 | * @return True if near or far state seen. False otherwise. 778 | */ 779 | bool SparkFun_APDS9960::processGestureData() 780 | { 781 | uint8_t u_first = 0; 782 | uint8_t d_first = 0; 783 | uint8_t l_first = 0; 784 | uint8_t r_first = 0; 785 | uint8_t u_last = 0; 786 | uint8_t d_last = 0; 787 | uint8_t l_last = 0; 788 | uint8_t r_last = 0; 789 | int ud_ratio_first; 790 | int lr_ratio_first; 791 | int ud_ratio_last; 792 | int lr_ratio_last; 793 | int ud_delta; 794 | int lr_delta; 795 | int i; 796 | 797 | /* If we have less than 4 total gestures, that's not enough */ 798 | if( gesture_data_.total_gestures <= 4 ) { 799 | return false; 800 | } 801 | 802 | /* Check to make sure our data isn't out of bounds */ 803 | if( (gesture_data_.total_gestures <= 32) && \ 804 | (gesture_data_.total_gestures > 0) ) { 805 | 806 | /* Find the first value in U/D/L/R above the threshold */ 807 | for( i = 0; i < gesture_data_.total_gestures; i++ ) { 808 | if( (gesture_data_.u_data[i] > GESTURE_THRESHOLD_OUT) && 809 | (gesture_data_.d_data[i] > GESTURE_THRESHOLD_OUT) && 810 | (gesture_data_.l_data[i] > GESTURE_THRESHOLD_OUT) && 811 | (gesture_data_.r_data[i] > GESTURE_THRESHOLD_OUT) ) { 812 | 813 | u_first = gesture_data_.u_data[i]; 814 | d_first = gesture_data_.d_data[i]; 815 | l_first = gesture_data_.l_data[i]; 816 | r_first = gesture_data_.r_data[i]; 817 | break; 818 | } 819 | } 820 | 821 | /* If one of the _first values is 0, then there is no good data */ 822 | if( (u_first == 0) || (d_first == 0) || \ 823 | (l_first == 0) || (r_first == 0) ) { 824 | 825 | return false; 826 | } 827 | /* Find the last value in U/D/L/R above the threshold */ 828 | for( i = gesture_data_.total_gestures - 1; i >= 0; i-- ) { 829 | #if DEBUG 830 | Serial.print(F("Finding last: ")); 831 | Serial.print(F("U:")); 832 | Serial.print(gesture_data_.u_data[i]); 833 | Serial.print(F(" D:")); 834 | Serial.print(gesture_data_.d_data[i]); 835 | Serial.print(F(" L:")); 836 | Serial.print(gesture_data_.l_data[i]); 837 | Serial.print(F(" R:")); 838 | Serial.println(gesture_data_.r_data[i]); 839 | #endif 840 | if( (gesture_data_.u_data[i] > GESTURE_THRESHOLD_OUT) && 841 | (gesture_data_.d_data[i] > GESTURE_THRESHOLD_OUT) && 842 | (gesture_data_.l_data[i] > GESTURE_THRESHOLD_OUT) && 843 | (gesture_data_.r_data[i] > GESTURE_THRESHOLD_OUT) ) { 844 | 845 | u_last = gesture_data_.u_data[i]; 846 | d_last = gesture_data_.d_data[i]; 847 | l_last = gesture_data_.l_data[i]; 848 | r_last = gesture_data_.r_data[i]; 849 | break; 850 | } 851 | } 852 | } 853 | 854 | /* Calculate the first vs. last ratio of up/down and left/right */ 855 | ud_ratio_first = ((u_first - d_first) * 100) / (u_first + d_first); 856 | lr_ratio_first = ((l_first - r_first) * 100) / (l_first + r_first); 857 | ud_ratio_last = ((u_last - d_last) * 100) / (u_last + d_last); 858 | lr_ratio_last = ((l_last - r_last) * 100) / (l_last + r_last); 859 | 860 | #if DEBUG 861 | Serial.print(F("Last Values: ")); 862 | Serial.print(F("U:")); 863 | Serial.print(u_last); 864 | Serial.print(F(" D:")); 865 | Serial.print(d_last); 866 | Serial.print(F(" L:")); 867 | Serial.print(l_last); 868 | Serial.print(F(" R:")); 869 | Serial.println(r_last); 870 | 871 | Serial.print(F("Ratios: ")); 872 | Serial.print(F("UD Fi: ")); 873 | Serial.print(ud_ratio_first); 874 | Serial.print(F(" UD La: ")); 875 | Serial.print(ud_ratio_last); 876 | Serial.print(F(" LR Fi: ")); 877 | Serial.print(lr_ratio_first); 878 | Serial.print(F(" LR La: ")); 879 | Serial.println(lr_ratio_last); 880 | #endif 881 | 882 | /* Determine the difference between the first and last ratios */ 883 | ud_delta = ud_ratio_last - ud_ratio_first; 884 | lr_delta = lr_ratio_last - lr_ratio_first; 885 | 886 | #if DEBUG 887 | Serial.print("Deltas: "); 888 | Serial.print("UD: "); 889 | Serial.print(ud_delta); 890 | Serial.print(" LR: "); 891 | Serial.println(lr_delta); 892 | #endif 893 | 894 | /* Accumulate the UD and LR delta values */ 895 | gesture_ud_delta_ += ud_delta; 896 | gesture_lr_delta_ += lr_delta; 897 | 898 | #if DEBUG 899 | Serial.print("Accumulations: "); 900 | Serial.print("UD: "); 901 | Serial.print(gesture_ud_delta_); 902 | Serial.print(" LR: "); 903 | Serial.println(gesture_lr_delta_); 904 | #endif 905 | 906 | /* Determine U/D gesture */ 907 | if( gesture_ud_delta_ >= GESTURE_SENSITIVITY_1 ) { 908 | gesture_ud_count_ = 1; 909 | } else if( gesture_ud_delta_ <= -GESTURE_SENSITIVITY_1 ) { 910 | gesture_ud_count_ = -1; 911 | } else { 912 | gesture_ud_count_ = 0; 913 | } 914 | 915 | /* Determine L/R gesture */ 916 | if( gesture_lr_delta_ >= GESTURE_SENSITIVITY_1 ) { 917 | gesture_lr_count_ = 1; 918 | } else if( gesture_lr_delta_ <= -GESTURE_SENSITIVITY_1 ) { 919 | gesture_lr_count_ = -1; 920 | } else { 921 | gesture_lr_count_ = 0; 922 | } 923 | 924 | /* Determine Near/Far gesture */ 925 | if( (gesture_ud_count_ == 0) && (gesture_lr_count_ == 0) ) { 926 | if( (abs(ud_delta) < GESTURE_SENSITIVITY_2) && \ 927 | (abs(lr_delta) < GESTURE_SENSITIVITY_2) ) { 928 | 929 | if( (ud_delta == 0) && (lr_delta == 0) ) { 930 | gesture_near_count_++; 931 | } else if( (ud_delta != 0) || (lr_delta != 0) ) { 932 | gesture_far_count_++; 933 | } 934 | 935 | if( (gesture_near_count_ >= 10) && (gesture_far_count_ >= 2) ) { 936 | if( (ud_delta == 0) && (lr_delta == 0) ) { 937 | gesture_state_ = NEAR_STATE; 938 | } else if( (ud_delta != 0) && (lr_delta != 0) ) { 939 | gesture_state_ = FAR_STATE; 940 | } 941 | return true; 942 | } 943 | } 944 | } else { 945 | if( (abs(ud_delta) < GESTURE_SENSITIVITY_2) && \ 946 | (abs(lr_delta) < GESTURE_SENSITIVITY_2) ) { 947 | 948 | if( (ud_delta == 0) && (lr_delta == 0) ) { 949 | gesture_near_count_++; 950 | } 951 | 952 | if( gesture_near_count_ >= 10 ) { 953 | gesture_ud_count_ = 0; 954 | gesture_lr_count_ = 0; 955 | gesture_ud_delta_ = 0; 956 | gesture_lr_delta_ = 0; 957 | } 958 | } 959 | } 960 | 961 | #if DEBUG 962 | Serial.print("UD_CT: "); 963 | Serial.print(gesture_ud_count_); 964 | Serial.print(" LR_CT: "); 965 | Serial.print(gesture_lr_count_); 966 | Serial.print(" NEAR_CT: "); 967 | Serial.print(gesture_near_count_); 968 | Serial.print(" FAR_CT: "); 969 | Serial.println(gesture_far_count_); 970 | Serial.println("----------"); 971 | #endif 972 | 973 | return false; 974 | } 975 | 976 | /** 977 | * @brief Determines swipe direction or near/far state 978 | * 979 | * @return True if near/far event. False otherwise. 980 | */ 981 | bool SparkFun_APDS9960::decodeGesture() 982 | { 983 | /* Return if near or far event is detected */ 984 | if( gesture_state_ == NEAR_STATE ) { 985 | gesture_motion_ = DIR_NEAR; 986 | return true; 987 | } else if ( gesture_state_ == FAR_STATE ) { 988 | gesture_motion_ = DIR_FAR; 989 | return true; 990 | } 991 | 992 | /* Determine swipe direction */ 993 | if( (gesture_ud_count_ == -1) && (gesture_lr_count_ == 0) ) { 994 | gesture_motion_ = DIR_UP; 995 | } else if( (gesture_ud_count_ == 1) && (gesture_lr_count_ == 0) ) { 996 | gesture_motion_ = DIR_DOWN; 997 | } else if( (gesture_ud_count_ == 0) && (gesture_lr_count_ == 1) ) { 998 | gesture_motion_ = DIR_RIGHT; 999 | } else if( (gesture_ud_count_ == 0) && (gesture_lr_count_ == -1) ) { 1000 | gesture_motion_ = DIR_LEFT; 1001 | } else if( (gesture_ud_count_ == -1) && (gesture_lr_count_ == 1) ) { 1002 | if( abs(gesture_ud_delta_) > abs(gesture_lr_delta_) ) { 1003 | gesture_motion_ = DIR_UP; 1004 | } else { 1005 | gesture_motion_ = DIR_RIGHT; 1006 | } 1007 | } else if( (gesture_ud_count_ == 1) && (gesture_lr_count_ == -1) ) { 1008 | if( abs(gesture_ud_delta_) > abs(gesture_lr_delta_) ) { 1009 | gesture_motion_ = DIR_DOWN; 1010 | } else { 1011 | gesture_motion_ = DIR_LEFT; 1012 | } 1013 | } else if( (gesture_ud_count_ == -1) && (gesture_lr_count_ == -1) ) { 1014 | if( abs(gesture_ud_delta_) > abs(gesture_lr_delta_) ) { 1015 | gesture_motion_ = DIR_UP; 1016 | } else { 1017 | gesture_motion_ = DIR_LEFT; 1018 | } 1019 | } else if( (gesture_ud_count_ == 1) && (gesture_lr_count_ == 1) ) { 1020 | if( abs(gesture_ud_delta_) > abs(gesture_lr_delta_) ) { 1021 | gesture_motion_ = DIR_DOWN; 1022 | } else { 1023 | gesture_motion_ = DIR_RIGHT; 1024 | } 1025 | } else { 1026 | return false; 1027 | } 1028 | 1029 | return true; 1030 | } 1031 | 1032 | /******************************************************************************* 1033 | * Getters and setters for register values 1034 | ******************************************************************************/ 1035 | 1036 | /** 1037 | * @brief Returns the lower threshold for proximity detection 1038 | * 1039 | * @return lower threshold 1040 | */ 1041 | uint8_t SparkFun_APDS9960::getProxIntLowThresh() 1042 | { 1043 | uint8_t val; 1044 | 1045 | /* Read value from PILT register */ 1046 | if( !wireReadDataByte(APDS9960_PILT, val) ) { 1047 | val = 0; 1048 | } 1049 | 1050 | return val; 1051 | } 1052 | 1053 | /** 1054 | * @brief Sets the lower threshold for proximity detection 1055 | * 1056 | * @param[in] threshold the lower proximity threshold 1057 | * @return True if operation successful. False otherwise. 1058 | */ 1059 | bool SparkFun_APDS9960::setProxIntLowThresh(uint8_t threshold) 1060 | { 1061 | if( !wireWriteDataByte(APDS9960_PILT, threshold) ) { 1062 | return false; 1063 | } 1064 | 1065 | return true; 1066 | } 1067 | 1068 | /** 1069 | * @brief Returns the high threshold for proximity detection 1070 | * 1071 | * @return high threshold 1072 | */ 1073 | uint8_t SparkFun_APDS9960::getProxIntHighThresh() 1074 | { 1075 | uint8_t val; 1076 | 1077 | /* Read value from PIHT register */ 1078 | if( !wireReadDataByte(APDS9960_PIHT, val) ) { 1079 | val = 0; 1080 | } 1081 | 1082 | return val; 1083 | } 1084 | 1085 | /** 1086 | * @brief Sets the high threshold for proximity detection 1087 | * 1088 | * @param[in] threshold the high proximity threshold 1089 | * @return True if operation successful. False otherwise. 1090 | */ 1091 | bool SparkFun_APDS9960::setProxIntHighThresh(uint8_t threshold) 1092 | { 1093 | if( !wireWriteDataByte(APDS9960_PIHT, threshold) ) { 1094 | return false; 1095 | } 1096 | 1097 | return true; 1098 | } 1099 | 1100 | /** 1101 | * @brief Returns LED drive strength for proximity and ALS 1102 | * 1103 | * Value LED Current 1104 | * 0 100 mA 1105 | * 1 50 mA 1106 | * 2 25 mA 1107 | * 3 12.5 mA 1108 | * 1109 | * @return the value of the LED drive strength. 0xFF on failure. 1110 | */ 1111 | uint8_t SparkFun_APDS9960::getLEDDrive() 1112 | { 1113 | uint8_t val; 1114 | 1115 | /* Read value from CONTROL register */ 1116 | if( !wireReadDataByte(APDS9960_CONTROL, val) ) { 1117 | return ERROR; 1118 | } 1119 | 1120 | /* Shift and mask out LED drive bits */ 1121 | val = (val >> 6) & 0b00000011; 1122 | 1123 | return val; 1124 | } 1125 | 1126 | /** 1127 | * @brief Sets the LED drive strength for proximity and ALS 1128 | * 1129 | * Value LED Current 1130 | * 0 100 mA 1131 | * 1 50 mA 1132 | * 2 25 mA 1133 | * 3 12.5 mA 1134 | * 1135 | * @param[in] drive the value (0-3) for the LED drive strength 1136 | * @return True if operation successful. False otherwise. 1137 | */ 1138 | bool SparkFun_APDS9960::setLEDDrive(uint8_t drive) 1139 | { 1140 | uint8_t val; 1141 | 1142 | /* Read value from CONTROL register */ 1143 | if( !wireReadDataByte(APDS9960_CONTROL, val) ) { 1144 | return false; 1145 | } 1146 | 1147 | /* Set bits in register to given value */ 1148 | drive &= 0b00000011; 1149 | drive = drive << 6; 1150 | val &= 0b00111111; 1151 | val |= drive; 1152 | 1153 | /* Write register value back into CONTROL register */ 1154 | if( !wireWriteDataByte(APDS9960_CONTROL, val) ) { 1155 | return false; 1156 | } 1157 | 1158 | return true; 1159 | } 1160 | 1161 | /** 1162 | * @brief Returns receiver gain for proximity detection 1163 | * 1164 | * Value Gain 1165 | * 0 1x 1166 | * 1 2x 1167 | * 2 4x 1168 | * 3 8x 1169 | * 1170 | * @return the value of the proximity gain. 0xFF on failure. 1171 | */ 1172 | uint8_t SparkFun_APDS9960::getProximityGain() 1173 | { 1174 | uint8_t val; 1175 | 1176 | /* Read value from CONTROL register */ 1177 | if( !wireReadDataByte(APDS9960_CONTROL, val) ) { 1178 | return ERROR; 1179 | } 1180 | 1181 | /* Shift and mask out PDRIVE bits */ 1182 | val = (val >> 2) & 0b00000011; 1183 | 1184 | return val; 1185 | } 1186 | 1187 | /** 1188 | * @brief Sets the receiver gain for proximity detection 1189 | * 1190 | * Value Gain 1191 | * 0 1x 1192 | * 1 2x 1193 | * 2 4x 1194 | * 3 8x 1195 | * 1196 | * @param[in] drive the value (0-3) for the gain 1197 | * @return True if operation successful. False otherwise. 1198 | */ 1199 | bool SparkFun_APDS9960::setProximityGain(uint8_t drive) 1200 | { 1201 | uint8_t val; 1202 | 1203 | /* Read value from CONTROL register */ 1204 | if( !wireReadDataByte(APDS9960_CONTROL, val) ) { 1205 | return false; 1206 | } 1207 | 1208 | /* Set bits in register to given value */ 1209 | drive &= 0b00000011; 1210 | drive = drive << 2; 1211 | val &= 0b11110011; 1212 | val |= drive; 1213 | 1214 | /* Write register value back into CONTROL register */ 1215 | if( !wireWriteDataByte(APDS9960_CONTROL, val) ) { 1216 | return false; 1217 | } 1218 | 1219 | return true; 1220 | } 1221 | 1222 | /** 1223 | * @brief Returns receiver gain for the ambient light sensor (ALS) 1224 | * 1225 | * Value Gain 1226 | * 0 1x 1227 | * 1 4x 1228 | * 2 16x 1229 | * 3 64x 1230 | * 1231 | * @return the value of the ALS gain. 0xFF on failure. 1232 | */ 1233 | uint8_t SparkFun_APDS9960::getAmbientLightGain() 1234 | { 1235 | uint8_t val; 1236 | 1237 | /* Read value from CONTROL register */ 1238 | if( !wireReadDataByte(APDS9960_CONTROL, val) ) { 1239 | return ERROR; 1240 | } 1241 | 1242 | /* Shift and mask out ADRIVE bits */ 1243 | val &= 0b00000011; 1244 | 1245 | return val; 1246 | } 1247 | 1248 | /** 1249 | * @brief Sets the receiver gain for the ambient light sensor (ALS) 1250 | * 1251 | * Value Gain 1252 | * 0 1x 1253 | * 1 4x 1254 | * 2 16x 1255 | * 3 64x 1256 | * 1257 | * @param[in] drive the value (0-3) for the gain 1258 | * @return True if operation successful. False otherwise. 1259 | */ 1260 | bool SparkFun_APDS9960::setAmbientLightGain(uint8_t drive) 1261 | { 1262 | uint8_t val; 1263 | 1264 | /* Read value from CONTROL register */ 1265 | if( !wireReadDataByte(APDS9960_CONTROL, val) ) { 1266 | return false; 1267 | } 1268 | 1269 | /* Set bits in register to given value */ 1270 | drive &= 0b00000011; 1271 | val &= 0b11111100; 1272 | val |= drive; 1273 | 1274 | /* Write register value back into CONTROL register */ 1275 | if( !wireWriteDataByte(APDS9960_CONTROL, val) ) { 1276 | return false; 1277 | } 1278 | 1279 | return true; 1280 | } 1281 | 1282 | /** 1283 | * @brief Get the current LED boost value 1284 | * 1285 | * Value Boost Current 1286 | * 0 100% 1287 | * 1 150% 1288 | * 2 200% 1289 | * 3 300% 1290 | * 1291 | * @return The LED boost value. 0xFF on failure. 1292 | */ 1293 | uint8_t SparkFun_APDS9960::getLEDBoost() 1294 | { 1295 | uint8_t val; 1296 | 1297 | /* Read value from CONFIG2 register */ 1298 | if( !wireReadDataByte(APDS9960_CONFIG2, val) ) { 1299 | return ERROR; 1300 | } 1301 | 1302 | /* Shift and mask out LED_BOOST bits */ 1303 | val = (val >> 4) & 0b00000011; 1304 | 1305 | return val; 1306 | } 1307 | 1308 | /** 1309 | * @brief Sets the LED current boost value 1310 | * 1311 | * Value Boost Current 1312 | * 0 100% 1313 | * 1 150% 1314 | * 2 200% 1315 | * 3 300% 1316 | * 1317 | * @param[in] drive the value (0-3) for current boost (100-300%) 1318 | * @return True if operation successful. False otherwise. 1319 | */ 1320 | bool SparkFun_APDS9960::setLEDBoost(uint8_t boost) 1321 | { 1322 | uint8_t val; 1323 | 1324 | /* Read value from CONFIG2 register */ 1325 | if( !wireReadDataByte(APDS9960_CONFIG2, val) ) { 1326 | return false; 1327 | } 1328 | 1329 | /* Set bits in register to given value */ 1330 | boost &= 0b00000011; 1331 | boost = boost << 4; 1332 | val &= 0b11001111; 1333 | val |= boost; 1334 | 1335 | /* Write register value back into CONFIG2 register */ 1336 | if( !wireWriteDataByte(APDS9960_CONFIG2, val) ) { 1337 | return false; 1338 | } 1339 | 1340 | return true; 1341 | } 1342 | 1343 | /** 1344 | * @brief Gets proximity gain compensation enable 1345 | * 1346 | * @return 1 if compensation is enabled. 0 if not. 0xFF on error. 1347 | */ 1348 | uint8_t SparkFun_APDS9960::getProxGainCompEnable() 1349 | { 1350 | uint8_t val; 1351 | 1352 | /* Read value from CONFIG3 register */ 1353 | if( !wireReadDataByte(APDS9960_CONFIG3, val) ) { 1354 | return ERROR; 1355 | } 1356 | 1357 | /* Shift and mask out PCMP bits */ 1358 | val = (val >> 5) & 0b00000001; 1359 | 1360 | return val; 1361 | } 1362 | 1363 | /** 1364 | * @brief Sets the proximity gain compensation enable 1365 | * 1366 | * @param[in] enable 1 to enable compensation. 0 to disable compensation. 1367 | * @return True if operation successful. False otherwise. 1368 | */ 1369 | bool SparkFun_APDS9960::setProxGainCompEnable(uint8_t enable) 1370 | { 1371 | uint8_t val; 1372 | 1373 | /* Read value from CONFIG3 register */ 1374 | if( !wireReadDataByte(APDS9960_CONFIG3, val) ) { 1375 | return false; 1376 | } 1377 | 1378 | /* Set bits in register to given value */ 1379 | enable &= 0b00000001; 1380 | enable = enable << 5; 1381 | val &= 0b11011111; 1382 | val |= enable; 1383 | 1384 | /* Write register value back into CONFIG3 register */ 1385 | if( !wireWriteDataByte(APDS9960_CONFIG3, val) ) { 1386 | return false; 1387 | } 1388 | 1389 | return true; 1390 | } 1391 | 1392 | /** 1393 | * @brief Gets the current mask for enabled/disabled proximity photodiodes 1394 | * 1395 | * 1 = disabled, 0 = enabled 1396 | * Bit Photodiode 1397 | * 3 UP 1398 | * 2 DOWN 1399 | * 1 LEFT 1400 | * 0 RIGHT 1401 | * 1402 | * @return Current proximity mask for photodiodes. 0xFF on error. 1403 | */ 1404 | uint8_t SparkFun_APDS9960::getProxPhotoMask() 1405 | { 1406 | uint8_t val; 1407 | 1408 | /* Read value from CONFIG3 register */ 1409 | if( !wireReadDataByte(APDS9960_CONFIG3, val) ) { 1410 | return ERROR; 1411 | } 1412 | 1413 | /* Mask out photodiode enable mask bits */ 1414 | val &= 0b00001111; 1415 | 1416 | return val; 1417 | } 1418 | 1419 | /** 1420 | * @brief Sets the mask for enabling/disabling proximity photodiodes 1421 | * 1422 | * 1 = disabled, 0 = enabled 1423 | * Bit Photodiode 1424 | * 3 UP 1425 | * 2 DOWN 1426 | * 1 LEFT 1427 | * 0 RIGHT 1428 | * 1429 | * @param[in] mask 4-bit mask value 1430 | * @return True if operation successful. False otherwise. 1431 | */ 1432 | bool SparkFun_APDS9960::setProxPhotoMask(uint8_t mask) 1433 | { 1434 | uint8_t val; 1435 | 1436 | /* Read value from CONFIG3 register */ 1437 | if( !wireReadDataByte(APDS9960_CONFIG3, val) ) { 1438 | return false; 1439 | } 1440 | 1441 | /* Set bits in register to given value */ 1442 | mask &= 0b00001111; 1443 | val &= 0b11110000; 1444 | val |= mask; 1445 | 1446 | /* Write register value back into CONFIG3 register */ 1447 | if( !wireWriteDataByte(APDS9960_CONFIG3, val) ) { 1448 | return false; 1449 | } 1450 | 1451 | return true; 1452 | } 1453 | 1454 | /** 1455 | * @brief Gets the entry proximity threshold for gesture sensing 1456 | * 1457 | * @return Current entry proximity threshold. 1458 | */ 1459 | uint8_t SparkFun_APDS9960::getGestureEnterThresh() 1460 | { 1461 | uint8_t val; 1462 | 1463 | /* Read value from GPENTH register */ 1464 | if( !wireReadDataByte(APDS9960_GPENTH, val) ) { 1465 | val = 0; 1466 | } 1467 | 1468 | return val; 1469 | } 1470 | 1471 | /** 1472 | * @brief Sets the entry proximity threshold for gesture sensing 1473 | * 1474 | * @param[in] threshold proximity value needed to start gesture mode 1475 | * @return True if operation successful. False otherwise. 1476 | */ 1477 | bool SparkFun_APDS9960::setGestureEnterThresh(uint8_t threshold) 1478 | { 1479 | if( !wireWriteDataByte(APDS9960_GPENTH, threshold) ) { 1480 | return false; 1481 | } 1482 | 1483 | return true; 1484 | } 1485 | 1486 | /** 1487 | * @brief Gets the exit proximity threshold for gesture sensing 1488 | * 1489 | * @return Current exit proximity threshold. 1490 | */ 1491 | uint8_t SparkFun_APDS9960::getGestureExitThresh() 1492 | { 1493 | uint8_t val; 1494 | 1495 | /* Read value from GEXTH register */ 1496 | if( !wireReadDataByte(APDS9960_GEXTH, val) ) { 1497 | val = 0; 1498 | } 1499 | 1500 | return val; 1501 | } 1502 | 1503 | /** 1504 | * @brief Sets the exit proximity threshold for gesture sensing 1505 | * 1506 | * @param[in] threshold proximity value needed to end gesture mode 1507 | * @return True if operation successful. False otherwise. 1508 | */ 1509 | bool SparkFun_APDS9960::setGestureExitThresh(uint8_t threshold) 1510 | { 1511 | if( !wireWriteDataByte(APDS9960_GEXTH, threshold) ) { 1512 | return false; 1513 | } 1514 | 1515 | return true; 1516 | } 1517 | 1518 | /** 1519 | * @brief Gets the gain of the photodiode during gesture mode 1520 | * 1521 | * Value Gain 1522 | * 0 1x 1523 | * 1 2x 1524 | * 2 4x 1525 | * 3 8x 1526 | * 1527 | * @return the current photodiode gain. 0xFF on error. 1528 | */ 1529 | uint8_t SparkFun_APDS9960::getGestureGain() 1530 | { 1531 | uint8_t val; 1532 | 1533 | /* Read value from GCONF2 register */ 1534 | if( !wireReadDataByte(APDS9960_GCONF2, val) ) { 1535 | return ERROR; 1536 | } 1537 | 1538 | /* Shift and mask out GGAIN bits */ 1539 | val = (val >> 5) & 0b00000011; 1540 | 1541 | return val; 1542 | } 1543 | 1544 | /** 1545 | * @brief Sets the gain of the photodiode during gesture mode 1546 | * 1547 | * Value Gain 1548 | * 0 1x 1549 | * 1 2x 1550 | * 2 4x 1551 | * 3 8x 1552 | * 1553 | * @param[in] gain the value for the photodiode gain 1554 | * @return True if operation successful. False otherwise. 1555 | */ 1556 | bool SparkFun_APDS9960::setGestureGain(uint8_t gain) 1557 | { 1558 | uint8_t val; 1559 | 1560 | /* Read value from GCONF2 register */ 1561 | if( !wireReadDataByte(APDS9960_GCONF2, val) ) { 1562 | return false; 1563 | } 1564 | 1565 | /* Set bits in register to given value */ 1566 | gain &= 0b00000011; 1567 | gain = gain << 5; 1568 | val &= 0b10011111; 1569 | val |= gain; 1570 | 1571 | /* Write register value back into GCONF2 register */ 1572 | if( !wireWriteDataByte(APDS9960_GCONF2, val) ) { 1573 | return false; 1574 | } 1575 | 1576 | return true; 1577 | } 1578 | 1579 | /** 1580 | * @brief Gets the drive current of the LED during gesture mode 1581 | * 1582 | * Value LED Current 1583 | * 0 100 mA 1584 | * 1 50 mA 1585 | * 2 25 mA 1586 | * 3 12.5 mA 1587 | * 1588 | * @return the LED drive current value. 0xFF on error. 1589 | */ 1590 | uint8_t SparkFun_APDS9960::getGestureLEDDrive() 1591 | { 1592 | uint8_t val; 1593 | 1594 | /* Read value from GCONF2 register */ 1595 | if( !wireReadDataByte(APDS9960_GCONF2, val) ) { 1596 | return ERROR; 1597 | } 1598 | 1599 | /* Shift and mask out GLDRIVE bits */ 1600 | val = (val >> 3) & 0b00000011; 1601 | 1602 | return val; 1603 | } 1604 | 1605 | /** 1606 | * @brief Sets the LED drive current during gesture mode 1607 | * 1608 | * Value LED Current 1609 | * 0 100 mA 1610 | * 1 50 mA 1611 | * 2 25 mA 1612 | * 3 12.5 mA 1613 | * 1614 | * @param[in] drive the value for the LED drive current 1615 | * @return True if operation successful. False otherwise. 1616 | */ 1617 | bool SparkFun_APDS9960::setGestureLEDDrive(uint8_t drive) 1618 | { 1619 | uint8_t val; 1620 | 1621 | /* Read value from GCONF2 register */ 1622 | if( !wireReadDataByte(APDS9960_GCONF2, val) ) { 1623 | return false; 1624 | } 1625 | 1626 | /* Set bits in register to given value */ 1627 | drive &= 0b00000011; 1628 | drive = drive << 3; 1629 | val &= 0b11100111; 1630 | val |= drive; 1631 | 1632 | /* Write register value back into GCONF2 register */ 1633 | if( !wireWriteDataByte(APDS9960_GCONF2, val) ) { 1634 | return false; 1635 | } 1636 | 1637 | return true; 1638 | } 1639 | 1640 | /** 1641 | * @brief Gets the time in low power mode between gesture detections 1642 | * 1643 | * Value Wait time 1644 | * 0 0 ms 1645 | * 1 2.8 ms 1646 | * 2 5.6 ms 1647 | * 3 8.4 ms 1648 | * 4 14.0 ms 1649 | * 5 22.4 ms 1650 | * 6 30.8 ms 1651 | * 7 39.2 ms 1652 | * 1653 | * @return the current wait time between gestures. 0xFF on error. 1654 | */ 1655 | uint8_t SparkFun_APDS9960::getGestureWaitTime() 1656 | { 1657 | uint8_t val; 1658 | 1659 | /* Read value from GCONF2 register */ 1660 | if( !wireReadDataByte(APDS9960_GCONF2, val) ) { 1661 | return ERROR; 1662 | } 1663 | 1664 | /* Mask out GWTIME bits */ 1665 | val &= 0b00000111; 1666 | 1667 | return val; 1668 | } 1669 | 1670 | /** 1671 | * @brief Sets the time in low power mode between gesture detections 1672 | * 1673 | * Value Wait time 1674 | * 0 0 ms 1675 | * 1 2.8 ms 1676 | * 2 5.6 ms 1677 | * 3 8.4 ms 1678 | * 4 14.0 ms 1679 | * 5 22.4 ms 1680 | * 6 30.8 ms 1681 | * 7 39.2 ms 1682 | * 1683 | * @param[in] the value for the wait time 1684 | * @return True if operation successful. False otherwise. 1685 | */ 1686 | bool SparkFun_APDS9960::setGestureWaitTime(uint8_t time) 1687 | { 1688 | uint8_t val; 1689 | 1690 | /* Read value from GCONF2 register */ 1691 | if( !wireReadDataByte(APDS9960_GCONF2, val) ) { 1692 | return false; 1693 | } 1694 | 1695 | /* Set bits in register to given value */ 1696 | time &= 0b00000111; 1697 | val &= 0b11111000; 1698 | val |= time; 1699 | 1700 | /* Write register value back into GCONF2 register */ 1701 | if( !wireWriteDataByte(APDS9960_GCONF2, val) ) { 1702 | return false; 1703 | } 1704 | 1705 | return true; 1706 | } 1707 | 1708 | /** 1709 | * @brief Gets the low threshold for ambient light interrupts 1710 | * 1711 | * @param[out] threshold current low threshold stored on the APDS-9960 1712 | * @return True if operation successful. False otherwise. 1713 | */ 1714 | bool SparkFun_APDS9960::getLightIntLowThreshold(uint16_t &threshold) 1715 | { 1716 | uint8_t val_byte; 1717 | threshold = 0; 1718 | 1719 | /* Read value from ambient light low threshold, low byte register */ 1720 | if( !wireReadDataByte(APDS9960_AILTL, val_byte) ) { 1721 | return false; 1722 | } 1723 | threshold = val_byte; 1724 | 1725 | /* Read value from ambient light low threshold, high byte register */ 1726 | if( !wireReadDataByte(APDS9960_AILTH, val_byte) ) { 1727 | return false; 1728 | } 1729 | threshold = threshold + ((uint16_t)val_byte << 8); 1730 | 1731 | return true; 1732 | } 1733 | 1734 | /** 1735 | * @brief Sets the low threshold for ambient light interrupts 1736 | * 1737 | * @param[in] threshold low threshold value for interrupt to trigger 1738 | * @return True if operation successful. False otherwise. 1739 | */ 1740 | bool SparkFun_APDS9960::setLightIntLowThreshold(uint16_t threshold) 1741 | { 1742 | uint8_t val_low; 1743 | uint8_t val_high; 1744 | 1745 | /* Break 16-bit threshold into 2 8-bit values */ 1746 | val_low = threshold & 0x00FF; 1747 | val_high = (threshold & 0xFF00) >> 8; 1748 | 1749 | /* Write low byte */ 1750 | if( !wireWriteDataByte(APDS9960_AILTL, val_low) ) { 1751 | return false; 1752 | } 1753 | 1754 | /* Write high byte */ 1755 | if( !wireWriteDataByte(APDS9960_AILTH, val_high) ) { 1756 | return false; 1757 | } 1758 | 1759 | return true; 1760 | } 1761 | 1762 | /** 1763 | * @brief Gets the high threshold for ambient light interrupts 1764 | * 1765 | * @param[out] threshold current low threshold stored on the APDS-9960 1766 | * @return True if operation successful. False otherwise. 1767 | */ 1768 | bool SparkFun_APDS9960::getLightIntHighThreshold(uint16_t &threshold) 1769 | { 1770 | uint8_t val_byte; 1771 | threshold = 0; 1772 | 1773 | /* Read value from ambient light high threshold, low byte register */ 1774 | if( !wireReadDataByte(APDS9960_AIHTL, val_byte) ) { 1775 | return false; 1776 | } 1777 | threshold = val_byte; 1778 | 1779 | /* Read value from ambient light high threshold, high byte register */ 1780 | if( !wireReadDataByte(APDS9960_AIHTH, val_byte) ) { 1781 | return false; 1782 | } 1783 | threshold = threshold + ((uint16_t)val_byte << 8); 1784 | 1785 | return true; 1786 | } 1787 | 1788 | /** 1789 | * @brief Sets the high threshold for ambient light interrupts 1790 | * 1791 | * @param[in] threshold high threshold value for interrupt to trigger 1792 | * @return True if operation successful. False otherwise. 1793 | */ 1794 | bool SparkFun_APDS9960::setLightIntHighThreshold(uint16_t threshold) 1795 | { 1796 | uint8_t val_low; 1797 | uint8_t val_high; 1798 | 1799 | /* Break 16-bit threshold into 2 8-bit values */ 1800 | val_low = threshold & 0x00FF; 1801 | val_high = (threshold & 0xFF00) >> 8; 1802 | 1803 | /* Write low byte */ 1804 | if( !wireWriteDataByte(APDS9960_AIHTL, val_low) ) { 1805 | return false; 1806 | } 1807 | 1808 | /* Write high byte */ 1809 | if( !wireWriteDataByte(APDS9960_AIHTH, val_high) ) { 1810 | return false; 1811 | } 1812 | 1813 | return true; 1814 | } 1815 | 1816 | /** 1817 | * @brief Gets the low threshold for proximity interrupts 1818 | * 1819 | * @param[out] threshold current low threshold stored on the APDS-9960 1820 | * @return True if operation successful. False otherwise. 1821 | */ 1822 | bool SparkFun_APDS9960::getProximityIntLowThreshold(uint8_t &threshold) 1823 | { 1824 | threshold = 0; 1825 | 1826 | /* Read value from proximity low threshold register */ 1827 | if( !wireReadDataByte(APDS9960_PILT, threshold) ) { 1828 | return false; 1829 | } 1830 | 1831 | return true; 1832 | } 1833 | 1834 | /** 1835 | * @brief Sets the low threshold for proximity interrupts 1836 | * 1837 | * @param[in] threshold low threshold value for interrupt to trigger 1838 | * @return True if operation successful. False otherwise. 1839 | */ 1840 | bool SparkFun_APDS9960::setProximityIntLowThreshold(uint8_t threshold) 1841 | { 1842 | 1843 | /* Write threshold value to register */ 1844 | if( !wireWriteDataByte(APDS9960_PILT, threshold) ) { 1845 | return false; 1846 | } 1847 | 1848 | return true; 1849 | } 1850 | 1851 | /** 1852 | * @brief Gets the high threshold for proximity interrupts 1853 | * 1854 | * @param[out] threshold current low threshold stored on the APDS-9960 1855 | * @return True if operation successful. False otherwise. 1856 | */ 1857 | bool SparkFun_APDS9960::getProximityIntHighThreshold(uint8_t &threshold) 1858 | { 1859 | threshold = 0; 1860 | 1861 | /* Read value from proximity low threshold register */ 1862 | if( !wireReadDataByte(APDS9960_PIHT, threshold) ) { 1863 | return false; 1864 | } 1865 | 1866 | return true; 1867 | } 1868 | 1869 | /** 1870 | * @brief Sets the high threshold for proximity interrupts 1871 | * 1872 | * @param[in] threshold high threshold value for interrupt to trigger 1873 | * @return True if operation successful. False otherwise. 1874 | */ 1875 | bool SparkFun_APDS9960::setProximityIntHighThreshold(uint8_t threshold) 1876 | { 1877 | 1878 | /* Write threshold value to register */ 1879 | if( !wireWriteDataByte(APDS9960_PIHT, threshold) ) { 1880 | return false; 1881 | } 1882 | 1883 | return true; 1884 | } 1885 | 1886 | /** 1887 | * @brief Gets if ambient light interrupts are enabled or not 1888 | * 1889 | * @return 1 if interrupts are enabled, 0 if not. 0xFF on error. 1890 | */ 1891 | uint8_t SparkFun_APDS9960::getAmbientLightIntEnable() 1892 | { 1893 | uint8_t val; 1894 | 1895 | /* Read value from ENABLE register */ 1896 | if( !wireReadDataByte(APDS9960_ENABLE, val) ) { 1897 | return ERROR; 1898 | } 1899 | 1900 | /* Shift and mask out AIEN bit */ 1901 | val = (val >> 4) & 0b00000001; 1902 | 1903 | return val; 1904 | } 1905 | 1906 | /** 1907 | * @brief Turns ambient light interrupts on or off 1908 | * 1909 | * @param[in] enable 1 to enable interrupts, 0 to turn them off 1910 | * @return True if operation successful. False otherwise. 1911 | */ 1912 | bool SparkFun_APDS9960::setAmbientLightIntEnable(uint8_t enable) 1913 | { 1914 | uint8_t val; 1915 | 1916 | /* Read value from ENABLE register */ 1917 | if( !wireReadDataByte(APDS9960_ENABLE, val) ) { 1918 | return false; 1919 | } 1920 | 1921 | /* Set bits in register to given value */ 1922 | enable &= 0b00000001; 1923 | enable = enable << 4; 1924 | val &= 0b11101111; 1925 | val |= enable; 1926 | 1927 | /* Write register value back into ENABLE register */ 1928 | if( !wireWriteDataByte(APDS9960_ENABLE, val) ) { 1929 | return false; 1930 | } 1931 | 1932 | return true; 1933 | } 1934 | 1935 | /** 1936 | * @brief Gets if proximity interrupts are enabled or not 1937 | * 1938 | * @return 1 if interrupts are enabled, 0 if not. 0xFF on error. 1939 | */ 1940 | uint8_t SparkFun_APDS9960::getProximityIntEnable() 1941 | { 1942 | uint8_t val; 1943 | 1944 | /* Read value from ENABLE register */ 1945 | if( !wireReadDataByte(APDS9960_ENABLE, val) ) { 1946 | return ERROR; 1947 | } 1948 | 1949 | /* Shift and mask out PIEN bit */ 1950 | val = (val >> 5) & 0b00000001; 1951 | 1952 | return val; 1953 | } 1954 | 1955 | /** 1956 | * @brief Turns proximity interrupts on or off 1957 | * 1958 | * @param[in] enable 1 to enable interrupts, 0 to turn them off 1959 | * @return True if operation successful. False otherwise. 1960 | */ 1961 | bool SparkFun_APDS9960::setProximityIntEnable(uint8_t enable) 1962 | { 1963 | uint8_t val; 1964 | 1965 | /* Read value from ENABLE register */ 1966 | if( !wireReadDataByte(APDS9960_ENABLE, val) ) { 1967 | return false; 1968 | } 1969 | 1970 | /* Set bits in register to given value */ 1971 | enable &= 0b00000001; 1972 | enable = enable << 5; 1973 | val &= 0b11011111; 1974 | val |= enable; 1975 | 1976 | /* Write register value back into ENABLE register */ 1977 | if( !wireWriteDataByte(APDS9960_ENABLE, val) ) { 1978 | return false; 1979 | } 1980 | 1981 | return true; 1982 | } 1983 | 1984 | /** 1985 | * @brief Gets if gesture interrupts are enabled or not 1986 | * 1987 | * @return 1 if interrupts are enabled, 0 if not. 0xFF on error. 1988 | */ 1989 | uint8_t SparkFun_APDS9960::getGestureIntEnable() 1990 | { 1991 | uint8_t val; 1992 | 1993 | /* Read value from GCONF4 register */ 1994 | if( !wireReadDataByte(APDS9960_GCONF4, val) ) { 1995 | return ERROR; 1996 | } 1997 | 1998 | /* Shift and mask out GIEN bit */ 1999 | val = (val >> 1) & 0b00000001; 2000 | 2001 | return val; 2002 | } 2003 | 2004 | /** 2005 | * @brief Turns gesture-related interrupts on or off 2006 | * 2007 | * @param[in] enable 1 to enable interrupts, 0 to turn them off 2008 | * @return True if operation successful. False otherwise. 2009 | */ 2010 | bool SparkFun_APDS9960::setGestureIntEnable(uint8_t enable) 2011 | { 2012 | uint8_t val; 2013 | 2014 | /* Read value from GCONF4 register */ 2015 | if( !wireReadDataByte(APDS9960_GCONF4, val) ) { 2016 | return false; 2017 | } 2018 | 2019 | /* Set bits in register to given value */ 2020 | enable &= 0b00000001; 2021 | enable = enable << 1; 2022 | val &= 0b11111101; 2023 | val |= enable; 2024 | 2025 | /* Write register value back into GCONF4 register */ 2026 | if( !wireWriteDataByte(APDS9960_GCONF4, val) ) { 2027 | return false; 2028 | } 2029 | 2030 | return true; 2031 | } 2032 | 2033 | /** 2034 | * @brief Clears the ambient light interrupt 2035 | * 2036 | * @return True if operation completed successfully. False otherwise. 2037 | */ 2038 | bool SparkFun_APDS9960::clearAmbientLightInt() 2039 | { 2040 | uint8_t throwaway; 2041 | if( !wireReadDataByte(APDS9960_AICLEAR, throwaway) ) { 2042 | return false; 2043 | } 2044 | 2045 | return true; 2046 | } 2047 | 2048 | /** 2049 | * @brief Clears the proximity interrupt 2050 | * 2051 | * @return True if operation completed successfully. False otherwise. 2052 | */ 2053 | bool SparkFun_APDS9960::clearProximityInt() 2054 | { 2055 | uint8_t throwaway; 2056 | if( !wireReadDataByte(APDS9960_PICLEAR, throwaway) ) { 2057 | return false; 2058 | } 2059 | 2060 | return true; 2061 | } 2062 | 2063 | /** 2064 | * @brief Tells if the gesture state machine is currently running 2065 | * 2066 | * @return 1 if gesture state machine is running, 0 if not. 0xFF on error. 2067 | */ 2068 | uint8_t SparkFun_APDS9960::getGestureMode() 2069 | { 2070 | uint8_t val; 2071 | 2072 | /* Read value from GCONF4 register */ 2073 | if( !wireReadDataByte(APDS9960_GCONF4, val) ) { 2074 | return ERROR; 2075 | } 2076 | 2077 | /* Mask out GMODE bit */ 2078 | val &= 0b00000001; 2079 | 2080 | return val; 2081 | } 2082 | 2083 | /** 2084 | * @brief Tells the state machine to either enter or exit gesture state machine 2085 | * 2086 | * @param[in] mode 1 to enter gesture state machine, 0 to exit. 2087 | * @return True if operation successful. False otherwise. 2088 | */ 2089 | bool SparkFun_APDS9960::setGestureMode(uint8_t mode) 2090 | { 2091 | uint8_t val; 2092 | 2093 | /* Read value from GCONF4 register */ 2094 | if( !wireReadDataByte(APDS9960_GCONF4, val) ) { 2095 | return false; 2096 | } 2097 | 2098 | /* Set bits in register to given value */ 2099 | mode &= 0b00000001; 2100 | val &= 0b11111110; 2101 | val |= mode; 2102 | 2103 | /* Write register value back into GCONF4 register */ 2104 | if( !wireWriteDataByte(APDS9960_GCONF4, val) ) { 2105 | return false; 2106 | } 2107 | 2108 | return true; 2109 | } 2110 | 2111 | /******************************************************************************* 2112 | * Raw I2C Reads and Writes 2113 | ******************************************************************************/ 2114 | 2115 | /** 2116 | * @brief Writes a single byte to the I2C device (no register) 2117 | * 2118 | * @param[in] val the 1-byte value to write to the I2C device 2119 | * @return True if successful write operation. False otherwise. 2120 | */ 2121 | bool SparkFun_APDS9960::wireWriteByte(uint8_t val) 2122 | { 2123 | Wire.beginTransmission(APDS9960_I2C_ADDR); 2124 | Wire.write(val); 2125 | if( Wire.endTransmission() != 0 ) { 2126 | return false; 2127 | } 2128 | 2129 | return true; 2130 | } 2131 | 2132 | /** 2133 | * @brief Writes a single byte to the I2C device and specified register 2134 | * 2135 | * @param[in] reg the register in the I2C device to write to 2136 | * @param[in] val the 1-byte value to write to the I2C device 2137 | * @return True if successful write operation. False otherwise. 2138 | */ 2139 | bool SparkFun_APDS9960::wireWriteDataByte(uint8_t reg, uint8_t val) 2140 | { 2141 | Wire.beginTransmission(APDS9960_I2C_ADDR); 2142 | Wire.write(reg); 2143 | Wire.write(val); 2144 | if( Wire.endTransmission() != 0 ) { 2145 | return false; 2146 | } 2147 | 2148 | return true; 2149 | } 2150 | 2151 | /** 2152 | * @brief Writes a block (array) of bytes to the I2C device and register 2153 | * 2154 | * @param[in] reg the register in the I2C device to write to 2155 | * @param[in] val pointer to the beginning of the data byte array 2156 | * @param[in] len the length (in bytes) of the data to write 2157 | * @return True if successful write operation. False otherwise. 2158 | */ 2159 | bool SparkFun_APDS9960::wireWriteDataBlock( uint8_t reg, 2160 | uint8_t *val, 2161 | unsigned int len) 2162 | { 2163 | unsigned int i; 2164 | 2165 | Wire.beginTransmission(APDS9960_I2C_ADDR); 2166 | Wire.write(reg); 2167 | for(i = 0; i < len; i++) { 2168 | Wire.beginTransmission(val[i]); 2169 | } 2170 | if( Wire.endTransmission() != 0 ) { 2171 | return false; 2172 | } 2173 | 2174 | return true; 2175 | } 2176 | 2177 | /** 2178 | * @brief Reads a single byte from the I2C device and specified register 2179 | * 2180 | * @param[in] reg the register to read from 2181 | * @param[out] the value returned from the register 2182 | * @return True if successful read operation. False otherwise. 2183 | */ 2184 | bool SparkFun_APDS9960::wireReadDataByte(uint8_t reg, uint8_t &val) 2185 | { 2186 | 2187 | /* Indicate which register we want to read from */ 2188 | if (!wireWriteByte(reg)) { 2189 | return false; 2190 | } 2191 | 2192 | /* Read from register */ 2193 | Wire.requestFrom(APDS9960_I2C_ADDR, 1); 2194 | while (Wire.available()) { 2195 | val = Wire.read(); 2196 | } 2197 | 2198 | return true; 2199 | } 2200 | 2201 | /** 2202 | * @brief Reads a block (array) of bytes from the I2C device and register 2203 | * 2204 | * @param[in] reg the register to read from 2205 | * @param[out] val pointer to the beginning of the data 2206 | * @param[in] len number of bytes to read 2207 | * @return Number of bytes read. -1 on read error. 2208 | */ 2209 | int SparkFun_APDS9960::wireReadDataBlock( uint8_t reg, 2210 | uint8_t *val, 2211 | unsigned int len) 2212 | { 2213 | unsigned char i = 0; 2214 | 2215 | /* Indicate which register we want to read from */ 2216 | if (!wireWriteByte(reg)) { 2217 | return -1; 2218 | } 2219 | 2220 | /* Read block data */ 2221 | Wire.requestFrom(APDS9960_I2C_ADDR, len); 2222 | while (Wire.available()) { 2223 | if (i >= len) { 2224 | return -1; 2225 | } 2226 | val[i] = Wire.read(); 2227 | i++; 2228 | } 2229 | 2230 | return i; 2231 | } -------------------------------------------------------------------------------- /src/SparkFun_APDS9960.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file SparkFun_APDS-9960.h 3 | * @brief Library for the SparkFun APDS-9960 breakout board 4 | * @author Shawn Hymel (SparkFun Electronics) 5 | * 6 | * @copyright This code is public domain but you buy me a beer if you use 7 | * this and we meet someday (Beerware license). 8 | * 9 | * This library interfaces the Avago APDS-9960 to Arduino over I2C. The library 10 | * relies on the Arduino Wire (I2C) library. to use the library, instantiate an 11 | * APDS9960 object, call init(), and call the appropriate functions. 12 | */ 13 | 14 | #ifndef SparkFun_APDS9960_H 15 | #define SparkFun_APDS9960_H 16 | 17 | #include 18 | 19 | /* Debug */ 20 | #define DEBUG 0 21 | 22 | /* APDS-9960 I2C address */ 23 | #define APDS9960_I2C_ADDR 0x39 24 | 25 | /* Gesture parameters */ 26 | #define GESTURE_THRESHOLD_OUT 10 27 | #define GESTURE_SENSITIVITY_1 50 28 | #define GESTURE_SENSITIVITY_2 20 29 | 30 | /* Error code for returned values */ 31 | #define ERROR 0xFF 32 | 33 | /* Acceptable device IDs */ 34 | #define APDS9960_ID_1 0xAB 35 | #define APDS9960_ID_2 0x9C 36 | 37 | /* Misc parameters */ 38 | #define FIFO_PAUSE_TIME 30 // Wait period (ms) between FIFO reads 39 | 40 | /* APDS-9960 register addresses */ 41 | #define APDS9960_ENABLE 0x80 42 | #define APDS9960_ATIME 0x81 43 | #define APDS9960_WTIME 0x83 44 | #define APDS9960_AILTL 0x84 45 | #define APDS9960_AILTH 0x85 46 | #define APDS9960_AIHTL 0x86 47 | #define APDS9960_AIHTH 0x87 48 | #define APDS9960_PILT 0x89 49 | #define APDS9960_PIHT 0x8B 50 | #define APDS9960_PERS 0x8C 51 | #define APDS9960_CONFIG1 0x8D 52 | #define APDS9960_PPULSE 0x8E 53 | #define APDS9960_CONTROL 0x8F 54 | #define APDS9960_CONFIG2 0x90 55 | #define APDS9960_ID 0x92 56 | #define APDS9960_STATUS 0x93 57 | #define APDS9960_CDATAL 0x94 58 | #define APDS9960_CDATAH 0x95 59 | #define APDS9960_RDATAL 0x96 60 | #define APDS9960_RDATAH 0x97 61 | #define APDS9960_GDATAL 0x98 62 | #define APDS9960_GDATAH 0x99 63 | #define APDS9960_BDATAL 0x9A 64 | #define APDS9960_BDATAH 0x9B 65 | #define APDS9960_PDATA 0x9C 66 | #define APDS9960_POFFSET_UR 0x9D 67 | #define APDS9960_POFFSET_DL 0x9E 68 | #define APDS9960_CONFIG3 0x9F 69 | #define APDS9960_GPENTH 0xA0 70 | #define APDS9960_GEXTH 0xA1 71 | #define APDS9960_GCONF1 0xA2 72 | #define APDS9960_GCONF2 0xA3 73 | #define APDS9960_GOFFSET_U 0xA4 74 | #define APDS9960_GOFFSET_D 0xA5 75 | #define APDS9960_GOFFSET_L 0xA7 76 | #define APDS9960_GOFFSET_R 0xA9 77 | #define APDS9960_GPULSE 0xA6 78 | #define APDS9960_GCONF3 0xAA 79 | #define APDS9960_GCONF4 0xAB 80 | #define APDS9960_GFLVL 0xAE 81 | #define APDS9960_GSTATUS 0xAF 82 | #define APDS9960_IFORCE 0xE4 83 | #define APDS9960_PICLEAR 0xE5 84 | #define APDS9960_CICLEAR 0xE6 85 | #define APDS9960_AICLEAR 0xE7 86 | #define APDS9960_GFIFO_U 0xFC 87 | #define APDS9960_GFIFO_D 0xFD 88 | #define APDS9960_GFIFO_L 0xFE 89 | #define APDS9960_GFIFO_R 0xFF 90 | 91 | /* Bit fields */ 92 | #define APDS9960_PON 0b00000001 93 | #define APDS9960_AEN 0b00000010 94 | #define APDS9960_PEN 0b00000100 95 | #define APDS9960_WEN 0b00001000 96 | #define APSD9960_AIEN 0b00010000 97 | #define APDS9960_PIEN 0b00100000 98 | #define APDS9960_GEN 0b01000000 99 | #define APDS9960_GVALID 0b00000001 100 | 101 | /* Status bit fields */ 102 | #define APDS9960_AVALID 0b0000001 103 | #define APDS9960_PVALID 0b0000010 104 | #define APDS9960_GINT 0b0000100 105 | #define APDS9960_AINT 0b0010000 106 | #define APDS9960_PGSAT 0b0100000 107 | #define APDS9960_CPSAT 0b1000000 108 | 109 | /* On/Off definitions */ 110 | #define OFF 0 111 | #define ON 1 112 | 113 | /* Acceptable parameters for setMode */ 114 | #define POWER 0 115 | #define AMBIENT_LIGHT 1 116 | #define PROXIMITY 2 117 | #define WAIT 3 118 | #define AMBIENT_LIGHT_INT 4 119 | #define PROXIMITY_INT 5 120 | #define GESTURE 6 121 | #define ALL 7 122 | 123 | /* LED Drive values */ 124 | #define LED_DRIVE_100MA 0 125 | #define LED_DRIVE_50MA 1 126 | #define LED_DRIVE_25MA 2 127 | #define LED_DRIVE_12_5MA 3 128 | 129 | /* Proximity Gain (PGAIN) values */ 130 | #define PGAIN_1X 0 131 | #define PGAIN_2X 1 132 | #define PGAIN_4X 2 133 | #define PGAIN_8X 3 134 | 135 | /* ALS Gain (AGAIN) values */ 136 | #define AGAIN_1X 0 137 | #define AGAIN_4X 1 138 | #define AGAIN_16X 2 139 | #define AGAIN_64X 3 140 | 141 | /* Gesture Gain (GGAIN) values */ 142 | #define GGAIN_1X 0 143 | #define GGAIN_2X 1 144 | #define GGAIN_4X 2 145 | #define GGAIN_8X 3 146 | 147 | /* LED Boost values */ 148 | #define LED_BOOST_100 0 149 | #define LED_BOOST_150 1 150 | #define LED_BOOST_200 2 151 | #define LED_BOOST_300 3 152 | 153 | /* Gesture wait time values */ 154 | #define GWTIME_0MS 0 155 | #define GWTIME_2_8MS 1 156 | #define GWTIME_5_6MS 2 157 | #define GWTIME_8_4MS 3 158 | #define GWTIME_14_0MS 4 159 | #define GWTIME_22_4MS 5 160 | #define GWTIME_30_8MS 6 161 | #define GWTIME_39_2MS 7 162 | 163 | /* Default values */ 164 | #define DEFAULT_ATIME 219 // 103ms 165 | #define DEFAULT_WTIME 246 // 27ms 166 | #define DEFAULT_PROX_PPULSE 0x87 // 16us, 8 pulses 167 | #define DEFAULT_GESTURE_PPULSE 0x89 // 16us, 10 pulses 168 | #define DEFAULT_POFFSET_UR 0 // 0 offset 169 | #define DEFAULT_POFFSET_DL 0 // 0 offset 170 | #define DEFAULT_CONFIG1 0x60 // No 12x wait (WTIME) factor 171 | #define DEFAULT_LDRIVE LED_DRIVE_100MA 172 | #define DEFAULT_PGAIN PGAIN_4X 173 | #define DEFAULT_AGAIN AGAIN_4X 174 | #define DEFAULT_PILT 0 // Low proximity threshold 175 | #define DEFAULT_PIHT 50 // High proximity threshold 176 | #define DEFAULT_AILT 0xFFFF // Force interrupt for calibration 177 | #define DEFAULT_AIHT 0 178 | #define DEFAULT_PERS 0x11 // 2 consecutive prox or ALS for int. 179 | #define DEFAULT_CONFIG2 0x01 // No saturation interrupts or LED boost 180 | #define DEFAULT_CONFIG3 0 // Enable all photodiodes, no SAI 181 | #define DEFAULT_GPENTH 40 // Threshold for entering gesture mode 182 | #define DEFAULT_GEXTH 30 // Threshold for exiting gesture mode 183 | #define DEFAULT_GCONF1 0x40 // 4 gesture events for int., 1 for exit 184 | #define DEFAULT_GGAIN GGAIN_4X 185 | #define DEFAULT_GLDRIVE LED_DRIVE_100MA 186 | #define DEFAULT_GWTIME GWTIME_2_8MS 187 | #define DEFAULT_GOFFSET 0 // No offset scaling for gesture mode 188 | #define DEFAULT_GPULSE 0xC9 // 32us, 10 pulses 189 | #define DEFAULT_GCONF3 0 // All photodiodes active during gesture 190 | #define DEFAULT_GIEN 0 // Disable gesture interrupts 191 | 192 | /* Direction definitions */ 193 | enum { 194 | DIR_NONE, 195 | DIR_LEFT, 196 | DIR_RIGHT, 197 | DIR_UP, 198 | DIR_DOWN, 199 | DIR_NEAR, 200 | DIR_FAR, 201 | DIR_ALL 202 | }; 203 | 204 | /* State definitions */ 205 | enum { 206 | NA_STATE, 207 | NEAR_STATE, 208 | FAR_STATE, 209 | ALL_STATE 210 | }; 211 | 212 | /* Container for gesture data */ 213 | typedef struct gesture_data_type { 214 | uint8_t u_data[32]; 215 | uint8_t d_data[32]; 216 | uint8_t l_data[32]; 217 | uint8_t r_data[32]; 218 | uint8_t index; 219 | uint8_t total_gestures; 220 | uint8_t in_threshold; 221 | uint8_t out_threshold; 222 | } gesture_data_type; 223 | 224 | /* APDS9960 Class */ 225 | class SparkFun_APDS9960 { 226 | public: 227 | 228 | /* Initialization methods */ 229 | SparkFun_APDS9960(); 230 | ~SparkFun_APDS9960(); 231 | bool init(); 232 | uint8_t getStatusRegister(); 233 | uint8_t getMode(); 234 | bool setMode(uint8_t mode, uint8_t enable); 235 | 236 | /* Turn the APDS-9960 on and off */ 237 | bool enablePower(); 238 | bool disablePower(); 239 | 240 | /* Enable or disable specific sensors */ 241 | bool enableLightSensor(bool interrupts = false); 242 | bool disableLightSensor(); 243 | bool enableProximitySensor(bool interrupts = false); 244 | bool disableProximitySensor(); 245 | bool enableGestureSensor(bool interrupts = true); 246 | bool disableGestureSensor(); 247 | 248 | /* LED drive strength control */ 249 | uint8_t getLEDDrive(); 250 | bool setLEDDrive(uint8_t drive); 251 | uint8_t getGestureLEDDrive(); 252 | bool setGestureLEDDrive(uint8_t drive); 253 | 254 | /* Gain control */ 255 | uint8_t getAmbientLightGain(); 256 | bool setAmbientLightGain(uint8_t gain); 257 | uint8_t getProximityGain(); 258 | bool setProximityGain(uint8_t gain); 259 | uint8_t getGestureGain(); 260 | bool setGestureGain(uint8_t gain); 261 | 262 | /* Get and set light interrupt thresholds */ 263 | bool getLightIntLowThreshold(uint16_t &threshold); 264 | bool setLightIntLowThreshold(uint16_t threshold); 265 | bool getLightIntHighThreshold(uint16_t &threshold); 266 | bool setLightIntHighThreshold(uint16_t threshold); 267 | 268 | /* Get and set proximity interrupt thresholds */ 269 | bool getProximityIntLowThreshold(uint8_t &threshold); 270 | bool setProximityIntLowThreshold(uint8_t threshold); 271 | bool getProximityIntHighThreshold(uint8_t &threshold); 272 | bool setProximityIntHighThreshold(uint8_t threshold); 273 | 274 | /* Get and set interrupt enables */ 275 | uint8_t getAmbientLightIntEnable(); 276 | bool setAmbientLightIntEnable(uint8_t enable); 277 | uint8_t getProximityIntEnable(); 278 | bool setProximityIntEnable(uint8_t enable); 279 | uint8_t getGestureIntEnable(); 280 | bool setGestureIntEnable(uint8_t enable); 281 | 282 | /* Clear interrupts */ 283 | bool clearAmbientLightInt(); 284 | bool clearProximityInt(); 285 | 286 | /* Ambient light methods */ 287 | bool readAmbientLight(uint16_t &val); 288 | bool readRedLight(uint16_t &val); 289 | bool readGreenLight(uint16_t &val); 290 | bool readBlueLight(uint16_t &val); 291 | 292 | /* Proximity methods */ 293 | bool readProximity(uint8_t &val); 294 | 295 | /* Gesture methods */ 296 | bool isGestureAvailable(); 297 | int readGesture(); 298 | 299 | private: 300 | 301 | /* Gesture processing */ 302 | void resetGestureParameters(); 303 | bool processGestureData(); 304 | bool decodeGesture(); 305 | 306 | /* Proximity Interrupt Threshold */ 307 | uint8_t getProxIntLowThresh(); 308 | bool setProxIntLowThresh(uint8_t threshold); 309 | uint8_t getProxIntHighThresh(); 310 | bool setProxIntHighThresh(uint8_t threshold); 311 | 312 | /* LED Boost Control */ 313 | uint8_t getLEDBoost(); 314 | bool setLEDBoost(uint8_t boost); 315 | 316 | /* Proximity photodiode select */ 317 | uint8_t getProxGainCompEnable(); 318 | bool setProxGainCompEnable(uint8_t enable); 319 | uint8_t getProxPhotoMask(); 320 | bool setProxPhotoMask(uint8_t mask); 321 | 322 | /* Gesture threshold control */ 323 | uint8_t getGestureEnterThresh(); 324 | bool setGestureEnterThresh(uint8_t threshold); 325 | uint8_t getGestureExitThresh(); 326 | bool setGestureExitThresh(uint8_t threshold); 327 | 328 | /* Gesture LED, gain, and time control */ 329 | uint8_t getGestureWaitTime(); 330 | bool setGestureWaitTime(uint8_t time); 331 | 332 | /* Gesture mode */ 333 | uint8_t getGestureMode(); 334 | bool setGestureMode(uint8_t mode); 335 | 336 | /* Raw I2C Commands */ 337 | bool wireWriteByte(uint8_t val); 338 | bool wireWriteDataByte(uint8_t reg, uint8_t val); 339 | bool wireWriteDataBlock(uint8_t reg, uint8_t *val, unsigned int len); 340 | bool wireReadDataByte(uint8_t reg, uint8_t &val); 341 | int wireReadDataBlock(uint8_t reg, uint8_t *val, unsigned int len); 342 | 343 | /* Members */ 344 | gesture_data_type gesture_data_; 345 | int gesture_ud_delta_; 346 | int gesture_lr_delta_; 347 | int gesture_ud_count_; 348 | int gesture_lr_count_; 349 | int gesture_near_count_; 350 | int gesture_far_count_; 351 | int gesture_state_; 352 | int gesture_motion_; 353 | }; 354 | 355 | #endif --------------------------------------------------------------------------------