├── .gitignore ├── APDS-9960 └── c++ │ ├── .gitignore │ ├── APDS9960.cpp │ ├── APDS9960.h │ ├── Makefile │ ├── color.cpp │ └── gesture.cpp ├── BH1750 └── c │ ├── .gitignore │ ├── BH1750.c │ ├── BH1750.h │ ├── BH1750_test.c │ └── Makefile ├── BMP180 └── c │ ├── .gitignore │ ├── BMP180.c │ ├── BMP180.h │ ├── BMP180_test.c │ ├── Makefile │ ├── smbus.c │ └── smbus.h ├── BMP280 ├── c │ ├── .gitignore │ ├── BMP280.c │ └── Makefile └── python │ └── BMP280_test.py ├── DC-motor-SN754410 └── c │ ├── .gitignore │ ├── Makefile │ └── sn754410.c ├── HC-SR04 └── python │ └── distance.py ├── HTU21D └── c │ ├── .gitignore │ ├── HTU21D.c │ ├── HTU21D.h │ ├── HTU21D_test.c │ └── Makefile ├── LED-RGB └── c │ ├── .gitignore │ ├── Makefile │ └── led-rgb.c ├── LED-SMD3528 └── c │ ├── .gitignore │ ├── Makefile │ ├── led-strip-smd3528-pwm.c │ └── led-strip-smd3528.c ├── LED └── bash │ ├── led.sh │ └── switch.sh ├── LICENSE ├── LM75A ├── bash │ └── lm75a.sh ├── c │ ├── .gitignore │ ├── LM75A.c │ └── Makefile └── python │ └── LM75A.py ├── MAX44009 └── c │ ├── .gitignore │ ├── MAX44009.c │ ├── MAX44009.h │ ├── MAX44009_test.c │ └── Makefile ├── MCP3002 └── python │ └── adc.py ├── MaPIE-LoRa-RP2040 └── circuitpython │ ├── code.py │ └── lib │ └── adafruit_rfm9x.py ├── PIR-sensor └── python │ └── motion.py ├── PN532 └── python │ ├── rfid-save.py │ └── rfid-scan.py ├── README.md ├── Ryanteck-RPi-Motor └── c │ ├── .gitignore │ ├── Makefile │ └── motor.c ├── SN754410 └── c │ └── motor.c ├── SSD1306 ├── FreePixel.ttf └── ssd1306-demo.py ├── TSL2561 └── c │ ├── example-wiringpi │ ├── .gitignore │ ├── Makefile │ └── TSL2561.c │ └── example │ ├── .gitignore │ ├── Makefile │ ├── TSL2561.c │ ├── TSL2561.h │ └── TSL2561_test.c ├── buzzer └── c │ ├── beep.c │ └── starwars.c └── pico └── micropython ├── blink └── main.py ├── mini-oled-i2c-ssd1306-draw └── main.py ├── mini-oled-i2c-ssd1306-hello └── main.py └── mini-oled-i2c-ssd1306-image └── main.py /.gitignore: -------------------------------------------------------------------------------- 1 | buzzer/c/beep 2 | buzzer/c/starwars 3 | -------------------------------------------------------------------------------- /APDS-9960/c++/.gitignore: -------------------------------------------------------------------------------- 1 | color 2 | gesture 3 | *.o 4 | -------------------------------------------------------------------------------- /APDS-9960/c++/APDS9960.cpp: -------------------------------------------------------------------------------- 1 | #include "APDS9960.h" 2 | 3 | /** 4 | * @brief Constructor - Instantiates APDS9960 object 5 | */ 6 | APDS9960::APDS9960() 7 | { 8 | gesture_ud_delta_ = 0; 9 | gesture_lr_delta_ = 0; 10 | 11 | gesture_ud_count_ = 0; 12 | gesture_lr_count_ = 0; 13 | 14 | gesture_near_count_ = 0; 15 | gesture_far_count_ = 0; 16 | 17 | gesture_state_ = 0; 18 | gesture_motion_ = DIR_NONE; 19 | } 20 | 21 | /** 22 | * @brief Destructor 23 | */ 24 | APDS9960::~APDS9960() 25 | { 26 | 27 | } 28 | 29 | /** 30 | * @brief Configures I2C communications and initializes registers to defaults 31 | * 32 | * @return True if initialized successfully. False otherwise. 33 | */ 34 | bool APDS9960::init() 35 | { 36 | uint8_t id; 37 | 38 | /* Initialize I2C */ 39 | fd_ = wiringPiI2CSetup(APDS9960_I2C_ADDR); 40 | if(fd_ == -1) { 41 | return false; 42 | } 43 | 44 | /* Read ID register and check against known values for APDS-9960 */ 45 | if( !wireReadDataByte(APDS9960_ID, id) ) { 46 | return false; 47 | } 48 | if( !(id == APDS9960_ID_1 || id == APDS9960_ID_2) ) { 49 | return false; 50 | } 51 | 52 | /* Set ENABLE register to 0 (disable all features) */ 53 | if( !setMode(ALL, OFF) ) { 54 | return false; 55 | } 56 | 57 | /* Set default values for ambient light and proximity registers */ 58 | if( !wireWriteDataByte(APDS9960_ATIME, DEFAULT_ATIME) ) { 59 | return false; 60 | } 61 | if( !wireWriteDataByte(APDS9960_WTIME, DEFAULT_WTIME) ) { 62 | return false; 63 | } 64 | if( !wireWriteDataByte(APDS9960_PPULSE, DEFAULT_PROX_PPULSE) ) { 65 | return false; 66 | } 67 | if( !wireWriteDataByte(APDS9960_POFFSET_UR, DEFAULT_POFFSET_UR) ) { 68 | return false; 69 | } 70 | if( !wireWriteDataByte(APDS9960_POFFSET_DL, DEFAULT_POFFSET_DL) ) { 71 | return false; 72 | } 73 | if( !wireWriteDataByte(APDS9960_CONFIG1, DEFAULT_CONFIG1) ) { 74 | return false; 75 | } 76 | if( !setLEDDrive(DEFAULT_LDRIVE) ) { 77 | return false; 78 | } 79 | if( !setProximityGain(DEFAULT_PGAIN) ) { 80 | return false; 81 | } 82 | if( !setAmbientLightGain(DEFAULT_AGAIN) ) { 83 | return false; 84 | } 85 | if( !setProxIntLowThresh(DEFAULT_PILT) ) { 86 | return false; 87 | } 88 | if( !setProxIntHighThresh(DEFAULT_PIHT) ) { 89 | return false; 90 | } 91 | if( !setLightIntLowThreshold(DEFAULT_AILT) ) { 92 | return false; 93 | } 94 | if( !setLightIntHighThreshold(DEFAULT_AIHT) ) { 95 | return false; 96 | } 97 | if( !wireWriteDataByte(APDS9960_PERS, DEFAULT_PERS) ) { 98 | return false; 99 | } 100 | if( !wireWriteDataByte(APDS9960_CONFIG2, DEFAULT_CONFIG2) ) { 101 | return false; 102 | } 103 | if( !wireWriteDataByte(APDS9960_CONFIG3, DEFAULT_CONFIG3) ) { 104 | return false; 105 | } 106 | 107 | /* Set default values for gesture sense registers */ 108 | if( !setGestureEnterThresh(DEFAULT_GPENTH) ) { 109 | return false; 110 | } 111 | if( !setGestureExitThresh(DEFAULT_GEXTH) ) { 112 | return false; 113 | } 114 | if( !wireWriteDataByte(APDS9960_GCONF1, DEFAULT_GCONF1) ) { 115 | return false; 116 | } 117 | if( !setGestureGain(DEFAULT_GGAIN) ) { 118 | return false; 119 | } 120 | if( !setGestureLEDDrive(DEFAULT_GLDRIVE) ) { 121 | return false; 122 | } 123 | if( !setGestureWaitTime(DEFAULT_GWTIME) ) { 124 | return false; 125 | } 126 | if( !wireWriteDataByte(APDS9960_GOFFSET_U, DEFAULT_GOFFSET) ) { 127 | return false; 128 | } 129 | if( !wireWriteDataByte(APDS9960_GOFFSET_D, DEFAULT_GOFFSET) ) { 130 | return false; 131 | } 132 | if( !wireWriteDataByte(APDS9960_GOFFSET_L, DEFAULT_GOFFSET) ) { 133 | return false; 134 | } 135 | if( !wireWriteDataByte(APDS9960_GOFFSET_R, DEFAULT_GOFFSET) ) { 136 | return false; 137 | } 138 | if( !wireWriteDataByte(APDS9960_GPULSE, DEFAULT_GPULSE) ) { 139 | return false; 140 | } 141 | if( !wireWriteDataByte(APDS9960_GCONF3, DEFAULT_GCONF3) ) { 142 | return false; 143 | } 144 | if( !setGestureIntEnable(DEFAULT_GIEN) ) { 145 | return false; 146 | } 147 | 148 | #if 0 149 | /* Gesture config register dump */ 150 | uint8_t reg; 151 | uint8_t val; 152 | 153 | for(reg = 0x80; reg <= 0xAF; reg++) { 154 | if( (reg != 0x82) && \ 155 | (reg != 0x8A) && \ 156 | (reg != 0x91) && \ 157 | (reg != 0xA8) && \ 158 | (reg != 0xAC) && \ 159 | (reg != 0xAD) ) 160 | { 161 | wireReadDataByte(reg, val); 162 | Serial.print(reg, HEX); 163 | Serial.print(": 0x"); 164 | Serial.println(val, HEX); 165 | } 166 | } 167 | 168 | for(reg = 0xE4; reg <= 0xE7; reg++) { 169 | wireReadDataByte(reg, val); 170 | Serial.print(reg, HEX); 171 | Serial.print(": 0x"); 172 | Serial.println(val, HEX); 173 | } 174 | #endif 175 | 176 | return true; 177 | } 178 | 179 | /******************************************************************************* 180 | * Public methods for controlling the APDS-9960 181 | ******************************************************************************/ 182 | 183 | /** 184 | * @brief Reads and returns the contents of the ENABLE register 185 | * 186 | * @return Contents of the ENABLE register. 0xFF if error. 187 | */ 188 | uint8_t APDS9960::getMode() 189 | { 190 | uint8_t enable_value; 191 | 192 | /* Read current ENABLE register */ 193 | if( !wireReadDataByte(APDS9960_ENABLE, enable_value) ) { 194 | return ERROR; 195 | } 196 | 197 | return enable_value; 198 | } 199 | 200 | /** 201 | * @brief Enables or disables a feature in the APDS-9960 202 | * 203 | * @param[in] mode which feature to enable 204 | * @param[in] enable ON (1) or OFF (0) 205 | * @return True if operation success. False otherwise. 206 | */ 207 | bool APDS9960::setMode(uint8_t mode, uint8_t enable) 208 | { 209 | uint8_t reg_val; 210 | 211 | /* Read current ENABLE register */ 212 | reg_val = getMode(); 213 | if( reg_val == ERROR ) { 214 | return false; 215 | } 216 | 217 | /* Change bit(s) in ENABLE register */ 218 | enable = enable & 0x01; 219 | if( mode >= 0 && mode <= 6 ) { 220 | if (enable) { 221 | reg_val |= (1 << mode); 222 | } else { 223 | reg_val &= ~(1 << mode); 224 | } 225 | } else if( mode == ALL ) { 226 | if (enable) { 227 | reg_val = 0x7F; 228 | } else { 229 | reg_val = 0x00; 230 | } 231 | } 232 | 233 | /* Write value back to ENABLE register */ 234 | if( !wireWriteDataByte(APDS9960_ENABLE, reg_val) ) { 235 | return false; 236 | } 237 | 238 | return true; 239 | } 240 | 241 | /** 242 | * @brief Starts the light (R/G/B/Ambient) sensor on the APDS-9960 243 | * 244 | * @param[in] interrupts true to enable hardware interrupt on high or low light 245 | * @return True if sensor enabled correctly. False on error. 246 | */ 247 | bool APDS9960::enableLightSensor(bool interrupts) 248 | { 249 | 250 | /* Set default gain, interrupts, enable power, and enable sensor */ 251 | if( !setAmbientLightGain(DEFAULT_AGAIN) ) { 252 | return false; 253 | } 254 | if( interrupts ) { 255 | if( !setAmbientLightIntEnable(1) ) { 256 | return false; 257 | } 258 | } else { 259 | if( !setAmbientLightIntEnable(0) ) { 260 | return false; 261 | } 262 | } 263 | if( !enablePower() ){ 264 | return false; 265 | } 266 | if( !setMode(AMBIENT_LIGHT, 1) ) { 267 | return false; 268 | } 269 | 270 | return true; 271 | 272 | } 273 | 274 | /** 275 | * @brief Ends the light sensor on the APDS-9960 276 | * 277 | * @return True if sensor disabled correctly. False on error. 278 | */ 279 | bool APDS9960::disableLightSensor() 280 | { 281 | if( !setAmbientLightIntEnable(0) ) { 282 | return false; 283 | } 284 | if( !setMode(AMBIENT_LIGHT, 0) ) { 285 | return false; 286 | } 287 | 288 | return true; 289 | } 290 | 291 | /** 292 | * @brief Starts the proximity sensor on the APDS-9960 293 | * 294 | * @param[in] interrupts true to enable hardware external interrupt on proximity 295 | * @return True if sensor enabled correctly. False on error. 296 | */ 297 | bool APDS9960::enableProximitySensor(bool interrupts) 298 | { 299 | /* Set default gain, LED, interrupts, enable power, and enable sensor */ 300 | if( !setProximityGain(DEFAULT_PGAIN) ) { 301 | return false; 302 | } 303 | if( !setLEDDrive(DEFAULT_LDRIVE) ) { 304 | return false; 305 | } 306 | if( interrupts ) { 307 | if( !setProximityIntEnable(1) ) { 308 | return false; 309 | } 310 | } else { 311 | if( !setProximityIntEnable(0) ) { 312 | return false; 313 | } 314 | } 315 | if( !enablePower() ){ 316 | return false; 317 | } 318 | if( !setMode(PROXIMITY, 1) ) { 319 | return false; 320 | } 321 | 322 | return true; 323 | } 324 | bool disableProximitySensor(); 325 | 326 | /** 327 | * @brief Starts the gesture recognition engine on the APDS-9960 328 | * 329 | * @param[in] interrupts true to enable hardware external interrupt on gesture 330 | * @return True if engine enabled correctly. False on error. 331 | */ 332 | bool APDS9960::enableGestureSensor(bool interrupts) 333 | { 334 | 335 | /* Enable gesture mode 336 | Set ENABLE to 0 (power off) 337 | Set WTIME to 0xFF 338 | Set AUX to LED_BOOST_300 339 | Enable PON, WEN, PEN, GEN in ENABLE 340 | */ 341 | resetGestureParameters(); 342 | if( !wireWriteDataByte(APDS9960_WTIME, 0xFF) ) { 343 | return false; 344 | } 345 | if( !wireWriteDataByte(APDS9960_PPULSE, DEFAULT_GESTURE_PPULSE) ) { 346 | return false; 347 | } 348 | if( !setLEDBoost(LED_BOOST_100) ) { 349 | return false; 350 | } 351 | if( interrupts ) { 352 | if( !setGestureIntEnable(1) ) { 353 | return false; 354 | } 355 | } else { 356 | if( !setGestureIntEnable(0) ) { 357 | return false; 358 | } 359 | } 360 | if( !setGestureMode(1) ) { 361 | return false; 362 | } 363 | if( !enablePower() ){ 364 | return false; 365 | } 366 | if( !setMode(WAIT, 1) ) { 367 | return false; 368 | } 369 | if( !setMode(PROXIMITY, 1) ) { 370 | return false; 371 | } 372 | if( !setMode(GESTURE, 1) ) { 373 | return false; 374 | } 375 | 376 | return true; 377 | } 378 | 379 | /** 380 | * @brief Ends the gesture recognition engine on the APDS-9960 381 | * 382 | * @return True if engine disabled correctly. False on error. 383 | */ 384 | bool APDS9960::disableGestureSensor() 385 | { 386 | resetGestureParameters(); 387 | if( !setGestureIntEnable(0) ) { 388 | return false; 389 | } 390 | if( !setGestureMode(0) ) { 391 | return false; 392 | } 393 | if( !setMode(GESTURE, 0) ) { 394 | return false; 395 | } 396 | 397 | return true; 398 | } 399 | 400 | /** 401 | * @brief Determines if there is a gesture available for reading 402 | * 403 | * @return True if gesture available. False otherwise. 404 | */ 405 | bool APDS9960::isGestureAvailable() 406 | { 407 | uint8_t val; 408 | 409 | /* Read value from GSTATUS register */ 410 | if( !wireReadDataByte(APDS9960_GSTATUS, val) ) { 411 | return ERROR; 412 | } 413 | 414 | /* Shift and mask out GVALID bit */ 415 | val &= APDS9960_GVALID; 416 | 417 | /* Return true/false based on GVALID bit */ 418 | if( val == 1) { 419 | return true; 420 | } else { 421 | return false; 422 | } 423 | } 424 | 425 | /** 426 | * @brief Processes a gesture event and returns best guessed gesture 427 | * 428 | * @return Number corresponding to gesture. -1 on error. 429 | */ 430 | int APDS9960::readGesture() 431 | { 432 | uint8_t fifo_level = 0; 433 | uint8_t bytes_read = 0; 434 | uint8_t fifo_data[128]; 435 | uint8_t gstatus; 436 | int motion; 437 | int i; 438 | 439 | /* Make sure that power and gesture is on and data is valid */ 440 | if( !isGestureAvailable() || !(getMode() & 0b01000001) ) { 441 | return DIR_NONE; 442 | } 443 | 444 | /* Keep looping as long as gesture data is valid */ 445 | while(1) { 446 | /* Wait some time to collect next batch of FIFO data */ 447 | delay(FIFO_PAUSE_TIME); 448 | 449 | /* Get the contents of the STATUS register. Is data still valid? */ 450 | if( !wireReadDataByte(APDS9960_GSTATUS, gstatus) ) { 451 | return ERROR; 452 | } 453 | 454 | /* If we have valid data, read in FIFO */ 455 | if( (gstatus & APDS9960_GVALID) == APDS9960_GVALID ) { 456 | 457 | /* Read the current FIFO level */ 458 | if( !wireReadDataByte(APDS9960_GFLVL, fifo_level) ) { 459 | return ERROR; 460 | } 461 | 462 | #if DEBUG 463 | Serial.print("FIFO Level: "); 464 | Serial.println(fifo_level); 465 | #endif 466 | 467 | /* If there's stuff in the FIFO, read it into our data block */ 468 | if( fifo_level > 0) { 469 | bytes_read = wireReadDataBlock( APDS9960_GFIFO_U, 470 | (uint8_t*)fifo_data, 471 | (fifo_level * 4) ); 472 | if( bytes_read == -1 ) { 473 | return ERROR; 474 | } 475 | #if DEBUG 476 | Serial.print("FIFO Dump: "); 477 | for ( i = 0; i < bytes_read; i++ ) { 478 | Serial.print(fifo_data[i]); 479 | Serial.print(" "); 480 | } 481 | Serial.println(); 482 | #endif 483 | 484 | /* If at least 1 set of data, sort the data into U/D/L/R */ 485 | if( bytes_read >= 4 ) { 486 | for( i = 0; i < bytes_read; i += 4 ) { 487 | gesture_data_.u_data[gesture_data_.index] = \ 488 | fifo_data[i + 0]; 489 | gesture_data_.d_data[gesture_data_.index] = \ 490 | fifo_data[i + 1]; 491 | gesture_data_.l_data[gesture_data_.index] = \ 492 | fifo_data[i + 2]; 493 | gesture_data_.r_data[gesture_data_.index] = \ 494 | fifo_data[i + 3]; 495 | gesture_data_.index++; 496 | gesture_data_.total_gestures++; 497 | } 498 | 499 | #if DEBUG 500 | Serial.print("Up Data: "); 501 | for ( i = 0; i < gesture_data_.total_gestures; i++ ) { 502 | Serial.print(gesture_data_.u_data[i]); 503 | Serial.print(" "); 504 | } 505 | Serial.println(); 506 | #endif 507 | 508 | /* Filter and process gesture data. Decode near/far state */ 509 | if( processGestureData() ) { 510 | if( decodeGesture() ) { 511 | //***TODO: U-Turn Gestures 512 | #if DEBUG 513 | //Serial.println(gesture_motion_); 514 | #endif 515 | } 516 | } 517 | 518 | /* Reset data */ 519 | gesture_data_.index = 0; 520 | gesture_data_.total_gestures = 0; 521 | } 522 | } 523 | } else { 524 | 525 | /* Determine best guessed gesture and clean up */ 526 | delay(FIFO_PAUSE_TIME); 527 | decodeGesture(); 528 | motion = gesture_motion_; 529 | #if DEBUG 530 | Serial.print("END: "); 531 | Serial.println(gesture_motion_); 532 | #endif 533 | resetGestureParameters(); 534 | return motion; 535 | } 536 | } 537 | } 538 | 539 | /** 540 | * Turn the APDS-9960 on 541 | * 542 | * @return True if operation successful. False otherwise. 543 | */ 544 | bool APDS9960::enablePower() 545 | { 546 | if( !setMode(POWER, 1) ) { 547 | return false; 548 | } 549 | 550 | return true; 551 | } 552 | 553 | /** 554 | * Turn the APDS-9960 off 555 | * 556 | * @return True if operation successful. False otherwise. 557 | */ 558 | bool APDS9960::disablePower() 559 | { 560 | if( !setMode(POWER, 0) ) { 561 | return false; 562 | } 563 | 564 | return true; 565 | } 566 | 567 | /******************************************************************************* 568 | * Ambient light and color sensor controls 569 | ******************************************************************************/ 570 | 571 | /** 572 | * @brief Reads the ambient (clear) light level as a 16-bit value 573 | * 574 | * @param[out] val value of the light sensor. 575 | * @return True if operation successful. False otherwise. 576 | */ 577 | bool APDS9960::readAmbientLight(uint16_t &val) 578 | { 579 | uint8_t val_byte; 580 | val = 0; 581 | 582 | /* Read value from clear channel, low byte register */ 583 | if( !wireReadDataByte(APDS9960_CDATAL, val_byte) ) { 584 | return false; 585 | } 586 | val = val_byte; 587 | 588 | /* Read value from clear channel, high byte register */ 589 | if( !wireReadDataByte(APDS9960_CDATAH, val_byte) ) { 590 | return false; 591 | } 592 | val = val + ((uint16_t)val_byte << 8); 593 | 594 | return true; 595 | } 596 | 597 | /** 598 | * @brief Reads the red light level as a 16-bit value 599 | * 600 | * @param[out] val value of the light sensor. 601 | * @return True if operation successful. False otherwise. 602 | */ 603 | bool APDS9960::readRedLight(uint16_t &val) 604 | { 605 | uint8_t val_byte; 606 | val = 0; 607 | 608 | /* Read value from clear channel, low byte register */ 609 | if( !wireReadDataByte(APDS9960_RDATAL, val_byte) ) { 610 | return false; 611 | } 612 | val = val_byte; 613 | 614 | /* Read value from clear channel, high byte register */ 615 | if( !wireReadDataByte(APDS9960_RDATAH, val_byte) ) { 616 | return false; 617 | } 618 | val = val + ((uint16_t)val_byte << 8); 619 | 620 | return true; 621 | } 622 | 623 | /** 624 | * @brief Reads the green 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 APDS9960::readGreenLight(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_GDATAL, val_byte) ) { 636 | return false; 637 | } 638 | val = val_byte; 639 | 640 | /* Read value from clear channel, high byte register */ 641 | if( !wireReadDataByte(APDS9960_GDATAH, 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 APDS9960::readBlueLight(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_BDATAL, val_byte) ) { 662 | return false; 663 | } 664 | val = val_byte; 665 | 666 | /* Read value from clear channel, high byte register */ 667 | if( !wireReadDataByte(APDS9960_BDATAH, val_byte) ) { 668 | return false; 669 | } 670 | val = val + ((uint16_t)val_byte << 8); 671 | 672 | return true; 673 | } 674 | 675 | /******************************************************************************* 676 | * Proximity sensor controls 677 | ******************************************************************************/ 678 | 679 | /** 680 | * @brief Reads the proximity level as an 8-bit value 681 | * 682 | * @param[out] val value of the proximity sensor. 683 | * @return True if operation successful. False otherwise. 684 | */ 685 | bool APDS9960::readProximity(uint8_t &val) 686 | { 687 | val = 0; 688 | 689 | /* Read value from proximity data register */ 690 | if( !wireReadDataByte(APDS9960_PDATA, val) ) { 691 | return false; 692 | } 693 | 694 | return true; 695 | } 696 | 697 | /******************************************************************************* 698 | * High-level gesture controls 699 | ******************************************************************************/ 700 | 701 | /** 702 | * @brief Resets all the parameters in the gesture data member 703 | */ 704 | void APDS9960::resetGestureParameters() 705 | { 706 | gesture_data_.index = 0; 707 | gesture_data_.total_gestures = 0; 708 | 709 | gesture_ud_delta_ = 0; 710 | gesture_lr_delta_ = 0; 711 | 712 | gesture_ud_count_ = 0; 713 | gesture_lr_count_ = 0; 714 | 715 | gesture_near_count_ = 0; 716 | gesture_far_count_ = 0; 717 | 718 | gesture_state_ = 0; 719 | gesture_motion_ = DIR_NONE; 720 | } 721 | 722 | /** 723 | * @brief Processes the raw gesture data to determine swipe direction 724 | * 725 | * @return True if near or far state seen. False otherwise. 726 | */ 727 | bool APDS9960::processGestureData() 728 | { 729 | uint8_t u_first = 0; 730 | uint8_t d_first = 0; 731 | uint8_t l_first = 0; 732 | uint8_t r_first = 0; 733 | uint8_t u_last = 0; 734 | uint8_t d_last = 0; 735 | uint8_t l_last = 0; 736 | uint8_t r_last = 0; 737 | int ud_ratio_first; 738 | int lr_ratio_first; 739 | int ud_ratio_last; 740 | int lr_ratio_last; 741 | int ud_delta; 742 | int lr_delta; 743 | int i; 744 | 745 | /* If we have less than 4 total gestures, that's not enough */ 746 | if( gesture_data_.total_gestures <= 4 ) { 747 | return false; 748 | } 749 | 750 | /* Check to make sure our data isn't out of bounds */ 751 | if( (gesture_data_.total_gestures <= 32) && \ 752 | (gesture_data_.total_gestures > 0) ) { 753 | 754 | /* Find the first value in U/D/L/R above the threshold */ 755 | for( i = 0; i < gesture_data_.total_gestures; i++ ) { 756 | if( (gesture_data_.u_data[i] > GESTURE_THRESHOLD_OUT) && 757 | (gesture_data_.d_data[i] > GESTURE_THRESHOLD_OUT) && 758 | (gesture_data_.l_data[i] > GESTURE_THRESHOLD_OUT) && 759 | (gesture_data_.r_data[i] > GESTURE_THRESHOLD_OUT) ) { 760 | 761 | u_first = gesture_data_.u_data[i]; 762 | d_first = gesture_data_.d_data[i]; 763 | l_first = gesture_data_.l_data[i]; 764 | r_first = gesture_data_.r_data[i]; 765 | break; 766 | } 767 | } 768 | 769 | /* If one of the _first values is 0, then there is no good data */ 770 | if( (u_first == 0) || (d_first == 0) || \ 771 | (l_first == 0) || (r_first == 0) ) { 772 | 773 | return false; 774 | } 775 | /* Find the last value in U/D/L/R above the threshold */ 776 | for( i = gesture_data_.total_gestures - 1; i >= 0; i-- ) { 777 | #if DEBUG 778 | Serial.print(F("Finding last: ")); 779 | Serial.print(F("U:")); 780 | Serial.print(gesture_data_.u_data[i]); 781 | Serial.print(F(" D:")); 782 | Serial.print(gesture_data_.d_data[i]); 783 | Serial.print(F(" L:")); 784 | Serial.print(gesture_data_.l_data[i]); 785 | Serial.print(F(" R:")); 786 | Serial.println(gesture_data_.r_data[i]); 787 | #endif 788 | if( (gesture_data_.u_data[i] > GESTURE_THRESHOLD_OUT) && 789 | (gesture_data_.d_data[i] > GESTURE_THRESHOLD_OUT) && 790 | (gesture_data_.l_data[i] > GESTURE_THRESHOLD_OUT) && 791 | (gesture_data_.r_data[i] > GESTURE_THRESHOLD_OUT) ) { 792 | 793 | u_last = gesture_data_.u_data[i]; 794 | d_last = gesture_data_.d_data[i]; 795 | l_last = gesture_data_.l_data[i]; 796 | r_last = gesture_data_.r_data[i]; 797 | break; 798 | } 799 | } 800 | } 801 | 802 | /* Calculate the first vs. last ratio of up/down and left/right */ 803 | ud_ratio_first = ((u_first - d_first) * 100) / (u_first + d_first); 804 | lr_ratio_first = ((l_first - r_first) * 100) / (l_first + r_first); 805 | ud_ratio_last = ((u_last - d_last) * 100) / (u_last + d_last); 806 | lr_ratio_last = ((l_last - r_last) * 100) / (l_last + r_last); 807 | 808 | #if DEBUG 809 | Serial.print(F("Last Values: ")); 810 | Serial.print(F("U:")); 811 | Serial.print(u_last); 812 | Serial.print(F(" D:")); 813 | Serial.print(d_last); 814 | Serial.print(F(" L:")); 815 | Serial.print(l_last); 816 | Serial.print(F(" R:")); 817 | Serial.println(r_last); 818 | 819 | Serial.print(F("Ratios: ")); 820 | Serial.print(F("UD Fi: ")); 821 | Serial.print(ud_ratio_first); 822 | Serial.print(F(" UD La: ")); 823 | Serial.print(ud_ratio_last); 824 | Serial.print(F(" LR Fi: ")); 825 | Serial.print(lr_ratio_first); 826 | Serial.print(F(" LR La: ")); 827 | Serial.println(lr_ratio_last); 828 | #endif 829 | 830 | /* Determine the difference between the first and last ratios */ 831 | ud_delta = ud_ratio_last - ud_ratio_first; 832 | lr_delta = lr_ratio_last - lr_ratio_first; 833 | 834 | #if DEBUG 835 | Serial.print("Deltas: "); 836 | Serial.print("UD: "); 837 | Serial.print(ud_delta); 838 | Serial.print(" LR: "); 839 | Serial.println(lr_delta); 840 | #endif 841 | 842 | /* Accumulate the UD and LR delta values */ 843 | gesture_ud_delta_ += ud_delta; 844 | gesture_lr_delta_ += lr_delta; 845 | 846 | #if DEBUG 847 | Serial.print("Accumulations: "); 848 | Serial.print("UD: "); 849 | Serial.print(gesture_ud_delta_); 850 | Serial.print(" LR: "); 851 | Serial.println(gesture_lr_delta_); 852 | #endif 853 | 854 | /* Determine U/D gesture */ 855 | if( gesture_ud_delta_ >= GESTURE_SENSITIVITY_1 ) { 856 | gesture_ud_count_ = 1; 857 | } else if( gesture_ud_delta_ <= -GESTURE_SENSITIVITY_1 ) { 858 | gesture_ud_count_ = -1; 859 | } else { 860 | gesture_ud_count_ = 0; 861 | } 862 | 863 | /* Determine L/R gesture */ 864 | if( gesture_lr_delta_ >= GESTURE_SENSITIVITY_1 ) { 865 | gesture_lr_count_ = 1; 866 | } else if( gesture_lr_delta_ <= -GESTURE_SENSITIVITY_1 ) { 867 | gesture_lr_count_ = -1; 868 | } else { 869 | gesture_lr_count_ = 0; 870 | } 871 | 872 | /* Determine Near/Far gesture */ 873 | if( (gesture_ud_count_ == 0) && (gesture_lr_count_ == 0) ) { 874 | if( (abs(ud_delta) < GESTURE_SENSITIVITY_2) && \ 875 | (abs(lr_delta) < GESTURE_SENSITIVITY_2) ) { 876 | 877 | if( (ud_delta == 0) && (lr_delta == 0) ) { 878 | gesture_near_count_++; 879 | } else if( (ud_delta != 0) || (lr_delta != 0) ) { 880 | gesture_far_count_++; 881 | } 882 | 883 | if( (gesture_near_count_ >= 10) && (gesture_far_count_ >= 2) ) { 884 | if( (ud_delta == 0) && (lr_delta == 0) ) { 885 | gesture_state_ = NEAR_STATE; 886 | } else if( (ud_delta != 0) && (lr_delta != 0) ) { 887 | gesture_state_ = FAR_STATE; 888 | } 889 | return true; 890 | } 891 | } 892 | } else { 893 | if( (abs(ud_delta) < GESTURE_SENSITIVITY_2) && \ 894 | (abs(lr_delta) < GESTURE_SENSITIVITY_2) ) { 895 | 896 | if( (ud_delta == 0) && (lr_delta == 0) ) { 897 | gesture_near_count_++; 898 | } 899 | 900 | if( gesture_near_count_ >= 10 ) { 901 | gesture_ud_count_ = 0; 902 | gesture_lr_count_ = 0; 903 | gesture_ud_delta_ = 0; 904 | gesture_lr_delta_ = 0; 905 | } 906 | } 907 | } 908 | 909 | #if DEBUG 910 | Serial.print("UD_CT: "); 911 | Serial.print(gesture_ud_count_); 912 | Serial.print(" LR_CT: "); 913 | Serial.print(gesture_lr_count_); 914 | Serial.print(" NEAR_CT: "); 915 | Serial.print(gesture_near_count_); 916 | Serial.print(" FAR_CT: "); 917 | Serial.println(gesture_far_count_); 918 | Serial.println("----------"); 919 | #endif 920 | 921 | return false; 922 | } 923 | 924 | /** 925 | * @brief Determines swipe direction or near/far state 926 | * 927 | * @return True if near/far event. False otherwise. 928 | */ 929 | bool APDS9960::decodeGesture() 930 | { 931 | /* Return if near or far event is detected */ 932 | if( gesture_state_ == NEAR_STATE ) { 933 | gesture_motion_ = DIR_NEAR; 934 | return true; 935 | } else if ( gesture_state_ == FAR_STATE ) { 936 | gesture_motion_ = DIR_FAR; 937 | return true; 938 | } 939 | 940 | /* Determine swipe direction */ 941 | if( (gesture_ud_count_ == -1) && (gesture_lr_count_ == 0) ) { 942 | gesture_motion_ = DIR_UP; 943 | } else if( (gesture_ud_count_ == 1) && (gesture_lr_count_ == 0) ) { 944 | gesture_motion_ = DIR_DOWN; 945 | } else if( (gesture_ud_count_ == 0) && (gesture_lr_count_ == 1) ) { 946 | gesture_motion_ = DIR_RIGHT; 947 | } else if( (gesture_ud_count_ == 0) && (gesture_lr_count_ == -1) ) { 948 | gesture_motion_ = DIR_LEFT; 949 | } else if( (gesture_ud_count_ == -1) && (gesture_lr_count_ == 1) ) { 950 | if( abs(gesture_ud_delta_) > abs(gesture_lr_delta_) ) { 951 | gesture_motion_ = DIR_UP; 952 | } else { 953 | gesture_motion_ = DIR_RIGHT; 954 | } 955 | } else if( (gesture_ud_count_ == 1) && (gesture_lr_count_ == -1) ) { 956 | if( abs(gesture_ud_delta_) > abs(gesture_lr_delta_) ) { 957 | gesture_motion_ = DIR_DOWN; 958 | } else { 959 | gesture_motion_ = DIR_LEFT; 960 | } 961 | } else if( (gesture_ud_count_ == -1) && (gesture_lr_count_ == -1) ) { 962 | if( abs(gesture_ud_delta_) > abs(gesture_lr_delta_) ) { 963 | gesture_motion_ = DIR_UP; 964 | } else { 965 | gesture_motion_ = DIR_LEFT; 966 | } 967 | } else if( (gesture_ud_count_ == 1) && (gesture_lr_count_ == 1) ) { 968 | if( abs(gesture_ud_delta_) > abs(gesture_lr_delta_) ) { 969 | gesture_motion_ = DIR_DOWN; 970 | } else { 971 | gesture_motion_ = DIR_RIGHT; 972 | } 973 | } else { 974 | return false; 975 | } 976 | 977 | return true; 978 | } 979 | 980 | /******************************************************************************* 981 | * Getters and setters for register values 982 | ******************************************************************************/ 983 | 984 | /** 985 | * @brief Returns the lower threshold for proximity detection 986 | * 987 | * @return lower threshold 988 | */ 989 | uint8_t APDS9960::getProxIntLowThresh() 990 | { 991 | uint8_t val; 992 | 993 | /* Read value from PILT register */ 994 | if( !wireReadDataByte(APDS9960_PILT, val) ) { 995 | val = 0; 996 | } 997 | 998 | return val; 999 | } 1000 | 1001 | /** 1002 | * @brief Sets the lower threshold for proximity detection 1003 | * 1004 | * @param[in] threshold the lower proximity threshold 1005 | * @return True if operation successful. False otherwise. 1006 | */ 1007 | bool APDS9960::setProxIntLowThresh(uint8_t threshold) 1008 | { 1009 | if( !wireWriteDataByte(APDS9960_PILT, threshold) ) { 1010 | return false; 1011 | } 1012 | 1013 | return true; 1014 | } 1015 | 1016 | /** 1017 | * @brief Returns the high threshold for proximity detection 1018 | * 1019 | * @return high threshold 1020 | */ 1021 | uint8_t APDS9960::getProxIntHighThresh() 1022 | { 1023 | uint8_t val; 1024 | 1025 | /* Read value from PIHT register */ 1026 | if( !wireReadDataByte(APDS9960_PIHT, val) ) { 1027 | val = 0; 1028 | } 1029 | 1030 | return val; 1031 | } 1032 | 1033 | /** 1034 | * @brief Sets the high threshold for proximity detection 1035 | * 1036 | * @param[in] threshold the high proximity threshold 1037 | * @return True if operation successful. False otherwise. 1038 | */ 1039 | bool APDS9960::setProxIntHighThresh(uint8_t threshold) 1040 | { 1041 | if( !wireWriteDataByte(APDS9960_PIHT, threshold) ) { 1042 | return false; 1043 | } 1044 | 1045 | return true; 1046 | } 1047 | 1048 | /** 1049 | * @brief Returns LED drive strength for proximity and ALS 1050 | * 1051 | * Value LED Current 1052 | * 0 100 mA 1053 | * 1 50 mA 1054 | * 2 25 mA 1055 | * 3 12.5 mA 1056 | * 1057 | * @return the value of the LED drive strength. 0xFF on failure. 1058 | */ 1059 | uint8_t APDS9960::getLEDDrive() 1060 | { 1061 | uint8_t val; 1062 | 1063 | /* Read value from CONTROL register */ 1064 | if( !wireReadDataByte(APDS9960_CONTROL, val) ) { 1065 | return ERROR; 1066 | } 1067 | 1068 | /* Shift and mask out LED drive bits */ 1069 | val = (val >> 6) & 0b00000011; 1070 | 1071 | return val; 1072 | } 1073 | 1074 | /** 1075 | * @brief Sets the LED drive strength for proximity and ALS 1076 | * 1077 | * Value LED Current 1078 | * 0 100 mA 1079 | * 1 50 mA 1080 | * 2 25 mA 1081 | * 3 12.5 mA 1082 | * 1083 | * @param[in] drive the value (0-3) for the LED drive strength 1084 | * @return True if operation successful. False otherwise. 1085 | */ 1086 | bool APDS9960::setLEDDrive(uint8_t drive) 1087 | { 1088 | uint8_t val; 1089 | 1090 | /* Read value from CONTROL register */ 1091 | if( !wireReadDataByte(APDS9960_CONTROL, val) ) { 1092 | return false; 1093 | } 1094 | 1095 | /* Set bits in register to given value */ 1096 | drive &= 0b00000011; 1097 | drive = drive << 6; 1098 | val &= 0b00111111; 1099 | val |= drive; 1100 | 1101 | /* Write register value back into CONTROL register */ 1102 | if( !wireWriteDataByte(APDS9960_CONTROL, val) ) { 1103 | return false; 1104 | } 1105 | 1106 | return true; 1107 | } 1108 | 1109 | /** 1110 | * @brief Returns receiver gain for proximity detection 1111 | * 1112 | * Value Gain 1113 | * 0 1x 1114 | * 1 2x 1115 | * 2 4x 1116 | * 3 8x 1117 | * 1118 | * @return the value of the proximity gain. 0xFF on failure. 1119 | */ 1120 | uint8_t APDS9960::getProximityGain() 1121 | { 1122 | uint8_t val; 1123 | 1124 | /* Read value from CONTROL register */ 1125 | if( !wireReadDataByte(APDS9960_CONTROL, val) ) { 1126 | return ERROR; 1127 | } 1128 | 1129 | /* Shift and mask out PDRIVE bits */ 1130 | val = (val >> 2) & 0b00000011; 1131 | 1132 | return val; 1133 | } 1134 | 1135 | /** 1136 | * @brief Sets the receiver gain for proximity detection 1137 | * 1138 | * Value Gain 1139 | * 0 1x 1140 | * 1 2x 1141 | * 2 4x 1142 | * 3 8x 1143 | * 1144 | * @param[in] drive the value (0-3) for the gain 1145 | * @return True if operation successful. False otherwise. 1146 | */ 1147 | bool APDS9960::setProximityGain(uint8_t drive) 1148 | { 1149 | uint8_t val; 1150 | 1151 | /* Read value from CONTROL register */ 1152 | if( !wireReadDataByte(APDS9960_CONTROL, val) ) { 1153 | return false; 1154 | } 1155 | 1156 | /* Set bits in register to given value */ 1157 | drive &= 0b00000011; 1158 | drive = drive << 2; 1159 | val &= 0b11110011; 1160 | val |= drive; 1161 | 1162 | /* Write register value back into CONTROL register */ 1163 | if( !wireWriteDataByte(APDS9960_CONTROL, val) ) { 1164 | return false; 1165 | } 1166 | 1167 | return true; 1168 | } 1169 | 1170 | /** 1171 | * @brief Returns receiver gain for the ambient light sensor (ALS) 1172 | * 1173 | * Value Gain 1174 | * 0 1x 1175 | * 1 4x 1176 | * 2 16x 1177 | * 3 64x 1178 | * 1179 | * @return the value of the ALS gain. 0xFF on failure. 1180 | */ 1181 | uint8_t APDS9960::getAmbientLightGain() 1182 | { 1183 | uint8_t val; 1184 | 1185 | /* Read value from CONTROL register */ 1186 | if( !wireReadDataByte(APDS9960_CONTROL, val) ) { 1187 | return ERROR; 1188 | } 1189 | 1190 | /* Shift and mask out ADRIVE bits */ 1191 | val &= 0b00000011; 1192 | 1193 | return val; 1194 | } 1195 | 1196 | /** 1197 | * @brief Sets the receiver gain for the ambient light sensor (ALS) 1198 | * 1199 | * Value Gain 1200 | * 0 1x 1201 | * 1 4x 1202 | * 2 16x 1203 | * 3 64x 1204 | * 1205 | * @param[in] drive the value (0-3) for the gain 1206 | * @return True if operation successful. False otherwise. 1207 | */ 1208 | bool APDS9960::setAmbientLightGain(uint8_t drive) 1209 | { 1210 | uint8_t val; 1211 | 1212 | /* Read value from CONTROL register */ 1213 | if( !wireReadDataByte(APDS9960_CONTROL, val) ) { 1214 | return false; 1215 | } 1216 | 1217 | /* Set bits in register to given value */ 1218 | drive &= 0b00000011; 1219 | val &= 0b11111100; 1220 | val |= drive; 1221 | 1222 | /* Write register value back into CONTROL register */ 1223 | if( !wireWriteDataByte(APDS9960_CONTROL, val) ) { 1224 | return false; 1225 | } 1226 | 1227 | return true; 1228 | } 1229 | 1230 | /** 1231 | * @brief Get the current LED boost value 1232 | * 1233 | * Value Boost Current 1234 | * 0 100% 1235 | * 1 150% 1236 | * 2 200% 1237 | * 3 300% 1238 | * 1239 | * @return The LED boost value. 0xFF on failure. 1240 | */ 1241 | uint8_t APDS9960::getLEDBoost() 1242 | { 1243 | uint8_t val; 1244 | 1245 | /* Read value from CONFIG2 register */ 1246 | if( !wireReadDataByte(APDS9960_CONFIG2, val) ) { 1247 | return ERROR; 1248 | } 1249 | 1250 | /* Shift and mask out LED_BOOST bits */ 1251 | val = (val >> 4) & 0b00000011; 1252 | 1253 | return val; 1254 | } 1255 | 1256 | /** 1257 | * @brief Sets the LED current boost value 1258 | * 1259 | * Value Boost Current 1260 | * 0 100% 1261 | * 1 150% 1262 | * 2 200% 1263 | * 3 300% 1264 | * 1265 | * @param[in] drive the value (0-3) for current boost (100-300%) 1266 | * @return True if operation successful. False otherwise. 1267 | */ 1268 | bool APDS9960::setLEDBoost(uint8_t boost) 1269 | { 1270 | uint8_t val; 1271 | 1272 | /* Read value from CONFIG2 register */ 1273 | if( !wireReadDataByte(APDS9960_CONFIG2, val) ) { 1274 | return false; 1275 | } 1276 | 1277 | /* Set bits in register to given value */ 1278 | boost &= 0b00000011; 1279 | boost = boost << 4; 1280 | val &= 0b11001111; 1281 | val |= boost; 1282 | 1283 | /* Write register value back into CONFIG2 register */ 1284 | if( !wireWriteDataByte(APDS9960_CONFIG2, val) ) { 1285 | return false; 1286 | } 1287 | 1288 | return true; 1289 | } 1290 | 1291 | /** 1292 | * @brief Gets proximity gain compensation enable 1293 | * 1294 | * @return 1 if compensation is enabled. 0 if not. 0xFF on error. 1295 | */ 1296 | uint8_t APDS9960::getProxGainCompEnable() 1297 | { 1298 | uint8_t val; 1299 | 1300 | /* Read value from CONFIG3 register */ 1301 | if( !wireReadDataByte(APDS9960_CONFIG3, val) ) { 1302 | return ERROR; 1303 | } 1304 | 1305 | /* Shift and mask out PCMP bits */ 1306 | val = (val >> 5) & 0b00000001; 1307 | 1308 | return val; 1309 | } 1310 | 1311 | /** 1312 | * @brief Sets the proximity gain compensation enable 1313 | * 1314 | * @param[in] enable 1 to enable compensation. 0 to disable compensation. 1315 | * @return True if operation successful. False otherwise. 1316 | */ 1317 | bool APDS9960::setProxGainCompEnable(uint8_t enable) 1318 | { 1319 | uint8_t val; 1320 | 1321 | /* Read value from CONFIG3 register */ 1322 | if( !wireReadDataByte(APDS9960_CONFIG3, val) ) { 1323 | return false; 1324 | } 1325 | 1326 | /* Set bits in register to given value */ 1327 | enable &= 0b00000001; 1328 | enable = enable << 5; 1329 | val &= 0b11011111; 1330 | val |= enable; 1331 | 1332 | /* Write register value back into CONFIG3 register */ 1333 | if( !wireWriteDataByte(APDS9960_CONFIG3, val) ) { 1334 | return false; 1335 | } 1336 | 1337 | return true; 1338 | } 1339 | 1340 | /** 1341 | * @brief Gets the current mask for enabled/disabled proximity photodiodes 1342 | * 1343 | * 1 = disabled, 0 = enabled 1344 | * Bit Photodiode 1345 | * 3 UP 1346 | * 2 DOWN 1347 | * 1 LEFT 1348 | * 0 RIGHT 1349 | * 1350 | * @return Current proximity mask for photodiodes. 0xFF on error. 1351 | */ 1352 | uint8_t APDS9960::getProxPhotoMask() 1353 | { 1354 | uint8_t val; 1355 | 1356 | /* Read value from CONFIG3 register */ 1357 | if( !wireReadDataByte(APDS9960_CONFIG3, val) ) { 1358 | return ERROR; 1359 | } 1360 | 1361 | /* Mask out photodiode enable mask bits */ 1362 | val &= 0b00001111; 1363 | 1364 | return val; 1365 | } 1366 | 1367 | /** 1368 | * @brief Sets the mask for enabling/disabling proximity photodiodes 1369 | * 1370 | * 1 = disabled, 0 = enabled 1371 | * Bit Photodiode 1372 | * 3 UP 1373 | * 2 DOWN 1374 | * 1 LEFT 1375 | * 0 RIGHT 1376 | * 1377 | * @param[in] mask 4-bit mask value 1378 | * @return True if operation successful. False otherwise. 1379 | */ 1380 | bool APDS9960::setProxPhotoMask(uint8_t mask) 1381 | { 1382 | uint8_t val; 1383 | 1384 | /* Read value from CONFIG3 register */ 1385 | if( !wireReadDataByte(APDS9960_CONFIG3, val) ) { 1386 | return false; 1387 | } 1388 | 1389 | /* Set bits in register to given value */ 1390 | mask &= 0b00001111; 1391 | val &= 0b11110000; 1392 | val |= mask; 1393 | 1394 | /* Write register value back into CONFIG3 register */ 1395 | if( !wireWriteDataByte(APDS9960_CONFIG3, val) ) { 1396 | return false; 1397 | } 1398 | 1399 | return true; 1400 | } 1401 | 1402 | /** 1403 | * @brief Gets the entry proximity threshold for gesture sensing 1404 | * 1405 | * @return Current entry proximity threshold. 1406 | */ 1407 | uint8_t APDS9960::getGestureEnterThresh() 1408 | { 1409 | uint8_t val; 1410 | 1411 | /* Read value from GPENTH register */ 1412 | if( !wireReadDataByte(APDS9960_GPENTH, val) ) { 1413 | val = 0; 1414 | } 1415 | 1416 | return val; 1417 | } 1418 | 1419 | /** 1420 | * @brief Sets the entry proximity threshold for gesture sensing 1421 | * 1422 | * @param[in] threshold proximity value needed to start gesture mode 1423 | * @return True if operation successful. False otherwise. 1424 | */ 1425 | bool APDS9960::setGestureEnterThresh(uint8_t threshold) 1426 | { 1427 | if( !wireWriteDataByte(APDS9960_GPENTH, threshold) ) { 1428 | return false; 1429 | } 1430 | 1431 | return true; 1432 | } 1433 | 1434 | /** 1435 | * @brief Gets the exit proximity threshold for gesture sensing 1436 | * 1437 | * @return Current exit proximity threshold. 1438 | */ 1439 | uint8_t APDS9960::getGestureExitThresh() 1440 | { 1441 | uint8_t val; 1442 | 1443 | /* Read value from GEXTH register */ 1444 | if( !wireReadDataByte(APDS9960_GEXTH, val) ) { 1445 | val = 0; 1446 | } 1447 | 1448 | return val; 1449 | } 1450 | 1451 | /** 1452 | * @brief Sets the exit proximity threshold for gesture sensing 1453 | * 1454 | * @param[in] threshold proximity value needed to end gesture mode 1455 | * @return True if operation successful. False otherwise. 1456 | */ 1457 | bool APDS9960::setGestureExitThresh(uint8_t threshold) 1458 | { 1459 | if( !wireWriteDataByte(APDS9960_GEXTH, threshold) ) { 1460 | return false; 1461 | } 1462 | 1463 | return true; 1464 | } 1465 | 1466 | /** 1467 | * @brief Gets the gain of the photodiode during gesture mode 1468 | * 1469 | * Value Gain 1470 | * 0 1x 1471 | * 1 2x 1472 | * 2 4x 1473 | * 3 8x 1474 | * 1475 | * @return the current photodiode gain. 0xFF on error. 1476 | */ 1477 | uint8_t APDS9960::getGestureGain() 1478 | { 1479 | uint8_t val; 1480 | 1481 | /* Read value from GCONF2 register */ 1482 | if( !wireReadDataByte(APDS9960_GCONF2, val) ) { 1483 | return ERROR; 1484 | } 1485 | 1486 | /* Shift and mask out GGAIN bits */ 1487 | val = (val >> 5) & 0b00000011; 1488 | 1489 | return val; 1490 | } 1491 | 1492 | /** 1493 | * @brief Sets the gain of the photodiode during gesture mode 1494 | * 1495 | * Value Gain 1496 | * 0 1x 1497 | * 1 2x 1498 | * 2 4x 1499 | * 3 8x 1500 | * 1501 | * @param[in] gain the value for the photodiode gain 1502 | * @return True if operation successful. False otherwise. 1503 | */ 1504 | bool APDS9960::setGestureGain(uint8_t gain) 1505 | { 1506 | uint8_t val; 1507 | 1508 | /* Read value from GCONF2 register */ 1509 | if( !wireReadDataByte(APDS9960_GCONF2, val) ) { 1510 | return false; 1511 | } 1512 | 1513 | /* Set bits in register to given value */ 1514 | gain &= 0b00000011; 1515 | gain = gain << 5; 1516 | val &= 0b10011111; 1517 | val |= gain; 1518 | 1519 | /* Write register value back into GCONF2 register */ 1520 | if( !wireWriteDataByte(APDS9960_GCONF2, val) ) { 1521 | return false; 1522 | } 1523 | 1524 | return true; 1525 | } 1526 | 1527 | /** 1528 | * @brief Gets the drive current of the LED during gesture mode 1529 | * 1530 | * Value LED Current 1531 | * 0 100 mA 1532 | * 1 50 mA 1533 | * 2 25 mA 1534 | * 3 12.5 mA 1535 | * 1536 | * @return the LED drive current value. 0xFF on error. 1537 | */ 1538 | uint8_t APDS9960::getGestureLEDDrive() 1539 | { 1540 | uint8_t val; 1541 | 1542 | /* Read value from GCONF2 register */ 1543 | if( !wireReadDataByte(APDS9960_GCONF2, val) ) { 1544 | return ERROR; 1545 | } 1546 | 1547 | /* Shift and mask out GLDRIVE bits */ 1548 | val = (val >> 3) & 0b00000011; 1549 | 1550 | return val; 1551 | } 1552 | 1553 | /** 1554 | * @brief Sets the LED drive current during gesture mode 1555 | * 1556 | * Value LED Current 1557 | * 0 100 mA 1558 | * 1 50 mA 1559 | * 2 25 mA 1560 | * 3 12.5 mA 1561 | * 1562 | * @param[in] drive the value for the LED drive current 1563 | * @return True if operation successful. False otherwise. 1564 | */ 1565 | bool APDS9960::setGestureLEDDrive(uint8_t drive) 1566 | { 1567 | uint8_t val; 1568 | 1569 | /* Read value from GCONF2 register */ 1570 | if( !wireReadDataByte(APDS9960_GCONF2, val) ) { 1571 | return false; 1572 | } 1573 | 1574 | /* Set bits in register to given value */ 1575 | drive &= 0b00000011; 1576 | drive = drive << 3; 1577 | val &= 0b11100111; 1578 | val |= drive; 1579 | 1580 | /* Write register value back into GCONF2 register */ 1581 | if( !wireWriteDataByte(APDS9960_GCONF2, val) ) { 1582 | return false; 1583 | } 1584 | 1585 | return true; 1586 | } 1587 | 1588 | /** 1589 | * @brief Gets the time in low power mode between gesture detections 1590 | * 1591 | * Value Wait time 1592 | * 0 0 ms 1593 | * 1 2.8 ms 1594 | * 2 5.6 ms 1595 | * 3 8.4 ms 1596 | * 4 14.0 ms 1597 | * 5 22.4 ms 1598 | * 6 30.8 ms 1599 | * 7 39.2 ms 1600 | * 1601 | * @return the current wait time between gestures. 0xFF on error. 1602 | */ 1603 | uint8_t APDS9960::getGestureWaitTime() 1604 | { 1605 | uint8_t val; 1606 | 1607 | /* Read value from GCONF2 register */ 1608 | if( !wireReadDataByte(APDS9960_GCONF2, val) ) { 1609 | return ERROR; 1610 | } 1611 | 1612 | /* Mask out GWTIME bits */ 1613 | val &= 0b00000111; 1614 | 1615 | return val; 1616 | } 1617 | 1618 | /** 1619 | * @brief Sets the time in low power mode between gesture detections 1620 | * 1621 | * Value Wait time 1622 | * 0 0 ms 1623 | * 1 2.8 ms 1624 | * 2 5.6 ms 1625 | * 3 8.4 ms 1626 | * 4 14.0 ms 1627 | * 5 22.4 ms 1628 | * 6 30.8 ms 1629 | * 7 39.2 ms 1630 | * 1631 | * @param[in] the value for the wait time 1632 | * @return True if operation successful. False otherwise. 1633 | */ 1634 | bool APDS9960::setGestureWaitTime(uint8_t time) 1635 | { 1636 | uint8_t val; 1637 | 1638 | /* Read value from GCONF2 register */ 1639 | if( !wireReadDataByte(APDS9960_GCONF2, val) ) { 1640 | return false; 1641 | } 1642 | 1643 | /* Set bits in register to given value */ 1644 | time &= 0b00000111; 1645 | val &= 0b11111000; 1646 | val |= time; 1647 | 1648 | /* Write register value back into GCONF2 register */ 1649 | if( !wireWriteDataByte(APDS9960_GCONF2, val) ) { 1650 | return false; 1651 | } 1652 | 1653 | return true; 1654 | } 1655 | 1656 | /** 1657 | * @brief Gets the low threshold for ambient light interrupts 1658 | * 1659 | * @param[out] threshold current low threshold stored on the APDS-9960 1660 | * @return True if operation successful. False otherwise. 1661 | */ 1662 | bool APDS9960::getLightIntLowThreshold(uint16_t &threshold) 1663 | { 1664 | uint8_t val_byte; 1665 | threshold = 0; 1666 | 1667 | /* Read value from ambient light low threshold, low byte register */ 1668 | if( !wireReadDataByte(APDS9960_AILTL, val_byte) ) { 1669 | return false; 1670 | } 1671 | threshold = val_byte; 1672 | 1673 | /* Read value from ambient light low threshold, high byte register */ 1674 | if( !wireReadDataByte(APDS9960_AILTH, val_byte) ) { 1675 | return false; 1676 | } 1677 | threshold = threshold + ((uint16_t)val_byte << 8); 1678 | 1679 | return true; 1680 | } 1681 | 1682 | /** 1683 | * @brief Sets the low threshold for ambient light interrupts 1684 | * 1685 | * @param[in] threshold low threshold value for interrupt to trigger 1686 | * @return True if operation successful. False otherwise. 1687 | */ 1688 | bool APDS9960::setLightIntLowThreshold(uint16_t threshold) 1689 | { 1690 | uint8_t val_low; 1691 | uint8_t val_high; 1692 | 1693 | /* Break 16-bit threshold into 2 8-bit values */ 1694 | val_low = threshold & 0x00FF; 1695 | val_high = (threshold & 0xFF00) >> 8; 1696 | 1697 | /* Write low byte */ 1698 | if( !wireWriteDataByte(APDS9960_AILTL, val_low) ) { 1699 | return false; 1700 | } 1701 | 1702 | /* Write high byte */ 1703 | if( !wireWriteDataByte(APDS9960_AILTH, val_high) ) { 1704 | return false; 1705 | } 1706 | 1707 | return true; 1708 | } 1709 | 1710 | /** 1711 | * @brief Gets the high threshold for ambient light interrupts 1712 | * 1713 | * @param[out] threshold current low threshold stored on the APDS-9960 1714 | * @return True if operation successful. False otherwise. 1715 | */ 1716 | bool APDS9960::getLightIntHighThreshold(uint16_t &threshold) 1717 | { 1718 | uint8_t val_byte; 1719 | threshold = 0; 1720 | 1721 | /* Read value from ambient light high threshold, low byte register */ 1722 | if( !wireReadDataByte(APDS9960_AIHTL, val_byte) ) { 1723 | return false; 1724 | } 1725 | threshold = val_byte; 1726 | 1727 | /* Read value from ambient light high threshold, high byte register */ 1728 | if( !wireReadDataByte(APDS9960_AIHTH, val_byte) ) { 1729 | return false; 1730 | } 1731 | threshold = threshold + ((uint16_t)val_byte << 8); 1732 | 1733 | return true; 1734 | } 1735 | 1736 | /** 1737 | * @brief Sets the high threshold for ambient light interrupts 1738 | * 1739 | * @param[in] threshold high threshold value for interrupt to trigger 1740 | * @return True if operation successful. False otherwise. 1741 | */ 1742 | bool APDS9960::setLightIntHighThreshold(uint16_t threshold) 1743 | { 1744 | uint8_t val_low; 1745 | uint8_t val_high; 1746 | 1747 | /* Break 16-bit threshold into 2 8-bit values */ 1748 | val_low = threshold & 0x00FF; 1749 | val_high = (threshold & 0xFF00) >> 8; 1750 | 1751 | /* Write low byte */ 1752 | if( !wireWriteDataByte(APDS9960_AIHTL, val_low) ) { 1753 | return false; 1754 | } 1755 | 1756 | /* Write high byte */ 1757 | if( !wireWriteDataByte(APDS9960_AIHTH, val_high) ) { 1758 | return false; 1759 | } 1760 | 1761 | return true; 1762 | } 1763 | 1764 | /** 1765 | * @brief Gets the low threshold for proximity interrupts 1766 | * 1767 | * @param[out] threshold current low threshold stored on the APDS-9960 1768 | * @return True if operation successful. False otherwise. 1769 | */ 1770 | bool APDS9960::getProximityIntLowThreshold(uint8_t &threshold) 1771 | { 1772 | threshold = 0; 1773 | 1774 | /* Read value from proximity low threshold register */ 1775 | if( !wireReadDataByte(APDS9960_PILT, threshold) ) { 1776 | return false; 1777 | } 1778 | 1779 | return true; 1780 | } 1781 | 1782 | /** 1783 | * @brief Sets the low threshold for proximity interrupts 1784 | * 1785 | * @param[in] threshold low threshold value for interrupt to trigger 1786 | * @return True if operation successful. False otherwise. 1787 | */ 1788 | bool APDS9960::setProximityIntLowThreshold(uint8_t threshold) 1789 | { 1790 | 1791 | /* Write threshold value to register */ 1792 | if( !wireWriteDataByte(APDS9960_PILT, threshold) ) { 1793 | return false; 1794 | } 1795 | 1796 | return true; 1797 | } 1798 | 1799 | /** 1800 | * @brief Gets the high threshold for proximity interrupts 1801 | * 1802 | * @param[out] threshold current low threshold stored on the APDS-9960 1803 | * @return True if operation successful. False otherwise. 1804 | */ 1805 | bool APDS9960::getProximityIntHighThreshold(uint8_t &threshold) 1806 | { 1807 | threshold = 0; 1808 | 1809 | /* Read value from proximity low threshold register */ 1810 | if( !wireReadDataByte(APDS9960_PIHT, threshold) ) { 1811 | return false; 1812 | } 1813 | 1814 | return true; 1815 | } 1816 | 1817 | /** 1818 | * @brief Sets the high threshold for proximity interrupts 1819 | * 1820 | * @param[in] threshold high threshold value for interrupt to trigger 1821 | * @return True if operation successful. False otherwise. 1822 | */ 1823 | bool APDS9960::setProximityIntHighThreshold(uint8_t threshold) 1824 | { 1825 | 1826 | /* Write threshold value to register */ 1827 | if( !wireWriteDataByte(APDS9960_PIHT, threshold) ) { 1828 | return false; 1829 | } 1830 | 1831 | return true; 1832 | } 1833 | 1834 | /** 1835 | * @brief Gets if ambient light interrupts are enabled or not 1836 | * 1837 | * @return 1 if interrupts are enabled, 0 if not. 0xFF on error. 1838 | */ 1839 | uint8_t APDS9960::getAmbientLightIntEnable() 1840 | { 1841 | uint8_t val; 1842 | 1843 | /* Read value from ENABLE register */ 1844 | if( !wireReadDataByte(APDS9960_ENABLE, val) ) { 1845 | return ERROR; 1846 | } 1847 | 1848 | /* Shift and mask out AIEN bit */ 1849 | val = (val >> 4) & 0b00000001; 1850 | 1851 | return val; 1852 | } 1853 | 1854 | /** 1855 | * @brief Turns ambient light interrupts on or off 1856 | * 1857 | * @param[in] enable 1 to enable interrupts, 0 to turn them off 1858 | * @return True if operation successful. False otherwise. 1859 | */ 1860 | bool APDS9960::setAmbientLightIntEnable(uint8_t enable) 1861 | { 1862 | uint8_t val; 1863 | 1864 | /* Read value from ENABLE register */ 1865 | if( !wireReadDataByte(APDS9960_ENABLE, val) ) { 1866 | return false; 1867 | } 1868 | 1869 | /* Set bits in register to given value */ 1870 | enable &= 0b00000001; 1871 | enable = enable << 4; 1872 | val &= 0b11101111; 1873 | val |= enable; 1874 | 1875 | /* Write register value back into ENABLE register */ 1876 | if( !wireWriteDataByte(APDS9960_ENABLE, val) ) { 1877 | return false; 1878 | } 1879 | 1880 | return true; 1881 | } 1882 | 1883 | /** 1884 | * @brief Gets if proximity interrupts are enabled or not 1885 | * 1886 | * @return 1 if interrupts are enabled, 0 if not. 0xFF on error. 1887 | */ 1888 | uint8_t APDS9960::getProximityIntEnable() 1889 | { 1890 | uint8_t val; 1891 | 1892 | /* Read value from ENABLE register */ 1893 | if( !wireReadDataByte(APDS9960_ENABLE, val) ) { 1894 | return ERROR; 1895 | } 1896 | 1897 | /* Shift and mask out PIEN bit */ 1898 | val = (val >> 5) & 0b00000001; 1899 | 1900 | return val; 1901 | } 1902 | 1903 | /** 1904 | * @brief Turns proximity interrupts on or off 1905 | * 1906 | * @param[in] enable 1 to enable interrupts, 0 to turn them off 1907 | * @return True if operation successful. False otherwise. 1908 | */ 1909 | bool APDS9960::setProximityIntEnable(uint8_t enable) 1910 | { 1911 | uint8_t val; 1912 | 1913 | /* Read value from ENABLE register */ 1914 | if( !wireReadDataByte(APDS9960_ENABLE, val) ) { 1915 | return false; 1916 | } 1917 | 1918 | /* Set bits in register to given value */ 1919 | enable &= 0b00000001; 1920 | enable = enable << 5; 1921 | val &= 0b11011111; 1922 | val |= enable; 1923 | 1924 | /* Write register value back into ENABLE register */ 1925 | if( !wireWriteDataByte(APDS9960_ENABLE, val) ) { 1926 | return false; 1927 | } 1928 | 1929 | return true; 1930 | } 1931 | 1932 | /** 1933 | * @brief Gets if gesture interrupts are enabled or not 1934 | * 1935 | * @return 1 if interrupts are enabled, 0 if not. 0xFF on error. 1936 | */ 1937 | uint8_t APDS9960::getGestureIntEnable() 1938 | { 1939 | uint8_t val; 1940 | 1941 | /* Read value from GCONF4 register */ 1942 | if( !wireReadDataByte(APDS9960_GCONF4, val) ) { 1943 | return ERROR; 1944 | } 1945 | 1946 | /* Shift and mask out GIEN bit */ 1947 | val = (val >> 1) & 0b00000001; 1948 | 1949 | return val; 1950 | } 1951 | 1952 | /** 1953 | * @brief Turns gesture-related interrupts on or off 1954 | * 1955 | * @param[in] enable 1 to enable interrupts, 0 to turn them off 1956 | * @return True if operation successful. False otherwise. 1957 | */ 1958 | bool APDS9960::setGestureIntEnable(uint8_t enable) 1959 | { 1960 | uint8_t val; 1961 | 1962 | /* Read value from GCONF4 register */ 1963 | if( !wireReadDataByte(APDS9960_GCONF4, val) ) { 1964 | return false; 1965 | } 1966 | 1967 | /* Set bits in register to given value */ 1968 | enable &= 0b00000001; 1969 | enable = enable << 1; 1970 | val &= 0b11111101; 1971 | val |= enable; 1972 | 1973 | /* Write register value back into GCONF4 register */ 1974 | if( !wireWriteDataByte(APDS9960_GCONF4, val) ) { 1975 | return false; 1976 | } 1977 | 1978 | return true; 1979 | } 1980 | 1981 | /** 1982 | * @brief Clears the ambient light interrupt 1983 | * 1984 | * @return True if operation completed successfully. False otherwise. 1985 | */ 1986 | bool APDS9960::clearAmbientLightInt() 1987 | { 1988 | uint8_t throwaway; 1989 | if( !wireReadDataByte(APDS9960_AICLEAR, throwaway) ) { 1990 | return false; 1991 | } 1992 | 1993 | return true; 1994 | } 1995 | 1996 | /** 1997 | * @brief Clears the proximity interrupt 1998 | * 1999 | * @return True if operation completed successfully. False otherwise. 2000 | */ 2001 | bool APDS9960::clearProximityInt() 2002 | { 2003 | uint8_t throwaway; 2004 | if( !wireReadDataByte(APDS9960_PICLEAR, throwaway) ) { 2005 | return false; 2006 | } 2007 | 2008 | return true; 2009 | } 2010 | 2011 | /** 2012 | * @brief Tells if the gesture state machine is currently running 2013 | * 2014 | * @return 1 if gesture state machine is running, 0 if not. 0xFF on error. 2015 | */ 2016 | uint8_t APDS9960::getGestureMode() 2017 | { 2018 | uint8_t val; 2019 | 2020 | /* Read value from GCONF4 register */ 2021 | if( !wireReadDataByte(APDS9960_GCONF4, val) ) { 2022 | return ERROR; 2023 | } 2024 | 2025 | /* Mask out GMODE bit */ 2026 | val &= 0b00000001; 2027 | 2028 | return val; 2029 | } 2030 | 2031 | /** 2032 | * @brief Tells the state machine to either enter or exit gesture state machine 2033 | * 2034 | * @param[in] mode 1 to enter gesture state machine, 0 to exit. 2035 | * @return True if operation successful. False otherwise. 2036 | */ 2037 | bool APDS9960::setGestureMode(uint8_t mode) 2038 | { 2039 | uint8_t val; 2040 | 2041 | /* Read value from GCONF4 register */ 2042 | if( !wireReadDataByte(APDS9960_GCONF4, val) ) { 2043 | return false; 2044 | } 2045 | 2046 | /* Set bits in register to given value */ 2047 | mode &= 0b00000001; 2048 | val &= 0b11111110; 2049 | val |= mode; 2050 | 2051 | /* Write register value back into GCONF4 register */ 2052 | if( !wireWriteDataByte(APDS9960_GCONF4, val) ) { 2053 | return false; 2054 | } 2055 | 2056 | return true; 2057 | } 2058 | 2059 | /******************************************************************************* 2060 | * Raw I2C Reads and Writes 2061 | ******************************************************************************/ 2062 | 2063 | /** 2064 | * @brief Writes a single byte to the I2C device (no register) 2065 | * 2066 | * @param[in] val the 1-byte value to write to the I2C device 2067 | * @return True if successful write operation. False otherwise. 2068 | */ 2069 | bool APDS9960::wireWriteByte(uint8_t val) 2070 | { 2071 | if(wiringPiI2CWrite(fd_, val) != 0) { 2072 | return false; 2073 | } 2074 | return true; 2075 | } 2076 | 2077 | /** 2078 | * @brief Writes a single byte to the I2C device and specified register 2079 | * 2080 | * @param[in] reg the register in the I2C device to write to 2081 | * @param[in] val the 1-byte value to write to the I2C device 2082 | * @return True if successful write operation. False otherwise. 2083 | */ 2084 | bool APDS9960::wireWriteDataByte(uint8_t reg, uint8_t val) 2085 | { 2086 | if(wiringPiI2CWriteReg8(fd_, reg, val) != 0) { 2087 | return false; 2088 | } 2089 | 2090 | return true; 2091 | } 2092 | 2093 | /** 2094 | * @brief Writes a block (array) of bytes to the I2C device and register 2095 | * 2096 | * @param[in] reg the register in the I2C device to write to 2097 | * @param[in] val pointer to the beginning of the data byte array 2098 | * @param[in] len the length (in bytes) of the data to write 2099 | * @return True if successful write operation. False otherwise. 2100 | */ 2101 | bool APDS9960::wireWriteDataBlock( uint8_t reg, 2102 | uint8_t *val, 2103 | unsigned int len) 2104 | { 2105 | if(wiringPiI2CWrite(fd_, reg) < 0) { 2106 | return false; 2107 | } 2108 | 2109 | unsigned char i = 0; 2110 | for(i = 0; i < len; i++) { 2111 | if(wiringPiI2CWrite(fd_, val[i]) < 0) { 2112 | return false; 2113 | } 2114 | } 2115 | return true; 2116 | } 2117 | 2118 | /** 2119 | * @brief Reads a single byte from the I2C device and specified register 2120 | * 2121 | * @param[in] reg the register to read from 2122 | * @param[out] the value returned from the register 2123 | * @return True if successful read operation. False otherwise. 2124 | */ 2125 | bool APDS9960::wireReadDataByte(uint8_t reg, uint8_t &val) 2126 | { 2127 | val = wiringPiI2CReadReg8(fd_, reg); 2128 | return true; 2129 | } 2130 | 2131 | /** 2132 | * @brief Reads a block (array) of bytes from the I2C device and register 2133 | * 2134 | * @param[in] reg the register to read from 2135 | * @param[out] val pointer to the beginning of the data 2136 | * @param[in] len number of bytes to read 2137 | * @return Number of bytes read. -1 on read error. 2138 | */ 2139 | int APDS9960::wireReadDataBlock( uint8_t reg, 2140 | uint8_t *val, 2141 | unsigned int len) 2142 | { 2143 | if(wiringPiI2CWrite(fd_, reg) < 0) { 2144 | return -1; 2145 | } 2146 | 2147 | unsigned char i = 0; 2148 | for(i = 0; i < len; i++) { 2149 | uint8_t dat; 2150 | if((dat = wiringPiI2CRead(fd_)) < 0) { 2151 | return -1; 2152 | } 2153 | val[i] = dat; 2154 | } 2155 | return i; 2156 | } 2157 | -------------------------------------------------------------------------------- /APDS-9960/c++/APDS9960.h: -------------------------------------------------------------------------------- 1 | #ifndef APDS9960_H 2 | #define APDS9960_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | /* Debug */ 10 | #define DEBUG 0 11 | 12 | /* APDS-9960 I2C address */ 13 | #define APDS9960_I2C_ADDR 0x39 14 | 15 | /* Gesture parameters */ 16 | #define GESTURE_THRESHOLD_OUT 10 17 | #define GESTURE_SENSITIVITY_1 50 18 | #define GESTURE_SENSITIVITY_2 20 19 | 20 | /* Error code for returned values */ 21 | #define ERROR 0xFF 22 | 23 | /* Acceptable device IDs */ 24 | #define APDS9960_ID_1 0xAB 25 | #define APDS9960_ID_2 0x9C 26 | 27 | /* Misc parameters */ 28 | #define FIFO_PAUSE_TIME 30 // Wait period (ms) between FIFO reads 29 | 30 | /* APDS-9960 register addresses */ 31 | #define APDS9960_ENABLE 0x80 32 | #define APDS9960_ATIME 0x81 33 | #define APDS9960_WTIME 0x83 34 | #define APDS9960_AILTL 0x84 35 | #define APDS9960_AILTH 0x85 36 | #define APDS9960_AIHTL 0x86 37 | #define APDS9960_AIHTH 0x87 38 | #define APDS9960_PILT 0x89 39 | #define APDS9960_PIHT 0x8B 40 | #define APDS9960_PERS 0x8C 41 | #define APDS9960_CONFIG1 0x8D 42 | #define APDS9960_PPULSE 0x8E 43 | #define APDS9960_CONTROL 0x8F 44 | #define APDS9960_CONFIG2 0x90 45 | #define APDS9960_ID 0x92 46 | #define APDS9960_STATUS 0x93 47 | #define APDS9960_CDATAL 0x94 48 | #define APDS9960_CDATAH 0x95 49 | #define APDS9960_RDATAL 0x96 50 | #define APDS9960_RDATAH 0x97 51 | #define APDS9960_GDATAL 0x98 52 | #define APDS9960_GDATAH 0x99 53 | #define APDS9960_BDATAL 0x9A 54 | #define APDS9960_BDATAH 0x9B 55 | #define APDS9960_PDATA 0x9C 56 | #define APDS9960_POFFSET_UR 0x9D 57 | #define APDS9960_POFFSET_DL 0x9E 58 | #define APDS9960_CONFIG3 0x9F 59 | #define APDS9960_GPENTH 0xA0 60 | #define APDS9960_GEXTH 0xA1 61 | #define APDS9960_GCONF1 0xA2 62 | #define APDS9960_GCONF2 0xA3 63 | #define APDS9960_GOFFSET_U 0xA4 64 | #define APDS9960_GOFFSET_D 0xA5 65 | #define APDS9960_GOFFSET_L 0xA7 66 | #define APDS9960_GOFFSET_R 0xA9 67 | #define APDS9960_GPULSE 0xA6 68 | #define APDS9960_GCONF3 0xAA 69 | #define APDS9960_GCONF4 0xAB 70 | #define APDS9960_GFLVL 0xAE 71 | #define APDS9960_GSTATUS 0xAF 72 | #define APDS9960_IFORCE 0xE4 73 | #define APDS9960_PICLEAR 0xE5 74 | #define APDS9960_CICLEAR 0xE6 75 | #define APDS9960_AICLEAR 0xE7 76 | #define APDS9960_GFIFO_U 0xFC 77 | #define APDS9960_GFIFO_D 0xFD 78 | #define APDS9960_GFIFO_L 0xFE 79 | #define APDS9960_GFIFO_R 0xFF 80 | 81 | /* Bit fields */ 82 | #define APDS9960_PON 0b00000001 83 | #define APDS9960_AEN 0b00000010 84 | #define APDS9960_PEN 0b00000100 85 | #define APDS9960_WEN 0b00001000 86 | #define APSD9960_AIEN 0b00010000 87 | #define APDS9960_PIEN 0b00100000 88 | #define APDS9960_GEN 0b01000000 89 | #define APDS9960_GVALID 0b00000001 90 | 91 | /* On/Off definitions */ 92 | #define OFF 0 93 | #define ON 1 94 | 95 | /* Acceptable parameters for setMode */ 96 | #define POWER 0 97 | #define AMBIENT_LIGHT 1 98 | #define PROXIMITY 2 99 | #define WAIT 3 100 | #define AMBIENT_LIGHT_INT 4 101 | #define PROXIMITY_INT 5 102 | #define GESTURE 6 103 | #define ALL 7 104 | 105 | /* LED Drive values */ 106 | #define LED_DRIVE_100MA 0 107 | #define LED_DRIVE_50MA 1 108 | #define LED_DRIVE_25MA 2 109 | #define LED_DRIVE_12_5MA 3 110 | 111 | /* Proximity Gain (PGAIN) values */ 112 | #define PGAIN_1X 0 113 | #define PGAIN_2X 1 114 | #define PGAIN_4X 2 115 | #define PGAIN_8X 3 116 | 117 | /* ALS Gain (AGAIN) values */ 118 | #define AGAIN_1X 0 119 | #define AGAIN_4X 1 120 | #define AGAIN_16X 2 121 | #define AGAIN_64X 3 122 | 123 | /* Gesture Gain (GGAIN) values */ 124 | #define GGAIN_1X 0 125 | #define GGAIN_2X 1 126 | #define GGAIN_4X 2 127 | #define GGAIN_8X 3 128 | 129 | /* LED Boost values */ 130 | #define LED_BOOST_100 0 131 | #define LED_BOOST_150 1 132 | #define LED_BOOST_200 2 133 | #define LED_BOOST_300 3 134 | 135 | /* Gesture wait time values */ 136 | #define GWTIME_0MS 0 137 | #define GWTIME_2_8MS 1 138 | #define GWTIME_5_6MS 2 139 | #define GWTIME_8_4MS 3 140 | #define GWTIME_14_0MS 4 141 | #define GWTIME_22_4MS 5 142 | #define GWTIME_30_8MS 6 143 | #define GWTIME_39_2MS 7 144 | 145 | /* Default values */ 146 | #define DEFAULT_ATIME 219 // 103ms 147 | #define DEFAULT_WTIME 246 // 27ms 148 | #define DEFAULT_PROX_PPULSE 0x87 // 16us, 8 pulses 149 | #define DEFAULT_GESTURE_PPULSE 0x89 // 16us, 10 pulses 150 | #define DEFAULT_POFFSET_UR 0 // 0 offset 151 | #define DEFAULT_POFFSET_DL 0 // 0 offset 152 | #define DEFAULT_CONFIG1 0x60 // No 12x wait (WTIME) factor 153 | #define DEFAULT_LDRIVE LED_DRIVE_100MA 154 | #define DEFAULT_PGAIN PGAIN_4X 155 | #define DEFAULT_AGAIN AGAIN_4X 156 | #define DEFAULT_PILT 0 // Low proximity threshold 157 | #define DEFAULT_PIHT 50 // High proximity threshold 158 | #define DEFAULT_AILT 0xFFFF // Force interrupt for calibration 159 | #define DEFAULT_AIHT 0 160 | #define DEFAULT_PERS 0x11 // 2 consecutive prox or ALS for int. 161 | #define DEFAULT_CONFIG2 0x01 // No saturation interrupts or LED boost 162 | #define DEFAULT_CONFIG3 0 // Enable all photodiodes, no SAI 163 | #define DEFAULT_GPENTH 40 // Threshold for entering gesture mode 164 | #define DEFAULT_GEXTH 30 // Threshold for exiting gesture mode 165 | #define DEFAULT_GCONF1 0x40 // 4 gesture events for int., 1 for exit 166 | #define DEFAULT_GGAIN GGAIN_4X 167 | #define DEFAULT_GLDRIVE LED_DRIVE_100MA 168 | #define DEFAULT_GWTIME GWTIME_2_8MS 169 | #define DEFAULT_GOFFSET 0 // No offset scaling for gesture mode 170 | #define DEFAULT_GPULSE 0xC9 // 32us, 10 pulses 171 | #define DEFAULT_GCONF3 0 // All photodiodes active during gesture 172 | #define DEFAULT_GIEN 0 // Disable gesture interrupts 173 | 174 | /* Direction definitions */ 175 | enum { 176 | DIR_NONE, 177 | DIR_LEFT, 178 | DIR_RIGHT, 179 | DIR_UP, 180 | DIR_DOWN, 181 | DIR_NEAR, 182 | DIR_FAR, 183 | DIR_ALL 184 | }; 185 | 186 | /* State definitions */ 187 | enum { 188 | NA_STATE, 189 | NEAR_STATE, 190 | FAR_STATE, 191 | ALL_STATE 192 | }; 193 | 194 | /* Container for gesture data */ 195 | typedef struct gesture_data_type { 196 | uint8_t u_data[32]; 197 | uint8_t d_data[32]; 198 | uint8_t l_data[32]; 199 | uint8_t r_data[32]; 200 | uint8_t index; 201 | uint8_t total_gestures; 202 | uint8_t in_threshold; 203 | uint8_t out_threshold; 204 | } gesture_data_type; 205 | 206 | /* APDS9960 Class */ 207 | class APDS9960 { 208 | public: 209 | 210 | /* Initialization methods */ 211 | APDS9960(); 212 | ~APDS9960(); 213 | bool init(); 214 | uint8_t getMode(); 215 | bool setMode(uint8_t mode, uint8_t enable); 216 | 217 | /* Turn the APDS-9960 on and off */ 218 | bool enablePower(); 219 | bool disablePower(); 220 | 221 | /* Enable or disable specific sensors */ 222 | bool enableLightSensor(bool interrupts = false); 223 | bool disableLightSensor(); 224 | bool enableProximitySensor(bool interrupts = false); 225 | bool disableProximitySensor(); 226 | bool enableGestureSensor(bool interrupts = true); 227 | bool disableGestureSensor(); 228 | 229 | /* LED drive strength control */ 230 | uint8_t getLEDDrive(); 231 | bool setLEDDrive(uint8_t drive); 232 | uint8_t getGestureLEDDrive(); 233 | bool setGestureLEDDrive(uint8_t drive); 234 | 235 | /* Gain control */ 236 | uint8_t getAmbientLightGain(); 237 | bool setAmbientLightGain(uint8_t gain); 238 | uint8_t getProximityGain(); 239 | bool setProximityGain(uint8_t gain); 240 | uint8_t getGestureGain(); 241 | bool setGestureGain(uint8_t gain); 242 | 243 | /* Get and set light interrupt thresholds */ 244 | bool getLightIntLowThreshold(uint16_t &threshold); 245 | bool setLightIntLowThreshold(uint16_t threshold); 246 | bool getLightIntHighThreshold(uint16_t &threshold); 247 | bool setLightIntHighThreshold(uint16_t threshold); 248 | 249 | /* Get and set proximity interrupt thresholds */ 250 | bool getProximityIntLowThreshold(uint8_t &threshold); 251 | bool setProximityIntLowThreshold(uint8_t threshold); 252 | bool getProximityIntHighThreshold(uint8_t &threshold); 253 | bool setProximityIntHighThreshold(uint8_t threshold); 254 | 255 | /* Get and set interrupt enables */ 256 | uint8_t getAmbientLightIntEnable(); 257 | bool setAmbientLightIntEnable(uint8_t enable); 258 | uint8_t getProximityIntEnable(); 259 | bool setProximityIntEnable(uint8_t enable); 260 | uint8_t getGestureIntEnable(); 261 | bool setGestureIntEnable(uint8_t enable); 262 | 263 | /* Clear interrupts */ 264 | bool clearAmbientLightInt(); 265 | bool clearProximityInt(); 266 | 267 | /* Ambient light methods */ 268 | bool readAmbientLight(uint16_t &val); 269 | bool readRedLight(uint16_t &val); 270 | bool readGreenLight(uint16_t &val); 271 | bool readBlueLight(uint16_t &val); 272 | 273 | /* Proximity methods */ 274 | bool readProximity(uint8_t &val); 275 | 276 | /* Gesture methods */ 277 | bool isGestureAvailable(); 278 | int readGesture(); 279 | 280 | private: 281 | 282 | /* Gesture processing */ 283 | void resetGestureParameters(); 284 | bool processGestureData(); 285 | bool decodeGesture(); 286 | 287 | /* Proximity Interrupt Threshold */ 288 | uint8_t getProxIntLowThresh(); 289 | bool setProxIntLowThresh(uint8_t threshold); 290 | uint8_t getProxIntHighThresh(); 291 | bool setProxIntHighThresh(uint8_t threshold); 292 | 293 | /* LED Boost Control */ 294 | uint8_t getLEDBoost(); 295 | bool setLEDBoost(uint8_t boost); 296 | 297 | /* Proximity photodiode select */ 298 | uint8_t getProxGainCompEnable(); 299 | bool setProxGainCompEnable(uint8_t enable); 300 | uint8_t getProxPhotoMask(); 301 | bool setProxPhotoMask(uint8_t mask); 302 | 303 | /* Gesture threshold control */ 304 | uint8_t getGestureEnterThresh(); 305 | bool setGestureEnterThresh(uint8_t threshold); 306 | uint8_t getGestureExitThresh(); 307 | bool setGestureExitThresh(uint8_t threshold); 308 | 309 | /* Gesture LED, gain, and time control */ 310 | uint8_t getGestureWaitTime(); 311 | bool setGestureWaitTime(uint8_t time); 312 | 313 | /* Gesture mode */ 314 | uint8_t getGestureMode(); 315 | bool setGestureMode(uint8_t mode); 316 | 317 | /* Raw I2C Commands */ 318 | bool wireWriteByte(uint8_t val); 319 | bool wireWriteDataByte(uint8_t reg, uint8_t val); 320 | bool wireWriteDataBlock(uint8_t reg, uint8_t *val, unsigned int len); 321 | bool wireReadDataByte(uint8_t reg, uint8_t &val); 322 | int wireReadDataBlock(uint8_t reg, uint8_t *val, unsigned int len); 323 | 324 | /* Members */ 325 | gesture_data_type gesture_data_; 326 | int gesture_ud_delta_; 327 | int gesture_lr_delta_; 328 | int gesture_ud_count_; 329 | int gesture_lr_count_; 330 | int gesture_near_count_; 331 | int gesture_far_count_; 332 | int gesture_state_; 333 | int gesture_motion_; 334 | int fd_; 335 | }; 336 | 337 | #endif 338 | -------------------------------------------------------------------------------- /APDS-9960/c++/Makefile: -------------------------------------------------------------------------------- 1 | CC=g++ 2 | CPPFLAGS=-Wall -I. 3 | DEPS = 4 | OBJC = APDS9960.o color.o 5 | OBJG = APDS9960.o gesture.o 6 | EXTRA_LIBS=-lwiringPi 7 | 8 | %.o: %.c $(DEPS) 9 | $(CC) -c -o $@ $< $(CPPFLAGS) 10 | 11 | all: color gesture 12 | 13 | color: $(OBJC) 14 | $(CC) -o $@ $^ $(CPPFLAGS) $(EXTRA_LIBS) 15 | 16 | gesture: $(OBJG) 17 | $(CC) -o $@ $^ $(CPPFLAGS) $(EXTRA_LIBS) 18 | 19 | .PHONY: clean 20 | 21 | clean: 22 | rm -f $(EXEC) $(OBJC) $(OBJ2) 23 | -------------------------------------------------------------------------------- /APDS-9960/c++/color.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "APDS9960.h" 3 | 4 | using namespace std; 5 | 6 | int main() 7 | { 8 | APDS9960 apds = APDS9960(); 9 | uint16_t ambient_light = 0; 10 | uint16_t red_light = 0; 11 | uint16_t green_light = 0; 12 | uint16_t blue_light = 0; 13 | 14 | cout << endl; 15 | cout << "------------------------------------" << endl; 16 | cout << "APDS-9960 - ColorSensor " << endl; 17 | cout << "------------------------------------" << endl; 18 | 19 | // Initialize APDS-9960 (configure I2C and initial values) 20 | if ( (false == apds.init()) || (false == apds.enableLightSensor(false)) ) 21 | { 22 | cout << "APDS-9960 init failed!" << endl; 23 | } 24 | 25 | 26 | // Wait for initialization and calibration to finish 27 | delay(500); 28 | 29 | while(1) { 30 | // Read the light levels (ambient, red, green, blue) 31 | if ( !apds.readAmbientLight(ambient_light) || 32 | !apds.readRedLight(red_light) || 33 | !apds.readGreenLight(green_light) || 34 | !apds.readBlueLight(blue_light) ) { 35 | cout << "Error reading light values" << endl; 36 | } 37 | else { 38 | cout << "Ambient: "; 39 | cout << int(ambient_light); 40 | cout << " Red: "; 41 | cout << int(red_light); 42 | cout << " Green: "; 43 | cout << int(green_light); 44 | cout << " Blue: "; 45 | cout << int(blue_light) << endl; 46 | } 47 | 48 | // Wait 1 second before next reading 49 | delay(1000); 50 | } 51 | return 0; 52 | } 53 | -------------------------------------------------------------------------------- /APDS-9960/c++/gesture.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "APDS9960.h" 3 | 4 | using namespace std; 5 | 6 | void handleGesture(APDS9960 apds); 7 | 8 | int main() 9 | { 10 | APDS9960 apds = APDS9960(); 11 | 12 | // init wiringPi 13 | wiringPiSetup(); 14 | 15 | // Initialize Serial port 16 | cout << endl; 17 | cout << "------------------------------------" << endl; 18 | cout << " SparkFun APDS-9960 - GestureTest " << endl; 19 | cout << "------------------------------------" << endl; 20 | 21 | // Initialize APDS-9960 (configure I2C and initial values) 22 | if ( (false == apds.init()) || (false == apds.enableGestureSensor(false)) ) 23 | { 24 | cout << "APDS-9960 init failed!" << endl; 25 | } 26 | 27 | while(1) 28 | { 29 | handleGesture(apds); 30 | } 31 | return 0; 32 | } 33 | 34 | void handleGesture(APDS9960 apds) 35 | { 36 | if ( false == apds.isGestureAvailable() ) 37 | { 38 | return; 39 | } 40 | 41 | switch ( apds.readGesture() ) 42 | { 43 | case DIR_UP: 44 | cout << "UP" << endl; 45 | break; 46 | case DIR_DOWN: 47 | cout << "DOWN" << endl; 48 | break; 49 | case DIR_LEFT: 50 | cout << "LEFT" << endl; 51 | break; 52 | case DIR_RIGHT: 53 | cout << "RIGHT" << endl; 54 | break; 55 | case DIR_NEAR: 56 | cout << "NEAR" << endl; 57 | break; 58 | case DIR_FAR: 59 | cout << "FAR" << endl; 60 | break; 61 | default: 62 | //Print empty line if gesture in not detected 63 | cout << endl; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /BH1750/c/.gitignore: -------------------------------------------------------------------------------- 1 | BH1750_test 2 | *.o 3 | -------------------------------------------------------------------------------- /BH1750/c/BH1750.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "BH1750.h" 3 | 4 | int getLux(int fd) 5 | { 6 | wiringPiI2CWrite(fd,0x10); 7 | delay(LUXDELAY); 8 | int word = wiringPiI2CReadReg16(fd, 0x00); 9 | int lux=((word & 0xff00)>>8) | ((word & 0x00ff)<<8); 10 | return lux; 11 | } 12 | -------------------------------------------------------------------------------- /BH1750/c/BH1750.h: -------------------------------------------------------------------------------- 1 | #ifndef _BH1750_H_ 2 | #define _BMP1750_H_ 3 | 4 | #define BH1750_ADDR 0x23 5 | 6 | //Delay getLux function 7 | #define LUXDELAY 500 8 | 9 | int getLux(int fd); 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /BH1750/c/BH1750_test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "BH1750.h" 3 | 4 | int main() 5 | { 6 | int fd = wiringPiI2CSetup(BH1750_ADDR) ; 7 | printf("Lux: %d \n", getLux(fd)); 8 | return 0 ; 9 | } 10 | -------------------------------------------------------------------------------- /BH1750/c/Makefile: -------------------------------------------------------------------------------- 1 | CC=gcc 2 | CFLAGS=-I. 3 | DEPS = 4 | OBJ = BH1750.o BH1750_test.o 5 | EXTRA_LIBS=-lwiringPi 6 | 7 | %.o: %.c $(DEPS) 8 | $(CC) -c -o $@ $< $(CFLAGS) 9 | 10 | BH1750_test: $(OBJ) 11 | $(CC) -o $@ $^ $(CFLAGS) $(EXTRA_LIBS) 12 | 13 | .PHONY: clean 14 | 15 | clean: 16 | rm -f BH1750 $(OBJ) 17 | -------------------------------------------------------------------------------- /BMP180/c/.gitignore: -------------------------------------------------------------------------------- 1 | BMP180_test 2 | *.o 3 | -------------------------------------------------------------------------------- /BMP180/c/BMP180.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "BMP180.h" 9 | #include "smbus.h" 10 | 11 | const unsigned char BMP085_OVERSAMPLING_SETTING = 3; 12 | 13 | // Open a connection to the bmp085 14 | // Returns a file id 15 | int begin() 16 | { 17 | int fd = 0; 18 | char *fileName = "/dev/i2c-1"; 19 | 20 | // Open port for reading and writing 21 | if ((fd = open(fileName, O_RDWR)) < 0) 22 | { 23 | exit(1); 24 | } 25 | 26 | // Set the port options and set the address of the device 27 | if (ioctl(fd, I2C_SLAVE, BMP180_I2C_ADDRESS) < 0) 28 | { 29 | close(fd); 30 | exit(1); 31 | } 32 | 33 | return fd; 34 | } 35 | 36 | // Read two words from the BMP085 and supply it as a 16 bit integer 37 | __s32 i2cReadInt(int fd, __u8 address) 38 | { 39 | __s32 res = i2c_smbus_read_word_data(fd, address); 40 | if (0 > res) 41 | { 42 | close(fd); 43 | exit(1); 44 | } 45 | 46 | // Convert result to 16 bits and swap bytes 47 | res = ((res<<8) & 0xFF00) | ((res>>8) & 0xFF); 48 | 49 | return res; 50 | } 51 | 52 | //Write a byte to the BMP085 53 | void i2cWriteByteData(int fd, __u8 address, __u8 value) 54 | { 55 | if (0 > i2c_smbus_write_byte_data(fd, address, value)) 56 | { 57 | close(fd); 58 | exit(1); 59 | } 60 | } 61 | 62 | // Read a block of data BMP085 63 | void i2cReadBlockData(int fd, __u8 address, __u8 length, __u8 *values) 64 | { 65 | if (0 > i2c_smbus_read_i2c_block_data(fd, address,length,values)) 66 | { 67 | close(fd); 68 | exit(1); 69 | } 70 | } 71 | 72 | 73 | void calibration() 74 | { 75 | int fd = begin(); 76 | cal.ac1 = i2cReadInt(fd,0xAA); 77 | cal.ac2 = i2cReadInt(fd,0xAC); 78 | cal.ac3 = i2cReadInt(fd,0xAE); 79 | cal.ac4 = i2cReadInt(fd,0xB0); 80 | cal.ac5 = i2cReadInt(fd,0xB2); 81 | cal.ac6 = i2cReadInt(fd,0xB4); 82 | cal.b1 = i2cReadInt(fd,0xB6); 83 | cal.b2 = i2cReadInt(fd,0xB8); 84 | cal.mb = i2cReadInt(fd,0xBA); 85 | cal.mc = i2cReadInt(fd,0xBC); 86 | cal.md = i2cReadInt(fd,0xBE); 87 | close(fd); 88 | } 89 | 90 | // Read the uncompensated temperature value 91 | unsigned int readRawTemperature() 92 | { 93 | int fd = begin(); 94 | 95 | // Write 0x2E into Register 0xF4 96 | // This requests a temperature reading 97 | i2cWriteByteData(fd,0xF4,0x2E); 98 | 99 | // Wait at least 4.5ms 100 | usleep(5000); 101 | 102 | // Read the two byte result from address 0xF6 103 | unsigned int ut = i2cReadInt(fd,0xF6); 104 | 105 | // Close the i2c file 106 | close (fd); 107 | 108 | return ut; 109 | } 110 | 111 | // Read the uncompensated pressure value 112 | unsigned int readRawPressure() 113 | { 114 | int fd = begin(); 115 | 116 | // Write 0x34+(BMP085_OVERSAMPLING_SETTING<<6) into register 0xF4 117 | // Request a pressure reading w/ oversampling setting 118 | i2cWriteByteData(fd,0xF4,0x34 + (BMP085_OVERSAMPLING_SETTING<<6)); 119 | 120 | // Wait for conversion, delay time dependent on oversampling setting 121 | usleep((2 + (3<> (8-BMP085_OVERSAMPLING_SETTING); 129 | 130 | // Close the i2c file 131 | close (fd); 132 | 133 | return up; 134 | } 135 | 136 | int compensateTemperature() 137 | { 138 | unsigned int ut = readRawTemperature(); 139 | int x1 = (((int)ut - (int)cal.ac6)*(int)cal.ac5) >> 15; 140 | int x2 = ((int)cal.mc << 11)/(x1 + cal.md); 141 | return x1 + x2; 142 | } 143 | 144 | // Calculate pressure given uncalibrated pressure 145 | // Value returned will be in units of Pa 146 | int getPressure() 147 | { 148 | unsigned int up = readRawPressure(); 149 | 150 | int b6 = compensateTemperature() - 4000; 151 | // Calculate B3 152 | int x1 = (cal.b2 * (b6 * b6)>>12)>>11; 153 | int x2 = (cal.ac2 * b6)>>11; 154 | int x3 = x1 + x2; 155 | int b3 = (((((int) cal.ac1)*4 + x3)<>2; 156 | 157 | // Calculate B4 158 | x1 = (cal.ac3 * b6)>>13; 159 | x2 = (cal.b1 * ((b6 * b6)>>12))>>16; 160 | x3 = ((x1 + x2) + 2)>>2; 161 | unsigned int b4 = (cal.ac4 * (unsigned int)(x3 + 32768))>>15; 162 | 163 | unsigned int b7 = ((unsigned int)(up - b3) * (50000>>BMP085_OVERSAMPLING_SETTING)); 164 | int p = (b7 < 0x80000000) ? (b7<<1)/b4 : (b7/b4)<<1; 165 | x1 = (p>>8) * (p>>8); 166 | x1 = (x1 * 3038)>>16; 167 | x2 = (-7357 * p)>>16; 168 | p += (x1 + x2 + 3791)>>4; 169 | 170 | return p; 171 | } 172 | 173 | // Calculate temperature given uncalibrated temperature 174 | double getTemperature() 175 | { 176 | // Retrieve temperature in units of 0.1 deg C 177 | int rawTemperature = ((compensateTemperature() + 8)>>4); 178 | return ((double)rawTemperature)/10; 179 | } 180 | 181 | double getAltitude() 182 | { 183 | double pressure = getPressure(); 184 | // Sea level pressure: 101325.0 185 | return 44330.0 * (1.0 - pow(pressure / 101325.0, (1.0/5.255))); 186 | } 187 | -------------------------------------------------------------------------------- /BMP180/c/BMP180.h: -------------------------------------------------------------------------------- 1 | /* 2 | Raspberry Pi Bosch BMP0180/BMP085 communication code. 3 | 4 | This is a derivative work based on: 5 | John Burns (www.john.geek.nz) 6 | Source: https://www.john.geek.nz/2013/02/update-bosch-bmp085-source-raspberry-pi/ 7 | BMP085 Extended Example Code 8 | by: Jim Lindblom 9 | SparkFun Electronics 10 | date: 1/18/11 11 | license: CC BY-SA v3.0 - http://creativecommons.org/licenses/by-sa/3.0/ 12 | Source: http://www.sparkfun.com/tutorial/Barometric/BMP085_Example_Code.pde 13 | 14 | Circuit detail: 15 | Using BMP180 Board Module 16 | 17 | VIN - 3.3V (Raspberry Pi pin 1) 18 | GND - GND (Raspberry Pi pin 14) 19 | SCL - SCL (Raspberry Pi pin 5) 20 | SDA - SDA (Raspberry Pi pin 3) 21 | 22 | Note: Make sure BMP180/085 is connected to 3.3V NOT the 5V pin! 23 | 24 | Note: Change /dev/i2c-1 to /dev/i2c-0 if you are using the very first Raspberry Pi. 25 | */ 26 | 27 | #ifndef _BMP180_H_ 28 | #define _BMP180_H_ 29 | 30 | #define BMP180_I2C_ADDRESS 0x77 31 | 32 | // Set default calibration values from values in the datasheet example 33 | // After that exact values will be read from BMP180/BMP085 sensor 34 | 35 | struct calibrate { 36 | short int ac1; 37 | short int ac2; 38 | short int ac3; 39 | unsigned short int ac4; 40 | unsigned short int ac5; 41 | unsigned short int ac6; 42 | short int b1; 43 | short int b2; 44 | short int mb; 45 | short int mc; 46 | short int md; 47 | } cal; 48 | 49 | // Calibrate BMP180/BMP085 50 | void calibration(); 51 | 52 | // Calculate pressure in Pa 53 | int getPressure(); 54 | 55 | // Calculate temperature in Celsius 56 | double getTemperature(); 57 | 58 | // Calculate 59 | double getAltitude(); 60 | 61 | #endif 62 | -------------------------------------------------------------------------------- /BMP180/c/BMP180_test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "BMP180.h" 4 | 5 | int main(int argc, char **argv) 6 | { 7 | calibration(); 8 | 9 | printf("Temperature\t%0.1f C\n", getTemperature()); 10 | printf("Pressure\t%0.2f hPa\n", (double)getPressure()/100); 11 | printf("Altitude\t%0.2f m\n", getAltitude()); 12 | 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /BMP180/c/Makefile: -------------------------------------------------------------------------------- 1 | CC=gcc 2 | CFLAGS=-I. 3 | DEPS = 4 | OBJ = smbus.o BMP180.o BMP180_test.o 5 | EXTRA_LIBS=-lm 6 | 7 | %.o: %.c $(DEPS) 8 | $(CC) -c -o $@ $< $(CFLAGS) 9 | 10 | BMP180_test: $(OBJ) 11 | $(CC) -o $@ $^ $(CFLAGS) $(EXTRA_LIBS) 12 | 13 | .PHONY: clean 14 | 15 | clean: 16 | rm -f BMP180_test $(OBJ) 17 | -------------------------------------------------------------------------------- /BMP180/c/smbus.c: -------------------------------------------------------------------------------- 1 | /* 2 | smbus.c - SMBus level access helper functions 3 | 4 | Copyright (C) 1995-97 Simon G. Vogl 5 | Copyright (C) 1998-99 Frodo Looijaard 6 | Copyright (C) 2012 Jean Delvare 7 | 8 | This program is free software; you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation; either version 2 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program; if not, write to the Free Software 20 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 21 | MA 02110-1301 USA. 22 | */ 23 | 24 | #include 25 | #include "smbus.h" // NB: Path changed! 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | //NB: Added by John Burns 32 | #ifndef NULL 33 | #define NULL 0 34 | #endif 35 | 36 | /* Compatibility defines */ 37 | #ifndef I2C_SMBUS_I2C_BLOCK_BROKEN 38 | #define I2C_SMBUS_I2C_BLOCK_BROKEN I2C_SMBUS_I2C_BLOCK_DATA 39 | #endif 40 | #ifndef I2C_FUNC_SMBUS_PEC 41 | #define I2C_FUNC_SMBUS_PEC I2C_FUNC_SMBUS_HWPEC_CALC 42 | #endif 43 | 44 | __s32 i2c_smbus_access(int file, char read_write, __u8 command, 45 | int size, union i2c_smbus_data *data) 46 | { 47 | struct i2c_smbus_ioctl_data args; 48 | __s32 err; 49 | 50 | args.read_write = read_write; 51 | args.command = command; 52 | args.size = size; 53 | args.data = data; 54 | 55 | err = ioctl(file, I2C_SMBUS, &args); 56 | if (err == -1) 57 | err = -errno; 58 | return err; 59 | } 60 | 61 | 62 | __s32 i2c_smbus_write_quick(int file, __u8 value) 63 | { 64 | return i2c_smbus_access(file, value, 0, I2C_SMBUS_QUICK, NULL); 65 | } 66 | 67 | __s32 i2c_smbus_read_byte(int file) 68 | { 69 | union i2c_smbus_data data; 70 | int err; 71 | 72 | err = i2c_smbus_access(file, I2C_SMBUS_READ, 0, I2C_SMBUS_BYTE, &data); 73 | if (err < 0) 74 | return err; 75 | 76 | return 0x0FF & data.byte; 77 | } 78 | 79 | __s32 i2c_smbus_write_byte(int file, __u8 value) 80 | { 81 | return i2c_smbus_access(file, I2C_SMBUS_WRITE, value, 82 | I2C_SMBUS_BYTE, NULL); 83 | } 84 | 85 | __s32 i2c_smbus_read_byte_data(int file, __u8 command) 86 | { 87 | union i2c_smbus_data data; 88 | int err; 89 | 90 | err = i2c_smbus_access(file, I2C_SMBUS_READ, command, 91 | I2C_SMBUS_BYTE_DATA, &data); 92 | if (err < 0) 93 | return err; 94 | 95 | return 0x0FF & data.byte; 96 | } 97 | 98 | __s32 i2c_smbus_write_byte_data(int file, __u8 command, __u8 value) 99 | { 100 | union i2c_smbus_data data; 101 | data.byte = value; 102 | return i2c_smbus_access(file, I2C_SMBUS_WRITE, command, 103 | I2C_SMBUS_BYTE_DATA, &data); 104 | } 105 | 106 | __s32 i2c_smbus_read_word_data(int file, __u8 command) 107 | { 108 | union i2c_smbus_data data; 109 | int err; 110 | 111 | err = i2c_smbus_access(file, I2C_SMBUS_READ, command, 112 | I2C_SMBUS_WORD_DATA, &data); 113 | if (err < 0) 114 | return err; 115 | 116 | return 0x0FFFF & data.word; 117 | } 118 | 119 | __s32 i2c_smbus_write_word_data(int file, __u8 command, __u16 value) 120 | { 121 | union i2c_smbus_data data; 122 | data.word = value; 123 | return i2c_smbus_access(file, I2C_SMBUS_WRITE, command, 124 | I2C_SMBUS_WORD_DATA, &data); 125 | } 126 | 127 | __s32 i2c_smbus_process_call(int file, __u8 command, __u16 value) 128 | { 129 | union i2c_smbus_data data; 130 | data.word = value; 131 | if (i2c_smbus_access(file, I2C_SMBUS_WRITE, command, 132 | I2C_SMBUS_PROC_CALL, &data)) 133 | return -1; 134 | else 135 | return 0x0FFFF & data.word; 136 | } 137 | 138 | /* Returns the number of read bytes */ 139 | __s32 i2c_smbus_read_block_data(int file, __u8 command, __u8 *values) 140 | { 141 | union i2c_smbus_data data; 142 | int i, err; 143 | 144 | err = i2c_smbus_access(file, I2C_SMBUS_READ, command, 145 | I2C_SMBUS_BLOCK_DATA, &data); 146 | if (err < 0) 147 | return err; 148 | 149 | for (i = 1; i <= data.block[0]; i++) 150 | values[i-1] = data.block[i]; 151 | return data.block[0]; 152 | } 153 | 154 | __s32 i2c_smbus_write_block_data(int file, __u8 command, __u8 length, 155 | const __u8 *values) 156 | { 157 | union i2c_smbus_data data; 158 | int i; 159 | if (length > I2C_SMBUS_BLOCK_MAX) 160 | length = I2C_SMBUS_BLOCK_MAX; 161 | for (i = 1; i <= length; i++) 162 | data.block[i] = values[i-1]; 163 | data.block[0] = length; 164 | return i2c_smbus_access(file, I2C_SMBUS_WRITE, command, 165 | I2C_SMBUS_BLOCK_DATA, &data); 166 | } 167 | 168 | /* Returns the number of read bytes */ 169 | /* Until kernel 2.6.22, the length is hardcoded to 32 bytes. If you 170 | ask for less than 32 bytes, your code will only work with kernels 171 | 2.6.23 and later. */ 172 | __s32 i2c_smbus_read_i2c_block_data(int file, __u8 command, __u8 length, 173 | __u8 *values) 174 | { 175 | union i2c_smbus_data data; 176 | int i, err; 177 | 178 | if (length > I2C_SMBUS_BLOCK_MAX) 179 | length = I2C_SMBUS_BLOCK_MAX; 180 | data.block[0] = length; 181 | 182 | err = i2c_smbus_access(file, I2C_SMBUS_READ, command, 183 | length == 32 ? I2C_SMBUS_I2C_BLOCK_BROKEN : 184 | I2C_SMBUS_I2C_BLOCK_DATA, &data); 185 | if (err < 0) 186 | return err; 187 | 188 | for (i = 1; i <= data.block[0]; i++) 189 | values[i-1] = data.block[i]; 190 | return data.block[0]; 191 | } 192 | 193 | __s32 i2c_smbus_write_i2c_block_data(int file, __u8 command, __u8 length, 194 | const __u8 *values) 195 | { 196 | union i2c_smbus_data data; 197 | int i; 198 | if (length > I2C_SMBUS_BLOCK_MAX) 199 | length = I2C_SMBUS_BLOCK_MAX; 200 | for (i = 1; i <= length; i++) 201 | data.block[i] = values[i-1]; 202 | data.block[0] = length; 203 | return i2c_smbus_access(file, I2C_SMBUS_WRITE, command, 204 | I2C_SMBUS_I2C_BLOCK_BROKEN, &data); 205 | } 206 | 207 | /* Returns the number of read bytes */ 208 | __s32 i2c_smbus_block_process_call(int file, __u8 command, __u8 length, 209 | __u8 *values) 210 | { 211 | union i2c_smbus_data data; 212 | int i, err; 213 | 214 | if (length > I2C_SMBUS_BLOCK_MAX) 215 | length = I2C_SMBUS_BLOCK_MAX; 216 | for (i = 1; i <= length; i++) 217 | data.block[i] = values[i-1]; 218 | data.block[0] = length; 219 | 220 | err = i2c_smbus_access(file, I2C_SMBUS_WRITE, command, 221 | I2C_SMBUS_BLOCK_PROC_CALL, &data); 222 | if (err < 0) 223 | return err; 224 | 225 | for (i = 1; i <= data.block[0]; i++) 226 | values[i-1] = data.block[i]; 227 | return data.block[0]; 228 | } 229 | -------------------------------------------------------------------------------- /BMP180/c/smbus.h: -------------------------------------------------------------------------------- 1 | /* 2 | smbus.h - SMBus level access helper functions 3 | 4 | Copyright (C) 1995-97 Simon G. Vogl 5 | Copyright (C) 1998-99 Frodo Looijaard 6 | 7 | This program is free software; you can redistribute it and/or modify 8 | it under the terms of the GNU General Public License as published by 9 | the Free Software Foundation; either version 2 of the License, or 10 | (at your option) any later version. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with this program; if not, write to the Free Software 19 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 20 | MA 02110-1301 USA. 21 | */ 22 | 23 | #ifndef LIB_I2C_SMBUS_H 24 | #define LIB_I2C_SMBUS_H 25 | 26 | #include 27 | #include 28 | 29 | extern __s32 i2c_smbus_access(int file, char read_write, __u8 command, 30 | int size, union i2c_smbus_data *data); 31 | 32 | extern __s32 i2c_smbus_write_quick(int file, __u8 value); 33 | extern __s32 i2c_smbus_read_byte(int file); 34 | extern __s32 i2c_smbus_write_byte(int file, __u8 value); 35 | extern __s32 i2c_smbus_read_byte_data(int file, __u8 command); 36 | extern __s32 i2c_smbus_write_byte_data(int file, __u8 command, __u8 value); 37 | extern __s32 i2c_smbus_read_word_data(int file, __u8 command); 38 | extern __s32 i2c_smbus_write_word_data(int file, __u8 command, __u16 value); 39 | extern __s32 i2c_smbus_process_call(int file, __u8 command, __u16 value); 40 | 41 | /* Returns the number of read bytes */ 42 | extern __s32 i2c_smbus_read_block_data(int file, __u8 command, __u8 *values); 43 | extern __s32 i2c_smbus_write_block_data(int file, __u8 command, __u8 length, 44 | const __u8 *values); 45 | 46 | /* Returns the number of read bytes */ 47 | /* Until kernel 2.6.22, the length is hardcoded to 32 bytes. If you 48 | ask for less than 32 bytes, your code will only work with kernels 49 | 2.6.23 and later. */ 50 | extern __s32 i2c_smbus_read_i2c_block_data(int file, __u8 command, __u8 length, 51 | __u8 *values); 52 | extern __s32 i2c_smbus_write_i2c_block_data(int file, __u8 command, __u8 length, 53 | const __u8 *values); 54 | 55 | /* Returns the number of read bytes */ 56 | extern __s32 i2c_smbus_block_process_call(int file, __u8 command, __u8 length, 57 | __u8 *values); 58 | 59 | #endif /* LIB_I2C_SMBUS_H */ 60 | -------------------------------------------------------------------------------- /BMP280/c/.gitignore: -------------------------------------------------------------------------------- 1 | BMP280 2 | *.o 3 | -------------------------------------------------------------------------------- /BMP280/c/BMP280.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "wiringPi.h" 9 | #include "wiringPiI2C.h" 10 | 11 | #define SWAP_2BYTES(x) (((x & 0xFFFF) >> 8) | ((x & 0xFF) << 8)) 12 | 13 | /* BMP280 default address */ 14 | #define BMP280_I2CADDR 0x76 15 | #define BMP280_CHIPID 0xD0 16 | 17 | /* BMP280 Registers */ 18 | 19 | #define BMP280_DIG_T1 0x88 /* R Unsigned Calibration data (16 bits) */ 20 | #define BMP280_DIG_T2 0x8A /* R Signed Calibration data (16 bits) */ 21 | #define BMP280_DIG_T3 0x8C /* R Signed Calibration data (16 bits) */ 22 | #define BMP280_DIG_P1 0x8E /* R Unsigned Calibration data (16 bits) */ 23 | #define BMP280_DIG_P2 0x90 /* R Signed Calibration data (16 bits) */ 24 | #define BMP280_DIG_P3 0x92 /* R Signed Calibration data (16 bits) */ 25 | #define BMP280_DIG_P4 0x94 /* R Signed Calibration data (16 bits) */ 26 | #define BMP280_DIG_P5 0x96 /* R Signed Calibration data (16 bits) */ 27 | #define BMP280_DIG_P6 0x98 /* R Signed Calibration data (16 bits) */ 28 | #define BMP280_DIG_P7 0x9A /* R Signed Calibration data (16 bits) */ 29 | #define BMP280_DIG_P8 0x9C /* R Signed Calibration data (16 bits) */ 30 | #define BMP280_DIG_P9 0x9E /* R Signed Calibration data (16 bits) */ 31 | 32 | #define BMP280_CONTROL 0xF4 33 | #define BMP280_RESET 0xE0 34 | #define BMP280_CONFIG 0xF5 35 | #define BMP280_PRESSUREDATA 0xF7 36 | #define BMP280_TEMPDATA 0xFA 37 | 38 | unsigned short int cal_t1 = 27504; 39 | short int cal_t2 = 26435; 40 | short int cal_t3 = -1000; 41 | unsigned short int cal_p1 = 36477; 42 | short int cal_p2 = -10685; 43 | short int cal_p3 = 3024; 44 | short int cal_p4 = 2855; 45 | short int cal_p5 = 140; 46 | short int cal_p6 = -7; 47 | short int cal_p7 = 15500; 48 | short int cal_p8 = -14500; 49 | short int cal_p9 = 6000; 50 | 51 | void load_calibration(int fd) 52 | { 53 | cal_t1 = wiringPiI2CReadReg16(fd, BMP280_DIG_T1); 54 | cal_t2 = wiringPiI2CReadReg16(fd, BMP280_DIG_T2); 55 | // TO DO: double check the value for t3 56 | //cal_t3 = wiringPiI2CReadReg16(fd, BMP280_DIG_T3); 57 | cal_p1 = wiringPiI2CReadReg16(fd, BMP280_DIG_P1); 58 | cal_p2 = wiringPiI2CReadReg16(fd, BMP280_DIG_P2); 59 | cal_p3 = wiringPiI2CReadReg16(fd, BMP280_DIG_P3); 60 | cal_p4 = wiringPiI2CReadReg16(fd, BMP280_DIG_P4); 61 | cal_p5 = wiringPiI2CReadReg16(fd, BMP280_DIG_P5); 62 | cal_p6 = wiringPiI2CReadReg16(fd, BMP280_DIG_P6); 63 | cal_p7 = wiringPiI2CReadReg16(fd, BMP280_DIG_P7); 64 | cal_p8 = wiringPiI2CReadReg16(fd, BMP280_DIG_P8); 65 | cal_p9 = wiringPiI2CReadReg16(fd, BMP280_DIG_P9); 66 | } 67 | 68 | int read_raw(int fd, int reg) 69 | { 70 | int raw = SWAP_2BYTES(wiringPiI2CReadReg16(fd, reg)); 71 | raw <<= 8; 72 | raw = raw | wiringPiI2CReadReg8(fd, reg + 2); 73 | raw >>= 4; 74 | return raw; 75 | } 76 | 77 | int32_t compensate_temp(int raw_temp) 78 | { 79 | int t1 = (((raw_temp >> 3) - (cal_t1 << 1)) * (cal_t2)) >> 11; 80 | int t2 = (((((raw_temp >> 4) - (cal_t1)) * 81 | ((raw_temp >> 4) - (cal_t1))) >> 12) * 82 | (cal_t3)) >> 14; 83 | return t1 + t2; 84 | } 85 | 86 | float read_temperature(int fd) 87 | { 88 | int raw_temp = read_raw(fd, BMP280_TEMPDATA); 89 | int compensated_temp = compensate_temp(raw_temp); 90 | return (float)((compensated_temp * 5 + 128) >> 8) / 100; 91 | } 92 | 93 | double read_pressure(int fd) 94 | { 95 | int raw_temp = read_raw(fd, BMP280_TEMPDATA); 96 | int32_t compensated_temp = compensate_temp(raw_temp); 97 | int raw_pressure = read_raw(fd, BMP280_PRESSUREDATA); 98 | 99 | int64_t p1 = compensated_temp/2 - 64000; 100 | int64_t p2 = p1 * p1 * (int64_t)cal_p6/32768; 101 | int64_t buf = (p1 * (int64_t)cal_p5*2); 102 | p2 += buf << 17; 103 | p2 += (int64_t)cal_p4 << 35; 104 | p1 = ((p1 * p1 * cal_p3) >> 8) + ((p1 * cal_p2) << 12); 105 | p1 = (((int64_t)1 << 47) + p1) * ((int64_t)cal_p1) >> 33; 106 | 107 | // Avoid exception caused by division by zero 108 | if (0 == p1) 109 | { 110 | return 0; 111 | } 112 | 113 | int64_t p = 1048576 - raw_pressure; 114 | p = (((p << 31) - p2) * 3125) / p1; 115 | p1 = ((int64_t)cal_p9 * (p >> 13) * (p >> 13)) >> 25; 116 | p2 = ((int64_t)cal_p8 * p) >> 19; 117 | p = ((p + p1 + p2) >> 8) + (((int64_t)cal_p7) << 4); 118 | 119 | return (double)(p / 256); 120 | } 121 | 122 | int main (void) 123 | { 124 | int fd = 0; 125 | wiringPiSetup(); 126 | 127 | if ((fd = wiringPiI2CSetup(BMP280_I2CADDR)) < 0) 128 | { 129 | fprintf(stderr, "Unable to open I2C device: %s\n", strerror (errno)); 130 | exit (-1); 131 | } 132 | 133 | if (0x58 != wiringPiI2CReadReg8(fd, BMP280_CHIPID)) 134 | { 135 | fprintf(stderr, "Unsupported chip\n"); 136 | exit (-2); 137 | } 138 | 139 | load_calibration(fd); 140 | wiringPiI2CWriteReg8(fd, BMP280_CONTROL, 0x3F); 141 | 142 | printf("%5.2f C\n", read_temperature(fd)); 143 | printf("%5.2f hPa\n", read_pressure(fd)/100); 144 | 145 | return 0; 146 | } 147 | -------------------------------------------------------------------------------- /BMP280/c/Makefile: -------------------------------------------------------------------------------- 1 | CC=gcc 2 | CFLAGS=-I. 3 | DEPS = 4 | OBJ = BMP280.o 5 | EXTRA_LIBS=-lwiringPi 6 | 7 | %.o: %.c $(DEPS) 8 | $(CC) -c -o $@ $< $(CFLAGS) 9 | 10 | BMP280: $(OBJ) 11 | $(CC) -o $@ $^ $(CFLAGS) $(EXTRA_LIBS) 12 | 13 | .PHONY: clean 14 | 15 | clean: 16 | rm -f BMP280 $(OBJ) 17 | -------------------------------------------------------------------------------- /BMP280/python/BMP280_test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # Depends on Adafruit Python BMP from Bastien Wirtz: 3 | # https://github.com/bastienwirtz/Adafruit_Python_BMP 4 | 5 | import Adafruit_BMP.BMP280 as BMP280 6 | 7 | sensor = BMP280.BMP280() 8 | 9 | print 'Temperature: {0:0.2f} *C'.format(sensor.read_temperature()) 10 | print 'Barometric Pressure: {0:0.2f} Pa'.format(sensor.read_pressure()) 11 | print 'Altitude: {0:0.2f} m'.format(sensor.read_altitude()) 12 | print 'Sealevel Pressure: {0:0.2f} Pa'.format(sensor.read_sealevel_pressure()) 13 | -------------------------------------------------------------------------------- /DC-motor-SN754410/c/.gitignore: -------------------------------------------------------------------------------- 1 | sn754410 2 | *.o 3 | -------------------------------------------------------------------------------- /DC-motor-SN754410/c/Makefile: -------------------------------------------------------------------------------- 1 | CC=gcc 2 | CFLAGS=-I. 3 | DEPS = 4 | OBJ = sn754410.o 5 | EXTRA_LIBS=-lwiringPi -lpthread 6 | 7 | %.o: %.c $(DEPS) 8 | $(CC) -c -o $@ $< $(CFLAGS) 9 | 10 | sn754410: $(OBJ) 11 | $(CC) -o $@ $^ $(CFLAGS) $(EXTRA_LIBS) 12 | 13 | .PHONY: clean 14 | 15 | clean: 16 | rm -f sn754410 $(OBJ) 17 | -------------------------------------------------------------------------------- /DC-motor-SN754410/c/sn754410.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | const int speedMax = 200; 10 | 11 | // Motor 1 1st: GPIO 12, aka pin 15 12 | const int motorPin1 = 3; 13 | // Motor 1 2nd: GPIO 23, aka pin 16 14 | const int motorPin2 = 4; 15 | 16 | void motor1(int pin1, int pin2) 17 | { 18 | digitalWrite(motorPin1, pin1); 19 | digitalWrite(motorPin2, pin2); 20 | } 21 | 22 | void brake() 23 | { 24 | softPwmWrite(motorPin1, 0); 25 | motor1(LOW, LOW); 26 | } 27 | 28 | void enablePWM(pin, speed) 29 | { 30 | if (0 != softPwmCreate(pin, 0, speed)) 31 | { 32 | printf("ERROR: Cannot enable software PWM for pin %d", pin); 33 | } 34 | } 35 | 36 | int init() 37 | { 38 | if (-1 == wiringPiSetup()) 39 | { 40 | printf("setup wiringPi failed!\n"); 41 | return 1; 42 | } 43 | 44 | signal(SIGINT, brake); 45 | 46 | // Set pin mode 47 | pinMode(motorPin1, OUTPUT); 48 | pinMode(motorPin2, OUTPUT); 49 | 50 | //Software PWM 51 | enablePWM(motorPin1, speedMax); 52 | enablePWM(motorPin2, speedMax); 53 | 54 | brake(); 55 | return 0; 56 | } 57 | 58 | void forward() 59 | { 60 | softPwmWrite(motorPin1, 90); 61 | 62 | motor1(HIGH, LOW); 63 | } 64 | 65 | void back(int speed) 66 | { 67 | softPwmWrite(motorPin2, speed); 68 | 69 | motor1(LOW, HIGH); 70 | } 71 | 72 | int main(int argc, char **argv) 73 | { 74 | char *direction = "forward"; 75 | opterr = 0; 76 | int argument = 0; 77 | int speed = 80; 78 | while ((argument = getopt (argc, argv, "d:s:")) != -1) 79 | { 80 | switch (argument) 81 | { 82 | case 'd': 83 | direction = optarg; 84 | break; 85 | 86 | case 's': 87 | speed = atoi(optarg); 88 | break; 89 | 90 | case '?': 91 | if (optopt == 'd') 92 | { 93 | fprintf (stderr, "Option -%c requires an argument: forward, back, stop, left or right.\n", optopt); 94 | } 95 | else if (isprint (optopt)) 96 | { 97 | fprintf (stderr, "Unknown option `-%c'.\n", optopt); 98 | } 99 | else 100 | { 101 | fprintf (stderr, 102 | "Unknown option character `\\x%x'.\n", 103 | optopt); 104 | } 105 | return 1; 106 | 107 | default: 108 | abort(); 109 | } 110 | } 111 | 112 | printf("Direction: %s Speed: %d\n", direction, speed); 113 | 114 | if (0 < init()) 115 | { 116 | return 1; 117 | } 118 | 119 | if (0 == strcmp(direction, "forward")) 120 | { 121 | printf("Moving forward...\n"); 122 | forward(speed); 123 | } 124 | else if (0 == strcmp(direction, "back")) 125 | { 126 | printf("Moving backward...\n"); 127 | back(speed); 128 | } 129 | else 130 | { 131 | printf("Unknown direction. Stopping...\n"); 132 | brake(); 133 | return 3; 134 | } 135 | sleep(5); 136 | brake(); 137 | return 0; 138 | } 139 | -------------------------------------------------------------------------------- /HC-SR04/python/distance.py: -------------------------------------------------------------------------------- 1 | import RPi.GPIO as GPIO 2 | import time 3 | import signal 4 | import sys 5 | 6 | # use Raspberry Pi board pin numbers 7 | GPIO.setmode(GPIO.BCM) 8 | 9 | # set GPIO Pins 10 | pinTrigger = 18 11 | pinEcho = 24 12 | 13 | def close(signal, frame): 14 | print("\nTurning off ultrasonic distance detection...\n") 15 | GPIO.cleanup() 16 | sys.exit(0) 17 | 18 | signal.signal(signal.SIGINT, close) 19 | 20 | # set GPIO input and output channels 21 | GPIO.setup(pinTrigger, GPIO.OUT) 22 | GPIO.setup(pinEcho, GPIO.IN) 23 | 24 | while True: 25 | # set Trigger to HIGH 26 | GPIO.output(pinTrigger, True) 27 | # set Trigger after 0.01ms to LOW 28 | time.sleep(0.00001) 29 | GPIO.output(pinTrigger, False) 30 | 31 | startTime = time.time() 32 | stopTime = time.time() 33 | 34 | # save start time 35 | while 0 == GPIO.input(pinEcho): 36 | startTime = time.time() 37 | 38 | # save time of arrival 39 | while 1 == GPIO.input(pinEcho): 40 | stopTime = time.time() 41 | 42 | # time difference between start and arrival 43 | TimeElapsed = stopTime - startTime 44 | # multiply with the sonic speed (34300 cm/s) 45 | # and divide by 2, because there and back 46 | distance = (TimeElapsed * 34300) / 2 47 | 48 | print ("Distance: %.1f cm" % distance) 49 | time.sleep(1) 50 | -------------------------------------------------------------------------------- /HTU21D/c/.gitignore: -------------------------------------------------------------------------------- 1 | HTU21D_test 2 | *.o 3 | -------------------------------------------------------------------------------- /HTU21D/c/HTU21D.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "wiringPi.h" 4 | #include "wiringPiI2C.h" 5 | 6 | #include "HTU21D.h" 7 | 8 | // Get temperature 9 | double getTemperature(int fd) 10 | { 11 | unsigned char buf [4]; 12 | wiringPiI2CWrite(fd, HTU21D_TEMP); 13 | delay(100); 14 | read(fd, buf, 3); 15 | unsigned int temp = (buf [0] << 8 | buf [1]) & 0xFFFC; 16 | // Convert sensor reading into temperature. 17 | // See page 14 of the datasheet 18 | double tSensorTemp = temp / 65536.0; 19 | return -46.85 + (175.72 * tSensorTemp); 20 | } 21 | 22 | // Get humidity 23 | double getHumidity(int fd) 24 | { 25 | unsigned char buf [4]; 26 | wiringPiI2CWrite(fd, HTU21D_HUMID); 27 | delay(100); 28 | read(fd, buf, 3); 29 | unsigned int humid = (buf [0] << 8 | buf [1]) & 0xFFFC; 30 | // Convert sensor reading into humidity. 31 | // See page 15 of the datasheet 32 | double tSensorHumid = humid / 65536.0; 33 | return -6.0 + (125.0 * tSensorHumid); 34 | } 35 | -------------------------------------------------------------------------------- /HTU21D/c/HTU21D.h: -------------------------------------------------------------------------------- 1 | #ifndef _HTU21D_H_ 2 | #define _HTU21D_H_ 3 | 4 | #define HTU21D_I2C_ADDR 0x40 5 | 6 | #define HTU21D_TEMP 0xF3 7 | #define HTU21D_HUMID 0xF5 8 | 9 | // Get temperature 10 | double getTemperature(int fd); 11 | 12 | // Get humidity 13 | double getHumidity(int fd); 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /HTU21D/c/HTU21D_test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "wiringPi.h" 6 | #include "wiringPiI2C.h" 7 | 8 | 9 | #include "HTU21D.h" 10 | 11 | int main () 12 | { 13 | wiringPiSetup(); 14 | int fd = wiringPiI2CSetup(HTU21D_I2C_ADDR); 15 | if ( 0 > fd ) 16 | { 17 | fprintf (stderr, "Unable to open I2C device: %s\n", strerror (errno)); 18 | exit (-1); 19 | } 20 | 21 | printf("%5.2fC\n", getTemperature(fd)); 22 | printf("%5.2f%%rh\n", getHumidity(fd)); 23 | 24 | return 0; 25 | } 26 | -------------------------------------------------------------------------------- /HTU21D/c/Makefile: -------------------------------------------------------------------------------- 1 | CC=gcc 2 | CFLAGS=-I. -Wall 3 | DEPS = 4 | OBJ = HTU21D.o HTU21D_test.o 5 | EXTRA_LIBS=-lwiringPi 6 | 7 | %.o: %.c $(DEPS) 8 | $(CC) -c -o $@ $< $(CFLAGS) 9 | 10 | HTU21D_test: $(OBJ) 11 | $(CC) -o $@ $^ $(CFLAGS) $(EXTRA_LIBS) 12 | 13 | .PHONY: clean 14 | 15 | clean: 16 | rm -f HTU21D $(OBJ) 17 | -------------------------------------------------------------------------------- /LED-RGB/c/.gitignore: -------------------------------------------------------------------------------- 1 | led-rgb 2 | *.o 3 | -------------------------------------------------------------------------------- /LED-RGB/c/Makefile: -------------------------------------------------------------------------------- 1 | CC=gcc 2 | CFLAGS=-I. 3 | DEPS = 4 | OBJ = led-rgb.o 5 | EXTRA_LIBS=-lwiringPi 6 | 7 | %.o: %.c $(DEPS) 8 | $(CC) -c -o $@ $< $(CFLAGS) 9 | 10 | led-rgb: $(OBJ) 11 | $(CC) -o $@ $^ $(CFLAGS) $(EXTRA_LIBS) 12 | 13 | .PHONY: clean 14 | 15 | clean: 16 | rm -f led-rgb $(OBJ) 17 | -------------------------------------------------------------------------------- /LED-RGB/c/led-rgb.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | // Red: GPIO 7, aka pin 7 6 | const int pinRed = 7; 7 | // Green: GPIO 0, aka pin 11 8 | const int pinGreen = 0; 9 | // Blue: GPIO 2, aka pin 13 10 | const int pinBlue = 2; 11 | 12 | void color(int colorRed, int colorGreen, int colorBlue) 13 | { 14 | digitalWrite(pinRed, colorRed); 15 | digitalWrite(pinGreen, colorGreen); 16 | digitalWrite(pinBlue, colorBlue); 17 | //Wait for 1 second 18 | delay(1000); 19 | } 20 | 21 | int main() 22 | { 23 | if (-1 == wiringPiSetup()) 24 | { 25 | printf("setup wiringPi failed!\n"); 26 | return 1; 27 | } 28 | 29 | // Set pin mode 30 | pinMode(pinRed, OUTPUT); 31 | pinMode(pinGreen, OUTPUT); 32 | pinMode(pinBlue, OUTPUT); 33 | 34 | for(;;) 35 | { 36 | // Red 37 | color(1, 0, 0); 38 | // Green 39 | color(0, 1, 0); 40 | //Blue 41 | color(0, 0, 1); 42 | } 43 | return 0; 44 | } 45 | -------------------------------------------------------------------------------- /LED-SMD3528/c/.gitignore: -------------------------------------------------------------------------------- 1 | led-blink 2 | led-pwm 3 | *.o 4 | -------------------------------------------------------------------------------- /LED-SMD3528/c/Makefile: -------------------------------------------------------------------------------- 1 | CC=gcc 2 | CFLAGS=-I. 3 | DEPS = 4 | OBJ1 = led-strip-smd3528.o 5 | OBJ2 = led-strip-smd3528-pwm.o 6 | EXTRA_LIBS=-lwiringPi -lpthread 7 | CFLAGS=-std=c99 8 | 9 | %.o: %.c $(DEPS) 10 | $(CC) -c -o $@ $< $(CFLAGS) 11 | 12 | led-blink: $(OBJ1) 13 | $(CC) -o $@ $^ $(CFLAGS) $(EXTRA_LIBS) 14 | 15 | led-pwm: $(OBJ2) 16 | $(CC) -o $@ $^ $(CFLAGS) $(EXTRA_LIBS) 17 | 18 | .PHONY: clean 19 | 20 | clean: 21 | rm -f led-blink led-pwm $(OBJ1) $(OBJ2) 22 | -------------------------------------------------------------------------------- /LED-SMD3528/c/led-strip-smd3528-pwm.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | // Pin for controlling the LED strip: GPIO 11, aka pin 11 8 | const int pinCtrl = 0; 9 | 10 | void close() 11 | { 12 | softPwmWrite(pinCtrl, 0); 13 | exit(0); 14 | } 15 | 16 | void enablePWM(int pin, int speed) 17 | { 18 | if (0 != softPwmCreate(pin, 0, speed)) 19 | { 20 | printf("ERROR: Cannot enable software PWM for pin %d\n", pin); 21 | } 22 | } 23 | 24 | int main() 25 | { 26 | // Process Ctrl+C to terminate the application 27 | signal(SIGINT, close); 28 | 29 | if (-1 == wiringPiSetup()) 30 | { 31 | printf("setup wiringPi failed!\n"); 32 | return 1; 33 | } 34 | 35 | // Enable PWM and set max value 36 | enablePWM(pinCtrl, 5); 37 | 38 | // Infinite loop 39 | for(;;) 40 | { 41 | // Increase brightness from 20% to 100% 42 | for (int fadeIn=1; fadeIn<6;fadeIn++) 43 | { 44 | printf("Brightness: %d%\n", fadeIn*20); 45 | softPwmWrite(pinCtrl, fadeIn); 46 | delay(3000); 47 | } 48 | 49 | // Decrease brightness from 80% to 40% 50 | for (int fadeOut=4; fadeOut>1; fadeOut--) 51 | { 52 | printf("Brightness: %d%\n", fadeOut*20); 53 | softPwmWrite(pinCtrl, fadeOut); 54 | delay(3000); 55 | } 56 | } 57 | return 0; 58 | } 59 | -------------------------------------------------------------------------------- /LED-SMD3528/c/led-strip-smd3528.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | // Pin for controlling the LED strip: GPIO 11, aka pin 11 7 | const int pinCtrl = 0; 8 | 9 | void close() 10 | { 11 | digitalWrite(pinCtrl, 0); 12 | exit(0); 13 | } 14 | 15 | int main() 16 | { 17 | signal(SIGINT, close); 18 | 19 | if (-1 == wiringPiSetup()) 20 | { 21 | printf("setup wiringPi failed!\n"); 22 | return 1; 23 | } 24 | 25 | // Set pin mode 26 | pinMode(pinCtrl, OUTPUT); 27 | 28 | for(;;) 29 | { 30 | digitalWrite(pinCtrl, 1); 31 | delay(1000); 32 | digitalWrite(pinCtrl, 0); 33 | delay(1000); 34 | } 35 | return 0; 36 | } 37 | -------------------------------------------------------------------------------- /LED/bash/led.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ "$1" == "on" ]; then 4 | led=1 5 | else 6 | led=0 7 | fi 8 | gpio mode 0 out 9 | gpio write 0 $led 10 | -------------------------------------------------------------------------------- /LED/bash/switch.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ `gpio read 0` == "1" ]; then 4 | led=0 5 | else 6 | led=1 7 | fi 8 | gpio mode 0 out 9 | gpio write 0 $led 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Leon Anavi 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /LM75A/bash/lm75a.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Raspberry Pi LM75A I2C temperature sample code. 4 | # Author: Leon Anavi 5 | 6 | # By default the address of LM75A is set to 0x48 7 | # aka A0, A1, and A2 are set to GND (0v). 8 | address=0x48 9 | 10 | # Check if another address has been specified 11 | if [ ! -z "$1" ]; then 12 | address=$1 13 | fi 14 | 15 | # Read from I2C and print temperature 16 | i2cget -y 1 $address 0x00 w | 17 | awk '{printf("%.2f\n", (a=( \ 18 | (("0x"substr($1,5,2)substr($1,3,1))*0.0625)+0.1) \ 19 | )>128?a-256:a)}' 20 | -------------------------------------------------------------------------------- /LM75A/c/.gitignore: -------------------------------------------------------------------------------- 1 | LM75A 2 | *.o 3 | -------------------------------------------------------------------------------- /LM75A/c/LM75A.c: -------------------------------------------------------------------------------- 1 | /* 2 | Raspberry Pi LM75A IC2 temperature sample code. 3 | 4 | Author: Leon Anavi 5 | 6 | For more information and other samples for Raspberry Pi visit: 7 | https://github.com/leon-anavi/rpi-examples 8 | 9 | Circuit detail: 10 | Using CJMCU-75 (LM75A) Board Module 11 | VIN - 3.3V (Raspberry Pi pin 1) 12 | GND - GND (Raspberry Pi pin 14) 13 | SDA - SDA (Raspberry Pi pin 3) 14 | SCL - SCL (Raspberry Pi pin 5) 15 | 16 | Note: Make sure LM75A is connected to 3.3V NOT the 5V pin! 17 | 18 | Slave address: 19 | By default the application uses I2C address 0x48. 20 | Solder pins A0, A1 and A2 of LM75A to ground to use the default address. 21 | 22 | Otherwise, you can specify another address as a command line argument, 23 | for example: ./LM75A 0x4c 24 | */ 25 | #include 26 | #include 27 | 28 | float getTemperature(int fd) 29 | { 30 | int raw = wiringPiI2CReadReg16(fd, 0x00); 31 | raw = ((raw << 8) & 0xFF00) + (raw >> 8); 32 | return (float)((raw / 32.0) / 8.0); 33 | } 34 | 35 | int main(int argc, char *argv[]) 36 | { 37 | /* By default the address of LM75A is set to 0x48 38 | aka A0, A1, and A2 are set to GND (0v). */ 39 | int address = 0x48; 40 | if (1 < argc) 41 | { 42 | address = (int)strtol(argv[1], NULL, 0); 43 | } 44 | 45 | /* Read from I2C and print temperature */ 46 | int fd = wiringPiI2CSetup(address); 47 | printf("%.2f\n", getTemperature(fd) ); 48 | return 0; 49 | } 50 | -------------------------------------------------------------------------------- /LM75A/c/Makefile: -------------------------------------------------------------------------------- 1 | CC=gcc 2 | CFLAGS=-I. 3 | DEPS = 4 | OBJ = LM75A.o 5 | EXTRA_LIBS=-lwiringPi 6 | 7 | %.o: %.c $(DEPS) 8 | $(CC) -c -o $@ $< $(CFLAGS) 9 | 10 | LM75A: $(OBJ) 11 | $(CC) -o $@ $^ $(CFLAGS) $(EXTRA_LIBS) 12 | 13 | .PHONY: clean 14 | 15 | clean: 16 | rm -f LM75A $(OBJ) 17 | -------------------------------------------------------------------------------- /LM75A/python/LM75A.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # Raspberry Pi LM75A I2C temperature sample code. 4 | # Author: Leon Anavi 5 | 6 | import sys 7 | import smbus 8 | 9 | # By default the address of LM75A is set to 0x48 10 | # aka A0, A1, and A2 are set to GND (0v). 11 | address = 0x48 12 | 13 | # Check if another address has been specified 14 | if 1 < len(sys.argv): 15 | address = int(sys.argv[1], 16) 16 | 17 | # Read I2C data and calculate temperature 18 | bus = smbus.SMBus(1) 19 | raw = bus.read_word_data(address, 0) & 0xFFFF 20 | raw = ((raw << 8) & 0xFF00) + (raw >> 8) 21 | temperature = (raw / 32.0) / 8.0 22 | # Print temperature 23 | print 'Temperature: {0:0.2f} *C'.format(temperature) 24 | -------------------------------------------------------------------------------- /MAX44009/c/.gitignore: -------------------------------------------------------------------------------- 1 | MAX44009_test 2 | *.o 3 | -------------------------------------------------------------------------------- /MAX44009/c/MAX44009.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "MAX44009.h" 4 | 5 | float getLux(int fd) 6 | { 7 | int vhigh = wiringPiI2CReadReg8(fd, lux_h_register); 8 | int vlow = wiringPiI2CReadReg8(fd, lux_l_register); 9 | 10 | int exponent=( vhigh & 0xF0 ) >> 4; 11 | int mantisa= ( vhigh & 0x0F ) << 4 | vlow; 12 | 13 | float lux= ( ( pow(2,(double)exponent) ) * (double)mantisa ) * 0.045; 14 | return lux; 15 | } 16 | -------------------------------------------------------------------------------- /MAX44009/c/MAX44009.h: -------------------------------------------------------------------------------- 1 | #ifndef _MAX44009_H_ 2 | #define _MAX44009_H_ 3 | 4 | #define MAX44009_ADDR 0x4A 5 | 6 | #define lux_h_register 0x03 7 | #define lux_l_register 0x04 8 | 9 | float getLux(int fd); 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /MAX44009/c/MAX44009_test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "MAX44009.h" 3 | 4 | int main() 5 | { 6 | int fd = wiringPiI2CSetup(MAX44009_ADDR) ; 7 | printf("Lux: %.3f \n", getLux(fd)); 8 | return 0 ; 9 | } 10 | -------------------------------------------------------------------------------- /MAX44009/c/Makefile: -------------------------------------------------------------------------------- 1 | CC=gcc 2 | CFLAGS=-I. -lm 3 | DEPS = 4 | OBJ = MAX44009.o MAX44009_test.o 5 | EXTRA_LIBS=-lwiringPi 6 | 7 | %.o: %.c $(DEPS) 8 | $(CC) -c -o $@ $< $(CFLAGS) 9 | 10 | MAX44009_test: $(OBJ) 11 | $(CC) -o $@ $^ $(CFLAGS) $(EXTRA_LIBS) 12 | 13 | .PHONY: clean 14 | 15 | clean: 16 | rm -f MAX44009 $(OBJ) 17 | -------------------------------------------------------------------------------- /MCP3002/python/adc.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | # Tested on Raspberry Pi OS. Requirements: enable SPI, for example 4 | # from raspi-config. The example is based on a SparkFun tutorial: 5 | # https://learn.sparkfun.com/tutorials/python-programming-tutorial-getting-started-with-the-raspberry-pi/experiment-3-spi-and-analog-input 6 | 7 | import signal 8 | import sys 9 | import time 10 | import spidev 11 | import RPi.GPIO as GPIO 12 | 13 | spi_ch = 0 14 | 15 | # Enable SPI 16 | spi = spidev.SpiDev(0, spi_ch) 17 | spi.max_speed_hz = 1200000 18 | 19 | def close(signal, frame): 20 | sys.exit(0) 21 | 22 | signal.signal(signal.SIGINT, close) 23 | 24 | def get_adc(channel): 25 | 26 | # Make sure ADC channel is 0 or 1 27 | if channel != 0: 28 | channel = 1 29 | 30 | # Construct SPI message 31 | # First bit (Start): Logic high (1) 32 | # Second bit (SGL/DIFF): 1 to select single mode 33 | # Third bit (ODD/SIGN): Select channel (0 or 1) 34 | # Fourth bit (MSFB): 0 for LSB first 35 | # Next 12 bits: 0 (don't care) 36 | msg = 0b11 37 | msg = ((msg << 1) + channel) << 5 38 | msg = [msg, 0b00000000] 39 | reply = spi.xfer2(msg) 40 | 41 | # Construct single integer out of the reply (2 bytes) 42 | adc = 0 43 | for n in reply: 44 | adc = (adc << 8) + n 45 | 46 | # Last bit (0) is not part of ADC value, shift to remove it 47 | adc = adc >> 1 48 | 49 | # Calculate voltage form ADC value 50 | # considering the soil moisture sensor is working at 5V 51 | voltage = (5 * adc) / 1024 52 | 53 | return voltage 54 | 55 | if __name__ == '__main__': 56 | # Report the channel 0 and channel 1 voltages to the terminal 57 | try: 58 | while True: 59 | adc_0 = get_adc(0) 60 | adc_1 = get_adc(1) 61 | print("ADC Channel 0:", round(adc_0, 2), "V ADC Channel 1:", round(adc_1, 2), "V") 62 | time.sleep(0.2) 63 | 64 | except KeyboardInterrupt: 65 | GPIO.cleanup() 66 | -------------------------------------------------------------------------------- /MaPIE-LoRa-RP2040/circuitpython/code.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries 2 | # SPDX-License-Identifier: MIT 3 | 4 | # Example to send a packet periodically between addressed nodes 5 | # Author: Leon Anavi 6 | # Modified to work directly on the MaPIE Lora RP2040 boards. 7 | # 8 | import time 9 | import board 10 | import busio 11 | import digitalio 12 | import adafruit_rfm9x 13 | 14 | # set the time interval (seconds) for sending packets 15 | transmit_interval = 5 16 | 17 | # Define radio parameters. 18 | RADIO_FREQ_MHZ = 868.0 # Frequency of the radio in Mhz. Must match your 19 | # module! Can be a value like 915.0, 433.0, etc. 20 | 21 | # Define pins connected to the chip. 22 | CS = digitalio.DigitalInOut(board.GP17) 23 | RESET = digitalio.DigitalInOut(board.GP20) 24 | 25 | # Initialize SPI bus. 26 | rfm95x_spi = busio.SPI(board.GP18, MOSI=board.GP19, MISO=board.GP16) 27 | # Initialze RFM radio 28 | rfm9x = adafruit_rfm9x.RFM9x(rfm95x_spi, CS, RESET, RADIO_FREQ_MHZ) 29 | 30 | # set node addresses 31 | # When trying this out with two boards, one board should have the reverse settings 32 | rfm9x.node = 1 33 | rfm9x.destination = 2 34 | # initialize counter 35 | counter = 0 36 | # send a broadcast message from my_node with ID = counter 37 | rfm9x.send( 38 | bytes("Startup message {} from node {}".format(counter, rfm9x.node), "UTF-8") 39 | ) 40 | 41 | # Wait to receive packets. 42 | print("Node: ", rfm9x.node) 43 | print("Waiting for packets...") 44 | now = time.monotonic() 45 | while True: 46 | # Look for a new packet: only accept if addresses to my_node 47 | packet = rfm9x.receive(with_header=True) 48 | # If no packet was received during the timeout then None is returned. 49 | if packet is not None: 50 | # Received a packet! 51 | # Print out the raw bytes of the packet: 52 | print("Received (raw header):", [hex(x) for x in packet[0:4]]) 53 | print("Received (raw payload): {0}".format(packet[4:])) 54 | print("Received RSSI: {0}".format(rfm9x.last_rssi)) 55 | if time.monotonic() - now > transmit_interval: 56 | now = time.monotonic() 57 | counter = counter + 1 58 | # send a mesage to destination_node from my_node 59 | rfm9x.send( 60 | bytes( 61 | "message number {} from node {}".format(counter, rfm9x.node), "UTF-8" 62 | ), 63 | keep_listening=True, 64 | ) 65 | button_pressed = None 66 | -------------------------------------------------------------------------------- /MaPIE-LoRa-RP2040/circuitpython/lib/adafruit_rfm9x.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2017 Tony DiCola for Adafruit Industries 2 | # 3 | # SPDX-License-Identifier: MIT 4 | 5 | """ 6 | `adafruit_rfm9x` 7 | ==================================================== 8 | 9 | CircuitPython module for the RFM95/6/7/8 LoRa 433/915mhz radio modules. This is 10 | adapted from the Radiohead library RF95 code from: 11 | http: www.airspayce.com/mikem/arduino/RadioHead/ 12 | 13 | * Author(s): Tony DiCola, Jerry Needell 14 | """ 15 | import random 16 | import time 17 | import adafruit_bus_device.spi_device as spidev 18 | from micropython import const 19 | 20 | HAS_SUPERVISOR = False 21 | 22 | try: 23 | import supervisor 24 | 25 | if hasattr(supervisor, "ticks_ms"): 26 | HAS_SUPERVISOR = True 27 | except ImportError: 28 | pass 29 | 30 | try: 31 | from typing import Optional, Type 32 | from digitalio import DigitalInOut 33 | from busio import SPI 34 | from circuitpython_typing import WriteableBuffer, ReadableBuffer 35 | 36 | try: 37 | from typing import Literal 38 | except ImportError: 39 | from typing_extensions import Literal 40 | 41 | except ImportError: 42 | pass 43 | 44 | __version__ = "0.0.0+auto.0" 45 | __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_RFM9x.git" 46 | 47 | # Internal constants: 48 | # Register names (FSK Mode even though we use LoRa instead, from table 85) 49 | _RH_RF95_REG_00_FIFO = const(0x00) 50 | _RH_RF95_REG_01_OP_MODE = const(0x01) 51 | _RH_RF95_REG_06_FRF_MSB = const(0x06) 52 | _RH_RF95_REG_07_FRF_MID = const(0x07) 53 | _RH_RF95_REG_08_FRF_LSB = const(0x08) 54 | _RH_RF95_REG_09_PA_CONFIG = const(0x09) 55 | _RH_RF95_REG_0A_PA_RAMP = const(0x0A) 56 | _RH_RF95_REG_0B_OCP = const(0x0B) 57 | _RH_RF95_REG_0C_LNA = const(0x0C) 58 | _RH_RF95_REG_0D_FIFO_ADDR_PTR = const(0x0D) 59 | _RH_RF95_REG_0E_FIFO_TX_BASE_ADDR = const(0x0E) 60 | _RH_RF95_REG_0F_FIFO_RX_BASE_ADDR = const(0x0F) 61 | _RH_RF95_REG_10_FIFO_RX_CURRENT_ADDR = const(0x10) 62 | _RH_RF95_REG_11_IRQ_FLAGS_MASK = const(0x11) 63 | _RH_RF95_REG_12_IRQ_FLAGS = const(0x12) 64 | _RH_RF95_REG_13_RX_NB_BYTES = const(0x13) 65 | _RH_RF95_REG_14_RX_HEADER_CNT_VALUE_MSB = const(0x14) 66 | _RH_RF95_REG_15_RX_HEADER_CNT_VALUE_LSB = const(0x15) 67 | _RH_RF95_REG_16_RX_PACKET_CNT_VALUE_MSB = const(0x16) 68 | _RH_RF95_REG_17_RX_PACKET_CNT_VALUE_LSB = const(0x17) 69 | _RH_RF95_REG_18_MODEM_STAT = const(0x18) 70 | _RH_RF95_REG_19_PKT_SNR_VALUE = const(0x19) 71 | _RH_RF95_REG_1A_PKT_RSSI_VALUE = const(0x1A) 72 | _RH_RF95_REG_1B_RSSI_VALUE = const(0x1B) 73 | _RH_RF95_REG_1C_HOP_CHANNEL = const(0x1C) 74 | _RH_RF95_REG_1D_MODEM_CONFIG1 = const(0x1D) 75 | _RH_RF95_REG_1E_MODEM_CONFIG2 = const(0x1E) 76 | _RH_RF95_REG_1F_SYMB_TIMEOUT_LSB = const(0x1F) 77 | _RH_RF95_REG_20_PREAMBLE_MSB = const(0x20) 78 | _RH_RF95_REG_21_PREAMBLE_LSB = const(0x21) 79 | _RH_RF95_REG_22_PAYLOAD_LENGTH = const(0x22) 80 | _RH_RF95_REG_23_MAX_PAYLOAD_LENGTH = const(0x23) 81 | _RH_RF95_REG_24_HOP_PERIOD = const(0x24) 82 | _RH_RF95_REG_25_FIFO_RX_BYTE_ADDR = const(0x25) 83 | _RH_RF95_REG_26_MODEM_CONFIG3 = const(0x26) 84 | 85 | _RH_RF95_REG_40_DIO_MAPPING1 = const(0x40) 86 | _RH_RF95_REG_41_DIO_MAPPING2 = const(0x41) 87 | _RH_RF95_REG_42_VERSION = const(0x42) 88 | 89 | _RH_RF95_REG_4B_TCXO = const(0x4B) 90 | _RH_RF95_REG_4D_PA_DAC = const(0x4D) 91 | _RH_RF95_REG_5B_FORMER_TEMP = const(0x5B) 92 | _RH_RF95_REG_61_AGC_REF = const(0x61) 93 | _RH_RF95_REG_62_AGC_THRESH1 = const(0x62) 94 | _RH_RF95_REG_63_AGC_THRESH2 = const(0x63) 95 | _RH_RF95_REG_64_AGC_THRESH3 = const(0x64) 96 | 97 | _RH_RF95_DETECTION_OPTIMIZE = const(0x31) 98 | _RH_RF95_DETECTION_THRESHOLD = const(0x37) 99 | 100 | _RH_RF95_PA_DAC_DISABLE = const(0x04) 101 | _RH_RF95_PA_DAC_ENABLE = const(0x07) 102 | 103 | # The crystal oscillator frequency of the module 104 | _RH_RF95_FXOSC = 32000000.0 105 | 106 | # The Frequency Synthesizer step = RH_RF95_FXOSC / 2^^19 107 | _RH_RF95_FSTEP = _RH_RF95_FXOSC / 524288 108 | 109 | # RadioHead specific compatibility constants. 110 | _RH_BROADCAST_ADDRESS = const(0xFF) 111 | 112 | # The acknowledgement bit in the FLAGS 113 | # The top 4 bits of the flags are reserved for RadioHead. The lower 4 bits are reserved 114 | # for application layer use. 115 | _RH_FLAGS_ACK = const(0x80) 116 | _RH_FLAGS_RETRY = const(0x40) 117 | 118 | # User facing constants: 119 | SLEEP_MODE = 0b000 120 | STANDBY_MODE = 0b001 121 | FS_TX_MODE = 0b010 122 | TX_MODE = 0b011 123 | FS_RX_MODE = 0b100 124 | RX_MODE = 0b101 125 | # supervisor.ticks_ms() contants 126 | _TICKS_PERIOD = const(1 << 29) 127 | _TICKS_MAX = const(_TICKS_PERIOD - 1) 128 | _TICKS_HALFPERIOD = const(_TICKS_PERIOD // 2) 129 | 130 | # Disable the too many instance members warning. Pylint has no knowledge 131 | # of the context and is merely guessing at the proper amount of members. This 132 | # is a complex chip which requires exposing many attributes and state. Disable 133 | # the warning to work around the error. 134 | # pylint: disable=too-many-instance-attributes 135 | # pylint: disable=too-many-statements 136 | 137 | 138 | def ticks_diff(ticks1: int, ticks2: int) -> int: 139 | """Compute the signed difference between two ticks values 140 | assuming that they are within 2**28 ticks 141 | """ 142 | diff = (ticks1 - ticks2) & _TICKS_MAX 143 | diff = ((diff + _TICKS_HALFPERIOD) & _TICKS_MAX) - _TICKS_HALFPERIOD 144 | return diff 145 | 146 | 147 | class RFM9x: 148 | """Interface to a RFM95/6/7/8 LoRa radio module. Allows sending and 149 | receiving bytes of data in long range LoRa mode at a support board frequency 150 | (433/915mhz). 151 | 152 | You must specify the following parameters: 153 | - spi: The SPI bus connected to the radio. 154 | - cs: The CS pin DigitalInOut connected to the radio. 155 | - reset: The reset/RST pin DigialInOut connected to the radio. 156 | - frequency: The frequency (in mhz) of the radio module (433/915mhz typically). 157 | 158 | You can optionally specify: 159 | - preamble_length: The length in bytes of the packet preamble (default 8). 160 | - high_power: Boolean to indicate a high power board (RFM95, etc.). Default 161 | is True for high power. 162 | - baudrate: Baud rate of the SPI connection, default is 10mhz but you might 163 | choose to lower to 1mhz if using long wires or a breadboard. 164 | - agc: Boolean to Enable/Disable Automatic Gain Control - Default=False (AGC off) 165 | - crc: Boolean to Enable/Disable Cyclic Redundancy Check - Default=True (CRC Enabled) 166 | Remember this library makes a best effort at receiving packets with pure 167 | Python code. Trying to receive packets too quickly will result in lost data 168 | so limit yourself to simple scenarios of sending and receiving single 169 | packets at a time. 170 | 171 | Also note this library tries to be compatible with raw RadioHead Arduino 172 | library communication. This means the library sets up the radio modulation 173 | to match RadioHead's defaults and assumes that each packet contains a 174 | 4 byte header compatible with RadioHead's implementation. 175 | Advanced RadioHead features like address/node specific packets 176 | or "reliable datagram" delivery are supported however due to the 177 | limitations noted, "reliable datagram" is still subject to missed packets but with it, 178 | sender is notified if a packet has potentially been missed. 179 | """ 180 | 181 | # Global buffer for SPI commands 182 | _BUFFER = bytearray(4) 183 | 184 | class _RegisterBits: 185 | # Class to simplify access to the many configuration bits avaialable 186 | # on the chip's registers. This is a subclass here instead of using 187 | # a higher level module to increase the efficiency of memory usage 188 | # (all of the instances of this bit class will share the same buffer 189 | # used by the parent RFM69 class instance vs. each having their own 190 | # buffer and taking too much memory). 191 | 192 | # Quirk of pylint that it requires public methods for a class. This 193 | # is a decorator class in Python and by design it has no public methods. 194 | # Instead it uses dunder accessors like get and set below. For some 195 | # reason pylint can't figure this out so disable the check. 196 | # pylint: disable=too-few-public-methods 197 | 198 | # Again pylint fails to see the true intent of this code and warns 199 | # against private access by calling the write and read functions below. 200 | # This is by design as this is an internally used class. Disable the 201 | # check from pylint. 202 | # pylint: disable=protected-access 203 | 204 | def __init__(self, address: int, *, offset: int = 0, bits: int = 1) -> None: 205 | assert 0 <= offset <= 7 206 | assert 1 <= bits <= 8 207 | assert (offset + bits) <= 8 208 | self._address = address 209 | self._mask = 0 210 | for _ in range(bits): 211 | self._mask <<= 1 212 | self._mask |= 1 213 | self._mask <<= offset 214 | self._offset = offset 215 | 216 | def __get__(self, obj: "RFM9x", objtype: Type["RFM9x"]) -> int: 217 | reg_value = obj._read_u8(self._address) 218 | return (reg_value & self._mask) >> self._offset 219 | 220 | def __set__(self, obj: "RFM9x", val: int) -> None: 221 | reg_value = obj._read_u8(self._address) 222 | reg_value &= ~self._mask 223 | reg_value |= (val & 0xFF) << self._offset 224 | obj._write_u8(self._address, reg_value) 225 | 226 | operation_mode = _RegisterBits(_RH_RF95_REG_01_OP_MODE, bits=3) 227 | 228 | low_frequency_mode = _RegisterBits(_RH_RF95_REG_01_OP_MODE, offset=3, bits=1) 229 | 230 | modulation_type = _RegisterBits(_RH_RF95_REG_01_OP_MODE, offset=5, bits=2) 231 | 232 | # Long range/LoRa mode can only be set in sleep mode! 233 | long_range_mode = _RegisterBits(_RH_RF95_REG_01_OP_MODE, offset=7, bits=1) 234 | 235 | output_power = _RegisterBits(_RH_RF95_REG_09_PA_CONFIG, bits=4) 236 | 237 | max_power = _RegisterBits(_RH_RF95_REG_09_PA_CONFIG, offset=4, bits=3) 238 | 239 | pa_select = _RegisterBits(_RH_RF95_REG_09_PA_CONFIG, offset=7, bits=1) 240 | 241 | pa_dac = _RegisterBits(_RH_RF95_REG_4D_PA_DAC, bits=3) 242 | 243 | dio0_mapping = _RegisterBits(_RH_RF95_REG_40_DIO_MAPPING1, offset=6, bits=2) 244 | 245 | auto_agc = _RegisterBits(_RH_RF95_REG_26_MODEM_CONFIG3, offset=2, bits=1) 246 | 247 | low_datarate_optimize = _RegisterBits( 248 | _RH_RF95_REG_26_MODEM_CONFIG3, offset=3, bits=1 249 | ) 250 | 251 | lna_boost_hf = _RegisterBits(_RH_RF95_REG_0C_LNA, offset=0, bits=2) 252 | 253 | auto_ifon = _RegisterBits(_RH_RF95_DETECTION_OPTIMIZE, offset=7, bits=1) 254 | 255 | detection_optimize = _RegisterBits(_RH_RF95_DETECTION_OPTIMIZE, offset=0, bits=3) 256 | 257 | bw_bins = (7800, 10400, 15600, 20800, 31250, 41700, 62500, 125000, 250000) 258 | 259 | def __init__( 260 | self, 261 | spi: SPI, 262 | cs: DigitalInOut, 263 | reset: DigitalInOut, 264 | frequency: int, 265 | *, 266 | preamble_length: int = 8, 267 | high_power: bool = True, 268 | baudrate: int = 5000000, 269 | agc: bool = False, 270 | crc: bool = True 271 | ) -> None: 272 | self.high_power = high_power 273 | # Device support SPI mode 0 (polarity & phase = 0) up to a max of 10mhz. 274 | # Set Default Baudrate to 5MHz to avoid problems 275 | self._device = spidev.SPIDevice(spi, cs, baudrate=baudrate, polarity=0, phase=0) 276 | # Setup reset as a digital output - initially High 277 | # This line is pulled low as an output quickly to trigger a reset. 278 | self._reset = reset 279 | # initialize Reset High 280 | self._reset.switch_to_output(value=True) 281 | self.reset() 282 | # No device type check! Catch an error from the very first request and 283 | # throw a nicer message to indicate possible wiring problems. 284 | version = self._read_u8(_RH_RF95_REG_42_VERSION) 285 | if version != 18: 286 | raise RuntimeError( 287 | "Failed to find rfm9x with expected version -- check wiring" 288 | ) 289 | 290 | # Set sleep mode, wait 10s and confirm in sleep mode (basic device check). 291 | # Also set long range mode (LoRa mode) as it can only be done in sleep. 292 | self.sleep() 293 | time.sleep(0.01) 294 | self.long_range_mode = True 295 | if self.operation_mode != SLEEP_MODE or not self.long_range_mode: 296 | raise RuntimeError("Failed to configure radio for LoRa mode, check wiring!") 297 | # clear default setting for access to LF registers if frequency > 525MHz 298 | if frequency > 525: 299 | self.low_frequency_mode = 0 300 | # Setup entire 256 byte FIFO 301 | self._write_u8(_RH_RF95_REG_0E_FIFO_TX_BASE_ADDR, 0x00) 302 | self._write_u8(_RH_RF95_REG_0F_FIFO_RX_BASE_ADDR, 0x00) 303 | # Set mode idle 304 | self.idle() 305 | # Set frequency 306 | self.frequency_mhz = frequency 307 | # Set preamble length (default 8 bytes to match radiohead). 308 | self.preamble_length = preamble_length 309 | # Defaults set modem config to RadioHead compatible Bw125Cr45Sf128 mode. 310 | self.signal_bandwidth = 125000 311 | self.coding_rate = 5 312 | self.spreading_factor = 7 313 | # Default to enable CRC checking on incoming packets. 314 | self.enable_crc = crc 315 | """CRC Enable state""" 316 | # set AGC - Default = False 317 | self.auto_agc = agc 318 | """Automatic Gain Control state""" 319 | # Set transmit power to 13 dBm, a safe value any module supports. 320 | self.tx_power = 13 321 | # initialize last RSSI reading 322 | self.last_rssi = 0.0 323 | """The RSSI of the last received packet. Stored when the packet was received. 324 | The instantaneous RSSI value may not be accurate once the 325 | operating mode has been changed. 326 | """ 327 | self.last_snr = 0.0 328 | """The SNR of the last received packet. Stored when the packet was received. 329 | The instantaneous SNR value may not be accurate once the 330 | operating mode has been changed. 331 | """ 332 | # initialize timeouts and delays delays 333 | self.ack_wait = 0.5 334 | """The delay time before attempting a retry after not receiving an ACK""" 335 | self.receive_timeout = 0.5 336 | """The amount of time to poll for a received packet. 337 | If no packet is received, the returned packet will be None 338 | """ 339 | self.xmit_timeout = 2.0 340 | """The amount of time to wait for the HW to transmit the packet. 341 | This is mainly used to prevent a hang due to a HW issue 342 | """ 343 | self.ack_retries = 5 344 | """The number of ACK retries before reporting a failure.""" 345 | self.ack_delay = None 346 | """The delay time before attemting to send an ACK. 347 | If ACKs are being missed try setting this to .1 or .2. 348 | """ 349 | # initialize sequence number counter for reliabe datagram mode 350 | self.sequence_number = 0 351 | # create seen Ids list 352 | self.seen_ids = bytearray(256) 353 | # initialize packet header 354 | # node address - default is broadcast 355 | self.node = _RH_BROADCAST_ADDRESS 356 | """The default address of this Node. (0-255). 357 | If not 255 (0xff) then only packets address to this node will be accepted. 358 | First byte of the RadioHead header. 359 | """ 360 | # destination address - default is broadcast 361 | self.destination = _RH_BROADCAST_ADDRESS 362 | """The default destination address for packet transmissions. (0-255). 363 | If 255 (0xff) then any receiving node should accept the packet. 364 | Second byte of the RadioHead header. 365 | """ 366 | # ID - contains seq count for reliable datagram mode 367 | self.identifier = 0 368 | """Automatically set to the sequence number when send_with_ack() used. 369 | Third byte of the RadioHead header. 370 | """ 371 | # flags - identifies ack/reetry packet for reliable datagram mode 372 | self.flags = 0 373 | """Upper 4 bits reserved for use by Reliable Datagram Mode. 374 | Lower 4 bits may be used to pass information. 375 | Fourth byte of the RadioHead header. 376 | """ 377 | self.crc_error_count = 0 378 | 379 | # pylint: disable=no-member 380 | # Reconsider pylint: disable when this can be tested 381 | def _read_into( 382 | self, address: int, buf: WriteableBuffer, length: Optional[int] = None 383 | ) -> None: 384 | # Read a number of bytes from the specified address into the provided 385 | # buffer. If length is not specified (the default) the entire buffer 386 | # will be filled. 387 | if length is None: 388 | length = len(buf) 389 | with self._device as device: 390 | self._BUFFER[0] = address & 0x7F # Strip out top bit to set 0 391 | # value (read). 392 | device.write(self._BUFFER, end=1) 393 | device.readinto(buf, end=length) 394 | 395 | def _read_u8(self, address: int) -> int: 396 | # Read a single byte from the provided address and return it. 397 | self._read_into(address, self._BUFFER, length=1) 398 | return self._BUFFER[0] 399 | 400 | def _write_from( 401 | self, address: int, buf: ReadableBuffer, length: Optional[int] = None 402 | ) -> None: 403 | # Write a number of bytes to the provided address and taken from the 404 | # provided buffer. If no length is specified (the default) the entire 405 | # buffer is written. 406 | if length is None: 407 | length = len(buf) 408 | with self._device as device: 409 | self._BUFFER[0] = (address | 0x80) & 0xFF # Set top bit to 1 to 410 | # indicate a write. 411 | device.write(self._BUFFER, end=1) 412 | device.write(buf, end=length) 413 | 414 | def _write_u8(self, address: int, val: int) -> None: 415 | # Write a byte register to the chip. Specify the 7-bit address and the 416 | # 8-bit value to write to that address. 417 | with self._device as device: 418 | self._BUFFER[0] = ( 419 | address | 0x80 420 | ) & 0xFF # Set top bit to 1 to indicate a write. 421 | self._BUFFER[1] = val & 0xFF 422 | device.write(self._BUFFER, end=2) 423 | 424 | def reset(self) -> None: 425 | """Perform a reset of the chip.""" 426 | # See section 7.2.2 of the datasheet for reset description. 427 | self._reset.value = False # Set Reset Low 428 | time.sleep(0.0001) # 100 us 429 | self._reset.value = True # set Reset High 430 | time.sleep(0.005) # 5 ms 431 | 432 | def idle(self) -> None: 433 | """Enter idle standby mode.""" 434 | self.operation_mode = STANDBY_MODE 435 | 436 | def sleep(self) -> None: 437 | """Enter sleep mode.""" 438 | self.operation_mode = SLEEP_MODE 439 | 440 | def listen(self) -> None: 441 | """Listen for packets to be received by the chip. Use :py:func:`receive` 442 | to listen, wait and retrieve packets as they're available. 443 | """ 444 | self.operation_mode = RX_MODE 445 | self.dio0_mapping = 0b00 # Interrupt on rx done. 446 | 447 | def transmit(self) -> None: 448 | """Transmit a packet which is queued in the FIFO. This is a low level 449 | function for entering transmit mode and more. For generating and 450 | transmitting a packet of data use :py:func:`send` instead. 451 | """ 452 | self.operation_mode = TX_MODE 453 | self.dio0_mapping = 0b01 # Interrupt on tx done. 454 | 455 | @property 456 | def preamble_length(self) -> int: 457 | """The length of the preamble for sent and received packets, an unsigned 458 | 16-bit value. Received packets must match this length or they are 459 | ignored! Set to 8 to match the RadioHead RFM95 library. 460 | """ 461 | msb = self._read_u8(_RH_RF95_REG_20_PREAMBLE_MSB) 462 | lsb = self._read_u8(_RH_RF95_REG_21_PREAMBLE_LSB) 463 | return ((msb << 8) | lsb) & 0xFFFF 464 | 465 | @preamble_length.setter 466 | def preamble_length(self, val: int) -> None: 467 | assert 0 <= val <= 65535 468 | self._write_u8(_RH_RF95_REG_20_PREAMBLE_MSB, (val >> 8) & 0xFF) 469 | self._write_u8(_RH_RF95_REG_21_PREAMBLE_LSB, val & 0xFF) 470 | 471 | @property 472 | def frequency_mhz(self) -> Literal[433.0, 915.0]: 473 | """The frequency of the radio in Megahertz. Only the allowed values for 474 | your radio must be specified (i.e. 433 vs. 915 mhz)! 475 | """ 476 | msb = self._read_u8(_RH_RF95_REG_06_FRF_MSB) 477 | mid = self._read_u8(_RH_RF95_REG_07_FRF_MID) 478 | lsb = self._read_u8(_RH_RF95_REG_08_FRF_LSB) 479 | frf = ((msb << 16) | (mid << 8) | lsb) & 0xFFFFFF 480 | frequency = (frf * _RH_RF95_FSTEP) / 1000000.0 481 | return frequency 482 | 483 | @frequency_mhz.setter 484 | def frequency_mhz(self, val: Literal[433.0, 915.0]) -> None: 485 | if val < 240 or val > 960: 486 | raise RuntimeError("frequency_mhz must be between 240 and 960") 487 | # Calculate FRF register 24-bit value. 488 | frf = int((val * 1000000.0) / _RH_RF95_FSTEP) & 0xFFFFFF 489 | # Extract byte values and update registers. 490 | msb = frf >> 16 491 | mid = (frf >> 8) & 0xFF 492 | lsb = frf & 0xFF 493 | self._write_u8(_RH_RF95_REG_06_FRF_MSB, msb) 494 | self._write_u8(_RH_RF95_REG_07_FRF_MID, mid) 495 | self._write_u8(_RH_RF95_REG_08_FRF_LSB, lsb) 496 | 497 | @property 498 | def tx_power(self) -> int: 499 | """The transmit power in dBm. Can be set to a value from 5 to 23 for 500 | high power devices (RFM95/96/97/98, high_power=True) or -1 to 14 for low 501 | power devices. Only integer power levels are actually set (i.e. 12.5 502 | will result in a value of 12 dBm). 503 | The actual maximum setting for high_power=True is 20dBm but for values > 20 504 | the PA_BOOST will be enabled resulting in an additional gain of 3dBm. 505 | The actual setting is reduced by 3dBm. 506 | The reported value will reflect the reduced setting. 507 | """ 508 | if self.high_power: 509 | return self.output_power + 5 510 | return self.output_power - 1 511 | 512 | @tx_power.setter 513 | def tx_power(self, val: int) -> None: 514 | val = int(val) 515 | if self.high_power: 516 | if val < 5 or val > 23: 517 | raise RuntimeError("tx_power must be between 5 and 23") 518 | # Enable power amp DAC if power is above 20 dB. 519 | # Lower setting by 3db when PA_BOOST enabled - see Data Sheet Section 6.4 520 | if val > 20: 521 | self.pa_dac = _RH_RF95_PA_DAC_ENABLE 522 | val -= 3 523 | else: 524 | self.pa_dac = _RH_RF95_PA_DAC_DISABLE 525 | self.pa_select = True 526 | self.output_power = (val - 5) & 0x0F 527 | else: 528 | assert -1 <= val <= 14 529 | self.pa_select = False 530 | self.max_power = 0b111 # Allow max power output. 531 | self.output_power = (val + 1) & 0x0F 532 | 533 | @property 534 | def rssi(self) -> int: 535 | """The received strength indicator (in dBm) of the last received message.""" 536 | # Read RSSI register and convert to value using formula in datasheet. 537 | # Remember in LoRa mode the payload register changes function to RSSI! 538 | raw_rssi = self._read_u8(_RH_RF95_REG_1A_PKT_RSSI_VALUE) 539 | if self.low_frequency_mode: 540 | raw_rssi -= 157 541 | else: 542 | raw_rssi -= 164 543 | return raw_rssi 544 | 545 | @property 546 | def snr(self) -> float: 547 | """The SNR (in dB) of the last received message.""" 548 | # Read SNR 0x19 register and convert to value using formula in datasheet. 549 | # SNR(dB) = PacketSnr [twos complement] / 4 550 | snr_byte = self._read_u8(_RH_RF95_REG_19_PKT_SNR_VALUE) 551 | if snr_byte > 127: 552 | snr_byte = (256 - snr_byte) * -1 553 | return snr_byte / 4 554 | 555 | @property 556 | def signal_bandwidth(self) -> int: 557 | """The signal bandwidth used by the radio (try setting to a higher 558 | value to increase throughput or to a lower value to increase the 559 | likelihood of successfully received payloads). Valid values are 560 | listed in RFM9x.bw_bins.""" 561 | bw_id = (self._read_u8(_RH_RF95_REG_1D_MODEM_CONFIG1) & 0xF0) >> 4 562 | if bw_id >= len(self.bw_bins): 563 | current_bandwidth = 500000 564 | else: 565 | current_bandwidth = self.bw_bins[bw_id] 566 | return current_bandwidth 567 | 568 | @signal_bandwidth.setter 569 | def signal_bandwidth(self, val: int) -> None: 570 | # Set signal bandwidth (set to 125000 to match RadioHead Bw125). 571 | for bw_id, cutoff in enumerate(self.bw_bins): 572 | if val <= cutoff: 573 | break 574 | else: 575 | bw_id = 9 576 | self._write_u8( 577 | _RH_RF95_REG_1D_MODEM_CONFIG1, 578 | (self._read_u8(_RH_RF95_REG_1D_MODEM_CONFIG1) & 0x0F) | (bw_id << 4), 579 | ) 580 | if val >= 500000: 581 | # see Semtech SX1276 errata note 2.3 582 | self.auto_ifon = True 583 | # see Semtech SX1276 errata note 2.1 584 | if self.low_frequency_mode: 585 | self._write_u8(0x36, 0x02) 586 | self._write_u8(0x3A, 0x7F) 587 | else: 588 | self._write_u8(0x36, 0x02) 589 | self._write_u8(0x3A, 0x64) 590 | else: 591 | # see Semtech SX1276 errata note 2.3 592 | self.auto_ifon = False 593 | self._write_u8(0x36, 0x03) 594 | if val == 7800: 595 | self._write_u8(0x2F, 0x48) 596 | elif val >= 62500: 597 | # see Semtech SX1276 errata note 2.3 598 | self._write_u8(0x2F, 0x40) 599 | else: 600 | self._write_u8(0x2F, 0x44) 601 | self._write_u8(0x30, 0) 602 | 603 | @property 604 | def coding_rate(self) -> Literal[5, 6, 7, 8]: 605 | """The coding rate used by the radio to control forward error 606 | correction (try setting to a higher value to increase tolerance of 607 | short bursts of interference or to a lower value to increase bit 608 | rate). Valid values are limited to 5, 6, 7, or 8.""" 609 | cr_id = (self._read_u8(_RH_RF95_REG_1D_MODEM_CONFIG1) & 0x0E) >> 1 610 | denominator = cr_id + 4 611 | return denominator 612 | 613 | @coding_rate.setter 614 | def coding_rate(self, val: Literal[5, 6, 7, 8]) -> None: 615 | # Set coding rate (set to 5 to match RadioHead Cr45). 616 | denominator = min(max(val, 5), 8) 617 | cr_id = denominator - 4 618 | self._write_u8( 619 | _RH_RF95_REG_1D_MODEM_CONFIG1, 620 | (self._read_u8(_RH_RF95_REG_1D_MODEM_CONFIG1) & 0xF1) | (cr_id << 1), 621 | ) 622 | 623 | @property 624 | def spreading_factor(self) -> Literal[6, 7, 8, 9, 10, 11, 12]: 625 | """The spreading factor used by the radio (try setting to a higher 626 | value to increase the receiver's ability to distinguish signal from 627 | noise or to a lower value to increase the data transmission rate). 628 | Valid values are limited to 6, 7, 8, 9, 10, 11, or 12.""" 629 | sf_id = (self._read_u8(_RH_RF95_REG_1E_MODEM_CONFIG2) & 0xF0) >> 4 630 | return sf_id 631 | 632 | @spreading_factor.setter 633 | def spreading_factor(self, val: Literal[6, 7, 8, 9, 10, 11, 12]) -> None: 634 | # Set spreading factor (set to 7 to match RadioHead Sf128). 635 | val = min(max(val, 6), 12) 636 | 637 | if val == 6: 638 | self.detection_optimize = 0x5 639 | else: 640 | self.detection_optimize = 0x3 641 | 642 | self._write_u8(_RH_RF95_DETECTION_THRESHOLD, 0x0C if val == 6 else 0x0A) 643 | self._write_u8( 644 | _RH_RF95_REG_1E_MODEM_CONFIG2, 645 | ( 646 | (self._read_u8(_RH_RF95_REG_1E_MODEM_CONFIG2) & 0x0F) 647 | | ((val << 4) & 0xF0) 648 | ), 649 | ) 650 | 651 | @property 652 | def enable_crc(self) -> bool: 653 | """Set to True to enable hardware CRC checking of incoming packets. 654 | Incoming packets that fail the CRC check are not processed. Set to 655 | False to disable CRC checking and process all incoming packets.""" 656 | return (self._read_u8(_RH_RF95_REG_1E_MODEM_CONFIG2) & 0x04) == 0x04 657 | 658 | @enable_crc.setter 659 | def enable_crc(self, val: bool) -> None: 660 | # Optionally enable CRC checking on incoming packets. 661 | if val: 662 | self._write_u8( 663 | _RH_RF95_REG_1E_MODEM_CONFIG2, 664 | self._read_u8(_RH_RF95_REG_1E_MODEM_CONFIG2) | 0x04, 665 | ) 666 | else: 667 | self._write_u8( 668 | _RH_RF95_REG_1E_MODEM_CONFIG2, 669 | self._read_u8(_RH_RF95_REG_1E_MODEM_CONFIG2) & 0xFB, 670 | ) 671 | 672 | def tx_done(self) -> bool: 673 | """Transmit status""" 674 | return (self._read_u8(_RH_RF95_REG_12_IRQ_FLAGS) & 0x8) >> 3 675 | 676 | def rx_done(self) -> bool: 677 | """Receive status""" 678 | return (self._read_u8(_RH_RF95_REG_12_IRQ_FLAGS) & 0x40) >> 6 679 | 680 | def crc_error(self) -> bool: 681 | """crc status""" 682 | return (self._read_u8(_RH_RF95_REG_12_IRQ_FLAGS) & 0x20) >> 5 683 | 684 | # pylint: disable=too-many-branches 685 | def send( 686 | self, 687 | data: ReadableBuffer, 688 | *, 689 | keep_listening: bool = False, 690 | destination: Optional[int] = None, 691 | node: Optional[int] = None, 692 | identifier: Optional[int] = None, 693 | flags: Optional[int] = None 694 | ) -> bool: 695 | """Send a string of data using the transmitter. 696 | You can only send 252 bytes at a time 697 | (limited by chip's FIFO size and appended headers). 698 | This appends a 4 byte header to be compatible with the RadioHead library. 699 | The header defaults to using the initialized attributes: 700 | (destination,node,identifier,flags) 701 | It may be temporarily overidden via the kwargs - destination,node,identifier,flags. 702 | Values passed via kwargs do not alter the attribute settings. 703 | The keep_listening argument should be set to True if you want to start listening 704 | automatically after the packet is sent. The default setting is False. 705 | 706 | Returns: True if success or False if the send timed out. 707 | """ 708 | # Disable pylint warning to not use length as a check for zero. 709 | # This is a puzzling warning as the below code is clearly the most 710 | # efficient and proper way to ensure a precondition that the provided 711 | # buffer be within an expected range of bounds. Disable this check. 712 | # pylint: disable=len-as-condition 713 | assert 0 < len(data) <= 252 714 | # pylint: enable=len-as-condition 715 | self.idle() # Stop receiving to clear FIFO and keep it clear. 716 | # Fill the FIFO with a packet to send. 717 | self._write_u8(_RH_RF95_REG_0D_FIFO_ADDR_PTR, 0x00) # FIFO starts at 0. 718 | # Combine header and data to form payload 719 | payload = bytearray(4) 720 | if destination is None: # use attribute 721 | payload[0] = self.destination 722 | else: # use kwarg 723 | payload[0] = destination 724 | if node is None: # use attribute 725 | payload[1] = self.node 726 | else: # use kwarg 727 | payload[1] = node 728 | if identifier is None: # use attribute 729 | payload[2] = self.identifier 730 | else: # use kwarg 731 | payload[2] = identifier 732 | if flags is None: # use attribute 733 | payload[3] = self.flags 734 | else: # use kwarg 735 | payload[3] = flags 736 | payload = payload + data 737 | # Write payload. 738 | self._write_from(_RH_RF95_REG_00_FIFO, payload) 739 | # Write payload and header length. 740 | self._write_u8(_RH_RF95_REG_22_PAYLOAD_LENGTH, len(payload)) 741 | # Turn on transmit mode to send out the packet. 742 | self.transmit() 743 | # Wait for tx done interrupt with explicit polling (not ideal but 744 | # best that can be done right now without interrupts). 745 | timed_out = False 746 | if HAS_SUPERVISOR: 747 | start = supervisor.ticks_ms() 748 | while not timed_out and not self.tx_done(): 749 | if ticks_diff(supervisor.ticks_ms(), start) >= self.xmit_timeout * 1000: 750 | timed_out = True 751 | else: 752 | start = time.monotonic() 753 | while not timed_out and not self.tx_done(): 754 | if time.monotonic() - start >= self.xmit_timeout: 755 | timed_out = True 756 | # Listen again if necessary and return the result packet. 757 | if keep_listening: 758 | self.listen() 759 | else: 760 | # Enter idle mode to stop receiving other packets. 761 | self.idle() 762 | # Clear interrupt. 763 | self._write_u8(_RH_RF95_REG_12_IRQ_FLAGS, 0xFF) 764 | return not timed_out 765 | 766 | def send_with_ack(self, data: ReadableBuffer) -> bool: 767 | """Reliable Datagram mode: 768 | Send a packet with data and wait for an ACK response. 769 | The packet header is automatically generated. 770 | If enabled, the packet transmission will be retried on failure 771 | """ 772 | if self.ack_retries: 773 | retries_remaining = self.ack_retries 774 | else: 775 | retries_remaining = 1 776 | got_ack = False 777 | self.sequence_number = (self.sequence_number + 1) & 0xFF 778 | while not got_ack and retries_remaining: 779 | self.identifier = self.sequence_number 780 | self.send(data, keep_listening=True) 781 | # Don't look for ACK from Broadcast message 782 | if self.destination == _RH_BROADCAST_ADDRESS: 783 | got_ack = True 784 | else: 785 | # wait for a packet from our destination 786 | ack_packet = self.receive(timeout=self.ack_wait, with_header=True) 787 | if ack_packet is not None: 788 | if ack_packet[3] & _RH_FLAGS_ACK: 789 | # check the ID 790 | if ack_packet[2] == self.identifier: 791 | got_ack = True 792 | break 793 | # pause before next retry -- random delay 794 | if not got_ack: 795 | # delay by random amount before next try 796 | time.sleep(self.ack_wait + self.ack_wait * random.random()) 797 | retries_remaining = retries_remaining - 1 798 | # set retry flag in packet header 799 | self.flags |= _RH_FLAGS_RETRY 800 | self.flags = 0 # clear flags 801 | return got_ack 802 | 803 | def receive( 804 | self, 805 | *, 806 | keep_listening: bool = True, 807 | with_header: bool = False, 808 | with_ack: bool = False, 809 | timeout: Optional[float] = None 810 | ) -> Optional[bytearray]: 811 | """Wait to receive a packet from the receiver. If a packet is found the payload bytes 812 | are returned, otherwise None is returned (which indicates the timeout elapsed with no 813 | reception). 814 | If keep_listening is True (the default) the chip will immediately enter listening mode 815 | after reception of a packet, otherwise it will fall back to idle mode and ignore any 816 | future reception. 817 | All packets must have a 4-byte header for compatibility with the 818 | RadioHead library. 819 | The header consists of 4 bytes (To,From,ID,Flags). The default setting will strip 820 | the header before returning the packet to the caller. 821 | If with_header is True then the 4 byte header will be returned with the packet. 822 | The payload then begins at packet[4]. 823 | If with_ack is True, send an ACK after receipt (Reliable Datagram mode) 824 | """ 825 | timed_out = False 826 | if timeout is None: 827 | timeout = self.receive_timeout 828 | if timeout is not None: 829 | # Wait for the payload_ready signal. This is not ideal and will 830 | # surely miss or overflow the FIFO when packets aren't read fast 831 | # enough, however it's the best that can be done from Python without 832 | # interrupt supports. 833 | # Make sure we are listening for packets. 834 | self.listen() 835 | timed_out = False 836 | if HAS_SUPERVISOR: 837 | start = supervisor.ticks_ms() 838 | while not timed_out and not self.rx_done(): 839 | if ticks_diff(supervisor.ticks_ms(), start) >= timeout * 1000: 840 | timed_out = True 841 | else: 842 | start = time.monotonic() 843 | while not timed_out and not self.rx_done(): 844 | if time.monotonic() - start >= timeout: 845 | timed_out = True 846 | # Payload ready is set, a packet is in the FIFO. 847 | packet = None 848 | # save last RSSI reading 849 | self.last_rssi = self.rssi 850 | 851 | # save the last SNR reading 852 | self.last_snr = self.snr 853 | 854 | # Enter idle mode to stop receiving other packets. 855 | self.idle() 856 | if not timed_out: 857 | if self.enable_crc and self.crc_error(): 858 | self.crc_error_count += 1 859 | else: 860 | # Read the data from the FIFO. 861 | # Read the length of the FIFO. 862 | fifo_length = self._read_u8(_RH_RF95_REG_13_RX_NB_BYTES) 863 | # Handle if the received packet is too small to include the 4 byte 864 | # RadioHead header and at least one byte of data --reject this packet and ignore it. 865 | if fifo_length > 0: # read and clear the FIFO if anything in it 866 | current_addr = self._read_u8(_RH_RF95_REG_10_FIFO_RX_CURRENT_ADDR) 867 | self._write_u8(_RH_RF95_REG_0D_FIFO_ADDR_PTR, current_addr) 868 | packet = bytearray(fifo_length) 869 | # Read the packet. 870 | self._read_into(_RH_RF95_REG_00_FIFO, packet) 871 | # Clear interrupt. 872 | self._write_u8(_RH_RF95_REG_12_IRQ_FLAGS, 0xFF) 873 | if fifo_length < 5: 874 | packet = None 875 | else: 876 | if ( 877 | self.node != _RH_BROADCAST_ADDRESS 878 | and packet[0] != _RH_BROADCAST_ADDRESS 879 | and packet[0] != self.node 880 | ): 881 | packet = None 882 | # send ACK unless this was an ACK or a broadcast 883 | elif ( 884 | with_ack 885 | and ((packet[3] & _RH_FLAGS_ACK) == 0) 886 | and (packet[0] != _RH_BROADCAST_ADDRESS) 887 | ): 888 | # delay before sending Ack to give receiver a chance to get ready 889 | if self.ack_delay is not None: 890 | time.sleep(self.ack_delay) 891 | # send ACK packet to sender (data is b'!') 892 | self.send( 893 | b"!", 894 | destination=packet[1], 895 | node=packet[0], 896 | identifier=packet[2], 897 | flags=(packet[3] | _RH_FLAGS_ACK), 898 | ) 899 | # reject Retries if we have seen this idetifier from this source before 900 | if (self.seen_ids[packet[1]] == packet[2]) and ( 901 | packet[3] & _RH_FLAGS_RETRY 902 | ): 903 | packet = None 904 | else: # save the packet identifier for this source 905 | self.seen_ids[packet[1]] = packet[2] 906 | if ( 907 | not with_header and packet is not None 908 | ): # skip the header if not wanted 909 | packet = packet[4:] 910 | # Listen again if necessary and return the result packet. 911 | if keep_listening: 912 | self.listen() 913 | else: 914 | # Enter idle mode to stop receiving other packets. 915 | self.idle() 916 | # Clear interrupt. 917 | self._write_u8(_RH_RF95_REG_12_IRQ_FLAGS, 0xFF) 918 | return packet 919 | -------------------------------------------------------------------------------- /PIR-sensor/python/motion.py: -------------------------------------------------------------------------------- 1 | from gpiozero import MotionSensor 2 | import time 3 | import signal 4 | import sys 5 | 6 | def close(signal, frame): 7 | sys.exit(0) 8 | 9 | signal.signal(signal.SIGINT, close) 10 | 11 | pir = MotionSensor(4) 12 | count = 0; 13 | 14 | while True: 15 | if pir.motion_detected: 16 | count += 1 17 | print "Motion detected: ", count 18 | time.sleep(1) 19 | -------------------------------------------------------------------------------- /PN532/python/rfid-save.py: -------------------------------------------------------------------------------- 1 | # Requires Adafruit_Python_PN532 2 | 3 | import binascii 4 | import sys 5 | import struct 6 | 7 | import Adafruit_PN532 as PN532 8 | 9 | # Hack to make code compatible with both Python 2 and 3 (since 3 moved 10 | # raw_input from a builtin to a different function, ugh). 11 | try: 12 | input = raw_input 13 | except NameError: 14 | pass 15 | 16 | # PN532 configuration for a Raspberry Pi GPIO: 17 | 18 | # GPIO 18, pin 12 19 | CS = 18 20 | # GPIO 23, pin 16 21 | MOSI = 23 22 | # GPIO 24, pin 18 23 | MISO = 24 24 | # GPIO 25, pin 22 25 | SCLK = 25 26 | 27 | # Configure the key to use for writing to the MiFare card. You probably don't 28 | # need to change this from the default below unless you know your card has a 29 | # different key associated with it. 30 | CARD_KEY = [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF] 31 | 32 | # Prefix, aka header from the card 33 | HEADER = b'BG' 34 | 35 | # Create and initialize an instance of the PN532 class. 36 | pn532 = PN532.PN532(cs=CS, sclk=SCLK, mosi=MOSI, miso=MISO) 37 | pn532.begin() 38 | pn532.SAM_configuration() 39 | 40 | # Step 1, wait for card to be present. 41 | print('PN532 NFC Module Writer') 42 | print('') 43 | print('== STEP 1 =========================') 44 | print('Place the card to be written on the PN532...') 45 | uid = pn532.read_passive_target() 46 | while uid is None: 47 | uid = pn532.read_passive_target() 48 | print('') 49 | print('Found card with UID: 0x{0}'.format(binascii.hexlify(uid))) 50 | print('') 51 | print('==============================================================') 52 | print('WARNING: DO NOT REMOVE CARD FROM PN532 UNTIL FINISHED WRITING!') 53 | print('==============================================================') 54 | print('') 55 | 56 | # Step 2, pick a block type. 57 | print('== STEP 2 =========================') 58 | block_choice = None 59 | while block_choice is None: 60 | print('') 61 | block_choice = input('Enter user ID: ') 62 | try: 63 | block_choice = int(block_choice) 64 | except ValueError: 65 | print('Error! Unrecognized option.') 66 | continue 67 | # Decimal value not greater than hex number with 6 digits 68 | if not (0 <= block_choice < 16777215): 69 | print('Error! User ID must be within 0 to 4294967295.') 70 | continue 71 | print('') 72 | print('You chose the block type: {0}'.format(block_choice)) 73 | print('') 74 | 75 | # Confirm writing the block type. 76 | print('== STEP 3 =========================') 77 | print('Confirm you are ready to write to the card:') 78 | print('User ID: {0}'.format(block_choice)) 79 | choice = input('Confirm card write (Y or N)? ') 80 | if choice.lower() != 'y' and choice.lower() != 'yes': 81 | print('Aborted!') 82 | sys.exit(0) 83 | print('Writing card (DO NOT REMOVE CARD FROM PN532)...') 84 | 85 | # Write the card! 86 | # First authenticate block 4. 87 | if not pn532.mifare_classic_authenticate_block(uid, 4, PN532.MIFARE_CMD_AUTH_B, 88 | CARD_KEY): 89 | print('Error! Failed to authenticate block 4 with the card.') 90 | sys.exit(-1) 91 | # Next build the data to write to the card. 92 | # Format is as follows: 93 | # - 2 bytes 0-1 store a header with ASCII value, for example 'BG' 94 | # - 6 bytes 2-7 store the user data, for example user ID 95 | data = bytearray(16) 96 | # Add header 97 | data[0:2] = HEADER 98 | # Convert int to hex string with up to 6 digits 99 | value = format(block_choice, 'x') 100 | while (6 > len(value)): 101 | value = '0' + value 102 | data[2:8] = value 103 | # Finally write the card. 104 | if not pn532.mifare_classic_write_block(4, data): 105 | print('Error! Failed to write to the card.') 106 | sys.exit(-1) 107 | print('Wrote card successfully! You may now remove the card from the PN532.') 108 | -------------------------------------------------------------------------------- /PN532/python/rfid-scan.py: -------------------------------------------------------------------------------- 1 | # Requires Adafruit_Python_PN532 2 | 3 | import binascii 4 | import socket 5 | import time 6 | import signal 7 | import sys 8 | 9 | import Adafruit_PN532 as PN532 10 | 11 | # PN532 configuration for a Raspberry Pi GPIO: 12 | 13 | # GPIO 18, pin 12 14 | CS = 18 15 | # GPIO 23, pin 16 16 | MOSI = 23 17 | # GPIO 24, pin 18 18 | MISO = 24 19 | # GPIO 25, pin 22 20 | SCLK = 25 21 | 22 | # Configure the key to use for writing to the MiFare card. You probably don't 23 | # need to change this from the default below unless you know your card has a 24 | # different key associated with it. 25 | CARD_KEY = [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF] 26 | 27 | # Number of seconds to delay after reading data. 28 | DELAY = 0.5 29 | 30 | # Prefix, aka header from the card 31 | HEADER = b'BG' 32 | 33 | def close(signal, frame): 34 | sys.exit(0) 35 | 36 | signal.signal(signal.SIGINT, close) 37 | 38 | # Create and initialize an instance of the PN532 class 39 | pn532 = PN532.PN532(cs=CS, sclk=SCLK, mosi=MOSI, miso=MISO) 40 | pn532.begin() 41 | pn532.SAM_configuration() 42 | 43 | print('PN532 NFC RFID 13.56MHz Card Reader') 44 | while True: 45 | # Wait for a card to be available 46 | uid = pn532.read_passive_target() 47 | # Try again if no card found 48 | if uid is None: 49 | continue 50 | # Found a card, now try to read block 4 to detect the block type 51 | print('') 52 | print('Card UID 0x{0}'.format(binascii.hexlify(uid))) 53 | # Authenticate and read block 4 54 | if not pn532.mifare_classic_authenticate_block(uid, 4, PN532.MIFARE_CMD_AUTH_B, 55 | CARD_KEY): 56 | print('Failed to authenticate with card!') 57 | continue 58 | data = pn532.mifare_classic_read_block(4) 59 | if data is None: 60 | print('Failed to read data from card!') 61 | continue 62 | # Check the header 63 | if data[0:2] != HEADER: 64 | print('Card is not written with proper block data!') 65 | continue 66 | # Parse out the block type and subtype 67 | print('User Id: {0}'.format(int(data[2:8].decode("utf-8"), 16))) 68 | time.sleep(DELAY); 69 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # rpi-examples 2 | 3 | This repository provides various examples for using peripheral devices such as sensors, buzzers, relays and add-on boards on Raspberry Pi single board computers written in popular programming languages C, C++, Python, etc. All examples are available under MIT license. 4 | 5 | These examples are appropriate for beginners. Hopefully, they will encourage more developers to join the Raspberry Pi community and to help them get started easily with various peripheral devices for both professional and hobby and DIY projects. 6 | 7 | # Videos 8 | 9 | * Buzzer: https://www.youtube.com/watch?v=j8HnKM58QXk 10 | * LM75A: https://www.youtube.com/watch?v=pyg27uj0Xns 11 | * HTU21D: https://www.youtube.com/watch?v=A_yruJtYUwE 12 | 13 | # Notes 14 | 15 | If you are interested in running any of the examples for I2C written in C/C++ as a regular user (not root) perform the following steps: 16 | * Remove line "wiringPiSetup();" in "HTU21D_test.c" 17 | * Add your user in "i2c" group 18 | 19 | ## Buzzer 20 | 21 | ### C 22 | 23 | #### Beep 24 | 25 | Simple application to test if a piezo buzzer attached to pin 11 is working. 26 | 27 | Install [wiringPi](http://wiringpi.com/download-and-install/) and after that execute the following command to build the application: 28 | 29 | ``` 30 | cd buzzer/c/ 31 | gcc beep.c -o beep -lwiringPi -std=c99 32 | ``` 33 | 34 | Execute the following command to run the application: 35 | ``` 36 | sudo ./beep 37 | ``` 38 | 39 | #### Star Wars 40 | 41 | Implementation of the Imperial March from Star Wars. 42 | 43 | Install [wiringPi](http://wiringpi.com/download-and-install/) and after that execute the following command to build the application: 44 | 45 | ``` 46 | cd buzzer/c/ 47 | gcc starwars.c -o starwars -lwiringPi -std=c99 48 | ``` 49 | 50 | Execute the following command to play the Imperial March: 51 | ``` 52 | sudo ./starwars 53 | ``` 54 | 55 | #### TSL2561 56 | 57 | Install i2c tools: 58 | ``` 59 | sudo apt-get install i2c-tools 60 | 61 | ``` 62 | 63 | Enable i2c on Raspberry Pi with Raspian GNU/Linux distribution: 64 | ``` 65 | sudo raspi-config 66 | ``` 67 | 68 | Go to Advanced Options > A7 I2C and reboot the board 69 | 70 | Verify that TSL2561 is detected on i2c address 39 on bus 1: 71 | ``` 72 | pi@raspberrypi:~ $ i2cdetect -y 1 73 | 0 1 2 3 4 5 6 7 8 9 a b c d e f 74 | 00: -- -- -- -- -- -- -- -- -- -- -- -- -- 75 | 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 76 | 20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 77 | 30: -- -- -- -- -- -- -- -- -- 39 -- -- -- -- -- -- 78 | 40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 79 | 50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 80 | 60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 81 | 70: -- -- -- -- -- -- -- -- 82 | ``` 83 | 84 | Build and run the source code 85 | ``` 86 | cd TSL2561/c/ 87 | make 88 | ./TSL2561_test 89 | ``` 90 | 91 | ## MAX44009 Ambient Light Sensor Module 92 | 93 | Build and run the source code 94 | ``` 95 | cd MAX44009/c/ 96 | make 97 | ./MAX44009_test 98 | ``` 99 | 100 | The example written in the C programming language has been cotributed by Pixel_K. 101 | 102 | ## PN532 NFC Module 103 | 104 | * Install Adafruit Python PN532: 105 | 106 | ``` 107 | sudo apt-get update 108 | sudo apt-get install build-essential python-dev git 109 | cd ~ 110 | git clone https://github.com/adafruit/Adafruit_Python_PN532.git 111 | cd Adafruit_Python_PN532 112 | sudo python setup.py install 113 | ``` 114 | 115 | * Clone rpi-examples: 116 | 117 | ``` 118 | cd ~ 119 | git clone https://github.com/leon-anavi/rpi-examples.git 120 | ``` 121 | 122 | * Save data to RFID/NFC card 123 | 124 | ``` 125 | cd ~/rpi-examples/PN532/python 126 | sudo python rfid-save.py 127 | ``` 128 | 129 | * Listen and scan for RFID/NFC cards 130 | 131 | ``` 132 | cd ~/rpi-examples/PN532/python 133 | sudo python rfid-scan.py 134 | ``` 135 | -------------------------------------------------------------------------------- /Ryanteck-RPi-Motor/c/.gitignore: -------------------------------------------------------------------------------- 1 | motor 2 | *.o 3 | -------------------------------------------------------------------------------- /Ryanteck-RPi-Motor/c/Makefile: -------------------------------------------------------------------------------- 1 | CC=gcc 2 | CFLAGS=-I. 3 | DEPS = 4 | OBJ = motor.o 5 | EXTRA_LIBS=-lwiringPi -lpthread 6 | 7 | %.o: %.c $(DEPS) 8 | $(CC) -c -o $@ $< $(CFLAGS) 9 | 10 | motor: $(OBJ) 11 | $(CC) -o $@ $^ $(CFLAGS) $(EXTRA_LIBS) 12 | 13 | .PHONY: clean 14 | 15 | clean: 16 | rm -f motor $(OBJ) 17 | -------------------------------------------------------------------------------- /Ryanteck-RPi-Motor/c/motor.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | const int speedMax = 200; 10 | 11 | // Motor 1 1st: GPIO 0, aka pin 11 12 | const int motor1pin1 = 0; 13 | // Motor 1 2nd: GPIO 1, aka pin 12 14 | const int motor1pin2 = 1; 15 | 16 | // Motor 2 1st: GPIO 3, aka pin 15 17 | const int motor2pin1 = 3; 18 | // Motor 2 2nd: GPIO 4, aka pin 16 19 | const int motor2pin2 = 4; 20 | 21 | void motor1(int pin1, int pin2) 22 | { 23 | digitalWrite(motor1pin1, pin1); 24 | digitalWrite(motor1pin2, pin2); 25 | } 26 | 27 | void motor2(int pin1, int pin2) 28 | { 29 | digitalWrite(motor2pin1, pin1); 30 | digitalWrite(motor2pin2, pin2); 31 | } 32 | 33 | void brake() 34 | { 35 | softPwmWrite(motor1pin1, 0); 36 | softPwmWrite(motor1pin2, 0); 37 | softPwmWrite(motor2pin1, 0); 38 | softPwmWrite(motor2pin2, 0); 39 | motor1(LOW, LOW); 40 | motor2(LOW, LOW); 41 | } 42 | 43 | void enablePWM(pin, speed) 44 | { 45 | if (0 != softPwmCreate(pin, 0, speed)) 46 | { 47 | printf("ERROR: Cannot enable software PWM for pin %d", pin); 48 | } 49 | } 50 | 51 | int init() 52 | { 53 | if (-1 == wiringPiSetup()) 54 | { 55 | printf("setup wiringPi failed!\n"); 56 | return 1; 57 | } 58 | 59 | signal(SIGINT, brake); 60 | 61 | // Set pin mode 62 | pinMode(motor1pin1, OUTPUT); 63 | pinMode(motor1pin2, OUTPUT); 64 | pinMode(motor2pin1, OUTPUT); 65 | pinMode(motor2pin2, OUTPUT); 66 | 67 | //Software PWM 68 | enablePWM(motor1pin1, speedMax); 69 | enablePWM(motor1pin2, speedMax); 70 | enablePWM(motor2pin1, speedMax); 71 | enablePWM(motor2pin2, speedMax); 72 | 73 | brake(); 74 | return 0; 75 | } 76 | 77 | void forward() 78 | { 79 | softPwmWrite(motor1pin1, 90); 80 | softPwmWrite(motor2pin1, 90); 81 | 82 | motor1(HIGH, LOW); 83 | motor2(HIGH, LOW); 84 | } 85 | 86 | void back(int speed) 87 | { 88 | softPwmWrite(motor1pin2, speed); 89 | softPwmWrite(motor2pin2, speed); 90 | 91 | motor1(LOW, HIGH); 92 | motor2(LOW, HIGH); 93 | } 94 | 95 | right(int speed) 96 | { 97 | softPwmWrite(motor1pin2, speed); 98 | softPwmWrite(motor2pin2, 0); 99 | 100 | motor1(LOW, HIGH); 101 | motor2(LOW, LOW); 102 | } 103 | 104 | left(int speed) 105 | { 106 | softPwmWrite(motor1pin2, 0); 107 | softPwmWrite(motor2pin2, speed); 108 | 109 | motor1(LOW, LOW); 110 | motor2(LOW, HIGH); 111 | } 112 | 113 | int main(int argc, char **argv) 114 | { 115 | char *direction = ""; 116 | opterr = 0; 117 | int argument = 0; 118 | int speed = 80; 119 | while ((argument = getopt (argc, argv, "d:s:")) != -1) 120 | { 121 | switch (argument) 122 | { 123 | case 'd': 124 | direction = optarg; 125 | break; 126 | 127 | case 's': 128 | speed = atoi(optarg); 129 | break; 130 | 131 | case '?': 132 | if (optopt == 'd') 133 | { 134 | fprintf (stderr, "Option -%c requires an argument: forward, back, stop, left or right.\n", optopt); 135 | } 136 | else if (isprint (optopt)) 137 | { 138 | fprintf (stderr, "Unknown option `-%c'.\n", optopt); 139 | } 140 | else 141 | { 142 | fprintf (stderr, 143 | "Unknown option character `\\x%x'.\n", 144 | optopt); 145 | } 146 | return 1; 147 | 148 | default: 149 | abort(); 150 | } 151 | } 152 | 153 | printf("Direction: %s Speed: %d\n", direction, speed); 154 | 155 | if (0 < init()) 156 | { 157 | return 1; 158 | } 159 | 160 | if (0 == strcmp(direction, "forward")) 161 | { 162 | printf("Moving forward...\n"); 163 | forward(speed); 164 | } 165 | else if (0 == strcmp(direction, "back")) 166 | { 167 | printf("Moving backward...\n"); 168 | back(speed); 169 | } 170 | else if (0 == strcmp(direction, "left")) 171 | { 172 | printf("Turning left...\n"); 173 | left(speed); 174 | } 175 | else if (0 == strcmp(direction, "right")) 176 | { 177 | printf("Turning right...\n"); 178 | right(speed); 179 | } 180 | else 181 | { 182 | printf("Unknown direction. Stopping...\n"); 183 | brake(); 184 | return 3; 185 | } 186 | sleep(1); 187 | brake(); 188 | return 0; 189 | } 190 | -------------------------------------------------------------------------------- /SN754410/c/motor.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | const int speedMax = 200; 10 | 11 | // Motor 1 1st: GPIO 0, aka pin 11 12 | const int motor1pin1 = 22; 13 | // Motor 1 2nd: GPIO 1, aka pin 12 14 | const int motor1pin2 = 23; 15 | 16 | // Motor 2 1st: GPIO 3, aka pin 15 17 | const int motor2pin1 = 24; 18 | // Motor 2 2nd: GPIO 4, aka pin 16 19 | const int motor2pin2 = 25; 20 | 21 | void motor1(int pin1, int pin2) 22 | { 23 | digitalWrite(motor1pin1, pin1); 24 | digitalWrite(motor1pin2, pin2); 25 | } 26 | 27 | void motor2(int pin1, int pin2) 28 | { 29 | digitalWrite(motor2pin1, pin1); 30 | digitalWrite(motor2pin2, pin2); 31 | } 32 | 33 | void brake() 34 | { 35 | softPwmWrite(motor1pin1, 0); 36 | softPwmWrite(motor1pin2, 0); 37 | softPwmWrite(motor2pin1, 0); 38 | softPwmWrite(motor2pin2, 0); 39 | motor1(LOW, LOW); 40 | motor2(LOW, LOW); 41 | } 42 | 43 | void enablePWM(pin, speed) 44 | { 45 | if (0 != softPwmCreate(pin, 0, speed)) 46 | { 47 | printf("ERROR: Cannot enable software PWM for pin %d", pin); 48 | } 49 | } 50 | 51 | int init() 52 | { 53 | if (-1 == wiringPiSetup()) 54 | { 55 | printf("setup wiringPi failed!\n"); 56 | return 1; 57 | } 58 | 59 | signal(SIGINT, brake); 60 | 61 | // Set pin mode 62 | pinMode(motor1pin1, OUTPUT); 63 | pinMode(motor1pin2, OUTPUT); 64 | pinMode(motor2pin1, OUTPUT); 65 | pinMode(motor2pin2, OUTPUT); 66 | 67 | //Software PWM 68 | enablePWM(motor1pin1, speedMax); 69 | enablePWM(motor1pin2, speedMax); 70 | enablePWM(motor2pin1, speedMax); 71 | enablePWM(motor2pin2, speedMax); 72 | 73 | brake(); 74 | return 0; 75 | } 76 | 77 | void forward(int speed) 78 | { 79 | softPwmWrite(motor1pin1, speed); 80 | softPwmWrite(motor2pin1, speed); 81 | 82 | motor1(HIGH, LOW); 83 | motor2(HIGH, LOW); 84 | } 85 | 86 | void back(int speed) 87 | { 88 | softPwmWrite(motor1pin2, speed); 89 | softPwmWrite(motor2pin2, speed); 90 | 91 | motor1(LOW, HIGH); 92 | motor2(LOW, HIGH); 93 | } 94 | 95 | right(int speed) 96 | { 97 | softPwmWrite(motor1pin2, speed); 98 | softPwmWrite(motor2pin2, 0); 99 | 100 | motor1(LOW, HIGH); 101 | motor2(LOW, LOW); 102 | } 103 | 104 | left(int speed) 105 | { 106 | softPwmWrite(motor1pin2, 0); 107 | softPwmWrite(motor2pin2, speed); 108 | 109 | motor1(LOW, LOW); 110 | motor2(LOW, HIGH); 111 | } 112 | 113 | int main(int argc, char **argv) 114 | { 115 | char *direction = ""; 116 | opterr = 0; 117 | int argument = 0; 118 | int speed = 80; 119 | while ((argument = getopt (argc, argv, "d:s:")) != -1) 120 | { 121 | switch (argument) 122 | { 123 | case 'd': 124 | direction = optarg; 125 | break; 126 | 127 | case 's': 128 | speed = atoi(optarg); 129 | break; 130 | 131 | case '?': 132 | if (optopt == 'd') 133 | { 134 | fprintf (stderr, "Option -%c requires an argument: forward, back, stop, left or right.\n", optopt); 135 | } 136 | else if (isprint (optopt)) 137 | { 138 | fprintf (stderr, "Unknown option `-%c'.\n", optopt); 139 | } 140 | else 141 | { 142 | fprintf (stderr, 143 | "Unknown option character `\\x%x'.\n", 144 | optopt); 145 | } 146 | return 1; 147 | 148 | default: 149 | abort(); 150 | } 151 | } 152 | 153 | printf("Direction: %s Speed: %d\n", direction, speed); 154 | 155 | if (0 < init()) 156 | { 157 | return 1; 158 | } 159 | 160 | if (0 == strcmp(direction, "forward")) 161 | { 162 | printf("Moving forward...\n"); 163 | forward(speed); 164 | } 165 | else if (0 == strcmp(direction, "back")) 166 | { 167 | printf("Moving backward...\n"); 168 | back(speed); 169 | } 170 | else if (0 == strcmp(direction, "left")) 171 | { 172 | printf("Turning left...\n"); 173 | left(speed); 174 | } 175 | else if (0 == strcmp(direction, "right")) 176 | { 177 | printf("Turning right...\n"); 178 | right(speed); 179 | } 180 | else 181 | { 182 | printf("Unknown direction. Stopping...\n"); 183 | brake(); 184 | return 3; 185 | } 186 | sleep(1); 187 | brake(); 188 | return 0; 189 | } 190 | -------------------------------------------------------------------------------- /SSD1306/FreePixel.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leon-anavi/rpi-examples/ff08e27d463a9871f067f0df4c248a268840432f/SSD1306/FreePixel.ttf -------------------------------------------------------------------------------- /SSD1306/ssd1306-demo.py: -------------------------------------------------------------------------------- 1 | # Install with: 2 | # sudo apt-get install -y python3-dev python3-pip libfreetype6-dev libjpeg-dev build-essential 3 | # sudo -H pip3 install --upgrade luma.oled 4 | # 5 | # Run with: 6 | # 7 | 8 | from luma.core.interface.serial import i2c 9 | from luma.core.render import canvas 10 | from luma.oled.device import ssd1306, ssd1325, ssd1331, sh1106 11 | import time 12 | from PIL import ImageFont, ImageDraw 13 | 14 | serial = i2c(port=1, address=0x3C) 15 | device = ssd1306(serial, rotate=0) 16 | 17 | # Box and text rendered in portrait mode 18 | with canvas(device) as draw: 19 | draw.rectangle(device.bounding_box, outline="white", fill="black") 20 | font = ImageFont.load_default() 21 | draw.text((10, 5), "Example", fill="white", font=font) 22 | draw.text((15, 25), "Hello", fill="white", font=font) 23 | font = ImageFont.truetype('./FreePixel.ttf', 20) 24 | draw.text((15, 35), "World", fill="white", font=font) 25 | input("Press Enter to exit...") 26 | -------------------------------------------------------------------------------- /TSL2561/c/example-wiringpi/.gitignore: -------------------------------------------------------------------------------- 1 | TSL2561 2 | *.o 3 | -------------------------------------------------------------------------------- /TSL2561/c/example-wiringpi/Makefile: -------------------------------------------------------------------------------- 1 | CC=gcc 2 | CFLAGS=-I. 3 | DEPS = 4 | OBJ = TSL2561.o 5 | EXTRA_LIBS=-lwiringPi 6 | 7 | %.o: %.c $(DEPS) 8 | $(CC) -c -o $@ $< $(CFLAGS) 9 | 10 | TSL2561: $(OBJ) 11 | $(CC) -o $@ $^ $(CFLAGS) $(EXTRA_LIBS) 12 | 13 | .PHONY: clean 14 | 15 | clean: 16 | rm -f TSL2561 $(OBJ) 17 | -------------------------------------------------------------------------------- /TSL2561/c/example-wiringpi/TSL2561.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | // ALL COMMAND TSL2561 8 | // Default I2C RPI address in (0x39) = FLOAT ADDR (Slave) Other [(0x49) = VCC ADDR / (0x29) = GROUND ADDR] 9 | #define TSL2561_ADDR_LOW (0x29) 10 | #define TSL2561_ADDR_FLOAT (0x39) 11 | #define TSL2561_ADDR_HIGH (0x49) 12 | #define TSL2561_CONTROL_POWERON (0x03) 13 | #define TSL2561_CONTROL_POWEROFF (0x00) 14 | #define TSL2561_GAIN_0X (0x00) //No gain 15 | #define TSL2561_GAIN_AUTO (0x01) 16 | #define TSL2561_GAIN_1X (0x02) 17 | #define TSL2561_GAIN_16X (0x12) // (0x10) 18 | #define TSL2561_INTEGRATIONTIME_13MS (0x00) // 13.7ms 19 | #define TSL2561_INTEGRATIONTIME_101MS (0x01) // 101ms 20 | #define TSL2561_INTEGRATIONTIME_402MS (0x02) // 402ms 21 | #define TSL2561_READBIT (0x01) 22 | #define TSL2561_COMMAND_BIT (0x80) //Must be 1 23 | #define TSL2561_CLEAR_BIT (0x40) //Clears any pending interrupt (write 1 to clear) 24 | #define TSL2561_WORD_BIT (0x20) // 1 = read/write word (rather than byte) 25 | #define TSL2561_BLOCK_BIT (0x10) // 1 = using block read/write 26 | #define TSL2561_REGISTER_CONTROL (0x00) 27 | #define TSL2561_REGISTER_TIMING (0x81) 28 | #define TSL2561_REGISTER_THRESHHOLDL_LOW (0x02) 29 | #define TSL2561_REGISTER_THRESHHOLDL_HIGH (0x03) 30 | #define TSL2561_REGISTER_THRESHHOLDH_LOW (0x04) 31 | #define TSL2561_REGISTER_THRESHHOLDH_HIGH (0x05) 32 | #define TSL2561_REGISTER_INTERRUPT (0x06) 33 | #define TSL2561_REGISTER_CRC (0x08) 34 | #define TSL2561_REGISTER_ID (0x0A) 35 | #define TSL2561_REGISTER_CHAN0_LOW (0x8C) 36 | #define TSL2561_REGISTER_CHAN0_HIGH (0x8D) 37 | #define TSL2561_REGISTER_CHAN1_LOW (0x8E) 38 | #define TSL2561_REGISTER_CHAN1_HIGH (0x8F) 39 | //Delay getLux function 40 | #define LUXDELAY 500 41 | 42 | int getLux(int fd){ 43 | // Enable the device 44 | wiringPiI2CWriteReg8(fd, TSL2561_COMMAND_BIT, TSL2561_CONTROL_POWERON); 45 | // Set timing (101 mSec) 46 | wiringPiI2CWriteReg8(fd, TSL2561_REGISTER_TIMING, TSL2561_GAIN_AUTO); 47 | //Wait for the conversion to complete 48 | delay(LUXDELAY); 49 | //Reads visible + IR diode from the I2C device auto 50 | uint16_t visible_and_ir = wiringPiI2CReadReg16(fd, TSL2561_REGISTER_CHAN0_LOW); 51 | // Disable the device 52 | wiringPiI2CWriteReg8(fd, TSL2561_COMMAND_BIT, TSL2561_CONTROL_POWEROFF); 53 | return visible_and_ir * 2; 54 | } 55 | 56 | void main(){ 57 | int fd = wiringPiI2CSetup(TSL2561_ADDR_FLOAT); 58 | printf("Lux: %d\n", getLux(fd)); 59 | } 60 | -------------------------------------------------------------------------------- /TSL2561/c/example/.gitignore: -------------------------------------------------------------------------------- 1 | TSL2561_test 2 | *.o 3 | -------------------------------------------------------------------------------- /TSL2561/c/example/Makefile: -------------------------------------------------------------------------------- 1 | CC=gcc 2 | CFLAGS=-I. 3 | DEPS = TSL2561.h 4 | OBJ = TSL2561.o TSL2561_test.o 5 | 6 | %.o: %.c $(DEPS) 7 | $(CC) -c -o $@ $< $(CFLAGS) 8 | 9 | TSL2561_test: $(OBJ) 10 | $(CC) -o $@ $^ $(CFLAGS) 11 | 12 | .PHONY: clean 13 | 14 | clean: 15 | rm -f TSL2561_test $(OBJ) 16 | -------------------------------------------------------------------------------- /TSL2561/c/example/TSL2561.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2014 Dino Ciuffetti 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include "TSL2561.h" 28 | 29 | /** 30 | * read two bytes from i2c bus getting a 16 bit unsigned integer 31 | */ 32 | static inline uint16_t tsl2561_read16(TSL2561 *sensor, uint8_t reg) { 33 | uint16_t x; 34 | 35 | if(sensor->adapter_fd == -1) { // not opened 36 | // TODO: choose a valid errno error 37 | sensor->lasterr = -1; 38 | return 0; 39 | } 40 | 41 | // ask for reading 42 | sensor->buf[0] = reg; 43 | if(write(sensor->adapter_fd, sensor->buf, 1) != 1) { 44 | sensor->lasterr = errno; 45 | return -1; 46 | } 47 | 48 | if(read(sensor->adapter_fd, sensor->buf, 2) != 2) { 49 | sensor->lasterr = errno; 50 | return 0; 51 | } 52 | 53 | //printf("x1: 0x%0x, x2: 0x%0x\n", sensor->buf[1], sensor->buf[0]); 54 | x = sensor->buf[1]; 55 | x <<= 8; 56 | x |= sensor->buf[0]; 57 | 58 | //printf("test: 0x%02x%02x: 0x%04x\n", sensor->buf[1], sensor->buf[0], x); 59 | 60 | return x; 61 | } 62 | /** 63 | * read one byte from i2c bus getting a 8 bit unsigned integer 64 | */ 65 | static inline uint8_t tsl2561_read8(TSL2561 *sensor, uint8_t reg) { 66 | uint8_t x; 67 | 68 | if(sensor->adapter_fd == -1) { // not opened 69 | // TODO: choose a valid errno error 70 | sensor->lasterr = -1; 71 | return 0; 72 | } 73 | 74 | // ask for reading 75 | sensor->buf[0] = reg; 76 | if(write(sensor->adapter_fd, sensor->buf, 1) != 1) { 77 | sensor->lasterr = errno; 78 | return -1; 79 | } 80 | 81 | if(read(sensor->adapter_fd, sensor->buf, 1) != 1) { 82 | sensor->lasterr = errno; 83 | return 0; 84 | } 85 | x = sensor->buf[0]; 86 | 87 | return x; 88 | } 89 | /** 90 | * write one byte to i2c bus getting 91 | */ 92 | static inline int tsl2561_write8(TSL2561 *sensor, uint8_t reg, uint32_t byte_value) { 93 | if(sensor->adapter_fd == -1) { // not opened 94 | // TODO: choose a valid errno error 95 | sensor->lasterr = -1; 96 | return -1; 97 | } 98 | 99 | // we mask with (& 0xFF) to get the last 8 bits from a 32 bit unsigned integer 100 | sensor->buf[0] = reg; 101 | sensor->buf[1] = (byte_value & 0xFF ); 102 | if(write(sensor->adapter_fd, sensor->buf, 2) != 2) { 103 | sensor->lasterr = errno; 104 | return -1; 105 | } 106 | return 0; 107 | } 108 | // TSL2561 Functions (inspired on Adafruit_TSL2561_U.cpp at https://github.com/adafruit/Adafruit_TSL2561) 109 | // wake up TSL2561 by setting the control bit 110 | static inline int TSL2561_ON(TSL2561 *sensor) { 111 | int rc; 112 | 113 | if(sensor->adapter_fd == -1) { // not opened 114 | // TODO: choose a valid errno error 115 | sensor->lasterr = -1; 116 | return -1; 117 | } 118 | 119 | rc = tsl2561_write8(sensor, TSL2561_COMMAND_BIT | TSL2561_REGISTER_CONTROL, TSL2561_CONTROL_POWERON); 120 | return rc; 121 | } 122 | // turn TSL2561 into power saving mode 123 | static inline int TSL2561_OFF(TSL2561 *sensor) { 124 | int rc; 125 | 126 | if(sensor->adapter_fd == -1) { // not opened 127 | // TODO: choose a valid errno error 128 | sensor->lasterr = -1; 129 | return -1; 130 | } 131 | 132 | rc = tsl2561_write8(sensor, TSL2561_COMMAND_BIT | TSL2561_REGISTER_CONTROL, TSL2561_CONTROL_POWEROFF); 133 | return rc; 134 | } 135 | // this is a private function that is used to get data from the sensor (infrared + full spectrum including infrared) 136 | static inline int tsl2561_getdata(TSL2561 *sensor, uint16_t *full_spectrum, uint16_t *infrared) { 137 | TSL2561_ON(sensor); 138 | // wait for the internal ADC to complete conversion 139 | switch(sensor->integration_time) { 140 | case TSL2561_INTEGRATIONTIME_13MS: 141 | usleep(20000); 142 | break; 143 | case TSL2561_INTEGRATIONTIME_101MS: 144 | usleep(150000); 145 | break; 146 | case TSL2561_INTEGRATIONTIME_402MS: 147 | usleep(450000); 148 | break; 149 | } 150 | //usleep(450000); 151 | // reads two bytes from channel 0 (full spectrum + infrared) 152 | //*full_spectrum = wiringPiI2CReadReg16(_fd, TSL2561_COMMAND_BIT | TSL2561_WORD_BIT | TSL2561_REGISTER_CHAN0_LOW); 153 | *full_spectrum = tsl2561_read16(sensor, TSL2561_COMMAND_BIT | TSL2561_WORD_BIT | TSL2561_REGISTER_CHAN0_LOW); 154 | //fprintf(stdout, "got 0x%04X for full spectrum light\n", *full_spectrum); 155 | 156 | // reads two bytes from channel 1 (infrared) 157 | //*infrared = wiringPiI2CReadReg16(_fd, TSL2561_COMMAND_BIT | TSL2561_WORD_BIT | TSL2561_REGISTER_CHAN1_LOW); 158 | *infrared = tsl2561_read16(sensor, TSL2561_COMMAND_BIT | TSL2561_WORD_BIT | TSL2561_REGISTER_CHAN1_LOW); 159 | //fprintf(stdout, "got 0x%04X for ir light\n", *infrared); 160 | 161 | // turn the device off to save power 162 | TSL2561_OFF(sensor); 163 | 164 | return 0; 165 | } 166 | /** 167 | * converts the raw sensor values to the standard SI lux equivalent. 168 | * returns 0 if the sensor is saturated and the values are unreliable. 169 | */ 170 | /**************************************************************************/ 171 | static uint32_t TSL2561_CALCULATE_LUX(TSL2561 *sensor, uint16_t broadband, uint16_t ir) { 172 | unsigned long chScale; 173 | unsigned long channel1; 174 | unsigned long channel0; 175 | uint16_t clipThreshold; 176 | unsigned long ratio1 = 0; 177 | unsigned long ratio; 178 | unsigned int b, m; 179 | unsigned long temp; 180 | uint32_t lux; 181 | 182 | // Make sure the sensor isn't saturated! 183 | switch (sensor->integration_time) { 184 | case TSL2561_INTEGRATIONTIME_13MS: 185 | clipThreshold = TSL2561_CLIPPING_13MS; 186 | break; 187 | case TSL2561_INTEGRATIONTIME_101MS: 188 | clipThreshold = TSL2561_CLIPPING_101MS; 189 | break; 190 | case TSL2561_INTEGRATIONTIME_402MS: 191 | clipThreshold = TSL2561_CLIPPING_402MS; 192 | break; 193 | default: 194 | clipThreshold = TSL2561_CLIPPING_402MS; 195 | break; 196 | } 197 | 198 | // return 0 lux if the sensor is saturated 199 | if ((broadband > clipThreshold) || (ir > clipThreshold)) { 200 | return 0; 201 | } 202 | 203 | // get the correct scale depending on the intergration time 204 | switch (sensor->integration_time) { 205 | case TSL2561_INTEGRATIONTIME_13MS: 206 | chScale = TSL2561_LUX_CHSCALE_TINT0; 207 | break; 208 | case TSL2561_INTEGRATIONTIME_101MS: 209 | chScale = TSL2561_LUX_CHSCALE_TINT1; 210 | break; 211 | case TSL2561_INTEGRATIONTIME_402MS: 212 | chScale = (1 << TSL2561_LUX_CHSCALE); 213 | break; 214 | default: /* No scaling ... integration time = 402ms */ 215 | chScale = (1 << TSL2561_LUX_CHSCALE); 216 | break; 217 | } 218 | 219 | // scale for gain (1x or 16x) 220 | if (!sensor->gain) chScale = chScale << 4; 221 | 222 | // scale the channel values 223 | channel0 = (broadband * chScale) >> TSL2561_LUX_CHSCALE; 224 | channel1 = (ir * chScale) >> TSL2561_LUX_CHSCALE; 225 | 226 | /* find the ratio of the channel values (Channel1/Channel0) */ 227 | if (channel0 != 0) ratio1 = (channel1 << (TSL2561_LUX_RATIOSCALE+1)) / channel0; 228 | 229 | // round the ratio value 230 | ratio = (ratio1 + 1) >> 1; 231 | 232 | #ifdef TSL2561_PACKAGE_CS 233 | if ((ratio >= 0) && (ratio <= TSL2561_LUX_K1C)) 234 | {b=TSL2561_LUX_B1C; m=TSL2561_LUX_M1C;} 235 | else if (ratio <= TSL2561_LUX_K2C) 236 | {b=TSL2561_LUX_B2C; m=TSL2561_LUX_M2C;} 237 | else if (ratio <= TSL2561_LUX_K3C) 238 | {b=TSL2561_LUX_B3C; m=TSL2561_LUX_M3C;} 239 | else if (ratio <= TSL2561_LUX_K4C) 240 | {b=TSL2561_LUX_B4C; m=TSL2561_LUX_M4C;} 241 | else if (ratio <= TSL2561_LUX_K5C) 242 | {b=TSL2561_LUX_B5C; m=TSL2561_LUX_M5C;} 243 | else if (ratio <= TSL2561_LUX_K6C) 244 | {b=TSL2561_LUX_B6C; m=TSL2561_LUX_M6C;} 245 | else if (ratio <= TSL2561_LUX_K7C) 246 | {b=TSL2561_LUX_B7C; m=TSL2561_LUX_M7C;} 247 | else if (ratio > TSL2561_LUX_K8C) 248 | {b=TSL2561_LUX_B8C; m=TSL2561_LUX_M8C;} 249 | #else 250 | if ((ratio >= 0) && (ratio <= TSL2561_LUX_K1T)) 251 | {b=TSL2561_LUX_B1T; m=TSL2561_LUX_M1T;} 252 | else if (ratio <= TSL2561_LUX_K2T) 253 | {b=TSL2561_LUX_B2T; m=TSL2561_LUX_M2T;} 254 | else if (ratio <= TSL2561_LUX_K3T) 255 | {b=TSL2561_LUX_B3T; m=TSL2561_LUX_M3T;} 256 | else if (ratio <= TSL2561_LUX_K4T) 257 | {b=TSL2561_LUX_B4T; m=TSL2561_LUX_M4T;} 258 | else if (ratio <= TSL2561_LUX_K5T) 259 | {b=TSL2561_LUX_B5T; m=TSL2561_LUX_M5T;} 260 | else if (ratio <= TSL2561_LUX_K6T) 261 | {b=TSL2561_LUX_B6T; m=TSL2561_LUX_M6T;} 262 | else if (ratio <= TSL2561_LUX_K7T) 263 | {b=TSL2561_LUX_B7T; m=TSL2561_LUX_M7T;} 264 | else if (ratio > TSL2561_LUX_K8T) 265 | {b=TSL2561_LUX_B8T; m=TSL2561_LUX_M8T;} 266 | #endif 267 | 268 | temp = ((channel0 * b) - (channel1 * m)); 269 | 270 | // do not allow negative lux value 271 | if (temp < 0) temp = 0; 272 | 273 | // round lsb (2^(LUX_SCALE-1)) 274 | temp += (1 << (TSL2561_LUX_LUXSCALE-1)); 275 | 276 | // strip off fractional portion 277 | lux = temp >> TSL2561_LUX_LUXSCALE; 278 | 279 | // Signal I2C had no errors */ 280 | return lux; 281 | } 282 | 283 | 284 | int TSL2561_SETINTEGRATIONTIME(TSL2561 *sensor, tsl2561IntegrationTime_t time) { 285 | int rc; 286 | 287 | if(sensor->adapter_fd == -1) { // not opened 288 | // TODO: choose a valid errno error 289 | sensor->lasterr = -1; 290 | return -1; 291 | } 292 | 293 | TSL2561_ON(sensor); 294 | rc = tsl2561_write8(sensor, TSL2561_COMMAND_BIT | TSL2561_REGISTER_TIMING, time | sensor->gain); 295 | TSL2561_OFF(sensor); 296 | if(rc == 0) { 297 | sensor->integration_time = time; 298 | //fprintf(stderr, "setting integration time: 0x%02x to 0x%02x\n", TSL2561_COMMAND_BIT | TSL2561_REGISTER_TIMING, time | sensor->gain); 299 | return 0; 300 | } else { 301 | //fprintf(stderr, "Error setting integration time: 0x%02x to 0x%02x\n", TSL2561_COMMAND_BIT | TSL2561_REGISTER_TIMING, time | sensor->gain); 302 | return -1; 303 | } 304 | return -1; 305 | } 306 | int TSL2561_SETGAIN(TSL2561 *sensor, tsl2561Gain_t gain) { 307 | int rc; 308 | 309 | if(sensor->adapter_fd == -1) { // not opened 310 | // TODO: choose a valid errno error 311 | sensor->lasterr = -1; 312 | return -1; 313 | } 314 | 315 | TSL2561_ON(sensor); 316 | rc = tsl2561_write8(sensor, TSL2561_COMMAND_BIT | TSL2561_REGISTER_TIMING, sensor->integration_time | gain); 317 | TSL2561_OFF(sensor); 318 | if(rc == 0) { 319 | sensor->gain = gain; 320 | //fprintf(stderr, "setting gain: 0x%02x to 0x%02x\n", TSL2561_COMMAND_BIT | TSL2561_REGISTER_TIMING, sensor->integration_time | gain); 321 | return 0; 322 | } else { 323 | //fprintf(stderr, "Error setting gain: 0x%02x to 0x%02x\n", TSL2561_COMMAND_BIT | TSL2561_REGISTER_TIMING, sensor->integration_time | gain); 324 | return -1; 325 | } 326 | return -1; 327 | } 328 | int TSL2561_OPEN(TSL2561 *sensor) { 329 | char filename[20]; 330 | 331 | if(sensor->adapter_fd != -1) { // already opened 332 | // TODO: choose a valid errno error 333 | sensor->lasterr = -1; 334 | return -1; 335 | } 336 | snprintf(filename, 20, "/dev/i2c-%d", sensor->adapter_nr); 337 | if ((sensor->adapter_fd = open(filename, O_RDWR)) < 0) { // open the device file (requests i2c-dev kernel module loaded) 338 | sensor->lasterr = errno; 339 | return -1; 340 | } 341 | 342 | if (ioctl(sensor->adapter_fd, I2C_SLAVE, sensor->sensor_addr) < 0) { // talk to the requested device 343 | sensor->lasterr = errno; 344 | close(sensor->adapter_fd); 345 | sensor->adapter_fd = -1; 346 | return -1; 347 | } 348 | 349 | TSL2561_SETINTEGRATIONTIME(sensor, TSL2561_INTEGRATIONTIME_402MS); 350 | TSL2561_SETGAIN(sensor, TSL2561_GAIN_16X); 351 | 352 | /* 353 | TSL2561_ON(sensor); 354 | tsl2561_write8(sensor, 0x81, 0x11); 355 | TSL2561_OFF(sensor); 356 | */ 357 | 358 | return 0; 359 | } 360 | void TSL2561_CLOSE(TSL2561 *sensor) { 361 | if(sensor->adapter_fd != -1) { 362 | close(sensor->adapter_fd); 363 | sensor->adapter_fd = -1; 364 | } 365 | } 366 | 367 | /** 368 | * sense the ambient light. Returns 0 on success, -1 on errors. 369 | * the parameter pointer fullspectrum is the quantity og light at full spectrum (including infrared) 370 | * the parameter pointer infrared is the quantity of infrared light 371 | * if autogain is 0 a single sensor reading is done with the gain and integration time previously selected by invoking 372 | * the TSL2561_SETINTEGRATIONTIME() and TSL2561_SETGAIN() functions. It autogain is 1 and automatic gain adjustment alghoritm is used 373 | */ 374 | int TSL2561_SENSELIGHT(TSL2561 *sensor, uint16_t *full_spectrum, uint16_t *infrared, uint32_t *lux, int autogain) { 375 | int rc=1; 376 | uint16_t fs, ir, hi, lo; 377 | //tsl2561Gain_t old_gain; 378 | 379 | if(sensor->adapter_fd == -1) { 380 | // TODO: choose a valid errno error 381 | sensor->lasterr = -1; 382 | return -1; 383 | } 384 | if (autogain == 0) { // autogain not requested. Executing a single sensor read 385 | rc = tsl2561_getdata(sensor, full_spectrum, infrared); 386 | *lux = TSL2561_CALCULATE_LUX(sensor, *full_spectrum, *infrared); 387 | return rc; 388 | } 389 | 390 | // autogain requested 391 | switch(sensor->integration_time) { 392 | case TSL2561_INTEGRATIONTIME_13MS: 393 | hi = TSL2561_AGC_THI_13MS; 394 | lo = TSL2561_AGC_TLO_13MS; 395 | break; 396 | case TSL2561_INTEGRATIONTIME_101MS: 397 | hi = TSL2561_AGC_THI_101MS; 398 | lo = TSL2561_AGC_TLO_101MS; 399 | break; 400 | case TSL2561_INTEGRATIONTIME_402MS: 401 | hi = TSL2561_AGC_THI_402MS; 402 | lo = TSL2561_AGC_TLO_402MS; 403 | break; 404 | default: 405 | hi = TSL2561_AGC_THI_402MS; 406 | lo = TSL2561_AGC_TLO_402MS; 407 | break; 408 | } 409 | 410 | // save the old gain 411 | //old_gain = sensor->gain; 412 | 413 | // try to adjust the gain 414 | rc = tsl2561_getdata(sensor, &fs, &ir); 415 | if(rc != 0) { 416 | return -1; // invalid read or sensor error 417 | } 418 | if ((fs < lo) && (sensor->gain == TSL2561_GAIN_1X)) { // light too low with this gain 419 | // raise the gain and redo the reading 420 | TSL2561_SETGAIN(sensor, TSL2561_GAIN_16X); 421 | //printf("gain raised\n"); 422 | rc = tsl2561_getdata(sensor, &fs, &ir); 423 | // restore the previous gain 424 | //TSL2561_SETGAIN(sensor, old_gain); 425 | if(rc != 0) { // invalid read or sensor error 426 | return -1; 427 | } else { 428 | // now consider the reading valid after being adjusted 429 | *full_spectrum = fs; 430 | *infrared = ir; 431 | *lux = TSL2561_CALCULATE_LUX(sensor, *full_spectrum, *infrared); 432 | return 0; 433 | } 434 | } 435 | if ((fs > hi) && (sensor->gain == TSL2561_GAIN_16X)) { // light too high with this gain 436 | // lower the gain and redo the reading 437 | TSL2561_SETGAIN(sensor, TSL2561_GAIN_1X); 438 | //printf("gain lowered\n"); 439 | rc = tsl2561_getdata(sensor, &fs, &ir); 440 | // restore the previous gain 441 | //TSL2561_SETGAIN(sensor, old_gain); 442 | if(rc != 0) { // invalid read or sensor error 443 | return -1; 444 | } else { 445 | // now consider the reading valid after being adjusted 446 | *full_spectrum = fs; 447 | *infrared = ir; 448 | *lux = TSL2561_CALCULATE_LUX(sensor, *full_spectrum, *infrared); 449 | return 0; 450 | } 451 | } 452 | 453 | // the reading was valid without gain adjustment (or chip limits encountered!) 454 | *full_spectrum = fs; 455 | *infrared = ir; 456 | *lux = TSL2561_CALCULATE_LUX(sensor, *full_spectrum, *infrared); 457 | return 0; 458 | } 459 | 460 | -------------------------------------------------------------------------------- /TSL2561/c/example/TSL2561.h: -------------------------------------------------------------------------------- 1 | /************************************************************************** 2 | * 3 | * @file TSL2561.h 4 | * @oldauthor K. Townsend (Adafruit Industries) 5 | * @newauthor Dino Ciuffetti 6 | * @date: 13/mar/2014 7 | * @modified Modified and redistributed according the license by Dino Ciuffetti 8 | * @section OLDLICENSE 9 | * 10 | * Software License Agreement (BSD License) 11 | * 12 | * Copyright (c) 2013, Adafruit Industries 13 | * All rights reserved. 14 | * 15 | * Redistribution and use in source and binary forms, with or without 16 | * modification, are permitted provided that the following conditions are met: 17 | * 1. Redistributions of source code must retain the above copyright 18 | * notice, this list of conditions and the following disclaimer. 19 | * 2. Redistributions in binary form must reproduce the above copyright 20 | * notice, this list of conditions and the following disclaimer in the 21 | * documentation and/or other materials provided with the distribution. 22 | * 3. Neither the name of the copyright holders nor the 23 | * names of its contributors may be used to endorse or promote products 24 | * derived from this software without specific prior written permission. 25 | * 26 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY 27 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 28 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 29 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY 30 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 31 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 32 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 33 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 35 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 | * 37 | * @section NEWLICENSE -- This software is redistributed as apache v2 license according to the old license 38 | * 39 | * Copyright 2014 Dino Ciuffetti 40 | * 41 | * Licensed under the Apache License, Version 2.0 (the "License"); 42 | * you may not use this file except in compliance with the License. 43 | * You may obtain a copy of the License at 44 | * 45 | * http://www.apache.org/licenses/LICENSE-2.0 46 | * 47 | * Unless required by applicable law or agreed to in writing, software 48 | * distributed under the License is distributed on an "AS IS" BASIS, 49 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 50 | * See the License for the specific language governing permissions and 51 | * limitations under the License. 52 | * 53 | **************************************************************************/ 54 | #ifndef _TSL2561_H_ 55 | #define _TSL2561_H_ 56 | 57 | #include 58 | #include 59 | #include 60 | 61 | #define TSL2561_VISIBLE 2 // channel 0 - channel 1 62 | #define TSL2561_INFRARED 1 // channel 1 63 | #define TSL2561_FULLSPECTRUM 0 // channel 0 64 | 65 | // I2C address options 66 | #define TSL2561_ADDR_LOW (0x29) 67 | #define TSL2561_ADDR_FLOAT (0x39) // Default address (pin left floating) 68 | #define TSL2561_ADDR_HIGH (0x49) 69 | 70 | // Lux calculations differ slightly for CS package 71 | //#define TSL2561_PACKAGE_CS 72 | #define TSL2561_PACKAGE_T_FN_CL 73 | 74 | #define TSL2561_COMMAND_BIT (0x80) // Must be 1 75 | #define TSL2561_CLEAR_BIT (0x40) // Clears any pending interrupt (write 1 to clear) 76 | #define TSL2561_WORD_BIT (0x20) // 1 = read/write word (rather than byte) 77 | #define TSL2561_BLOCK_BIT (0x10) // 1 = using block read/write 78 | 79 | #define TSL2561_CONTROL_POWERON (0x03) 80 | #define TSL2561_CONTROL_POWEROFF (0x00) 81 | 82 | #define TSL2561_LUX_LUXSCALE (14) // Scale by 2^14 83 | #define TSL2561_LUX_RATIOSCALE (9) // Scale ratio by 2^9 84 | #define TSL2561_LUX_CHSCALE (10) // Scale channel values by 2^10 85 | #define TSL2561_LUX_CHSCALE_TINT0 (0x7517) // 322/11 * 2^TSL2561_LUX_CHSCALE 86 | #define TSL2561_LUX_CHSCALE_TINT1 (0x0FE7) // 322/81 * 2^TSL2561_LUX_CHSCALE 87 | 88 | // T, FN and CL package values 89 | #define TSL2561_LUX_K1T (0x0040) // 0.125 * 2^RATIO_SCALE 90 | #define TSL2561_LUX_B1T (0x01f2) // 0.0304 * 2^LUX_SCALE 91 | #define TSL2561_LUX_M1T (0x01be) // 0.0272 * 2^LUX_SCALE 92 | #define TSL2561_LUX_K2T (0x0080) // 0.250 * 2^RATIO_SCALE 93 | #define TSL2561_LUX_B2T (0x0214) // 0.0325 * 2^LUX_SCALE 94 | #define TSL2561_LUX_M2T (0x02d1) // 0.0440 * 2^LUX_SCALE 95 | #define TSL2561_LUX_K3T (0x00c0) // 0.375 * 2^RATIO_SCALE 96 | #define TSL2561_LUX_B3T (0x023f) // 0.0351 * 2^LUX_SCALE 97 | #define TSL2561_LUX_M3T (0x037b) // 0.0544 * 2^LUX_SCALE 98 | #define TSL2561_LUX_K4T (0x0100) // 0.50 * 2^RATIO_SCALE 99 | #define TSL2561_LUX_B4T (0x0270) // 0.0381 * 2^LUX_SCALE 100 | #define TSL2561_LUX_M4T (0x03fe) // 0.0624 * 2^LUX_SCALE 101 | #define TSL2561_LUX_K5T (0x0138) // 0.61 * 2^RATIO_SCALE 102 | #define TSL2561_LUX_B5T (0x016f) // 0.0224 * 2^LUX_SCALE 103 | #define TSL2561_LUX_M5T (0x01fc) // 0.0310 * 2^LUX_SCALE 104 | #define TSL2561_LUX_K6T (0x019a) // 0.80 * 2^RATIO_SCALE 105 | #define TSL2561_LUX_B6T (0x00d2) // 0.0128 * 2^LUX_SCALE 106 | #define TSL2561_LUX_M6T (0x00fb) // 0.0153 * 2^LUX_SCALE 107 | #define TSL2561_LUX_K7T (0x029a) // 1.3 * 2^RATIO_SCALE 108 | #define TSL2561_LUX_B7T (0x0018) // 0.00146 * 2^LUX_SCALE 109 | #define TSL2561_LUX_M7T (0x0012) // 0.00112 * 2^LUX_SCALE 110 | #define TSL2561_LUX_K8T (0x029a) // 1.3 * 2^RATIO_SCALE 111 | #define TSL2561_LUX_B8T (0x0000) // 0.000 * 2^LUX_SCALE 112 | #define TSL2561_LUX_M8T (0x0000) // 0.000 * 2^LUX_SCALE 113 | 114 | // CS package values 115 | #define TSL2561_LUX_K1C (0x0043) // 0.130 * 2^RATIO_SCALE 116 | #define TSL2561_LUX_B1C (0x0204) // 0.0315 * 2^LUX_SCALE 117 | #define TSL2561_LUX_M1C (0x01ad) // 0.0262 * 2^LUX_SCALE 118 | #define TSL2561_LUX_K2C (0x0085) // 0.260 * 2^RATIO_SCALE 119 | #define TSL2561_LUX_B2C (0x0228) // 0.0337 * 2^LUX_SCALE 120 | #define TSL2561_LUX_M2C (0x02c1) // 0.0430 * 2^LUX_SCALE 121 | #define TSL2561_LUX_K3C (0x00c8) // 0.390 * 2^RATIO_SCALE 122 | #define TSL2561_LUX_B3C (0x0253) // 0.0363 * 2^LUX_SCALE 123 | #define TSL2561_LUX_M3C (0x0363) // 0.0529 * 2^LUX_SCALE 124 | #define TSL2561_LUX_K4C (0x010a) // 0.520 * 2^RATIO_SCALE 125 | #define TSL2561_LUX_B4C (0x0282) // 0.0392 * 2^LUX_SCALE 126 | #define TSL2561_LUX_M4C (0x03df) // 0.0605 * 2^LUX_SCALE 127 | #define TSL2561_LUX_K5C (0x014d) // 0.65 * 2^RATIO_SCALE 128 | #define TSL2561_LUX_B5C (0x0177) // 0.0229 * 2^LUX_SCALE 129 | #define TSL2561_LUX_M5C (0x01dd) // 0.0291 * 2^LUX_SCALE 130 | #define TSL2561_LUX_K6C (0x019a) // 0.80 * 2^RATIO_SCALE 131 | #define TSL2561_LUX_B6C (0x0101) // 0.0157 * 2^LUX_SCALE 132 | #define TSL2561_LUX_M6C (0x0127) // 0.0180 * 2^LUX_SCALE 133 | #define TSL2561_LUX_K7C (0x029a) // 1.3 * 2^RATIO_SCALE 134 | #define TSL2561_LUX_B7C (0x0037) // 0.00338 * 2^LUX_SCALE 135 | #define TSL2561_LUX_M7C (0x002b) // 0.00260 * 2^LUX_SCALE 136 | #define TSL2561_LUX_K8C (0x029a) // 1.3 * 2^RATIO_SCALE 137 | #define TSL2561_LUX_B8C (0x0000) // 0.000 * 2^LUX_SCALE 138 | #define TSL2561_LUX_M8C (0x0000) // 0.000 * 2^LUX_SCALE 139 | 140 | // Auto-gain thresholds 141 | #define TSL2561_AGC_THI_13MS (4850) // Max value at Ti 13ms = 5047 142 | #define TSL2561_AGC_TLO_13MS (100) 143 | #define TSL2561_AGC_THI_101MS (36000) // Max value at Ti 101ms = 37177 144 | #define TSL2561_AGC_TLO_101MS (200) 145 | #define TSL2561_AGC_THI_402MS (63000) // Max value at Ti 402ms = 65535 146 | #define TSL2561_AGC_TLO_402MS (500) 147 | 148 | // Clipping thresholds 149 | #define TSL2561_CLIPPING_13MS (4900) 150 | #define TSL2561_CLIPPING_101MS (37000) 151 | #define TSL2561_CLIPPING_402MS (65000) 152 | 153 | enum 154 | { 155 | TSL2561_REGISTER_CONTROL = 0x00, 156 | TSL2561_REGISTER_TIMING = 0x01, 157 | TSL2561_REGISTER_THRESHHOLDL_LOW = 0x02, 158 | TSL2561_REGISTER_THRESHHOLDL_HIGH = 0x03, 159 | TSL2561_REGISTER_THRESHHOLDH_LOW = 0x04, 160 | TSL2561_REGISTER_THRESHHOLDH_HIGH = 0x05, 161 | TSL2561_REGISTER_INTERRUPT = 0x06, 162 | TSL2561_REGISTER_CRC = 0x08, 163 | TSL2561_REGISTER_ID = 0x0A, 164 | TSL2561_REGISTER_CHAN0_LOW = 0x0C, 165 | TSL2561_REGISTER_CHAN0_HIGH = 0x0D, 166 | TSL2561_REGISTER_CHAN1_LOW = 0x0E, 167 | TSL2561_REGISTER_CHAN1_HIGH = 0x0F 168 | }; 169 | 170 | typedef enum 171 | { 172 | TSL2561_INTEGRATIONTIME_13MS = 0x00, // 13.7ms 173 | TSL2561_INTEGRATIONTIME_101MS = 0x01, // 101ms 174 | TSL2561_INTEGRATIONTIME_402MS = 0x02 // 402ms 175 | } tsl2561IntegrationTime_t; 176 | 177 | typedef enum 178 | { 179 | TSL2561_GAIN_1X = 0x00, // No gain 180 | TSL2561_GAIN_16X = 0x10, // 16x gain 181 | } tsl2561Gain_t; 182 | 183 | typedef struct TSL2561 184 | { 185 | int adapter_nr; 186 | tsl2561IntegrationTime_t integration_time; 187 | tsl2561Gain_t gain; 188 | int adapter_fd; 189 | uint8_t sensor_addr; 190 | int lasterr; 191 | uint8_t buf[10]; 192 | } TSL2561; 193 | 194 | 195 | /* INITIALIZATION FUNCTIONS AND MACRO */ 196 | /** 197 | * Prepare the sensor. 198 | * The first parameter is the raspberry pi i2c master controller attached to the TSL2561, the second is the i2c selection jumper. 199 | * The i2c selection address can be one of: TSL2561_ADDR_LOW, TSL2561_ADDR_FLOAT or TSL2561_ADDR_HIGH 200 | */ 201 | #define TSL2561_INIT(i2cadapter, lightaddr) { \ 202 | .adapter_nr = i2cadapter, \ 203 | .integration_time = TSL2561_INTEGRATIONTIME_402MS, \ 204 | .gain = TSL2561_GAIN_16X, \ 205 | .adapter_fd = -1, \ 206 | .sensor_addr = lightaddr, \ 207 | .lasterr = 0, \ 208 | .buf = {0} \ 209 | }; 210 | /** 211 | * Initialize the sensor. Returns 0 on success, -1 on errors. 212 | */ 213 | int TSL2561_OPEN(TSL2561 *sensor); 214 | /** 215 | * Close the sensor. 216 | */ 217 | void TSL2561_CLOSE(TSL2561 *sensor); 218 | /** 219 | * Set the integration time. Returns 0 on success, -1 on errors. 220 | * TSL2561_INTEGRATIONTIME_402MS or TSL2561_INTEGRATIONTIME_101MS or TSL2561_INTEGRATIONTIME_13MS 221 | * TSL2561_INTEGRATIONTIME_402MS is slower but more precise, TSL2561_INTEGRATIONTIME_13MS is very fast but not so precise 222 | */ 223 | int TSL2561_SETINTEGRATIONTIME(TSL2561 *sensor, tsl2561IntegrationTime_t time); 224 | /** 225 | * Set the gain. Returns 0 on success, -1 on errors. 226 | * It can be TSL2561_GAIN_1X or TSL2561_GAIN_16X 227 | * Use 16X gain to get more precision in dark ambients, or enable auto gain with TSL2561_SENSELIGHT() 228 | */ 229 | int TSL2561_SETGAIN(TSL2561 *sensor, tsl2561Gain_t gain); 230 | /** 231 | * Sense the ambient light. Returns 0 on success, -1 on errors. 232 | * the parameter pointer fullspectrum is the quantity og light at full spectrum (including infrared) 233 | * the parameter pointer infrared is the quantity of infrared light 234 | * if autogain is 0 a single sensor reading is done with the gain and integration time previously selected by invoking 235 | * the TSL2561_SETINTEGRATIONTIME() and TSL2561_SETGAIN() functions. It autogain is 1 and automatic gain adjustment alghoritm is used 236 | */ 237 | int TSL2561_SENSELIGHT(TSL2561 *sensor, uint16_t *full_spectrum, uint16_t *infrared, uint32_t *lux, int autogain); 238 | 239 | #endif 240 | -------------------------------------------------------------------------------- /TSL2561/c/example/TSL2561_test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "TSL2561.h" 4 | 5 | int main() { 6 | int rc; 7 | uint16_t broadband, ir; 8 | uint32_t lux=0; 9 | // prepare the sensor 10 | // (the first parameter is the raspberry pi i2c master controller attached to the TSL2561, the second is the i2c selection jumper) 11 | // The i2c selection address can be one of: TSL2561_ADDR_LOW, TSL2561_ADDR_FLOAT or TSL2561_ADDR_HIGH 12 | TSL2561 light1 = TSL2561_INIT(1, TSL2561_ADDR_FLOAT); 13 | 14 | // initialize the sensor 15 | rc = TSL2561_OPEN(&light1); 16 | if(rc != 0) { 17 | fprintf(stderr, "Error initializing TSL2561 sensor (%s). Check your i2c bus (es. i2cdetect)\n", strerror(light1.lasterr)); 18 | // you don't need to TSL2561_CLOSE() if TSL2561_OPEN() failed, but it's safe doing it. 19 | TSL2561_CLOSE(&light1); 20 | return 1; 21 | } 22 | 23 | // set the gain to 1X (it can be TSL2561_GAIN_1X or TSL2561_GAIN_16X) 24 | // use 16X gain to get more precision in dark ambients, or enable auto gain below 25 | rc = TSL2561_SETGAIN(&light1, TSL2561_GAIN_1X); 26 | 27 | // set the integration time 28 | // (TSL2561_INTEGRATIONTIME_402MS or TSL2561_INTEGRATIONTIME_101MS or TSL2561_INTEGRATIONTIME_13MS) 29 | // TSL2561_INTEGRATIONTIME_402MS is slower but more precise, TSL2561_INTEGRATIONTIME_13MS is very fast but not so precise 30 | rc = TSL2561_SETINTEGRATIONTIME(&light1, TSL2561_INTEGRATIONTIME_101MS); 31 | 32 | // sense the luminosity from the sensor (lux is the luminosity taken in "lux" measure units) 33 | // the last parameter can be 1 to enable library auto gain, or 0 to disable it 34 | rc = TSL2561_SENSELIGHT(&light1, &broadband, &ir, &lux, 1); 35 | printf("Test. RC: %i(%s), broadband: %i, ir: %i, lux: %i\n", rc, strerror(light1.lasterr), broadband, ir, lux); 36 | 37 | TSL2561_CLOSE(&light1); 38 | 39 | return 0; 40 | } 41 | -------------------------------------------------------------------------------- /buzzer/c/beep.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | //Pin 11 on Raspberry Pi corresponds to BCM GPIO 17 and wiringPi pin 0 5 | #define BeepPin 0 6 | 7 | int main(void) 8 | { 9 | if(-1 == wiringPiSetup()) 10 | { 11 | printf("setup wiringPi failed!"); 12 | return 1; 13 | } 14 | 15 | //Set GPIO pin 16 | pinMode(BeepPin, OUTPUT); 17 | 18 | //Play a sound until the user closes the app 19 | while(1) 20 | { 21 | digitalWrite(BeepPin, LOW); 22 | delay(2); 23 | digitalWrite(BeepPin, HIGH); 24 | delay(2); 25 | } 26 | 27 | return 0; 28 | } 29 | -------------------------------------------------------------------------------- /buzzer/c/starwars.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | //Pin 11 on Raspberry Pi corresponds to BCM GPIO 17 and wiringPi pin 0 5 | #define BeepPin 0 6 | 7 | //FREQUENCIES 8 | #define cL 129 9 | #define cLS 139 10 | #define dL 146 11 | #define dLS 156 12 | #define eL 163 13 | #define fL 173 14 | #define fLS 185 15 | #define gL 194 16 | #define gLS 207 17 | #define aL 219 18 | #define aLS 228 19 | #define bL 232 20 | 21 | #define c 261 22 | #define cS 277 23 | #define d 294 24 | #define dS 311 25 | #define e 329 26 | #define f 349 27 | #define fS 370 28 | #define g 391 29 | #define gS 415 30 | #define a 440 31 | #define aS 455 32 | #define b 466 33 | 34 | #define cH 523 35 | #define cHS 554 36 | #define dH 587 37 | #define dHS 622 38 | #define eH 659 39 | #define fH 698 40 | #define fHS 740 41 | #define gH 784 42 | #define gHS 830 43 | #define aH 880 44 | #define aHS 910 45 | #define bH 933 46 | 47 | //This function generates the square wave that makes the piezo speaker sound at a determinated frequency. 48 | void beep(unsigned int note, unsigned int duration) 49 | { 50 | //This is the semiperiod of each note. 51 | long beepDelay = (long)(1000000/note); 52 | //This is how much time we need to spend on the note. 53 | long time = (long)((duration*1000)/(beepDelay*2)); 54 | for (int i=0;i\x02p\x00\x00\x0c\x00\x06`\x000\x00\x00\x0c\x00\x06`\x000\x00\x00\x0c\x10\x03\xc0\x08\x10\x00\x00\x0e\x0c\x03\xc000\x00\x00\x0c\x03\x01\x80\xc00\x00\x00\x06\x00\xc1\x83\x00`\x00\x00\x06\x00c\xc6\x00`\x00\x00\x03\x003\xec\x00\xc0\x00\x00\x03\x00\x0f\xf0\x00\xc0\x00\x00\x01\x80\x0f\xf0\x01\x80\x00\x00\x00\xe0\x1f\xf8\x07\x00\x00\x00\x00|\x7f\xfe\x1e\x00\x00\x00\x00?\xff\xff\xfc\x00\x00\x00\x00?\xf0\x0f\xfc\x00\x00\x00\x00p`\x04\x1e\x00\x00\x00\x00\xc0\xc0\x02\x07\x00\x00\x00\x01\x81\xc0\x03\x03\x80\x00\x00\x01\x03\xe0\x07\x81\x80\x00\x00\x01\x07\xf0\x0f\xc1\x80\x00\x00\x03\x0f\xff\xff\xf1\xc0\x00\x00\x03>\x0f\xf08\xc0\x00\x00\x03\xf8\x07\xc0\x1e\xc0\x00\x00\x03\xf0\x03\xc0\x0f\xc0\x00\x00\x0f\xf0\x03\xc0\x0f\xf0\x00\x00\x1c\xe0\x01\x80\x068\x00\x00\x18\xe0\x01\x80\x06\x18\x00\x00\x18\xe0\x01\xc0\x02\x18\x00\x000\xc0\x03\xc0\x02\x1c\x00\x000\xe0\x03\xc0\x06\x0c\x00\x000\xe0\x07\xe0\x06\x0c\x00\x000\xe0\x07\xf0\x0f\x0c\x00\x000\xf0\x0f\xf8\x0f\x1c\x00\x001\xf88\x1e?\x1c\x00\x00\x19\xff\xf0\x07\xff\xb8\x00\x00\x1f\xff\xe0\x07\xf8\xf8\x00\x00\x0f\x1f\xc0\x03\xf0\xf0\x00\x00\x0e\x07\xc0\x03\xc0p\x00\x00\x06\x03\xc0\x03\x80`\x00\x00\x06\x01\xc0\x03\x80`\x00\x00\x06\x01\xc0\x03\x00`\x00\x00\x06\x00\xc0\x03\x00`\x00\x00\x03\x00\xe0\x07\x00\xc0\x00\x00\x03\x00\xf0\x0e\x00\xc0\x00\x00\x01\x80\xfc>\x01\x80\x00\x00\x00\xc0\xff\xfe\x03\x00\x00\x00\x00q\xff\xff\x0e\x00\x00\x00\x00?\xe0\x07\xfc\x00\x00\x00\x00\x0f\xc0\x03\xf0\x00\x00\x00\x00\x03\xc0\x03\xc0\x00\x00\x00\x00\x01\xe0\x07\x80\x00\x00\x00\x00\x00p\x1e\x00\x00\x00\x00\x00\x00>x\x00\x00\x00\x00\x00\x00\x0f\xe0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') 8 | fb = framebuf.FrameBuffer(TH,64,64, framebuf.MONO_HLSB) 9 | oled.fill(0) 10 | oled.blit(fb,32,0) 11 | oled.show() --------------------------------------------------------------------------------