diff --git a/.github/workflows/add_issue_to_project.yml b/.github/workflows/add_issue_to_project.yml new file mode 100644 index 0000000..6b60cc3 --- /dev/null +++ b/.github/workflows/add_issue_to_project.yml @@ -0,0 +1,18 @@ +name: Add new issue to our main project + +on: + issues: + types: + - opened + +jobs: + add-to-project: + name: Add issue to project + runs-on: ubuntu-latest + steps: + - uses: actions/add-to-project@main + with: + # You can target a project in a different organization + # to the issue + project-url: https://github.com/orgs/sparkfun/projects/19 + github-token: ${{ secrets.DEFECT_ADD_TO_PROJECT }} diff --git a/README.md b/README.md index fed3d77..7abf646 100644 --- a/README.md +++ b/README.md @@ -19,8 +19,8 @@ Documentation -------------- * **[Installing an Arduino Library Guide](https://learn.sparkfun.com/tutorials/installing-an-arduino-library)** - Basic information on how to install an Arduino library. -* **[Hookup Guide](https://docs.sparkfun.com/SparkFun_IoT_Brushless_Motor_Driver)** - Basic hookup guide for the SparkFun IoT Motor Driver Breakout (ESP32, TMC6300). -* **[Product Repository](https://github.com/sparkfun/SparkFun_IoT_Brushless_Motor_Driver)** - Main repository for the IoT Motor Driver (including hardware files) +* **[Hookup Guide](https://docs.sparkfun.com/SparkFun_Qwiic_Human_Presence_Sensor-STHS34PF80/introduction/)** - Basic hookup guide for the SparkFun Qwiic STHS34PF80. +* **[Product Repository](https://github.com/sparkfun/SparkFun_Qwiic_Human_Presence_Sensor-STHS34PF80)** - Main repository for the SparkFun Qwiic STHS34PF80 (including hardware files) Products that use this Library diff --git a/examples/Example1_BasicReadings/Example1_BasicReadings.ino b/examples/Example1_BasicReadings/Example1_BasicReadings.ino index de71b2e..857d18d 100644 --- a/examples/Example1_BasicReadings/Example1_BasicReadings.ino +++ b/examples/Example1_BasicReadings/Example1_BasicReadings.ino @@ -1,3 +1,49 @@ +/****************************************************************************** + Example1_BasicReadings.ino + + Read human presence detection values from the STHS34PF80 sensor, print them + to terminal. Prints raw IR presence (cm^-1), if motion was detected, and + temperature in degrees C. + + SparkFun STHS34PF80 Arduino Library + Madison Chodikov @ SparkFun Electronics + Original Creation Date: September 19th, 2023 + https://github.com/sparkfun/SparkFun_STHS34PF80_Arduino_Library + + Development environment specifics: + + IDE: Arduino 2.2.1 + Hardware Platform: SparkFun RedBoard Qwiic + SparkFun Human Presence and Motion Sensor - STHS34PF80 (Qwiic) Version: 1.0 + SparkFun Qwiic Mini Human Presence and Motion Sensor - STHS34PF80 Version: 1.0 + + Do you like this library? Help support SparkFun. Buy a board! + + SparkFun Human Presence and Motion Sensor - STHS34PF80 (Qwiic) + https://www.sparkfun.com/products/22494 + + SparkFun Qwiic Mini Human Presence and Motion Sensor - STHS34PF80 + https://www.sparkfun.com/products/23253 + + Hardware Connections: + Use a Qwiic cable to connect from the RedBoard Qwiic to the STHS34PF80 breakout (QWIIC). + You can also choose to wire up the connections using the header pins like so: + + ARDUINO --> STHS34PF80 + SDA (A4) --> SDA + SCL (A5) --> SCL + 3.3V --> 3.3V + GND --> GND + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +******************************************************************************/ + #include "SparkFun_STHS34PF80_Arduino_Library.h" #include @@ -15,14 +61,10 @@ void setup() Serial.println("STHS34PF80 Example 1: Basic Readings"); // Begin I2C - if(Wire.begin() == 0) - { - Serial.println("I2C Error - check I2C Address"); - while(1); - } + Wire.begin() // Establish communication with device - if(mySensor.begin() != 0) + if(mySensor.begin() == false) { Serial.println("Error setting up device - please check wiring."); while(1); diff --git a/examples/Example2_Interrupts/Example2_Interrupts.ino b/examples/Example2_Interrupts/Example2_Interrupts.ino index ef2167b..9026d1d 100644 --- a/examples/Example2_Interrupts/Example2_Interrupts.ino +++ b/examples/Example2_Interrupts/Example2_Interrupts.ino @@ -1,3 +1,50 @@ +/****************************************************************************** + Example2_Interrupts.ino + + Read human presence detection value from the STHS34PF80 sensor, print them + to terminal using the interrupt flag instead of the typical data ready flag. + Prints raw IR presence values (cm^-1). + + SparkFun STHS34PF80 Arduino Library + Madison Chodikov @ SparkFun Electronics + Original Creation Date: September 19th, 2023 + https://github.com/sparkfun/SparkFun_STHS34PF80_Arduino_Library + + Development environment specifics: + + IDE: Arduino 2.2.1 + Hardware Platform: SparkFun RedBoard Qwiic + SparkFun Human Presence and Motion Sensor - STHS34PF80 (Qwiic) Version: 1.0 + SparkFun Qwiic Mini Human Presence and Motion Sensor - STHS34PF80 Version: 1.0 + + Do you like this library? Help support SparkFun. Buy a board! + + SparkFun Human Presence and Motion Sensor - STHS34PF80 (Qwiic) + https://www.sparkfun.com/products/22494 + + SparkFun Qwiic Mini Human Presence and Motion Sensor - STHS34PF80 + https://www.sparkfun.com/products/23253 + + Hardware Connections: + Use a Qwiic cable to connect from the RedBoard Qwiic to the STHS34PF80 breakout (QWIIC). + You can also choose to wire up the connections using the header pins like so: + + ARDUINO --> STHS34PF80 + SDA (A4) --> SDA + SCL (A5) --> SCL + INT (2) --> INT + 3.3V --> 3.3V + GND --> GND + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +******************************************************************************/ + #include "SparkFun_STHS34PF80_Arduino_Library.h" #include @@ -7,7 +54,7 @@ STHS34PF80_I2C mySensor; int16_t presenceVal = 0; // Change the pin number to the pin that has been chosen for your setup -int intPin = 12; +int intPin = 2; // Star the flag as false bool volatile interruptFlag = false; @@ -24,14 +71,10 @@ void setup() Serial.println("STHS34PF80 Example 2: Interrupts"); // Begin I2C - if(Wire.begin() == 0) - { - Serial.println("I2C Error - check I2C Address"); - while(1); - } + Wire.begin() // Establish communication with device - if(mySensor.begin() != 0) + if(mySensor.begin() == false) { Serial.println("Error setting up device - please check wiring."); while(1); diff --git a/examples/Example3_EmbeddedFunctions/Example3_EmbeddedFunctions.ino b/examples/Example3_EmbeddedFunctions/Example3_EmbeddedFunctions.ino index 88fa295..e1fa9b8 100644 --- a/examples/Example3_EmbeddedFunctions/Example3_EmbeddedFunctions.ino +++ b/examples/Example3_EmbeddedFunctions/Example3_EmbeddedFunctions.ino @@ -1,3 +1,49 @@ +/****************************************************************************** + Example3_EmbeddedFunctions.ino + + Set the hysteresis values for the presence and motion detection, read human + presence detection values from the STHS34PF80 sensor, print them to terminal. + Prints raw IR presence (cm^-1) and if motion was detected. + + SparkFun STHS34PF80 Arduino Library + Madison Chodikov @ SparkFun Electronics + Original Creation Date: September 19th, 2023 + https://github.com/sparkfun/SparkFun_STHS34PF80_Arduino_Library + + Development environment specifics: + + IDE: Arduino 2.2.1 + Hardware Platform: SparkFun RedBoard Qwiic + SparkFun Human Presence and Motion Sensor - STHS34PF80 (Qwiic) Version: 1.0 + SparkFun Qwiic Mini Human Presence and Motion Sensor - STHS34PF80 Version: 1.0 + + Do you like this library? Help support SparkFun. Buy a board! + + SparkFun Human Presence and Motion Sensor - STHS34PF80 (Qwiic) + https://www.sparkfun.com/products/22494 + + SparkFun Qwiic Mini Human Presence and Motion Sensor - STHS34PF80 + https://www.sparkfun.com/products/23253 + + Hardware Connections: + Use a Qwiic cable to connect from the RedBoard Qwiic to the STHS34PF80 breakout (QWIIC). + You can also choose to wire up the connections using the header pins like so: + + ARDUINO --> STHS34PF80 + SDA (A4) --> SDA + SCL (A5) --> SCL + 3.3V --> 3.3V + GND --> GND + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +******************************************************************************/ + #include "SparkFun_STHS34PF80_Arduino_Library.h" #include @@ -16,14 +62,10 @@ void setup() Serial.println("STHS34PF80 Example 3: Using Embedded Functions"); // Begin I2C - if(Wire.begin() == 0) - { - Serial.println("I2C Error - check I2C Address"); - while(1); - } + Wire.begin() // Establish communication with device - if(mySensor.begin() != 0) + if(mySensor.begin() == false) { Serial.println("Error setting up device - please check wiring."); while(1); diff --git a/examples/Example4_SPIFunctionality/Example4_SPIFunctionality.ino b/examples/Example4_SPIFunctionality/Example4_SPIFunctionality.ino index 63aebc2..92bb700 100644 --- a/examples/Example4_SPIFunctionality/Example4_SPIFunctionality.ino +++ b/examples/Example4_SPIFunctionality/Example4_SPIFunctionality.ino @@ -1,3 +1,51 @@ +/****************************************************************************** + Example4_SPIFunctionality.ino + + Read human presence detection values from the STHS34PF80 sensor, print them + to terminal using SPI communication instead of I2C. + Prints raw IR presence (cm^-1), if motion was detected, and temperature + in degrees C. + + SparkFun STHS34PF80 Arduino Library + Madison Chodikov @ SparkFun Electronics + Original Creation Date: September 19th, 2023 + https://github.com/sparkfun/SparkFun_STHS34PF80_Arduino_Library + + Development environment specifics: + + IDE: Arduino 2.2.1 + Hardware Platform: SparkFun RedBoard Qwiic + SparkFun Human Presence and Motion Sensor - STHS34PF80 (Qwiic) Version: 1.0 + SparkFun Qwiic Mini Human Presence and Motion Sensor - STHS34PF80 Version: 1.0 + + Do you like this library? Help support SparkFun. Buy a board! + + SparkFun Human Presence and Motion Sensor - STHS34PF80 (Qwiic) + https://www.sparkfun.com/products/22494 + + SparkFun Qwiic Mini Human Presence and Motion Sensor - STHS34PF80 + https://www.sparkfun.com/products/23253 + + Hardware Connections: + Wire the SPI Connections from the RedBoard Qwiic to the STHS34PF80 Breakout + with a resistive divider using the header pins like so: + + ARDUINO --> STHS34PF80 + SCK/SCL (13) --> Clock + SDI/SDA (12) --> Data in + !CS (10) --> Chip Select + 3.3V --> 3.3V + GND --> GND + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +******************************************************************************/ + #include "SparkFun_STHS34PF80_Arduino_Library.h" #include @@ -8,7 +56,7 @@ int16_t presenceVal = 0; float temperatureVal = 0; // Set your chip select pin according to your setup -uint8_t chipSelect = 12; +uint8_t chipSelect = 10; void setup() { @@ -23,7 +71,7 @@ void setup() SPI.begin(); // Establish communication with device - if(mySensor.begin(chipSelect) != 0) + if(mySensor.begin(chipSelect) == false) { Serial.println("Error setting up device - please check wiring."); while(1); @@ -36,7 +84,6 @@ void loop() { sths34pf80_tmos_drdy_status_t dataReady; mySensor.getDataReady(&dataReady); - Serial.println(dataReady.drdy); // Check whether sensor has new data - run through loop if data is ready if(dataReady.drdy == 1) diff --git a/examples/Example5_ArduinoPlotterOutput/Example5_ArduinoPlotterOutput.ino b/examples/Example5_ArduinoPlotterOutput/Example5_ArduinoPlotterOutput.ino index 8b56397..2958c18 100644 --- a/examples/Example5_ArduinoPlotterOutput/Example5_ArduinoPlotterOutput.ino +++ b/examples/Example5_ArduinoPlotterOutput/Example5_ArduinoPlotterOutput.ino @@ -1,3 +1,49 @@ +/****************************************************************************** + Example5_ArduinoPlotterOutput.ino + + Read human presence detection values from the STHS34PF80 sensor, print them + to Arduino Serial Plotter. + Prints raw IR presence values (cm^-1). + + SparkFun STHS34PF80 Arduino Library + Madison Chodikov @ SparkFun Electronics + Original Creation Date: September 19th, 2023 + https://github.com/sparkfun/SparkFun_STHS34PF80_Arduino_Library + + Development environment specifics: + + IDE: Arduino 2.2.1 + Hardware Platform: SparkFun RedBoard Qwiic + SparkFun Human Presence and Motion Sensor - STHS34PF80 (Qwiic) Version: 1.0 + SparkFun Qwiic Mini Human Presence and Motion Sensor - STHS34PF80 Version: 1.0 + + Do you like this library? Help support SparkFun. Buy a board! + + SparkFun Human Presence and Motion Sensor - STHS34PF80 (Qwiic) + https://www.sparkfun.com/products/22494 + + SparkFun Qwiic Mini Human Presence and Motion Sensor - STHS34PF80 + https://www.sparkfun.com/products/23253 + + Hardware Connections: + Use a Qwiic cable to connect from the RedBoard Qwiic to the STHS34PF80 breakout (QWIIC). + You can also choose to wire up the connections using the header pins like so: + + ARDUINO --> STHS34PF80 + SDA (A4) --> SDA + SCL (A5) --> SCL + 3.3V --> 3.3V + GND --> GND + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +******************************************************************************/ + #include "SparkFun_STHS34PF80_Arduino_Library.h" #include @@ -12,14 +58,10 @@ void setup() Serial.println("STHS34PF80 Example 5: Arduino Serial Plotter Output"); // Begin I2C - if(Wire.begin() == 0) - { - Serial.println("I2C Error - check I2C Address"); - while(1); - } + Wire.begin() // Establish communication with device - if(mySensor.begin() != 0) + if(mySensor.begin() == false) { Serial.println("Error setting up device - please check wiring."); while(1); diff --git a/library.properties b/library.properties index 69ef2f0..54c6b36 100644 --- a/library.properties +++ b/library.properties @@ -1,9 +1,9 @@ name=SparkFun STHS34PF80 Arduino Library -version=1.0.0 +version=1.0.4 author=SparkFun Electronics maintainer=SparkFun Electronics sentence=A library to drive the STMicroelectronics infrared sensor STHS34PF80. paragraph=The STHS34PF80 is a low-power, high-sensitivity infrared sensor for presence and motion detection. category=Sensors url=https://github.com/sparkfun/SparkFun_STHS34PF80_Arduino_Library -architectures=* \ No newline at end of file +architectures=* diff --git a/src/SparkFun_STHS34PF80_Arduino_Library.cpp b/src/SparkFun_STHS34PF80_Arduino_Library.cpp index a6f9e56..4091fd9 100644 --- a/src/SparkFun_STHS34PF80_Arduino_Library.cpp +++ b/src/SparkFun_STHS34PF80_Arduino_Library.cpp @@ -1,30 +1,28 @@ #include "SparkFun_STHS34PF80_Arduino_Library.h" -int32_t STHS34PF80_I2C::begin(uint8_t devAddr, TwoWire& wirePort) + +bool STHS34PF80_I2C::begin(uint8_t devAddr, TwoWire& wirePort) { - bus.init(devAddr, Wire); + _i2cBus.init(wirePort, false); sensor.read_reg = STHS34PF80_I2C::read; sensor.write_reg = STHS34PF80_I2C::write; sensor.mdelay = STHS34PF80_I2C::delayMS; - sensor.handle = &bus; + sensor.handle = this; + deviceAddress = devAddr; - STHS34PF80::begin(); + // call super class begin -- it returns 0 on no error + return STHS34PF80::begin() == 0; - return 0; // returns error code here } -int32_t STHS34PF80_I2C::read(void* bus, uint8_t addr, uint8_t* data, uint16_t numData) +int32_t STHS34PF80_I2C::read(void* device, uint8_t addr, uint8_t* data, uint16_t numData) { - ((SFE_BusI2C*) bus)->readRegs(addr, data, numData); - - return 0; // returns error code here + return ((STHS34PF80_I2C*)device)->_i2cBus.readRegisterRegion(((STHS34PF80_I2C*)device)->deviceAddress, addr, data, numData); } -int32_t STHS34PF80_I2C::write(void* bus, uint8_t addr, const uint8_t* data, uint16_t numData) +int32_t STHS34PF80_I2C::write(void* device, uint8_t addr, const uint8_t* data, uint16_t numData) { - ((SFE_BusI2C*) bus)->writeRegs(addr, data, numData); - - return 0; // returns error code here + return ((STHS34PF80_I2C*)device)->_i2cBus.writeRegisterRegion(((STHS34PF80_I2C*)device)->deviceAddress, addr, data, numData); } void STHS34PF80_I2C::delayMS(uint32_t millisec) @@ -32,27 +30,28 @@ void STHS34PF80_I2C::delayMS(uint32_t millisec) delay(millisec); } -int32_t STHS34PF80_SPI::begin(uint8_t chipSelect, SPIClass &spiPort) +bool STHS34PF80_SPI::begin(uint8_t chipSelect, SPIClass &spiPort) { - bus.init(chipSelect, spiPort, false); + SPISettings spiSettings = SPISettings(3000000, MSBFIRST, SPI_MODE0); + _spiBus.init(spiPort, spiSettings, chipSelect); sensor.read_reg = STHS34PF80_SPI::read; sensor.write_reg = STHS34PF80_SPI::write; sensor.mdelay = STHS34PF80_SPI::delayMS; - sensor.handle = &bus; + sensor.handle = this; - STHS34PF80::begin(); + // call super class begin -- it returns 0 on no error + return STHS34PF80::begin() == 0; - return 0; // returns error code here } -int32_t STHS34PF80_SPI::read(void* bus, uint8_t addr, uint8_t* data, uint16_t numData) +int32_t STHS34PF80_SPI::read(void* device, uint8_t addr, uint8_t* data, uint16_t numData) { - return ((SFE_BusSPI*) bus)->readRegisterRegion(0, data, numData); + return ((STHS34PF80_SPI*)device)->_spiBus.readRegisterRegion(0, addr, data, numData); } -int32_t STHS34PF80_SPI::write(void* bus, uint8_t addr, const uint8_t* data, uint16_t numData) +int32_t STHS34PF80_SPI::write(void* device, uint8_t addr, const uint8_t* data, uint16_t numData) { - return ((SFE_BusSPI*) bus)->writeRegisterRegion(0, data, numData); + return ((STHS34PF80_SPI*)device)->_spiBus.writeRegisterRegion(0, addr, data, numData); } void STHS34PF80_SPI::delayMS(uint32_t millisec) diff --git a/src/SparkFun_STHS34PF80_Arduino_Library.h b/src/SparkFun_STHS34PF80_Arduino_Library.h index a6f0cb3..704cf03 100644 --- a/src/SparkFun_STHS34PF80_Arduino_Library.h +++ b/src/SparkFun_STHS34PF80_Arduino_Library.h @@ -19,7 +19,7 @@ Distributed as-is; no warranty is given. #include "sths34pf80_class.h" -#include "SFE_Bus.h" +#include "sfe_bus.h" #include #include #include @@ -28,25 +28,26 @@ Distributed as-is; no warranty is given. class STHS34PF80_I2C : public STHS34PF80 { public: - int32_t begin(uint8_t devAddr = STHS34PF80_I2C_ADD >> 1, TwoWire& wirePort = Wire); + bool begin(uint8_t devAddr = STHS34PF80_I2C_ADDRESS, TwoWire& wirePort = Wire); static int32_t read(void *, uint8_t, uint8_t *, uint16_t); static int32_t write(void *, uint8_t, const uint8_t *, uint16_t); static void delayMS(uint32_t millisec); private: - SFE_BusI2C bus; + sfe_STHS34PF80::QwI2C _i2cBus; + uint8_t deviceAddress; }; class STHS34PF80_SPI : public STHS34PF80 { public: - int32_t begin(uint8_t chipSelect, SPIClass &spiPort=SPI); + bool begin(uint8_t chipSelect, SPIClass &spiPort=SPI); static int32_t read(void *, uint8_t, uint8_t *, uint16_t); static int32_t write(void *, uint8_t, const uint8_t *, uint16_t); static void delayMS(uint32_t millisec); private: - SFE_BusSPI bus; + sfe_STHS34PF80::SfeSPI _spiBus; }; diff --git a/src/sfe_bus.cpp b/src/sfe_bus.cpp index 8e0bf62..5ac3f69 100644 --- a/src/sfe_bus.cpp +++ b/src/sfe_bus.cpp @@ -1,163 +1,389 @@ +// sfe_bus.cpp +// +// This is a library written for SparkFun Human Presence Sensor STHS34PF80 +// (Qwiic) +// +// SparkFun sells these boards at its website: www.sparkfun.com +// +// Do you like this library? Help support SparkFun. Buy a board! +// +// SparkFun Human Presence Sensor STHS34PF80 (Qwiic) +// https://www.sparkfun.com/products/22494 +// +// Written by Madison Chodikov @ SparkFun Electronics, October 2023 +// +// Repository: +// https://github.com/sparkfun/SparkFun_STHS34PF80_Arduino_Library/tree/main +// +// +// SparkFun code, firmware, and software is released under the MIT +// License(http://opensource.org/licenses/MIT). +// +// SPDX-License-Identifier: MIT +// +// The MIT License (MIT) +// +// Copyright (c) 2022 SparkFun Electronics +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: The +// above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED +// "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT +// NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +// The following classes specify the behavior for communicating +// over the respective data buses: Inter-Integrated Circuit (I2C) +// and Serial Peripheral Interface (SPI). For ease of implementation +// an abstract interface (QwIDeviceBus) is used. + #include "sfe_bus.h" +#include + +#define kMaxTransferBuffer 32 +#define SPI_READ 0x80 + +// What we use for transfer chunk size +const static uint16_t kChunkSize = kMaxTransferBuffer; -/// @brief Constructor -/// @param addr Address of the device -/// @param port Wire port chosen to be used for I2C transactions -/// @return Error code -int32_t SFE_BusI2C::init(uint8_t addr, TwoWire& port) +////////////////////////////////////////////////////////////////////////////////////////////////// +// Constructor +// + +namespace sfe_STHS34PF80 { - devAddr = addr; - devPort = &port; - return 0; +QwI2C::QwI2C(void) : _i2cPort{nullptr} +{ } -/// @brief Reads a register at the requested address for the requested -/// number of bytes. -/// @param regAddress Register address -/// @param dataBuffer Data buffer -/// @param numBytes Number of bytes requested from register address -/// @return Error code (true for success, ) -int32_t SFE_BusI2C::readRegs(uint8_t regAddress, uint8_t* dataBuffer, uint8_t numBytes) +////////////////////////////////////////////////////////////////////////////////////////////////// +// I2C init() +// +// Methods to init/setup this device. The caller can provide a Wire Port, or +// this class will use the default + +bool QwI2C::init(TwoWire &wirePort, bool bInit) { - // Jump to desired register address - devPort->beginTransmission(devAddr); - devPort->write(regAddress); - if(devPort->endTransmission()) + + // if we don't have a wire port already + if (!_i2cPort) { - return 0; + _i2cPort = &wirePort; + + if (bInit) + _i2cPort->begin(); } - // Read bytes from these registers - devPort->requestFrom(devAddr, numBytes); + return true; +} - // Store all requested bytes - for(uint32_t i = 0; i < numBytes && devPort->available(); i++) - { - dataBuffer[i] = devPort->read(); - } +////////////////////////////////////////////////////////////////////////////////////////////////// +// I2C init() +// +// Methods to init/setup this device. The caller can provide a Wire Port, or +// this class will use the default +bool QwI2C::init() +{ + if (!_i2cPort) + return init(Wire); + else + return false; +} - return 0; +////////////////////////////////////////////////////////////////////////////////////////////////// +// ping() +// +// Is a device connected? +bool QwI2C::ping(uint8_t i2c_address) +{ + + if (!_i2cPort) + return false; + + _i2cPort->beginTransmission(i2c_address); + return _i2cPort->endTransmission() == 0; } -/// @brief Writes to the devices register -/// @param regAddress Register address -/// @param dataBuffer Data buffer -/// @param numBytes Number of bytes requested from register address -/// @return Error code (false for error, true for success) -int32_t SFE_BusI2C::writeRegs(uint8_t regAddress, const uint8_t* dataBuffer, uint8_t numBytes) +////////////////////////////////////////////////////////////////////////////////////////////////// +// writeRegisterByte() +// +// Write a byte to a register + +bool QwI2C::writeRegisterByte(uint8_t i2c_address, uint8_t offset, uint8_t dataToWrite) { - // Begin transmission - devPort->beginTransmission(devAddr); - // Write the address - devPort->write(regAddress); - - // Write all the data - for(uint32_t i = 0; i < numBytes; i++) - { - devPort->write(dataBuffer[i]); - } + if (!_i2cPort) + return false; - // End transmission - if(devPort->endTransmission()) - { + _i2cPort->beginTransmission(i2c_address); + _i2cPort->write(offset); + _i2cPort->write(dataToWrite); + return _i2cPort->endTransmission() == 0; +} + +////////////////////////////////////////////////////////////////////////////////////////////////// +// writeRegisterRegion() +// +// Write a block of data to a device. + +int QwI2C::writeRegisterRegion(uint8_t i2c_address, uint8_t offset, const uint8_t *data, uint16_t length) +{ + + _i2cPort->beginTransmission(i2c_address); + _i2cPort->write(offset); + _i2cPort->write(data, (int)length); + + return _i2cPort->endTransmission() ? -1 : 0; // -1 = error, 0 = success +} + +int QwI2C::writeRegisterRegion(uint8_t i2c_address, uint8_t offset, uint8_t data, uint16_t length) +{ + + _i2cPort->beginTransmission(i2c_address); + _i2cPort->write(offset); + _i2cPort->write(data); + + return _i2cPort->endTransmission() ? -1 : 0; // -1 = error, 0 = success +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////// +// readRegisterRegion() +// +// Reads a block of data from an i2c register on the devices. +// +// For large buffers, the data is chuncked over KMaxI2CBufferLength at a time +// +// +int QwI2C::readRegisterRegion(uint8_t addr, uint8_t reg, uint8_t *data, uint16_t numBytes) +{ + uint8_t nChunk; + uint16_t nReturned; + + if (!_i2cPort) return -1; - } - return 0; + int i; // counter in loop + bool bFirstInter = true; // Flag for first iteration - used to send register + + while (numBytes > 0) + { + _i2cPort->beginTransmission(addr); + + if (bFirstInter) + { + _i2cPort->write(reg); + bFirstInter = false; + } + + if (_i2cPort->endTransmission() != 0) + return -1; // error with the end transmission + + // We're chunking in data - keeping the max chunk to kMaxI2CBufferLength + nChunk = numBytes > kChunkSize ? kChunkSize : numBytes; + + nReturned = _i2cPort->requestFrom((int)addr, (int)nChunk, (int)true); + + // No data returned, no dice + if (nReturned == 0) + return -1; // error + + // Copy the retrieved data chunk to the current index in the data segment + for (i = 0; i < nReturned; i++) + { + *data++ = _i2cPort->read(); + } + + // Decrement the amount of data recieved from the overall data request + // amount + numBytes = numBytes - nReturned; + + } // end while + + return 0; // Success } +////////////////////////////////////////////////////////////////////////////////////////////////// +// Constructor +// + +SfeSPI::SfeSPI(void) : _spiPort{nullptr} +{ +} -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ SPI Functions ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +//////////////////////////////////////////////////////////////////////////////////////////////// +// SPI init() +// +// Methods to init/setup this device. The caller can provide a SPI Port, or this +// class will use the default -/// @brief This function containts the methods to init/setup this device. The caller can provide -/// a SPI port, or this class will use the default. -/// @param spiPort SPI port chosen by user -/// @param ismSPISettings SPI settings for every transaction -/// @param cs Chip Select Pin -/// @param bInit True or false for initialization -/// @return Error code -int32_t SFE_BusSPI::init(uint8_t cs, SPIClass& spiPort, bool bInit) +bool SfeSPI::init(SPIClass &spiPort, SPISettings &sthsSPISettings, uint8_t cs, bool bInit) { + // if we don't have a SPI port already - if( !_spiPort ) + if (!_spiPort) { _spiPort = &spiPort; - if( bInit ) + if (bInit) _spiPort->begin(); } - // SPI settings are needed for every transaction - _sfeSPISettings = SPISettings(1000000, MSBFIRST, SPI_MODE0); + // SPI settings are needed for every transaction + _sfeSPISettings = sthsSPISettings; - // The chip select pin can vary from platform to platform and project to project - // and so it must be given by the user. - if( !cs ) - return -1; - - _cs = cs; + // The chip select pin can vary from platform to platform and project to + // project and so it must be given by the user. + if (!cs) + return false; - return 0; + _cs = cs; + + return true; } -/// @brief This function writes a block of data to a device -/// @param i2c_address Address to write to -/// @param offset Offset of register -/// @param data Data to write to register -/// @param length Length of data to be written to register -/// @return Error code -int32_t SFE_BusSPI::writeRegisterRegion(uint8_t offset, const uint8_t *data, uint16_t length) +//////////////////////////////////////////////////////////////////////////////////////////////// +// SPI init() +// +// Methods to init/setup this device. The caller can provide a SPI Port, or this +// class will use the default +bool SfeSPI::init(uint8_t cs, bool bInit) { - int i; - // Apply settings + // If the transaction settings are not provided by the user they are built + // here. + SPISettings spiSettings = SPISettings(3000000, MSBFIRST, SPI_MODE0); + + // In addition of the port is not provided by the user, it defaults to SPI + // here. + return init(SPI, spiSettings, cs, bInit); +} + +////////////////////////////////////////////////////////////////////////////////////////////////// +// ping() +// +// Is a device connected? The SPI ping is not relevant but is defined here to +// keep consistency with I2C class i.e. provided for the interface. +// + +bool SfeSPI::ping(uint8_t i2c_address) +{ + return true; +} + +////////////////////////////////////////////////////////////////////////////////////////////////// +// writeRegisterByte() +// +// Write a byte to a register + +bool SfeSPI::writeRegisterByte(uint8_t i2c_address, uint8_t offset, uint8_t dataToWrite) +{ + + if (!_spiPort) + return false; + + // Apply settings _spiPort->beginTransaction(_sfeSPISettings); - // Signal communication start - digitalWrite(_cs, LOW); + // Signal communication start + digitalWrite(_cs, LOW); + _spiPort->transfer(offset); + _spiPort->transfer(dataToWrite); + + // End communcation + digitalWrite(_cs, HIGH); + _spiPort->endTransaction(); + + return true; +} - for(i = 0; i < length; i++) - { - _spiPort->transfer(*data++); - } +////////////////////////////////////////////////////////////////////////////////////////////////// +// writeRegisterRegion() +// +// Write a block of data to a device. - // End communication - digitalWrite(_cs, HIGH); +int SfeSPI::writeRegisterRegion(uint8_t i2c_address, uint8_t offset, const uint8_t *data, uint16_t length) +{ + + int i; + + // Apply settings + _spiPort->beginTransaction(_sfeSPISettings); + // Signal communication start + digitalWrite(_cs, LOW); + + for (i = 0; i < length; i++) + { + // Increment Address (Device does not do this when using SPI) + _spiPort->transfer(offset + i); + _spiPort->transfer(*data++); + } + + // End communication + digitalWrite(_cs, HIGH); _spiPort->endTransaction(); - return 0; + return 0; } -/// @brief This function reads a block of data from the register on the device. -/// @param addr Address chosing to read from -/// @param reg Register -/// @param data Data to be filled -/// @param numBytes Number of bytes to read from -/// @return Returns the data from the register desired to read from. -int32_t SFE_BusSPI::readRegisterRegion(uint8_t reg, uint8_t *data, uint16_t numBytes) +int SfeSPI::writeRegisterRegion(uint8_t i2c_address, uint8_t offset, uint8_t data, uint16_t length) +{ + + // Apply settings + _spiPort->beginTransaction(_sfeSPISettings); + // Signal communication start + digitalWrite(_cs, LOW); + + // ENS160 expects bits [7:1] to be the address and the leading + // bit to be a "zero" for a write. + _spiPort->transfer(offset << 1); + _spiPort->transfer(data); + + // End communication + digitalWrite(_cs, HIGH); + _spiPort->endTransaction(); + return 0; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////// +// readRegisterRegion() +// +// Reads a block of data from the register on the device. +// +// +// + +int SfeSPI::readRegisterRegion(uint8_t addr, uint8_t reg, uint8_t *data, uint16_t numBytes) { if (!_spiPort) return -1; int i; // counter in loop - - // Apply settings + // Apply settings _spiPort->beginTransaction(_sfeSPISettings); - // Signal communication start - digitalWrite(_cs, LOW); - // A leading "1" must be added to transfer with register to indicate a "read" - reg = (reg | SPI_READ); + // Signal communication start + digitalWrite(_cs, LOW); + + // ENS160 expects bits [7:1] to be the address and the leading + // bit to be a "one" for a read. + reg = (reg | SPI_READ); _spiPort->transfer(reg); - for(i = 0; i < numBytes; i++) - { - *data++ = _spiPort->transfer(0x00); - } + for (i = 0; i < numBytes; i++) + { + *data++ = _spiPort->transfer(0x00); + } - // End transaction - digitalWrite(_cs, HIGH); + // End transaction + digitalWrite(_cs, HIGH); _spiPort->endTransaction(); - return 0; + return 0; +} -} \ No newline at end of file +} // namespace sfe_STHS34PF80 \ No newline at end of file diff --git a/src/sfe_bus.h b/src/sfe_bus.h index 53b5ea3..097deed 100644 --- a/src/sfe_bus.h +++ b/src/sfe_bus.h @@ -1,38 +1,125 @@ -#ifndef __SparkFun_Bus_H__ -#define __SparkFun_Bus_H__ +// sfe_bus.h +// +// This is a library written for SparkFun Human Presence Sensor STHS34PF80 +// (Qwiic) +// +// SparkFun sells these boards at its website: www.sparkfun.com +// +// Do you like this library? Help support SparkFun. Buy a board! +// +// SparkFun Human Presence Sensor STHS34PF80 (Qwiic) +// https://www.sparkfun.com/products/22494 +// +// Written by Madison Chodikov @ SparkFun Electronics, October 2023 +// +// Repository: +// hhttps://github.com/sparkfun/SparkFun_STHS34PF80_Arduino_Library/tree/main +// +// +// SparkFun code, firmware, and software is released under the MIT +// License(http://opensource.org/licenses/MIT). +// +// SPDX-License-Identifier: MIT +// +// The MIT License (MIT) +// +// Copyright (c) 2022 SparkFun Electronics +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: The +// above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED +// "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT +// NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +// The following classes specify the behavior for communicating +// over the respective data buses: Inter-Integrated Circuit (I2C) +// and Serial Peripheral Interface (SPI). For ease of implementation +// an abstract interface (QwIDeviceBus) is used. + +#pragma once -#include -#include #include +#include + +namespace sfe_STHS34PF80 +{ +// The following abstract class is used an interface for upstream +// implementation. +class QwIDeviceBus +{ + public: + virtual bool ping(uint8_t address) = 0; + + virtual bool writeRegisterByte(uint8_t address, uint8_t offset, uint8_t data) = 0; + + virtual int writeRegisterRegion(uint8_t address, uint8_t offset, const uint8_t *data, uint16_t length) = 0; -#define SPI_READ 0x80 + virtual int writeRegisterRegion(uint8_t address, uint8_t offset, uint8_t data, uint16_t length) = 0; -class SFE_BusI2C + virtual int readRegisterRegion(uint8_t addr, uint8_t reg, uint8_t *data, uint16_t numBytes) = 0; +}; + +// The QwI2C device defines behavior for I2C implementation based around the +// TwoWire class (Wire). This is Arduino specific. +class QwI2C : public QwIDeviceBus { - public: - int32_t init(uint8_t addr, TwoWire& port=Wire); - int32_t readRegs(uint8_t regAddr, uint8_t* data, uint8_t numData); - int32_t writeRegs(uint8_t regAddr, const uint8_t* data, uint8_t numData); - - private: - uint8_t devAddr; - TwoWire* devPort; + public: + QwI2C(void); + + bool init(); + + bool init(TwoWire &wirePort, bool bInit = false); + + bool ping(uint8_t address); + + bool writeRegisterByte(uint8_t address, uint8_t offset, uint8_t data); + + int writeRegisterRegion(uint8_t address, uint8_t offset, const uint8_t *data, uint16_t length); + + int writeRegisterRegion(uint8_t address, uint8_t offset, uint8_t data, uint16_t length); + + int readRegisterRegion(uint8_t addr, uint8_t reg, uint8_t *data, uint16_t numBytes); + + private: + TwoWire *_i2cPort; }; -class SFE_BusSPI +// The SfeSPI class defines behavior for SPI implementation based around the +// SPIClass class (SPI). This is Arduino specific. Paramaters like "address" are +// kept although irrelevant to SPI due to the use of the abstract class as +// interface, QwIDeviceBus. +class SfeSPI : public QwIDeviceBus { - public: + public: + SfeSPI(void); + + bool init(uint8_t cs, bool bInit = false); + + bool init(SPIClass &spiPort, SPISettings &sthsSPISettings, uint8_t cs, bool bInit = false); + + bool ping(uint8_t address); + + bool writeRegisterByte(uint8_t address, uint8_t offset, uint8_t data); + + int writeRegisterRegion(uint8_t address, uint8_t offset, const uint8_t *data, uint16_t length); - int32_t init(uint8_t cs, SPIClass& spiPort=SPI, bool bInit=false); - int32_t writeRegisterRegion(uint8_t offset, const uint8_t* data, uint16_t length); - int32_t readRegisterRegion(uint8_t reg, uint8_t* data, uint16_t numBytes); + int writeRegisterRegion(uint8_t address, uint8_t offset, uint8_t data, uint16_t length); - private: + int readRegisterRegion(uint8_t addr, uint8_t reg, uint8_t *data, uint16_t numBytes); - SPIClass* _spiPort; - // Settings are used for every transaction. - SPISettings _sfeSPISettings; - uint8_t _cs; + private: + SPIClass *_spiPort; + // Settings are used for every transaction. + SPISettings _sfeSPISettings; + uint8_t _cs; }; -#endif \ No newline at end of file +}; // namespace sfe_STHS34PF80 diff --git a/src/sths34pf80_class.cpp b/src/sths34pf80_class.cpp index 7542f15..f656da2 100644 --- a/src/sths34pf80_class.cpp +++ b/src/sths34pf80_class.cpp @@ -8,7 +8,7 @@ /// @return Error code (0 no error) int32_t STHS34PF80::begin() { - if (isConnected() == 0) + if (isConnected() != 0) { return -1; } @@ -57,11 +57,11 @@ int32_t STHS34PF80::isConnected() uint8_t devId = 0; int32_t err = sths34pf80_device_id_get(&sensor, &devId); - if (devId == STHS34PF80_ID) + if (devId != STHS34PF80_ID) { return -1; } - return err; + return err; } /// @brief Checks to see if the data ready flag is high diff --git a/src/sths34pf80_class.h b/src/sths34pf80_class.h index 26610f6..14a108f 100644 --- a/src/sths34pf80_class.h +++ b/src/sths34pf80_class.h @@ -4,11 +4,17 @@ #include "sths34pf80_api/sths34pf80_reg.h" #include "sfe_bus.h" + +// define a standard i2c address (7 bit) macro + +#define STHS34PF80_I2C_ADDRESS (STHS34PF80_I2C_ADD >> 1) + class STHS34PF80 { public: int32_t begin(); // Resets the device and sets the values needed for sensor use int32_t isConnected(); // Determines connection to device + int32_t getDataReady(sths34pf80_tmos_drdy_status_t *drdy); // Returns if the data is ready to be read or not int32_t getStatus(sths34pf80_tmos_func_status_t *statusVal); // Returns the status of the device int32_t reset(); // Set the boot bit, wait 3ms (as per the datasheet), then resets the algorithm