diff --git a/examples/Example01_Basic_OneShot/Example01_Basic_OneShot.ino b/examples/Example01_Basic_OneShot/Example01_Basic_OneShot.ino index 4ea33a3..8485b4f 100644 --- a/examples/Example01_Basic_OneShot/Example01_Basic_OneShot.ino +++ b/examples/Example01_Basic_OneShot/Example01_Basic_OneShot.ino @@ -22,57 +22,58 @@ https://www.sparkfun.com/products/23518 - Qwiic Mini */ -#include "SparkFun_AS7331.h" +#include +#include +#include SfeAS7331ArdI2C myUVSensor; -int8_t result = SFE_BUS_OK; - void setup() { Serial.begin(115200); while(!Serial){delay(100);}; - Serial.println("UV LED Example."); + Serial.println("AS7331 UV A/B/C Command (One-shot) mode Example."); + + Wire.begin(); // Initialize sensor and run default setup. if(myUVSensor.begin() == false) { Serial.println("Sensor failed to begin. Please check your wiring!"); - Serial.println("Spinning..."); + Serial.println("Halting..."); while(1); } Serial.println("Sensor began."); // Set measurement mode and change device operating mode to measure. - if(myUVSensor.startMeasurement(MEAS_MODE_CMD) == false) { + if(myUVSensor.prepareMeasurement(MEAS_MODE_CMD) == false) { Serial.println("Sensor did not get set properly."); - Serial.println("Spinning..."); + Serial.println("Halting..."); while(1); } Serial.println("Set mode to command."); - } void loop() { // Send a start measurement command. - if(SFE_BUS_OK != myUVSensor.setStartStateMode(START_STATE_ENABLED)) + if(kSTkErrOk != myUVSensor.setStartState(true)) Serial.println("Error starting reading!"); // Wait for a bit longer than the conversion time. - delay(2+(1 << myUVSensor.getConfigConversionTime())); + delay(2+myUVSensor.getConversionTimeMillis()); // Read UV values. - if(SFE_BUS_OK != myUVSensor.readAllUV()) + if(kSTkErrOk != myUVSensor.readAllUV()) Serial.println("Error reading UV."); Serial.print("UVA:"); - Serial.print(myUVSensor.measures.uva); + Serial.print(myUVSensor.getUVA()); Serial.print(" UVB:"); - Serial.print(myUVSensor.measures.uvb); + Serial.print(myUVSensor.getUVB()); Serial.print(" UVC:"); - Serial.println(myUVSensor.measures.uvc); + Serial.println(myUVSensor.getUVC()); delay(2000); -}; +} diff --git a/examples/Example02_CONT_Mode/Example02_CONT_Mode.ino b/examples/Example02_CONT_Mode/Example02_CONT_Mode.ino index a269c8b..44586b3 100644 --- a/examples/Example02_CONT_Mode/Example02_CONT_Mode.ino +++ b/examples/Example02_CONT_Mode/Example02_CONT_Mode.ino @@ -23,12 +23,12 @@ https://www.sparkfun.com/products/23518 - Qwiic Mini */ -#include "SparkFun_AS7331.h" +#include +#include +#include SfeAS7331ArdI2C myUVSensor; -int8_t result = SFE_BUS_OK; - const uint8_t interruptPin = 26; volatile bool newDataReady = false; @@ -37,6 +37,8 @@ void setup() { while(!Serial){delay(100);}; Serial.println("AS7331 UV A/B/C Continuous mode example."); + Wire.begin(); + // Configure Interrupt. pinMode(interruptPin, INPUT); attachInterrupt(digitalPinToInterrupt(interruptPin), dataReadyInterrupt, RISING); @@ -44,21 +46,23 @@ void setup() { // Initialize sensor and run default setup. if(myUVSensor.begin() == false) { Serial.println("Sensor failed to begin. Please check your wiring!"); - Serial.println("Spinning..."); + Serial.println("Halting..."); while(1); } Serial.println("Sensor began."); + // Set the delay between measurements so that the processor can read out the + // results without interfering with the ADC. // Set break time to 900us (112 * 8us) to account for the time it takes to poll data. - if(SFE_BUS_OK != myUVSensor.setBreakTime(112)) { + if(kSTkErrOk != myUVSensor.setBreakTime(112)) { Serial.println("Sensor did not set break time properly."); - Serial.println("Spinning..."); + Serial.println("Halting..."); while(1); } // Set measurement mode and change device operating mode to measure. - if(myUVSensor.startMeasurement(MEAS_MODE_CONT) == false) { + if(myUVSensor.prepareMeasurement(MEAS_MODE_CONT) == false) { Serial.println("Sensor did not get set properly."); Serial.println("Spinning..."); while(1); @@ -67,7 +71,7 @@ void setup() { Serial.println("Set mode to continuous. Starting measurement..."); // Begin measurement. - if(SFE_BUS_OK != myUVSensor.setStartStateMode(START_STATE_ENABLED)) + if(kSTkErrOk != myUVSensor.setStartState(true)) Serial.println("Error starting reading!"); } @@ -78,15 +82,15 @@ void loop() { if(newDataReady) { newDataReady = false; - if(SFE_BUS_OK != myUVSensor.readAllUV()) + if(kSTkErrOk != myUVSensor.readAllUV()) Serial.println("Error reading UV."); Serial.print("UVA:"); - Serial.print(myUVSensor.measures.uva); + Serial.print(myUVSensor.getUVA()); Serial.print(" UVB:"); - Serial.print(myUVSensor.measures.uvb); + Serial.print(myUVSensor.getUVB()); Serial.print(" UVC:"); - Serial.println(myUVSensor.measures.uvc); + Serial.println(myUVSensor.getUVC()); } } diff --git a/examples/Example03_SYNS_Mode/Example03_SYNS_Mode.ino b/examples/Example03_SYNS_Mode/Example03_SYNS_Mode.ino index 78e4f02..f5b690e 100644 --- a/examples/Example03_SYNS_Mode/Example03_SYNS_Mode.ino +++ b/examples/Example03_SYNS_Mode/Example03_SYNS_Mode.ino @@ -24,12 +24,12 @@ https://www.sparkfun.com/products/23518 - Qwiic Mini */ -#include "SparkFun_AS7331.h" +#include +#include +#include SfeAS7331ArdI2C myUVSensor; -int8_t result = SFE_BUS_OK; - const uint8_t synPin = 27; const uint8_t interruptPin = 26; @@ -40,6 +40,8 @@ void setup() { while(!Serial){delay(100);}; Serial.println("AS7331 UV A/B/C Synchronous Start mode example."); + Wire.begin(); + // Configure SYN pin. pinMode(synPin, OUTPUT); digitalWrite(synPin, HIGH); // Active low, so start high. @@ -51,23 +53,23 @@ void setup() { // Initialize sensor and run default setup. if(myUVSensor.begin() == false) { Serial.println("Sensor failed to begin. Please check your wiring!"); - Serial.println("Spinning..."); + Serial.println("Halting..."); while(1); } Serial.println("Sensor began."); // Set measurement mode and change device operating mode to measure. - if(myUVSensor.startMeasurement(MEAS_MODE_SYNS) == false) { + if(myUVSensor.prepareMeasurement(MEAS_MODE_SYNS) == false) { Serial.println("Sensor did not get set properly."); - Serial.println("Spinning..."); + Serial.println("Halting..."); while(1); } Serial.println("Set mode to synchronous start (SYNS). Starting measurement..."); // Set device to be ready to measure. - if(SFE_BUS_OK != myUVSensor.setStartStateMode(START_STATE_ENABLED)) + if(kSTkErrOk != myUVSensor.setStartState(true)) Serial.println("Error starting reading!"); // Send start toggle. @@ -83,7 +85,7 @@ void loop() { if(newDataReady) { newDataReady = false; - if(SFE_BUS_OK != myUVSensor.readAllUV()) + if(kSTkErrOk != myUVSensor.readAllUV()) Serial.println("Error reading UV."); // Start next measurement @@ -92,11 +94,11 @@ void loop() { digitalWrite(synPin, HIGH); Serial.print("UVA:"); - Serial.print(myUVSensor.measures.uva); + Serial.print(myUVSensor.getUVA()); Serial.print(" UVB:"); - Serial.print(myUVSensor.measures.uvb); + Serial.print(myUVSensor.getUVB()); Serial.print(" UVC:"); - Serial.println(myUVSensor.measures.uvc); + Serial.println(myUVSensor.getUVC()); } } diff --git a/examples/Example04_SYND_Mode/Example04_SYND_Mode.ino b/examples/Example04_SYND_Mode/Example04_SYND_Mode.ino index 08196d4..b59b24c 100644 --- a/examples/Example04_SYND_Mode/Example04_SYND_Mode.ino +++ b/examples/Example04_SYND_Mode/Example04_SYND_Mode.ino @@ -24,12 +24,12 @@ https://www.sparkfun.com/products/23518 - Qwiic Mini */ -#include "SparkFun_AS7331.h" +#include +#include +#include SfeAS7331ArdI2C myUVSensor; -int8_t result = SFE_BUS_OK; - const uint8_t synPin = 27; void setup() { @@ -37,6 +37,8 @@ void setup() { while(!Serial){delay(100);}; Serial.println("AS7331 UV A/B/C Synchronous Start and End (SYND) mode example."); + Wire.begin(); + // Configure SYN pin. pinMode(synPin, OUTPUT); digitalWrite(synPin, HIGH); // Active low, so start high. @@ -44,23 +46,23 @@ void setup() { // Initialize sensor and run default setup. if(myUVSensor.begin() == false) { Serial.println("Sensor failed to begin. Please check your wiring!"); - Serial.println("Spinning..."); + Serial.println("Halting..."); while(1); } Serial.println("Sensor began."); // Set measurement mode and change device operating mode to measure. - if(myUVSensor.startMeasurement(MEAS_MODE_SYND) == false) { + if(myUVSensor.prepareMeasurement(MEAS_MODE_SYND) == false) { Serial.println("Sensor did not get set properly."); - Serial.println("Spinning..."); + Serial.println("Halting..."); while(1); } Serial.println("Set mode to synchronous start/end (SYND). Starting measurement..."); // Set device to be ready to measure. - if(SFE_BUS_OK != myUVSensor.setStartStateMode(START_STATE_ENABLED)) + if(kSTkErrOk != myUVSensor.setStartState(true)) Serial.println("Error starting reading!"); // Send start toggle. @@ -79,15 +81,15 @@ void loop() { delay(1); digitalWrite(synPin, HIGH); - if(SFE_BUS_OK != myUVSensor.readAllUV()) + if(kSTkErrOk != myUVSensor.readAllUV()) Serial.println("Error reading UV."); Serial.print("UVA:"); - Serial.print(myUVSensor.measures.uva); + Serial.print(myUVSensor.getUVA()); Serial.print(" UVB:"); - Serial.print(myUVSensor.measures.uvb); + Serial.print(myUVSensor.getUVB()); Serial.print(" UVC:"); - Serial.println(myUVSensor.measures.uvc); + Serial.println(myUVSensor.getUVC()); // Start next measurement. digitalWrite(synPin, LOW); diff --git a/keywords.txt b/keywords.txt index c22c8ac..92f5af0 100644 --- a/keywords.txt +++ b/keywords.txt @@ -1,104 +1,94 @@ # Syntax Coloring Map for SparkFun AS7331 Arduino Library -# Datatypes (KEYWORD1) -as7331_device_op_state_t KEYWORD1 -as7331_power_state_t KEYWORD1 -as7331_startstate_t KEYWORD1 -as7331_gain_t KEYWORD1 -as7331_ext_syn_temp_meas_t KEYWORD1 -as7331_conv_clk_freq_t KEYWORD1 -as7331_ready_pin_mode_t KEYWORD1 -as7331_standby_mode_t KEYWORD1 -as7331_meas_mode_t KEYWORD1 -as7331_simple_reg_read_mode_t KEYWORD1 -as7331_conv_time_t KEYWORD1 -as7331_divider_enable_t KEYWORD1 -as7331_divider_val_t KEYWORD1 -sfe_as7331_reg_cfg_break_t KEYWORD1 -sfe_as7331_reg_cfg_edges_t KEYWORD1 +# Datatypes (KEYWORD1) +as7331_dev_op_state_t KEYWORD1 +as7331_gain_t KEYWORD1 +as7331_conv_clk_freq_t KEYWORD1 +as7331_meas_mode_t KEYWORD1 +as7331_conv_time_t KEYWORD1 +as7331_divider_val_t KEYWORD1 +as7331_uv_type KEYWORD1 # Methods and Functions (KEYWORD2) -begin KEYWORD2 -init KEYWORD2 -writeRegister KEYWORD2 -readRegister KEYWORD2 -isConnected KEYWORD2 -getDeviceID KEYWORD2 -runDefaultSetup KEYWORD2 -startMeasurement KEYWORD2 -setCommunicationBus KEYWORD2 -setCommunicationDevSettings KEYWORD2 -setDeviceAddress KEYWORD2 -reset KEYWORD2 -readTemp KEYWORD2 -readUVA KEYWORD2 -readUVB KEYWORD2 -readUVC KEYWORD2 -readAllUV KEYWORD2 -readAll KEYWORD2 -readOutConv KEYWORD2 -getState KEYWORD2 -getConfig KEYWORD2 -setGain KEYWORD2 -setConversionTime KEYWORD2 -setCClk KEYWORD2 -setEnableDivider KEYWORD2 -setDigitalDivider KEYWORD2 -setReadyPinMode KEYWORD2 -setEnableTemperatureConversion KEYWORD2 -setIndexMode KEYWORD2 -setBreakTime KEYWORD2 -setNumEdges KEYWORD2 -getConfigGain KEYWORD2 -getConfigCClk KEYWORD2 -getConfigConversionTime KEYWORD2 -getConfigReadyPinMode KEYWORD2 -getConfigDividerEnabled KEYWORD2 -getConfigDividerRange KEYWORD2 -getConfigExternalSyncTempConversion KEYWORD2 -getConfigIndexMode KEYWORD2 -getConfigBreakTime KEYWORD2 -getConfigNumEdges KEYWORD2 -getPowerState KEYWORD2 -setPowerState KEYWORD2 -getOperationMode KEYWORD2 -setOperationMode KEYWORD2 -getMeasurementMode KEYWORD2 -setMeasurementMode KEYWORD2 -getStandbyMode KEYWORD2 -setStandbyMode KEYWORD2 -getStartStateMode KEYWORD2 -setStartStateMode KEYWORD2 -getStatePower KEYWORD2 -getStateOperational KEYWORD2 -getStateMeasurement KEYWORD2 -getStateStandby KEYWORD2 -getStateStart KEYWORD2 -getStatus KEYWORD2 -getOSR KEYWORD2 -setOSR KEYWORD2 -getCReg1 KEYWORD2 -setCReg1 KEYWORD2 -getCReg2 KEYWORD2 -setCReg2 KEYWORD2 -getCReg3 KEYWORD2 -setCReg3 KEYWORD2 -getBreak KEYWORD2 -setBreak KEYWORD2 -getEdges KEYWORD2 -setEdges KEYWORD2 -getOptIndex KEYWORD2 -setOptIndex KEYWORD2 -convertRawTempToTempC KEYWORD2 -calculateConversionFactors KEYWORD2 +begin KEYWORD2 +getDeviceID KEYWORD2 +setCommunicationBus KEYWORD2 +setDeviceAddress KEYWORD2 +getDeviceAddress KEYWORD2 +runDefaultSetup KEYWORD2 +prepareMeasurement KEYWORD2 +reset KEYWORD2 +readTemp KEYWORD2 +readUVA KEYWORD2 +readUVB KEYWORD2 +readUVC KEYWORD2 +readAllUV KEYWORD2 +readAll KEYWORD2 +readOutConv KEYWORD2 +getUVA KEYWORD2 +getUVB KEYWORD2 +getUVC KEYWORD2 +getTemp KEYWORD2 +getOutConv KEYWORD2 +getGainRaw KEYWORD2 +getGainValue KEYWORD2 +setGain KEYWORD2 +getCClkRaw KEYWORD2 +getCClkKHz KEYWORD2 +setCClk KEYWORD2 +getConversionTimeRaw KEYWORD2 +getConversionTimeMillis KEYWORD2 +setConversionTime KEYWORD2 +getReadyPinMode KEYWORD2 +setReadyPinMode KEYWORD2 +getDigitalDividerEnabled KEYWORD2 +setDigitalDividerEnabled KEYWORD2 +getDigitalDividerRange KEYWORD2 +setDigitalDividerRange KEYWORD2 +getSyndTempConversionEnabled KEYWORD2 +setSyndTempConversionEnabled KEYWORD2 +getIndexMode KEYWORD2 +setIndexMode KEYWORD2 +getBreakTime KEYWORD2 +setBreakTime KEYWORD2 +getNumEdges KEYWORD2 +setNumEdges KEYWORD2 +getPowerDownState KEYWORD2 +setPowerDownState KEYWORD2 +getOperationMode KEYWORD2 +setOperationMode KEYWORD2 +getMeasurementMode KEYWORD2 +setMeasurementMode KEYWORD2 +getStandbyState KEYWORD2 +setStandbyState KEYWORD2 +getStartState KEYWORD2 +setStartState KEYWORD2 +getStatus KEYWORD2 +getOSR KEYWORD2 +setOSR KEYWORD2 +getCReg1 KEYWORD2 +setCReg1 KEYWORD2 +getCReg2 KEYWORD2 +setCReg2 KEYWORD2 +getCReg3 KEYWORD2 +setCReg3 KEYWORD2 +getBreak KEYWORD2 +setBreak KEYWORD2 +getEdges KEYWORD2 +setEdges KEYWORD2 +getOptIndex KEYWORD2 +setOptIndex KEYWORD2 +readRawUV KEYWORD2 +convertRawTempToTempC KEYWORD2 +convertRawUVVal KEYWORD2 +calculateConversionFactors KEYWORD2 +setDefaultSettings KEYWORD2 +isConnected KEYWORD2 # Instances (KEYWORD2) # Structures (KEYWORD3) -sfeAS7331_measures_t KEYWORD3 -sfeAS7331_config_t KEYWORD3 -sfeAS7331_state_t KEYWORD3 sfe_as7331_reg_cfg_osr_t KEYWORD3 sfe_as7331_reg_cfg_agen_t KEYWORD3 sfe_as7331_reg_cfg_creg1_t KEYWORD3 @@ -106,33 +96,29 @@ sfe_as7331_reg_cfg_creg2_t KEYWORD3 sfe_as7331_reg_cfg_creg3_t KEYWORD3 sfe_as7331_reg_cfg_optreg_t KEYWORD3 sfe_as7331_reg_meas_osr_status_t KEYWORD3 -sfe_as7331_reg_meas_temp_t KEYWORD3 -sfe_as7331_reg_meas_mres1_t KEYWORD3 -sfe_as7331_reg_meas_mres2_t KEYWORD3 -sfe_as7331_reg_meas_mres3_t KEYWORD3 -sfe_as7331_reg_meas_outconv_l_t KEYWORD3 -sfe_as7331_reg_meas_outconv_h_t KEYWORD3 - # Constants (LITERAL1) -AS7331_ADDR_DEFAULT LITERAL1 -AS7331_ADDR_SEC LITERAL1 -AS7331_ADDR_TER LITERAL1 -AS7331_ADDR_QUA LITERAL1 -AS7331_DEFAULT_DEV_ID LITERAL1 -AS7331_DEV_ID_HIGH LITERAL1 -SFE_AS7331_REGISTER_CFG_OSR LITERAL1 -SFE_AS7331_REGISTER_CFG_AGEN LITERAL1 -SFE_AS7331_REGISTER_CFG_CREG1 LITERAL1 -SFE_AS7331_REGISTER_CFG_CREG2 LITERAL1 -SFE_AS7331_REGISTER_CFG_CREG3 LITERAL1 -SFE_AS7331_REGISTER_CFG_BREAK LITERAL1 -SFE_AS7331_REGISTER_CFG_EDGES LITERAL1 -SFE_AS7331_REGISTER_CFG_OPTREG LITERAL1 -SFE_AS7331_REGISTER_MEAS_OSR_STATUS LITERAL1 -SFE_AS7331_REGISTER_MEAS_TEMP LITERAL1 -SFE_AS7331_REGISTER_MEAS_MRES1 LITERAL1 -SFE_AS7331_REGISTER_MEAS_MRES2 LITERAL1 -SFE_AS7331_REGISTER_MEAS_MRES3 LITERAL1 -SFE_AS7331_REGISTER_MEAS_OUTCONV_L LITERAL1 -SFE_AS7331_REGISTER_MEAS_OUTCONV_H LITERAL1 +kDefaultAS7331Addr LITERAL1 +kSecondaryAS7331Addr LITERAL1 +kTertiaryAS7331Addr LITERAL1 +kQuaternaryAS7331Addr LITERAL1 +kDefaultAS7331DeviceID LITERAL1 +kAS7331DeviceIDTopNibble LITERAL1 +kSfeAS7331RegCfgOsr LITERAL1 +kSfeAS7331RegCfgAgen LITERAL1 +kSfeAS7331RegCfgCreg1 LITERAL1 +kSfeAS7331RegCfgCreg2 LITERAL1 +kSfeAS7331RegCfgCreg3 LITERAL1 +kSfeAS7331RegCfgBreak LITERAL1 +kSfeAS7331RegCfgEdges LITERAL1 +kSfeAS7331RegCfgOptReg LITERAL1 +kSfeAS7331RegMeasOsrStatus LITERAL1 +kSfeAS7331RegMeasTemp LITERAL1 +kSfeAS7331RegMeasMres1 LITERAL1 +kSfeAS7331RegMeasMres2 LITERAL1 +kSfeAS7331RegMeasMres3 LITERAL1 +kSfeAS7331RegMeasOutConvL LITERAL1 +kSfeAS7331RegMeasOutConvH LITERAL1 +_fsrA LITERAL1 +_fsrB LITERAL1 +_fsrC LITERAL1 diff --git a/library.properties b/library.properties index 7f9743b..5ac192a 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=SparkFun AS7331 Arduino Library -version=1.0.0 +version=2.0.0 author=SparkFun Electronics maintainer=SparkFun Electronics sentence=An Arduino library to make use of the Qwiic and Qwiic Mini AS7331 Spectral UV Sensor @@ -7,4 +7,5 @@ paragraph= category=Sensors url=https://github.com/sparkfun/SparkFun_AS7331_Arduino_Library architectures=* +depends=SparkFun Toolkit includes=SparkFun_AS7331.h diff --git a/src/SparkFun_AS7331.h b/src/SparkFun_AS7331.h index 869cc82..580bbe7 100644 --- a/src/SparkFun_AS7331.h +++ b/src/SparkFun_AS7331.h @@ -2,9 +2,9 @@ SparkFun Spectral UV Sensor - AS7331 Qwiic 1x1 - https://www.sparkfun.com/products/ + https://www.sparkfun.com/products/23517 Qwiic Mini - https://www.sparkfun.com/products/ + https://www.sparkfun.com/products/23518 Repository https://github.com/sparkfun/SparkFun_AS7331_Arduino_Library @@ -14,1312 +14,54 @@ Copyright (c) 2023 SparkFun Electronics Name: SparkFun_AS7331.h - + Description: - The SfeAS7331ArdI2C is a templated class that defines Arduino specific - behavior for initializing devices. It inherits from the base C++ class - SfeAS7331Base which defines the functions for interacting with the AS7331 - Spectral UV Sensor. + The SfeAS7331ArdI2C class defines the Arduino specific behavior for + initializing and interadcting with devices. */ #pragma once -#include "sfe_as7331_registers.h" - +#include "sfeAS7331.h" #include -#include "sfe_i2c_arduino.h" - -/// @brief Measures structure to hold return values. -typedef struct { - float uva; - float uvb; - float uvc; - float temperature; - uint32_t outputConversionTime; -} sfeAS7331_measures_t; - -/// @brief Configuration struct to hold local sensor configuration. -typedef struct { - as7331_gain_t sensorGain; - as7331_conv_clk_freq_t cclk; - as7331_conv_time_t conversionTime; - as7331_ready_pin_mode_t readyPinMode; - as7331_divider_enable_t dividerEnabled; - as7331_divider_val_t dividerRange; - as7331_ext_syn_temp_meas_t enableTempConv; - as7331_simple_reg_read_mode_t indexMode; - uint8_t breakTime; - uint8_t numEdges; -} sfeAS7331_config_t; - -/// @brief State struct to hold local sensor state. -typedef struct { - as7331_power_state_t pd; - as7331_device_op_state_t opMode; - as7331_meas_mode_t mmode; - as7331_standby_mode_t sb; - as7331_startstate_t ss; -} sfeAS7331_state_t; - -/// @brief Default measures struct for initialization and reset. -const sfeAS7331_measures_t measuresDefault = { - .uva = (uint16_t)(-1), - .uvb = (uint16_t)(-1), - .uvc = (uint16_t)(-1), - .temperature = (uint16_t)(-1), - .outputConversionTime = (uint32_t)(-1) - }; - -/// @brief Default configuration struct for initialization and reset. -const sfeAS7331_config_t configDefault = { - .sensorGain = GAIN_2, - .cclk = CCLK_1_024_MHZ, - .conversionTime = TIME_64MS, - .readyPinMode = READYPIN_PUSHPULL, - .dividerEnabled = DIVIDER_DISABLED, - .dividerRange = DIV_2, - .enableTempConv = SYN_TEMP_ENABLED, - .indexMode = INDEX_REPEAT_START, - .breakTime = 25, // 25 * 8us = 200us - .numEdges = 1 - }; - -/// @brief Default state struct for initialization and reset. -const sfeAS7331_state_t stateDefault = { - .pd = POWER_DOWN_ENABLE, - .opMode = DEVICE_MODE_CFG, - .mmode = MEAS_MODE_CMD, - .sb = STANDBY_DISABLED, - .ss = START_STATE_DISABLED - }; - -/// @class SfeAS7331Base -/// @brief Template device class for the AS7331 Spectral UV Sensor. -template -class SfeAS7331Base { - public: - SfeAS7331Base(){ - _state = stateDefault; - - _config = configDefault; - - measures = measuresDefault; - }; - - /// @brief This method is called to initialize the AS7331 device through the specified bus. - /// @param theBus Pointer to the bus object. - /// @param devSettings Pointer to the device settings object. - /// @param deviceAddress I2C address for the device. - /// @return True if successful, false if it fails. - bool begin(sfeBusDevice *theBus, sfeBusDeviceSettings *devSettings, const uint8_t deviceAddress = AS7331_ADDR_DEFAULT) - { - setCommunicationBus(theBus, devSettings); - return begin(deviceAddress); - } - - /// @brief This method is called to initialize the AS7331 device through the specified bus. - /// @param theBus Pointer to the bus object. - /// @param deviceAddress I2C address for the device. - /// @return True if successful, false if it fails. - bool begin(sfeBusDevice *theBus, uint8_t deviceAddress = AS7331_ADDR_DEFAULT) - { - setCommunicationBus(theBus); - return begin(deviceAddress); - } - - /// @brief This method is called to initialize the AS7331 device at the specified bus address. - /// @param deviceAddress I2C address for the device. - /// @return True if successful, false if it fails. - bool begin(uint8_t deviceAddress = AS7331_ADDR_DEFAULT) - { - if(!_sfeBus) - setCommunicationBus(); - - setDeviceAddress(deviceAddress); - - _sfeBus->begin(); - - return init(); - } - - /// @brief Finds the device and initializes the default state. - /// @param runSetup Flag to run the default setup if set. - /// @return True if successful, false if it fails. - bool init(bool runSetup = true) - { - if(SFE_BUS_OK != _sfeBus->ping(_devSettings)) - return false; - - reset(); - - if(!isConnected()) - return false; - - if(runSetup) - return runDefaultSetup(); - - return true; - } - - /// @brief Writes to the data to the given register. - /// @param offset The register to write to. - /// @param data The data to write to the register. - /// @param length The number of writes - /// @return The SFE_BUS status code on the write to the given register. - int8_t writeRegister(const uint8_t offset, const uint8_t *data, const uint16_t length = 1) - { - return _sfeBus->writeRegisterBytes((SFEBusDevSettings*)_devSettings, offset, data, length); - } - - /// @brief Reads data from the specified register. - /// @param offset The register to read from. - /// @param data The pointer to the value to store the value. - /// @param length The number of reads - /// @return The SFE_BUS status code on the read to the given register. - int8_t readRegister(const uint8_t offset, uint8_t *data, const uint16_t length = 1) - { - return _sfeBus->readRegisterBytes((SFEBusDevSettings*)_devSettings, offset, data, length); - } - - /// @brief Checks to see if the AS7331 is connected. - /// @return True if successful, false otherwise. - bool isConnected(void) - { - return (AS7331_DEFAULT_DEV_ID == getDeviceID()); - } - - /// @brief Requests the device ID from the sensor. - /// @return The device ID of the sensor.` - uint8_t getDeviceID(void) - { - uint8_t devID; - - if(SFE_BUS_OK != readRegister(SFE_AS7331_REGISTER_CFG_AGEN, &devID)) - return 0; - - return devID; - } - - /// @brief Helper class that sets up the sensor and state in the POR configuration. - /// @param runSoftReset Flag that runs the soft reset function to reset the device. - /// @return True if successful, false otherwise. - bool runDefaultSetup(bool runSoftReset = false) - { - if(runSoftReset) - return reset(); - else - { - _state = stateDefault; - _config = configDefault; - measures = measuresDefault; - } - - sfe_as7331_reg_cfg_osr_t osr; - if(SFE_BUS_OK != getOSR(&osr)) - return false; - - uint8_t regs[6]; - if(SFE_BUS_OK != readRegister(SFE_AS7331_REGISTER_CFG_CREG1, regs, 6U)) - return false; - - sfe_as7331_reg_cfg_creg1_t creg1 = {.byte = regs[0]}; - sfe_as7331_reg_cfg_creg2_t creg2 = {.byte = regs[1]}; - sfe_as7331_reg_cfg_creg3_t creg3 = {.byte = regs[2]}; - sfe_as7331_reg_cfg_break_t breakreg = regs[3]; - sfe_as7331_reg_cfg_edges_t edgesreg = regs[4]; - sfe_as7331_reg_cfg_optreg_t optreg = {.byte = regs[5]}; - - osr.ss = _state.ss; - osr.pd = _state.pd; - osr.dos = _state.opMode; - - creg1.gain = _config.sensorGain; - creg1.time = _config.conversionTime; - - creg2.en_tm = _config.enableTempConv; - creg2.en_div = _config.dividerEnabled; - creg2.div = _config.dividerRange; - - creg3.mmode = _state.mmode; - creg3.sb = _state.sb; - creg3.rdyod = _config.readyPinMode; - creg3.cclk = _config.cclk; - - breakreg = _config.breakTime; - - edgesreg = _config.numEdges; - - optreg.init_idx = _config.indexMode; - - if(SFE_BUS_OK != setOSR(&osr)) - return false; - - regs[0] = creg1.byte; - regs[1] = creg2.byte; - regs[2] = creg3.byte; - regs[3] = breakreg; - regs[4] = edgesreg; - regs[5] = optreg.byte; - - if(SFE_BUS_OK != writeRegister(SFE_AS7331_REGISTER_CFG_CREG1, regs, 6U)) - return false; - - calculateConversionFactors(); - - return true; - } - - /// @brief Puts the sensor in the specified measurement mode. - /// @param measMode Measurement mode to enter. - /// @param startMeasure Flag to start measuring immediately if set. - /// @return True if successful, false otherwise. - bool startMeasurement(const as7331_meas_mode_t measMode = MEAS_MODE_CONT, bool startMeasure = false) - { - if(_state.pd == POWER_DOWN_ENABLE) - if(SFE_BUS_OK != setPowerState(POWER_DOWN_DISABLE)) return false; - - if(_state.mmode != measMode) - { - if(SFE_BUS_OK != setStandbyMode(STANDBY_DISABLED)) - return false; - if(SFE_BUS_OK != setMeasurementMode(measMode)) - return false; - } - - if(_state.opMode != DEVICE_MODE_MEAS) - if(SFE_BUS_OK != setOperationMode(DEVICE_MODE_MEAS)) return false; - - if(startMeasure) - if(SFE_BUS_OK != setStartStateMode(START_STATE_ENABLED)) return false; - - return true; - } - - /// @brief Sets the communication bus to the specified bus and device settings. - /// @param theBus Bus to set as the communication device. - /// @param deviceSettings Device settings to use when setting the bus for this sensor. - /// @return 0 if successful, negative if error, positive for warning. - int8_t setCommunicationBus(sfeBusDevice *theBus, sfeBusDeviceSettings *deviceSettings) - { - int8_t result = setCommunicationBus(theBus); - if(SFE_BUS_OK != result) - return result; - - return setCommunicationDevSettings(deviceSettings); - } - - /// @brief Sets teh communication bus to the specified bus. Creates new instance if none specified. - /// @param theBus Bus to set as the communication devie. - /// @return 0 if successful, negative if error, positive for warning. - int8_t setCommunicationBus(sfeBusDevice *theBus = nullptr) - { - if(theBus == nullptr) - theBus = new sfeBusDevice(); - - if(!theBus) - return SFE_BUS_E_NULL_PTR; - - _sfeBus = theBus; - - return SFE_BUS_OK; - } - - /// @brief Sets settings of this sensor's device. - /// @param deviceSettings Settings structure for this device. Creates new instance if none specified. - /// @return 0 if successful, negative if error, positive for warning. - int8_t setCommunicationDevSettings(sfeBusDeviceSettings *deviceSettings = nullptr) - { - if(deviceSettings == nullptr) - deviceSettings = new sfeBusDeviceSettings(); - - if(!deviceSettings) - return SFE_BUS_E_NULL_DEV_SETTINGS; - - _devSettings = deviceSettings; - - return SFE_BUS_OK; - } - - /// @brief Sets the address that the bus uses to communicate with the sensor. - /// @param deviceAddress Device address to use. - /// @return 0 if successful, negative if error, positive for warning. - int8_t setDeviceAddress(const uint8_t deviceAddress) - { - int8_t result = SFE_BUS_OK; - - if(!_devSettings) - result = setCommunicationDevSettings(); - - if(SFE_BUS_OK != result) - return result; - - _devSettings->devAddr = deviceAddress; - - return SFE_BUS_OK; - } - - /// @brief Performs a soft reset of the sensor. - /// @return True if successful, false otherwise. - bool reset(void) - { - sfe_as7331_reg_cfg_osr_t osr; - - - if(SFE_BUS_OK != getOSR(&osr)) - return false; - - osr.sw_res = 1; - - if(SFE_BUS_OK != setOSR(&osr)) - return false; - - _state = stateDefault; - _config = configDefault; - measures = measuresDefault; - - return true; - } - - /// @brief Reads the sensor's temperature, converts it to a usable form, and saves it to the measures struct. - /// @return 0 if successful, negative if error, positive for warning. - int8_t readTemp(void) - { - uint8_t tempRaw[2]; - - int8_t result = readRegister(SFE_AS7331_REGISTER_MEAS_TEMP, tempRaw, 2U); - - if(SFE_BUS_OK != result) - return result; - - measures.temperature = convertRawTempToTempC((uint16_t)(((uint16_t)tempRaw[1] << 8 | tempRaw[0]))); - - return SFE_BUS_OK; - } - - /// @brief Reads the sensor's UVA register, converts it to a usable form, and saves it to the measures struct. - /// @return 0 if successful, negative if error, positive for warning. - int8_t readUVA(void) - { - uint8_t uvaRaw[2]; - - int8_t result = readRegister(SFE_AS7331_REGISTER_MEAS_MRES1, uvaRaw, 2U); - - if(SFE_BUS_OK != result) - return result; - - if(_state.mmode == MEAS_MODE_SYND) { - result = readOutConv(); - - if(SFE_BUS_OK != result) - return result; - - float divFactor = (bool)_config.dividerEnabled ? (float)(1 << (1+_config.dividerRange)) : 1.0f; - float convFactor = ((float)measures.outputConversionTime)*((float)(1 << (11 - _config.sensorGain))); - measures.uva = (float)((uint16_t)(((uint16_t)uvaRaw[1]) << 8 | uvaRaw[0])-1.0f)*fsrA*divFactor/convFactor; - } - else { - measures.uva = (float)((uint16_t)(((uint16_t)uvaRaw[1]) << 8 | uvaRaw[0])-1.0f)*_conversionA; - } - - return SFE_BUS_OK; - } - - /// @brief Reads the sensor's UVB register, converts it to a usable form, and saves it to the measures struct. - /// @return 0 if successful, negative if error, positive for warning. - int8_t readUVB(void) - { - uint8_t uvbRaw[2]; - - int8_t result = readRegister(SFE_AS7331_REGISTER_MEAS_MRES2, uvbRaw, 2U); - - if(SFE_BUS_OK != result) - return result; - - if(_state.mmode == MEAS_MODE_SYND) { - result = readOutConv(); - - if(SFE_BUS_OK != result) - return result; - - float divFactor = (bool)_config.dividerEnabled ? (float)(1 << (1+_config.dividerRange)) : 1.0f; - float convFactor = ((float)measures.outputConversionTime)*((float)(1 << (11 - _config.sensorGain))); - measures.uvb = (float)((uint16_t)(((uint16_t)uvbRaw[1]) << 8 | uvbRaw[0])-1.0f)*fsrB*divFactor/convFactor; - } - else { - measures.uvb = (float)((uint16_t)(((uint16_t)uvbRaw[1]) << 8 | uvbRaw[0])-1.0f)*_conversionB; - } - - return SFE_BUS_OK; - } - - /// @brief Reads the sensor's UVC register, converts it to a usable form, and saves it to the measures struct. - /// @return 0 if successful, negative if error, positive for warning. - int8_t readUVC(void) - { - uint8_t uvcRaw[2]; - - int8_t result = readRegister(SFE_AS7331_REGISTER_MEAS_MRES3, uvcRaw, 2U); - - if(SFE_BUS_OK != result) - return result; - - if(_state.mmode == MEAS_MODE_SYND) { - result = readOutConv(); - - if(SFE_BUS_OK != result) - return result; - - float divFactor = (bool)_config.dividerEnabled ? (float)(1 << (1+_config.dividerRange)) : 1.0f; - float convFactor = ((float)measures.outputConversionTime)*((float)(1 << (11 - _config.sensorGain))); - measures.uvc = (float)((uint16_t)(((uint16_t)uvcRaw[1]) << 8 | uvcRaw[0])-1.0f)*fsrC*divFactor/convFactor; - } - else { - measures.uvc = (float)((uint16_t)(((uint16_t)uvcRaw[1]) << 8 | uvcRaw[0])-1.0f)*_conversionC; - } - - return SFE_BUS_OK; - } - - /// @brief Read's all three UV registers, converts them to a usable form, then saves them to the measures struct. - /// @return 0 if successful, negative if error, positive for warning. - int8_t readAllUV(void) - { - uint8_t dataRaw[6]; - - int8_t result = readRegister(SFE_AS7331_REGISTER_MEAS_MRES1, dataRaw, 6U); - - if(SFE_BUS_OK != result) - return result; - - if(_state.mmode == MEAS_MODE_SYND) { - result = readOutConv(); - - if(SFE_BUS_OK != result) - return result; - - float divFactor = (bool)_config.dividerEnabled ? (float)(1 << (1+_config.dividerRange)) : 1.0f; - float convFactor = ((float)measures.outputConversionTime)*((float)(1 << (11 - _config.sensorGain))); - measures.uva = (float)((uint16_t)(((uint16_t)dataRaw[1]) << 8 | dataRaw[0])-1.0f)*fsrA*divFactor/convFactor; - measures.uvb = (float)((uint16_t)(((uint16_t)dataRaw[3]) << 8 | dataRaw[2])-1.0f)*fsrB*divFactor/convFactor; - measures.uvc = (float)((uint16_t)(((uint16_t)dataRaw[5]) << 8 | dataRaw[4])-1.0f)*fsrC*divFactor/convFactor; - } - else { - measures.uva = (float)((uint16_t)(((uint16_t)dataRaw[1]) << 8 | dataRaw[0])-1.0f)*_conversionA; - measures.uvb = (float)((uint16_t)(((uint16_t)dataRaw[3]) << 8 | dataRaw[2])-1.0f)*_conversionB; - measures.uvc = (float)((uint16_t)(((uint16_t)dataRaw[5]) << 8 | dataRaw[4])-1.0f)*_conversionC; - } - - return SFE_BUS_OK; - } - - /// @brief Read the sensor's temperature, UV, and external time conversion clock counts, converts them, and then saves them to the measures struct. - /// @return 0 if successful, negative if error, positive for warning. - int8_t readAll(void) - { - uint8_t dataRaw[8]; - - int8_t result = readRegister(SFE_AS7331_REGISTER_MEAS_TEMP, dataRaw, 8U); - - if(SFE_BUS_OK != result) - return result; - - result = readOutConv(); - if(SFE_BUS_OK != result) - return result; - - if(_state.mmode == MEAS_MODE_SYND) { - float divFactor = (bool)_config.dividerEnabled ? (float)(1 << (1+_config.dividerRange)) : 1.0f; - float convFactor = ((float)measures.outputConversionTime)*((float)(1 << (11 - _config.sensorGain))); - measures.uva = (float)((uint16_t)(((uint16_t)dataRaw[3]) << 8 | dataRaw[2])-1.0f)*fsrA*divFactor/convFactor; - measures.uvb = (float)((uint16_t)(((uint16_t)dataRaw[5]) << 8 | dataRaw[4])-1.0f)*fsrB*divFactor/convFactor; - measures.uvc = (float)((uint16_t)(((uint16_t)dataRaw[7]) << 8 | dataRaw[6])-1.0f)*fsrC*divFactor/convFactor; - } - else { - measures.uva = (float)((uint16_t)(((uint16_t)dataRaw[3]) << 8 | dataRaw[2])-1.0f)*_conversionA; - measures.uvb = (float)((uint16_t)(((uint16_t)dataRaw[5]) << 8 | dataRaw[4])-1.0f)*_conversionB; - measures.uvc = (float)((uint16_t)(((uint16_t)dataRaw[7]) << 8 | dataRaw[6])-1.0f)*_conversionC; - } - - measures.temperature = convertRawTempToTempC((uint16_t)(((uint16_t)dataRaw[1] << 8 | dataRaw[0]))); - - return SFE_BUS_OK; - } - - /// @brief Read the conversion clock counts register and saves it to the measures struct. - /// @return 0 if successful, negative if error, positive for warning. - int8_t readOutConv(void) - { - uint8_t tconvRaw[4]; - - int8_t result = readRegister(SFE_AS7331_REGISTER_MEAS_OUTCONV_L, tconvRaw, 4U); - - if(SFE_BUS_OK != result) - return result; - - measures.outputConversionTime = (uint32_t)(((uint32_t)tconvRaw[3] << 24) | ((uint32_t)tconvRaw[2] << 16) | ((uint32_t)tconvRaw[1] << 8) | tconvRaw[0]); - - return SFE_BUS_OK; - } - - /// @brief Getter function to get the current internal state. - /// @return internal state struct. - sfeAS7331_state_t getState(void) - { - return _state; - } - - /// @brief Getter function to get the current internal configuration. - /// @return internal configuration struct. - sfeAS7331_config_t getConfig(void) - { - return _config; - } - - /// @brief Sets the UV sensor's gain. - /// @param gain The gain to set the sensor to. - /// @return 0 if successful, negative if error, positive for warning. - int8_t setGain(const as7331_gain_t gain) - { - int8_t result = SFE_BUS_OK; - - sfe_as7331_reg_cfg_creg1_t creg1; - - result = getCReg1(&creg1); - if(SFE_BUS_OK != result) - return result; - - creg1.gain = gain; - - result = setCReg1(&creg1); - if(SFE_BUS_OK != result) - return result; - - _config.sensorGain = gain; - - calculateConversionFactors(); - - return SFE_BUS_OK; - } - - /// @brief Sets the conversion time that the sensor will run to. - /// @param convTime Conversion time to set the sensor to. - /// @return 0 if successful, negative if error, positive for warning. - int8_t setConversionTime(const as7331_conv_time_t convTime) - { - int8_t result = SFE_BUS_OK; - - sfe_as7331_reg_cfg_creg1_t creg1; - - result = getCReg1(&creg1); - if(SFE_BUS_OK != result) - return result; - - creg1.time = convTime; - - result = setCReg1(&creg1); - if(SFE_BUS_OK != result) - return result; - - _config.conversionTime = convTime; - - calculateConversionFactors(); - - return SFE_BUS_OK; - } - - /// @brief Set the sensor's internal clock speed. - /// @param cclk Clock speed to set on the sensor. - /// @return 0 if successful, negative if error, positive for warning. - int8_t setCClk(const as7331_conv_clk_freq_t cclk) - { - int8_t result = SFE_BUS_OK; - - sfe_as7331_reg_cfg_creg3_t creg3; - - result = getCReg1(&creg3); - if(SFE_BUS_OK != result) - return result; - - creg3.cclk = cclk; - - result = setCReg1(&creg3); - if(SFE_BUS_OK != result) - return result; - - _config.cclk = cclk; - - calculateConversionFactors(); - - return SFE_BUS_OK; - } +#include - /// @brief Enables or disables the internal UV result divider. - /// @param isEnabled Enable or disable the divder. - /// @return 0 if successful, negative if error, positive for warning. - int8_t setEnableDivider(const as7331_divider_enable_t isEnabled) - { - if(_config.dividerEnabled == isEnabled) - return SFE_BUS_OK; - - int8_t result = SFE_BUS_OK; - - sfe_as7331_reg_cfg_creg2_t creg2; - - result = getCReg2(&creg2); - if(SFE_BUS_OK != result) - return result; - - creg2.en_div = isEnabled; - - result = setCReg2(&creg2); - if(SFE_BUS_OK != result) - return result; - - _config.dividerEnabled = isEnabled; - - if(isEnabled == DIVIDER_ENABLED) - calculateConversionFactors(); - - return SFE_BUS_OK; - } - - /// @brief Sets the value of the internal UV result divider. - /// @param divider Divider value to set. - /// @param setEnableDiv Option to turn on the divider if desired. - /// @return 0 if successful, negative if error, positive for warning. - int8_t setDigitalDivider(const as7331_divider_val_t divider, const bool setEnableDiv = false) - { - int8_t result = SFE_BUS_OK; - - sfe_as7331_reg_cfg_creg2_t creg2; - - result = getCReg2(&creg2); - if(SFE_BUS_OK != result) - return result; - - creg2.div = divider; - - result = setCReg2(&creg2); - if(SFE_BUS_OK != result) - return result; - - _config.dividerRange = divider; - - if(setEnableDiv) - result = setEnableDivider(DIVIDER_ENABLED); - else - calculateConversionFactors(); - - return SFE_BUS_OK; - } - - /// @brief Sets the ready pin type to push-pull or open-drain. - /// @param pinMode Mode to set the ready pin to. - /// @return 0 if successful, negative if error, positive for warning. - int8_t setReadyPinMode(const as7331_ready_pin_mode_t pinMode) - { - int8_t result = SFE_BUS_OK; - - sfe_as7331_reg_cfg_creg3_t creg3; - - result = getCReg3(&creg3); - if(SFE_BUS_OK != result) - return result; - - creg3.rdyod = pinMode; - - result = setCReg3(&creg3); - if(SFE_BUS_OK != result) - return result; - - _config.readyPinMode = pinMode; - - return SFE_BUS_OK; - } - - /// @brief Enables or disables the temperature conversion when in the SYND mode. - /// @param isEnabled Enable or disable the feature. - /// @return 0 if successful, negative if error, positive for warning. - int8_t setEnableTemperatureConversion(const as7331_ext_syn_temp_meas_t isEnabled) - { - int8_t result = SFE_BUS_OK; - - sfe_as7331_reg_cfg_creg2_t creg2; - - result = getCReg2(&creg2); - if(SFE_BUS_OK != result) - return result; - - creg2.en_tm = isEnabled; - - result = setCReg2(&creg2); - if(SFE_BUS_OK != result) - return result; - - _config.enableTempConv = isEnabled; - - return SFE_BUS_OK; - } - - /// @brief Set the index mode for compatibility with I2C controllers that don't support repeated start. - /// @param indexMode Simple or standard I2C addressing mode. - /// @return 0 if successful, negative if error, positive for warning. - int8_t setIndexMode(const as7331_simple_reg_read_mode_t indexMode) - { - int8_t result = SFE_BUS_OK; - - sfe_as7331_reg_cfg_optreg_t optreg; - - result = getOptIndex(&optreg); - if(SFE_BUS_OK != result) - return result; - - optreg.init_idx = indexMode; - - result = setOptIndex(&optreg); - if(SFE_BUS_OK != result) - return result; - - _config.indexMode = indexMode; - - return SFE_BUS_OK; - } - - /// @brief Set the minimum break time between measurements in CONT, SYNS, and SYND modes. - /// @param breakTime Time between measurements, 8us step time, max 2048us. A 0 value is a minimum of 3 fclk cycles. - /// @return 0 if successful, negative if error, positive for warning. - int8_t setBreakTime(const uint8_t breakTime) - { - int8_t result = SFE_BUS_OK; - - sfe_as7331_reg_cfg_break_t breakreg; - - result = getBreak(&breakreg); - if(SFE_BUS_OK != result) - return result; - - breakreg = breakTime; - - result = setBreak(&breakreg); - if(SFE_BUS_OK != result) - return result; - - _config.breakTime = breakTime; - - return SFE_BUS_OK; - } - - /// @brief Set the minimum number of falling edges required at the SYN input until the conversion is terminated. Only operational in SYND mode. - /// @param numEdges Number of edges prior to terminating conversion in SYND mode. 0 is not allowed, 1 is the minimum. - /// @return 0 if successful, negative if error, positive for warning. - int8_t setNumEdges(const uint8_t numEdges) - { - int8_t result = SFE_BUS_OK; - - sfe_as7331_reg_cfg_edges_t edgesreg; - - result = getEdges(&edgesreg); - if(SFE_BUS_OK != result) - return result; - - edgesreg = numEdges; - - result = setEdges(&edgesreg); - if(SFE_BUS_OK != result) - return result; - - _config.numEdges = numEdges; - - return SFE_BUS_OK; - } - - /// @brief Getter for the currently configured gain. - /// @return Sensor's gain expressed as (1 << (11 - gain)). - as7331_gain_t getConfigGain(void) - { - return _config.sensorGain; - } - - /// @brief Getter for the currently configured conversion clock. - /// @return Sensor's conversion clock expressed as 1024*(1 << cclk). - as7331_conv_clk_freq_t getConfigCClk(void) - { - return _config.cclk; - } - - /// @brief Getter for the currently configured conversion time. - /// @return Sensor's conversion time expressed as (1 << time). - as7331_conv_time_t getConfigConversionTime(void) - { - return _config.conversionTime; - } - - /// @brief Getter for the currently configured pin mode. - /// @return Sensor's ready pin configuration. - as7331_ready_pin_mode_t getConfigReadyPinMode(void) - { - return _config.readyPinMode; - } - - /// @brief Getter for the currently configured divider status. - /// @return Whether the sensor's divider is enabled or disabled. - as7331_divider_enable_t getConfigDividerEnabled(void) - { - return _config.dividerEnabled; - } - - /// @brief Getter for the currently configured divider range. - /// @return Sensor's internal UV predivider range. - as7331_divider_val_t getConfigDividerRange(void) - { - return _config.dividerRange; - } - - /// @brief Getter for the currently configured SYND temperature conversion status. - /// @return Whether the sensor will output temperature in SYND mode. - as7331_ext_syn_temp_meas_t getConfigExternalSyncTempConversion(void) - { - return _config.enableTempConv; - } - - /// @brief Getter for the currently configured I2C compatibility mode. - /// @return Sensor's configuration for interacting with simpler I2C controllers. - as7331_simple_reg_read_mode_t getConfigIndexMode(void) - { - return _config.indexMode; - } - - /// @brief Getter for the currently configured minimum break time in CONT, CMD, SYNS modes. - /// @return Sensor's breaktime in 8us steps. - uint8_t getConfigBreakTime(void) - { - return _config.breakTime; - } - - /// @brief Getter for the currently configured minimum number of edges to end conversion when in SYND mode. - /// @return Sensor's minimum number of edges, minimum 1 edge. - uint8_t getConfigNumEdges(void) - { - return _config.numEdges; - } - - /// @brief Gets the current power state from the sensor. - /// @param pd Pointer to an enum to store the current power state. - /// @return 0 if successful, negative if error, positive for warning. - int8_t getPowerState(as7331_power_state_t *pd) - { - int8_t result = SFE_BUS_OK; - - sfe_as7331_reg_cfg_osr_t osr; - - result = getOSR(&osr); - if(SFE_BUS_OK != result) - return result; - - _state.pd = (as7331_power_state_t)osr.pd; - *pd = _state.pd; - - return SFE_BUS_OK; - } - - /// @brief Sets the power state of the sensor. - /// @param pd Power state to set. - /// @return 0 if successful, negative if error, positive for warning. - int8_t setPowerState(const as7331_power_state_t pd = POWER_DOWN_DISABLE) - { - int8_t result = SFE_BUS_OK; - - sfe_as7331_reg_cfg_osr_t osr; - - result = getOSR(&osr); - if(SFE_BUS_OK != result) - return result; - - osr.pd = pd; - - result = setOSR(&osr); - if(SFE_BUS_OK != result) - return result; - - _state.pd = pd; - - return SFE_BUS_OK; - } - - /// @brief Gets the current operation mode from the sensor. - /// @param opMode Pointer to an enum to store the current operating mode. - /// @return 0 if successful, negative if error, positive for warning. - int8_t getOperationMode(as7331_device_op_state_t *opMode) - { - sfe_as7331_reg_cfg_osr_t osr; - int8_t result = getOSR(&osr); - if(SFE_BUS_OK != result) - return result; - - _state.opMode = (as7331_device_op_state_t)osr.dos; - *opMode = _state.opMode; - - return SFE_BUS_OK; - } - - /// @brief Set the sensor's operating mode. - /// @param opMode Operating mode to set. - /// @return 0 if successful, negative if error, positive for warning. - int8_t setOperationMode(const as7331_device_op_state_t opMode) - { - int8_t result = SFE_BUS_OK; - - sfe_as7331_reg_cfg_osr_t osr; - - result = getOSR(&osr); - if(SFE_BUS_OK != result) - return result; - - osr.dos = opMode; - - result = setOSR(&osr); - if(SFE_BUS_OK != result) - return result; - - _state.opMode = opMode; - - return SFE_BUS_OK; - } - - /// @brief Gets the sensor's current measurement mode. - /// @param measMode Pointer to an enum to store the current measurment mode. - /// @return 0 if successful, negative if error, positive for warning. - int8_t getMeasurementMode(as7331_meas_mode_t *measMode) - { - sfe_as7331_reg_cfg_creg3_t creg3; - int8_t result = getCReg3(&creg3); - if(SFE_BUS_OK != result) - return result; - - _state.mmode = (as7331_meas_mode_t)creg3.mmode; - *measMode = _state.mmode; - - return SFE_BUS_OK; - } - - /// @brief Sets the sensor's measurement mode. - /// @param measMode Measurement mode to set. - /// @return 0 if successful, negative if error, positive for warning. - int8_t setMeasurementMode(const as7331_meas_mode_t measMode) - { - int8_t result = SFE_BUS_OK; - - sfe_as7331_reg_cfg_creg3_t creg3; - - result = getCReg3(&creg3); - if(SFE_BUS_OK != result) - return result; - - creg3.mmode = measMode; - - result = setCReg3(&creg3); - if(SFE_BUS_OK != result) - return result; - - _state.mmode = measMode; - - return SFE_BUS_OK; - } - - /// @brief Gets the sensor's current standby mode state. - /// @param standby Pointer to an enum to store the current standby state. - /// @return 0 if successful, negative if error, positive for warning. - int8_t getStandbyMode(as7331_standby_mode_t *standby) - { - int8_t result = SFE_BUS_OK; - - sfe_as7331_reg_cfg_creg3_t creg3; - - result = getCReg3(&creg3); - if(SFE_BUS_OK != result) - return result; - - _state.sb = (as7331_standby_mode_t)creg3.sb; - *standby = _state.sb; - - return SFE_BUS_OK; - } - - /// @brief Sets the sensor's standby mode. - /// @param standby State to set. - /// @return 0 if successful, negative if error, positive for warning. - int8_t setStandbyMode(const as7331_standby_mode_t standby) - { - int8_t result = SFE_BUS_OK; - - sfe_as7331_reg_cfg_creg3_t creg3; - - result = getCReg3(&creg3); - if(SFE_BUS_OK != result) - return result; - - creg3.sb = standby; - - result = setCReg3(&creg3); - if(SFE_BUS_OK != result) - return result; - - _state.sb = standby; - - return SFE_BUS_OK; - } - - /// @brief Gets the sensor's current start state. - /// @param startState Pointer to an enum to store the current start state. - /// @return 0 if successful, negative if error, positive for warning. - int8_t getStartStateMode(as7331_startstate_t *startState) - { - int8_t result = SFE_BUS_OK; - - sfe_as7331_reg_cfg_osr_t osr; - - result = getOSR(&osr); - if(SFE_BUS_OK != result) - return result; - - _state.ss = (as7331_startstate_t)osr.ss; - *startState = _state.ss; - - return SFE_BUS_OK; - } - - /// @brief Sets the sensor's start state. This begins measurement. - /// @param startState Start state to set. - /// @return 0 if successful, negative if error, positive for warning. - int8_t setStartStateMode(const as7331_startstate_t startState) - { - int8_t result = SFE_BUS_OK; - - sfe_as7331_reg_cfg_osr_t osr; - - result = getOSR(&osr); - if(SFE_BUS_OK != result) - return result; - - osr.ss = startState; - - result = setOSR(&osr); - if(SFE_BUS_OK != result) - return result; - - _state.ss = startState; - - return SFE_BUS_OK; - } - - /// @brief Getter for the current power state. - /// @return Sensor's power state. - as7331_power_state_t getStatePower(void) - { - return _state.pd; - } - - /// @brief Getter for the current operational state. - /// @return Sensor's operational state. - as7331_device_op_state_t getStateOperational(void) - { - return _state.opMode; - } - - /// @brief Getter for the current measurement state. - /// @return Sensor's measurement state. - as7331_meas_mode_t getStateMeasurement(void) - { - return _state.mmode; - } - - /// @brief Getter for the current standby state. - /// @return Sensor's standby state. - as7331_standby_mode_t getStateStandby(void) - { - return _state.sb; - } - - /// @brief Getter for the current start state. - /// @return Sensor's start state. - as7331_startstate_t getStateStart(void) - { - return _state.ss; - } - - /// @brief Gets the sensor's status when in measurement operation mode. - /// @param statusReg Pointer to a register struct to store the sensor's current status. - /// @return 0 if successful, negative if error, positive for warning. - int8_t getStatus(sfe_as7331_reg_meas_osr_status_t *statusReg) - { - int8_t result = SFE_BUS_OK; - uint8_t statusRaw[2]; - - result = readRegister(SFE_AS7331_REGISTER_MEAS_OSR_STATUS, statusRaw, 2U); - - if(SFE_BUS_OK != result) - return result; - - statusReg->word = ((uint16_t)statusRaw[1] << 8) | statusRaw[0]; - - return SFE_BUS_OK; - } - - /// @brief Gets the operational state register when in configuration operation mode. - /// @param osrReg Pointer to a register struct to store the sensor's current OSR register. - /// @return 0 if successful, negative if error, positive for warning. - int8_t getOSR(sfe_as7331_reg_cfg_osr_t *osrReg) - { - return readRegister(SFE_AS7331_REGISTER_CFG_OSR, &osrReg->byte); - } - - /// @brief Sets the operational state register when in configuration operation mode. - /// @param osrReg Pointer to a register struct that has the new register configuration. - /// @return 0 if successful, negative if error, positive for warning. - int8_t setOSR(const sfe_as7331_reg_cfg_osr_t *osrReg) - { - return writeRegister(SFE_AS7331_REGISTER_CFG_OSR, &osrReg->byte); - } - - /// @brief Gets the configuration register #1 when in configuration operation mode. - /// @param creg1 Pointer to a register struct to store the sensor's current creg1 register. - /// @return 0 if successful, negative if error, positive for warning. - int8_t getCReg1(sfe_as7331_reg_cfg_creg1_t *creg1) - { - return readRegister(SFE_AS7331_REGISTER_CFG_CREG1, &creg1->byte); - } - - /// @brief Sets the configuration register #1 when in configuration operation mode. - /// @param creg1 Pointer to a register struct that has the new register configuration. - /// @return 0 if successful, negative if error, positive for warning. - int8_t setCReg1(const sfe_as7331_reg_cfg_creg1_t *creg1) - { - return writeRegister(SFE_AS7331_REGISTER_CFG_CREG1, &creg1->byte); - } - - /// @brief Gets the configuration register #2 when in configuration operation mode. - /// @param creg2 Pointer to a register struct to store the sensor's current creg2 register. - /// @return 0 if successful, negative if error, positive for warning. - int8_t getCReg2(sfe_as7331_reg_cfg_creg2_t *creg2) - { - return readRegister(SFE_AS7331_REGISTER_CFG_CREG2, &creg2->byte); - } - - /// @brief Sets the configuration register #2 when in configuration operation mode. - /// @param creg2 Pointer to a register struct that has the new register configuration. - /// @return 0 if successful, negative if error, positive for warning. - int8_t setCReg2(const sfe_as7331_reg_cfg_creg2_t *creg2) - { - return writeRegister(SFE_AS7331_REGISTER_CFG_CREG2, &creg2->byte); - } - - /// @brief Gets the configuration register #3 when in configuration operation mode. - /// @param creg3 Pointer to a register struct to store the sensor's current creg3 register. - /// @return 0 if successful, negative if error, positive for warning. - int8_t getCReg3(sfe_as7331_reg_cfg_creg3_t *creg3) - { - return readRegister(SFE_AS7331_REGISTER_CFG_CREG3, &creg3->byte); - } - - /// @brief Sets the configuration register #3 when in configuration operation mode. - /// @param creg3 Pointer to a register struct that has the new register configuration. - /// @return 0 if successful, negative if error, positive for warning. - int8_t setCReg3(const sfe_as7331_reg_cfg_creg3_t *creg3) - { - return writeRegister(SFE_AS7331_REGISTER_CFG_CREG3, &creg3->byte); - } - - /// @brief Gets the break register when in configuration operation mode. - /// @param breakReg Pointer to a register struct to store the sensor's current break register. - /// @return 0 if successful, negative if error, positive for warning. - int8_t getBreak(sfe_as7331_reg_cfg_break_t *breakReg) - { - return readRegister(SFE_AS7331_REGISTER_CFG_BREAK, breakReg); - } - - /// @brief Sets the break register when in configuration operation mode. - /// @param breakReg Pointer to a register struct that has the new register configuration. - /// @return 0 if successful, negative if error, positive for warning. - int8_t setBreak(const sfe_as7331_reg_cfg_break_t *breakReg) - { - return writeRegister(SFE_AS7331_REGISTER_CFG_BREAK, breakReg); - } - - /// @brief Gets the edges register when in configuration operation mode. - /// @param edgesReg Pointer to a register struct to store the sensor's current edges register. - /// @return 0 if successful, negative if error, positive for warning. - int8_t getEdges(sfe_as7331_reg_cfg_edges_t *edgesReg) - { - return readRegister(SFE_AS7331_REGISTER_CFG_EDGES, edgesReg); - } - - - /// @brief Sets the edges register when in configuration operation mode. - /// @param edgesReg Pointer to a register struct that has the new register configuration. - /// @return 0 if successful, negative if error, positive for warning. - int8_t setEdges(const sfe_as7331_reg_cfg_edges_t *edgesReg) - { - return writeRegister(SFE_AS7331_REGISTER_CFG_EDGES, edgesReg); - } - - /// @brief Gets the option register when in configuration operation mode. - /// @param optReg Pointer to a register struct to store the sensor's current option register. - /// @return 0 if successful, negative if error, positive for warning. - int8_t getOptIndex(sfe_as7331_reg_cfg_optreg_t *optReg) - { - return readRegister(SFE_AS7331_REGISTER_CFG_OPTREG, &optReg->byte); - } - - /// @brief Sets the option register when in configuration operation mode. - /// @param optReg Pointer to a register struct that has the new register configuration. - /// @return 0 if successful, negative if error, positive for warning. - int8_t setOptIndex(const sfe_as7331_reg_cfg_optreg_t *optReg) - { - return writeRegister(SFE_AS7331_REGISTER_CFG_OPTREG, &optReg->byte); - } - - sfeAS7331_measures_t measures; +class SfeAS7331ArdI2C : public SfeAS7331Driver +{ + public: + SfeAS7331ArdI2C() + { + } - private: - /// @brief Converts the raw temperature value to a human readable form. - /// @param inputVal Raw temperature value to convert. - /// @return The converted device temperature in degree C. - float convertRawTempToTempC(const uint16_t inputVal) - { - // T_chip = TEMP*0.05 - 66.9 - // EX: TEMP=0x922 aka TEMP=0d2338, returns 50.0 - return ((float)(inputVal) * 0.05f) - 66.9f; - } + /// @brief Sets up Arduino I2C driver using the specified I2C address then calls the super class begin. + /// @param address Address of the I2C device. + /// @return True if successful, false otherwise. + bool begin(const uint8_t &address = kDefaultAS7331Addr, TwoWire &wirePort = Wire) + { + if (_theI2CBus.init(wirePort, address) != kSTkErrOk) + return false; - /// @brief Called when changing values that affect the conversion, calculates a new conversion factor to reduce the conversion overhead. - void calculateConversionFactors(void) - { - float divFactor = (bool)_config.dividerEnabled ? (float)(1 << (1+_config.dividerRange)) : 1.0f; - _conversionA = fsrA/((float)(1 << (11 - _config.sensorGain)))/((float)(1 << _config.conversionTime))/((float)(1024.0 * (1 << _config.cclk)))*divFactor; - _conversionB = fsrB/((float)(1 << (11 - _config.sensorGain)))/((float)(1 << _config.conversionTime))/((float)(1024.0 * (1 << _config.cclk)))*divFactor; - _conversionC = fsrC/((float)(1 << (11 - _config.sensorGain)))/((float)(1 << _config.conversionTime))/((float)(1024.0 * (1 << _config.cclk)))*divFactor; - } + // Device supports repeat starts, enable it. + _theI2CBus.setStop(false); - sfeBusDevice *_sfeBus; // Pointer to bus device. - sfeBusDeviceSettings *_devSettings; // Pointer to the device settings for this sensor. + setCommunicationBus(&_theI2CBus); - sfeAS7331_config_t _config; // Internal sensor configuration. - sfeAS7331_state_t _state; // Internal sensor state. + isConnected(); - float _conversionA; // Internal conversion factor for the UVA sensor. - float _conversionB; // Internal conversion factor for the UVB sensor. - float _conversionC; // Internal conversion factor for the UVC sensor. + return SfeAS7331Driver::begin(address); + } - static constexpr float fsrA = 348160.0; // Full Scale Resolution for the UVA sensor. - static constexpr float fsrB = 387072.0; // Full Scale Resolution for the UVB sensor. - static constexpr float fsrC = 169984.0; // Full Scale Resolution for the UVC sensor. + /// @brief Checks to see if the AS7331 is connected. + /// @return True if successful, false otherwise. + bool isConnected(void) + { + if (_theI2CBus.ping() != kSTkErrOk) + return false; -}; + return (kDefaultAS7331DeviceID == getDeviceID()); + } -/// @class SfeAS7331ArdI2C -/// @brief Arduino I2C implementation of the SfeAS7331Base class for the AS7331 Spectral UV Sensor. -class SfeAS7331ArdI2C : public SfeAS7331Base -{ - /* Nothing to see here, see above. */ + private: + sfeTkArdI2C _theI2CBus; }; diff --git a/src/sfeAS7331.cpp b/src/sfeAS7331.cpp new file mode 100644 index 0000000..7e168a0 --- /dev/null +++ b/src/sfeAS7331.cpp @@ -0,0 +1,1108 @@ +#include "sfeAS7331.h" + +bool SfeAS7331Driver::begin(const uint8_t &deviceAddress, sfeTkIBus *theBus) +{ + // Nullptr check. + if (!_theBus && !theBus) + return false; + + // Set the internal bus pointer, overriding current bus if it exists. + if (theBus != nullptr) + setCommunicationBus(theBus); + + // If the address passed in isn't the default, set the new address. + if (kDefaultAS7331Addr != deviceAddress) + setDeviceAddress(deviceAddress); + + // Get the device setup and ready. + return runDefaultSetup(); +} + +uint8_t SfeAS7331Driver::getDeviceID(void) +{ + // Nullptr check. + if (!_theBus) + return 0; + + // Check sensor's operating mode. + sfe_as7331_reg_cfg_osr_t osr; + if (kSTkErrOk != getOSR(osr)) + return 0; + + bool needsToBeChangedBack = false; + + // Change if necessary. + if (osr.dos != DEVICE_MODE_CFG) + { + needsToBeChangedBack = true; + + osr.dos = DEVICE_MODE_CFG; + + if(kSTkErrOk != setOSR(osr)) + return 0; + } + + uint8_t devID; + + // Read the device ID register, if it errors then return 0. + if (kSTkErrOk != _theBus->readRegisterByte(kSfeAS7331RegCfgAgen, devID)) + return 0; + + // If we changed it at first, change it back. + if(needsToBeChangedBack) + { + osr.dos = DEVICE_MODE_MEAS; + + if(kSTkErrOk != setOSR(osr)) + return 0; + } + + return devID; +} + +void SfeAS7331Driver::setCommunicationBus(sfeTkIBus *theBus) +{ + _theBus = theBus; +} + +void SfeAS7331Driver::setDeviceAddress(const uint8_t &deviceAddress) +{ + switch(deviceAddress) + { + // If it's any of the allowed addresses, set it. + case kDefaultAS7331Addr: + case kSecondaryAS7331Addr: + case kTertiaryAS7331Addr: + case kQuaternaryAS7331Addr: + _devAddress = deviceAddress; + break; + default: // Default to doing nothing. + break; + } +} + +uint8_t SfeAS7331Driver::getDeviceAddress(void) +{ + return _devAddress; +} + +bool SfeAS7331Driver::runDefaultSetup(const bool &runSoftReset) +{ + // Nullptr check. + if (!_theBus) + return false; + + // Do we need to run a software reset? + if (runSoftReset) + reset(); + else + { + setDefaultSettings(); + + // Read the OSR register by itself since the offset isn't contiguous with the rest. + sfe_as7331_reg_cfg_osr_t osr; + if (kSTkErrOk != getOSR(osr)) + return false; + + // Change operation mode if necessary. + if (osr.dos != DEVICE_MODE_CFG) + { + osr.dos = DEVICE_MODE_CFG; + + if(kSTkErrOk != setOSR(osr)) + return false; + } + + // Read all the configuration registers in. + uint8_t regs[6]; + + uint32_t nRead = 0; + sfeTkError_t result = _theBus->readRegisterRegion(kSfeAS7331RegCfgCreg1, regs, 6U, nRead); + if (nRead != 6 || result != kSTkErrOk) + return false; + + // Assign the read in bytes to each register's byte union. + // This allows us to address the individual bits and set them. + sfe_as7331_reg_cfg_creg1_t creg1 = {.byte = regs[0]}; + sfe_as7331_reg_cfg_creg2_t creg2 = {.byte = regs[1]}; + sfe_as7331_reg_cfg_creg3_t creg3 = {.byte = regs[2]}; + uint8_t breakreg = regs[3]; + uint8_t edgesreg = regs[4]; + sfe_as7331_reg_cfg_optreg_t optreg = {.byte = regs[5]}; + + // Here we make sure the sensor's settings match the local settings + // by changing the sensor's settings. + osr.ss = _startState; + osr.pd = _powerDownEnableState; + osr.dos = _opMode; + + creg1.gain = _sensorGain; + creg1.time = _conversionTime; + + creg2.en_tm = _tempConvEnabled; + creg2.en_div = _dividerEnabled; + creg2.div = _dividerRange; + + creg3.mmode = _mmode; + creg3.sb = _standbyState; + creg3.rdyod = _readyPinMode; + creg3.cclk = _cclk; + + breakreg = _breakTime; + + edgesreg = _numEdges; + + optreg.init_idx = _indexMode; + + // Write OSR first, since the offset is different from the rest. + if (kSTkErrOk != setOSR(osr)) + return false; + + // Assign the registers to a byte array for writing to the device. + regs[0] = creg1.byte; + regs[1] = creg2.byte; + regs[2] = creg3.byte; + regs[3] = breakreg; + regs[4] = edgesreg; + regs[5] = optreg.byte; + + // Write the bytes to the sensor, ensuring the device matches local settings. + if (kSTkErrOk != _theBus->writeRegisterRegion(kSfeAS7331RegCfgCreg1, regs, 6U)) + return false; + } + + // Calculate new conversion factors to make sure they match the current settings. + calculateConversionFactors(); + + return true; +} + +bool SfeAS7331Driver::prepareMeasurement(const as7331_meas_mode_t &measMode, const bool &startMeasure) +{ + // If the device is currently in power down mode. + if (_powerDownEnableState) + { + if (kSTkErrOk != setPowerDownState(false)) // Set the device to be powered up. + return false; + } + + // If the device is currently in standby mode. + if (_standbyState) + { + if (kSTkErrOk != setStandbyState(false)) // Set the device to not be in standby. + return false; + } + + // If the device's currently configured measurement mode is different than the desired mode. + // This is just to reduce unnecessary calls. + if (_mmode != measMode) + { + if (kSTkErrOk != setMeasurementMode(measMode)) // Set the new mode. + return false; + } + + // If the device is in start state and we don't want it to be. + // This prevents starting automatically in the next step. + if (_startState && !startMeasure) + { + if (kSTkErrOk != setStartState(false)) // Stop it from running automatically. + return false; + } + + // Now that we've configured ourselves to measure properly, move the device op mode to measure. + if (kSTkErrOk != setOperationMode(DEVICE_MODE_MEAS)) + return false; + + // If the device is supposed to be started automatically and isn't configured that way. + if (!_startState && startMeasure) + { + if (kSTkErrOk != setStartState(true)) // Set the device to being measuring. + return false; + } + + return true; +} + +bool SfeAS7331Driver::reset(void) +{ + // OSR is available in all modes, no need to change modes. + + // Standard read-modify-write sequence. + sfe_as7331_reg_cfg_osr_t osr; + + if (kSTkErrOk != getOSR(osr)) + return false; + + // Set software reset bit. + osr.sw_res = 1; + + if (kSTkErrOk != setOSR(osr)) + return false; + + // Set internal variables back to defaults. + setDefaultSettings(); + + return true; +} + +sfeTkError_t SfeAS7331Driver::readTemp(void) +{ + // Temperature is only available in Measurement mode. + if (!_theBus || _opMode != DEVICE_MODE_MEAS) + return kSTkErrFail; + + uint16_t tempRaw; + + // Read in the raw value. + sfeTkError_t result = _theBus->readRegisterWord(kSfeAS7331RegMeasTemp, tempRaw); + + if (kSTkErrOk != result) + return result; + + // Since temperature is more than 1 byte, need to order it correctly before conversion. + _temperature = convertRawTempToTempC(tempRaw); + + return kSTkErrOk; +} + +sfeTkError_t SfeAS7331Driver::readUVA(void) +{ + return readRawUV(AS7331_UVA); +} + +sfeTkError_t SfeAS7331Driver::readUVB(void) +{ + return readRawUV(AS7331_UVB); +} + +sfeTkError_t SfeAS7331Driver::readUVC(void) +{ + return readRawUV(AS7331_UVC); +} + +sfeTkError_t SfeAS7331Driver::readAllUV(void) +{ + // UV results are only available in Measurement mode. + if (!_theBus || _opMode != DEVICE_MODE_MEAS) + return kSTkErrFail; + + uint8_t dataRaw[6]; + + // Read in the raw data from the results registers. + uint32_t nRead = 0; + + sfeTkError_t result = _theBus->readRegisterRegion(kSfeAS7331RegMeasMres1, dataRaw, 6U, nRead); + + if (nRead != 6 || result != kSTkErrOk) + return result; + + // If we're in SYND mode, need to calculate conversion based on the conversion time. + if (_mmode == MEAS_MODE_SYND) + { + result = readOutConv(); + if (kSTkErrOk != result) + return result; + + // See datasheet section 7.4 Equation 4. + // fsrX + // -------------- + // gain * outConv + float convFactor = 1.0f / (((float)_outputConversionTime) * ((float)(1 << (11 - _sensorGain)))); + + // Since result is more than 1 byte, need to order it correctly before conversion. + // FSR is dependent on the channel being measured, so do that here. + _uva = convertRawUVVal(((uint16_t)dataRaw[1] << 8 | dataRaw[0]) * _fsrA, convFactor); + _uvb = convertRawUVVal(((uint16_t)dataRaw[3] << 8 | dataRaw[2]) * _fsrB, convFactor); + _uvc = convertRawUVVal(((uint16_t)dataRaw[5] << 8 | dataRaw[4]) * _fsrC, convFactor); + } + else + { + // If we're in CONT, CMD, or SYNS mode, use the normally calculated conversion factor. + // Since result is more than 1 byte, need to order it correctly before conversion. + _uva = convertRawUVVal((uint16_t)dataRaw[1] << 8 | dataRaw[0], _conversionA); + _uvb = convertRawUVVal((uint16_t)dataRaw[3] << 8 | dataRaw[2], _conversionB); + _uvc = convertRawUVVal((uint16_t)dataRaw[5] << 8 | dataRaw[4], _conversionC); + } + + return kSTkErrOk; +} + +sfeTkError_t SfeAS7331Driver::readAll(void) +{ + // Results are only available in Measurement mode. + if (!_theBus || _opMode != DEVICE_MODE_MEAS) + return kSTkErrFail; + + uint8_t dataRaw[8]; + + uint32_t nRead = 0; + sfeTkError_t result = _theBus->readRegisterRegion(kSfeAS7331RegMeasTemp, dataRaw, 8U, nRead); + + if (nRead != 8 || result != kSTkErrOk) + return result; + + result = readOutConv(); + if (kSTkErrOk != result) + return result; + + // If we're in SYND mode, need to calculate conversion based on the conversion time. + if (_mmode == MEAS_MODE_SYND) + { + // See datasheet section 7.4 Equation 4. + // fsrX + // -------------- + // gain * outConv + float convFactor = 1.0f / (((float)_outputConversionTime) * ((float)(1 << (11 - _sensorGain)))); + + // Since result is more than 1 byte, need to order it correctly before conversion. + // FSR is dependent on the channel being measured, so do that part here. + _uva = convertRawUVVal(((uint16_t)dataRaw[3] << 8 | dataRaw[2]) * _fsrA, convFactor); + _uvb = convertRawUVVal(((uint16_t)dataRaw[5] << 8 | dataRaw[4]) * _fsrB, convFactor); + _uvc = convertRawUVVal(((uint16_t)dataRaw[7] << 8 | dataRaw[6]) * _fsrC, convFactor); + } + else + { + // If we're in CONT, CMD, or SYNS mode, use the normally calculated conversion factor. + // Since result is more than 1 byte, need to order it correctly before conversion. + _uva = convertRawUVVal((uint16_t)dataRaw[3] << 8 | dataRaw[2], _conversionA); + _uvb = convertRawUVVal((uint16_t)dataRaw[5] << 8 | dataRaw[4], _conversionB); + _uvc = convertRawUVVal((uint16_t)dataRaw[7] << 8 | dataRaw[6], _conversionC); + } + + // Since result is more than 1 byte, need to order it correctly before conversion. + _temperature = convertRawTempToTempC((uint16_t)dataRaw[1] << 8 | dataRaw[0]); + + return kSTkErrOk; +} + +sfeTkError_t SfeAS7331Driver::readOutConv(void) +{ + // Results are only available in Measurement mode. + if (!_theBus || _opMode != DEVICE_MODE_MEAS) + return kSTkErrFail; + + uint8_t tconvRaw[4]; + + uint32_t nRead = 0; + + sfeTkError_t result = _theBus->readRegisterRegion(kSfeAS7331RegMeasOutConvL, tconvRaw, 4U, nRead); + + if (nRead != 4 || result != kSTkErrOk) + return result; + + // Since result is more than 1 byte, need to order it correctly. + _outputConversionTime = (uint32_t)(((uint32_t)tconvRaw[3] << 24) | ((uint32_t)tconvRaw[2] << 16) | + ((uint32_t)tconvRaw[1] << 8) | tconvRaw[0]); + + return kSTkErrOk; +} + +float SfeAS7331Driver::getUVA(void) +{ + return _uva; +} + +float SfeAS7331Driver::getUVB(void) +{ + return _uvb; +} + +float SfeAS7331Driver::getUVC(void) +{ + return _uvc; +} + +float SfeAS7331Driver::getTemp(void) +{ + return _temperature; +} + +uint32_t SfeAS7331Driver::getOutConv(void) +{ + return _outputConversionTime; +} + +as7331_gain_t SfeAS7331Driver::getGainRaw(void) +{ + return _sensorGain; +} + +uint16_t SfeAS7331Driver::getGainValue(void) +{ + return (1 << (11 - _sensorGain)); +} + +sfeTkError_t SfeAS7331Driver::setGain(const as7331_gain_t &gain) +{ + sfe_as7331_reg_cfg_creg1_t creg1; + + // Standard read-modify-write sequence. + sfeTkError_t result = getCReg1(creg1); + if (kSTkErrOk != result) + return result; + + creg1.gain = gain; + + result = setCReg1(creg1); + if (kSTkErrOk != result) + return result; + + // If write is successful, save to internal state. + _sensorGain = gain; + + // Gain affects the conversion factors, so calculate new ones with the updated values. + calculateConversionFactors(); + + return kSTkErrOk; +} + +as7331_conv_clk_freq_t SfeAS7331Driver::getCClkRaw(void) +{ + return _cclk; +} + +uint16_t SfeAS7331Driver::getCClkKHz(void) +{ + return 1024*(1 << _cclk); +} + +sfeTkError_t SfeAS7331Driver::setCClk(const as7331_conv_clk_freq_t &cclk) +{ + sfe_as7331_reg_cfg_creg3_t creg3; + + // Standard read-modify-write sequence. + sfeTkError_t result = getCReg3(creg3); + if (kSTkErrOk != result) + return result; + + creg3.cclk = cclk; + + result = setCReg3(creg3); + if (kSTkErrOk != result) + return result; + + // If write is successful, save to internal state. + _cclk = cclk; + + // CClk affects the conversion factors, so calculate new ones with the updated values. + calculateConversionFactors(); + + return kSTkErrOk; +} + +as7331_conv_time_t SfeAS7331Driver::getConversionTimeRaw(void) +{ + return _conversionTime; +} + +uint16_t SfeAS7331Driver::getConversionTimeMillis(void) +{ + return (1 << _conversionTime); +} + +sfeTkError_t SfeAS7331Driver::setConversionTime(const as7331_conv_time_t &convTime) +{ + sfe_as7331_reg_cfg_creg1_t creg1; + + // Standard read-modify-write sequence. + sfeTkError_t result = getCReg1(creg1); + if (kSTkErrOk != result) + return result; + + creg1.time = convTime; + + result = setCReg1(creg1); + if (kSTkErrOk != result) + return result; + + // If write is successful, save to internal state. + _conversionTime = convTime; + + // Conversion Time affects the conversion factors, so calculate new ones with the updated values. + calculateConversionFactors(); + + return kSTkErrOk; +} + +bool SfeAS7331Driver::getReadyPinMode(void) +{ + return _readyPinMode; +} + +sfeTkError_t SfeAS7331Driver::setReadyPinMode(const bool &pinMode) +{ + sfe_as7331_reg_cfg_creg3_t creg3; + + // Standard read-modify-write sequence. + sfeTkError_t result = getCReg3(creg3); + if (kSTkErrOk != result) + return result; + + creg3.rdyod = pinMode; + + result = setCReg3(creg3); + if (kSTkErrOk != result) + return result; + + // If write is successful, save to internal state. + _readyPinMode = pinMode; + + return kSTkErrOk; +} + +bool SfeAS7331Driver::getDigitalDividerEnabled(void) +{ + return _dividerEnabled; +} + +sfeTkError_t SfeAS7331Driver::setDigitalDividerEnabled(const bool &isEnabled) +{ + if (_dividerEnabled == isEnabled) + return kSTkErrOk; + + sfe_as7331_reg_cfg_creg2_t creg2; + + // Standard read-modify-write sequence. + sfeTkError_t result = getCReg2(creg2); + if (kSTkErrOk != result) + return result; + + creg2.en_div = isEnabled; + + result = setCReg2(creg2); + if (kSTkErrOk != result) + return result; + + // If write is successful, save to internal state. + _dividerEnabled = isEnabled; + + // Digital divider affects the conversion factors, so calculate new ones with the updated values. + calculateConversionFactors(); + + return kSTkErrOk; +} + +as7331_divider_val_t SfeAS7331Driver::getDigitalDividerRange(void) +{ + return _dividerRange; +} + +sfeTkError_t SfeAS7331Driver::setDigitalDividerRange(const as7331_divider_val_t ÷r, const bool &enableDiv) +{ + sfe_as7331_reg_cfg_creg2_t creg2; + + // Standard read-modify-write sequence. + sfeTkError_t result = getCReg2(creg2); + if (kSTkErrOk != result) + return result; + + creg2.div = divider; + creg2.en_div = enableDiv; + + result = setCReg2(creg2); + if (kSTkErrOk != result) + return result; + + // If write is successful, save to internal state. + _dividerRange = divider; + _dividerEnabled = enableDiv; + + // Digital divider affects the conversion factors, so calculate new ones with the updated values. + calculateConversionFactors(); + + return kSTkErrOk; +} + +bool SfeAS7331Driver::getSyndTempConversionEnabled(void) +{ + return _tempConvEnabled; +} + +sfeTkError_t SfeAS7331Driver::setSyndTempConversionEnabled(const bool &isEnabled) +{ + sfe_as7331_reg_cfg_creg2_t creg2; + + // Standard read-modify-write sequence. + sfeTkError_t result = getCReg2(creg2); + if (kSTkErrOk != result) + return result; + + creg2.en_tm = isEnabled; + + result = setCReg2(creg2); + if (kSTkErrOk != result) + return result; + + // If write is successful, save to internal state. + _tempConvEnabled = isEnabled; + + return kSTkErrOk; +} + +bool SfeAS7331Driver::getIndexMode(void) +{ + return _indexMode; +} + +sfeTkError_t SfeAS7331Driver::setIndexMode(const bool &indexMode) +{ + sfe_as7331_reg_cfg_optreg_t optreg; + + // Standard read-modify-write sequence. + sfeTkError_t result = getOptIndex(optreg); + if (kSTkErrOk != result) + return result; + + optreg.init_idx = indexMode; + + result = setOptIndex(optreg); + if (kSTkErrOk != result) + return result; + + // If write is successful, save to internal state. + _indexMode = indexMode; + + return kSTkErrOk; +} + +uint8_t SfeAS7331Driver::getBreakTime(void) +{ + return _breakTime; +} + +sfeTkError_t SfeAS7331Driver::setBreakTime(const uint8_t &breakTime) +{ + uint8_t breakreg; + + // Standard read-modify-write sequence. + sfeTkError_t result = getBreak(breakreg); + if (kSTkErrOk != result) + return result; + + breakreg = breakTime; + + result = setBreak(breakreg); + if (kSTkErrOk != result) + return result; + + // If write is successful, save to internal state. + _breakTime = breakTime; + + return kSTkErrOk; +} + +uint8_t SfeAS7331Driver::getNumEdges(void) +{ + return _numEdges; +} + +sfeTkError_t SfeAS7331Driver::setNumEdges(const uint8_t &numEdges) +{ + uint8_t edgesreg; + + // Standard read-modify-write sequence. + sfeTkError_t result = getEdges(edgesreg); + if (kSTkErrOk != result) + return result; + + edgesreg = numEdges; + + result = setEdges(edgesreg); + if (kSTkErrOk != result) + return result; + + // If write is successful, save to internal state. + _numEdges = numEdges; + + return kSTkErrOk; +} + +bool SfeAS7331Driver::getPowerDownState(void) +{ + return _powerDownEnableState; +} + +sfeTkError_t SfeAS7331Driver::setPowerDownState(const bool &pd) +{ + sfe_as7331_reg_cfg_osr_t osr; + + // Standard read-modify-write sequence. + sfeTkError_t result = getOSR(osr); + if (kSTkErrOk != result) + return result; + + osr.pd = pd; + + result = setOSR(osr); + if (kSTkErrOk != result) + return result; + + // If write is successful, save to internal state. + _powerDownEnableState = pd; + + return kSTkErrOk; +} + +as7331_dev_op_state_t SfeAS7331Driver::getOperationMode(void) +{ + return _opMode; +} + +sfeTkError_t SfeAS7331Driver::setOperationMode(const as7331_dev_op_state_t &opMode) +{ + sfe_as7331_reg_cfg_osr_t osr; + + // Standard read-modify-write sequence. + sfeTkError_t result = getOSR(osr); + if (kSTkErrOk != result) + return result; + + osr.dos = opMode; + + result = setOSR(osr); + if (kSTkErrOk != result) + return result; + + // If write is successful, save to internal state. + _opMode = opMode; + + return kSTkErrOk; +} + +as7331_meas_mode_t SfeAS7331Driver::getMeasurementMode(void) +{ + return _mmode; +} + +sfeTkError_t SfeAS7331Driver::setMeasurementMode(const as7331_meas_mode_t &measMode) +{ + sfe_as7331_reg_cfg_creg3_t creg3; + + // Standard read-modify-write sequence. + sfeTkError_t result = getCReg3(creg3); + if (kSTkErrOk != result) + return result; + + creg3.mmode = measMode; + + result = setCReg3(creg3); + if (kSTkErrOk != result) + return result; + + // If write is successful, save to internal state. + _mmode = measMode; + + return kSTkErrOk; +} + +bool SfeAS7331Driver::getStandbyState(void) +{ + return _standbyState; +} + +sfeTkError_t SfeAS7331Driver::setStandbyState(const bool &standby) +{ + sfe_as7331_reg_cfg_creg3_t creg3; + + // Standard read-modify-write sequence. + sfeTkError_t result = getCReg3(creg3); + if (kSTkErrOk != result) + return result; + + creg3.sb = standby; + + result = setCReg3(creg3); + if (kSTkErrOk != result) + return result; + + // If write is successful, save to internal state. + _standbyState = standby; + + return kSTkErrOk; +} + +bool SfeAS7331Driver::getStartState(void) +{ + return _startState; +} + +sfeTkError_t SfeAS7331Driver::setStartState(const bool &startState) +{ + sfe_as7331_reg_cfg_osr_t osr; + + // Standard read-modify-write sequence. + sfeTkError_t result = getOSR(osr); + if (kSTkErrOk != result) + return result; + + osr.ss = startState; + + result = setOSR(osr); + if (kSTkErrOk != result) + return result; + + // If write is successful, save to internal state. + _startState = startState; + + return kSTkErrOk; +} + +sfeTkError_t SfeAS7331Driver::getStatus(sfe_as7331_reg_meas_osr_status_t &statusReg) +{ + // Status register is only available in Measurement mode. + if (!_theBus || _opMode != DEVICE_MODE_MEAS) + return kSTkErrFail; + + uint16_t statusRaw; + + sfeTkError_t result = _theBus->readRegisterWord(kSfeAS7331RegMeasOsrStatus, statusRaw); + + if (kSTkErrOk != result) + return result; + + statusReg.word = statusRaw; + + return kSTkErrOk; +} + +sfeTkError_t SfeAS7331Driver::getOSR(sfe_as7331_reg_cfg_osr_t &osrReg) +{ + // OSR is available in both operation modes. + if (!_theBus) + return kSTkErrFail; + + return _theBus->readRegisterByte(kSfeAS7331RegCfgOsr, osrReg.byte); +} + +sfeTkError_t SfeAS7331Driver::setOSR(const sfe_as7331_reg_cfg_osr_t &osrReg) +{ + // OSR is available in both operation modes. + if (!_theBus) + return kSTkErrFail; + + return _theBus->writeRegisterByte(kSfeAS7331RegCfgOsr, osrReg.byte); +} + +sfeTkError_t SfeAS7331Driver::getCReg1(sfe_as7331_reg_cfg_creg1_t &creg1) +{ + // Config registers are only available in Configuration mode. + if (!_theBus || _opMode != DEVICE_MODE_CFG) + return kSTkErrFail; + + return _theBus->readRegisterByte(kSfeAS7331RegCfgCreg1, creg1.byte); +} + +sfeTkError_t SfeAS7331Driver::setCReg1(const sfe_as7331_reg_cfg_creg1_t &creg1) +{ + // Config registers are only available in Configuration mode. + if (!_theBus || _opMode != DEVICE_MODE_CFG) + return kSTkErrFail; + + return _theBus->writeRegisterByte(kSfeAS7331RegCfgCreg1, creg1.byte); +} + +sfeTkError_t SfeAS7331Driver::getCReg2(sfe_as7331_reg_cfg_creg2_t &creg2) +{ + // Config registers are only available in Configuration mode. + if (!_theBus || _opMode != DEVICE_MODE_CFG) + return kSTkErrFail; + + return _theBus->readRegisterByte(kSfeAS7331RegCfgCreg2, creg2.byte); +} + +sfeTkError_t SfeAS7331Driver::setCReg2(const sfe_as7331_reg_cfg_creg2_t &creg2) +{ + // Config registers are only available in Configuration mode. + if (!_theBus || _opMode != DEVICE_MODE_CFG) + return kSTkErrFail; + + return _theBus->writeRegisterByte(kSfeAS7331RegCfgCreg2, creg2.byte); +} + +sfeTkError_t SfeAS7331Driver::getCReg3(sfe_as7331_reg_cfg_creg3_t &creg3) +{ + // Config registers are only available in Configuration mode. + if (!_theBus || _opMode != DEVICE_MODE_CFG) + return kSTkErrFail; + + return _theBus->readRegisterByte(kSfeAS7331RegCfgCreg3, creg3.byte); +} + +sfeTkError_t SfeAS7331Driver::setCReg3(const sfe_as7331_reg_cfg_creg3_t &creg3) +{ + // Config registers are only available in Configuration mode. + if (!_theBus || _opMode != DEVICE_MODE_CFG) + return kSTkErrFail; + + return _theBus->writeRegisterByte(kSfeAS7331RegCfgCreg3, creg3.byte); +} + +sfeTkError_t SfeAS7331Driver::getBreak(uint8_t &breakReg) +{ + // Config registers are only available in Configuration mode. + if (!_theBus || _opMode != DEVICE_MODE_CFG) + return kSTkErrFail; + + return _theBus->readRegisterByte(kSfeAS7331RegCfgBreak, breakReg); +} + +sfeTkError_t SfeAS7331Driver::setBreak(const uint8_t &breakReg) +{ + // Config registers are only available in Configuration mode. + if (!_theBus || _opMode != DEVICE_MODE_CFG) + return kSTkErrFail; + + return _theBus->writeRegisterByte(kSfeAS7331RegCfgBreak, breakReg); +} + +sfeTkError_t SfeAS7331Driver::getEdges(uint8_t &edgesReg) +{ + // Config registers are only available in Configuration mode. + if (!_theBus || _opMode != DEVICE_MODE_CFG) + return kSTkErrFail; + + return _theBus->readRegisterByte(kSfeAS7331RegCfgEdges, edgesReg); +} + +sfeTkError_t SfeAS7331Driver::setEdges(const uint8_t &edgesReg) +{ + // Config registers are only available in Configuration mode. + if (!_theBus || _opMode != DEVICE_MODE_CFG) + return kSTkErrFail; + + return _theBus->writeRegisterByte(kSfeAS7331RegCfgEdges, edgesReg); +} + +sfeTkError_t SfeAS7331Driver::getOptIndex(sfe_as7331_reg_cfg_optreg_t &optReg) +{ + // Config registers are only available in Configuration mode. + if (!_theBus || _opMode != DEVICE_MODE_CFG) + return kSTkErrFail; + + return _theBus->readRegisterByte(kSfeAS7331RegCfgOptReg, optReg.byte); +} + +sfeTkError_t SfeAS7331Driver::setOptIndex(const sfe_as7331_reg_cfg_optreg_t &optReg) +{ + // Config registers are only available in Configuration mode. + if (!_theBus || _opMode != DEVICE_MODE_CFG) + return kSTkErrFail; + + return _theBus->writeRegisterByte(kSfeAS7331RegCfgOptReg, optReg.byte); +} + +sfeTkError_t SfeAS7331Driver::readRawUV(const as7331_uv_type &uv_type) +{ + if (!_theBus || _opMode != DEVICE_MODE_MEAS) + return kSTkErrFail; + + uint16_t uvRawVal; + uint8_t regAddress = 0; + float *retUV = nullptr; + float *conv = nullptr; + const float *fsr = nullptr; + + // Set variables based on the UV channel requested. + switch (uv_type) + { + default: // Since it's an enum, you can't miscall this function, so default to A. + case AS7331_UVA: + regAddress = kSfeAS7331RegMeasMres1; + fsr = &_fsrA; + retUV = &_uva; + conv = &_conversionA; + break; + case AS7331_UVB: + regAddress = kSfeAS7331RegMeasMres2; + fsr = &_fsrB; + retUV = &_uvb; + conv = &_conversionB; + break; + case AS7331_UVC: + regAddress = kSfeAS7331RegMeasMres3; + fsr = &_fsrC; + retUV = &_uvc; + conv = &_conversionC; + break; + } + + sfeTkError_t result = _theBus->readRegisterWord(regAddress, uvRawVal); + + if (kSTkErrOk != result) + return result; + + // If we're in SYND mode, need to calculate conversion based on the conversion time. + if (_mmode == MEAS_MODE_SYND) + { + result = readOutConv(); + + if (kSTkErrOk != result) + return result; + + // See datasheet section 7.4 Equation 4. + // fsrX + // -------------- + // gain * outConv + float convFactor = (*fsr) / (((float)_outputConversionTime) * ((float)(1 << (11 - _sensorGain)))); + + // Since result is more than 1 byte, need to order it correctly before conversion. + *retUV = convertRawUVVal(uvRawVal, convFactor); + } + else + { + // Since result is more than 1 byte, need to order it correctly before conversion. + *retUV = convertRawUVVal(uvRawVal, *conv); + } + + return kSTkErrOk; +} + +float SfeAS7331Driver::convertRawTempToTempC(const uint16_t &inputVal) +{ + // T_chip = TEMP*0.05 - 66.9 + // EX: TEMP=0x922 aka TEMP=0d2338, returns 50.0 + return ((float)(inputVal) * 0.05f) - 66.9f; +} + +float SfeAS7331Driver::convertRawUVVal(const uint16_t &rawVal, const float &convFactor) +{ + // If the divider is enabled, then we need to include the division factor. + float divFactor = _dividerEnabled ? (float)(1 << (1 + _dividerRange)) : 1.0f; + + return ((float)rawVal) * divFactor * convFactor; +} + +void SfeAS7331Driver::calculateConversionFactors(void) +{ + // See datasheet section 7.4 Equation 3. + // fsrX + // ------------------- + // gain * tconv * cclk + // Calculates a conversion factor based on the sensor gain, conversion time, and conversion clock frequency. + // Only valid for CONT, CMD, SYNS modes. + float convFactor = 1.0f / (((float)(1 << (11 - _sensorGain))) * ((float)(1 << _conversionTime)) * + ((float)(1024.0 * (1 << _cclk)))); + + _conversionA = _fsrA * convFactor; + _conversionB = _fsrB * convFactor; + _conversionC = _fsrC * convFactor; +} + +void SfeAS7331Driver::setDefaultSettings() +{ + _breakTime = 25; // 25 * 8us = 200us. + _numEdges = 1; // 1 edge. + _readyPinMode = false; // Push-pull. + _dividerEnabled = false; // Predivider disabled. + _tempConvEnabled = true; // Temp conversion in synd mode enabled. + _indexMode = true; // Repeat start enabled. + _standbyState = false; // Not in standby mode. + _startState = false; // Not started. + _powerDownEnableState = true; // Device is powered down. + _opMode = DEVICE_MODE_CFG; // Device is in configuration mode. + _sensorGain = GAIN_2; // Gain of 2x. + _cclk = CCLK_1_024_MHZ; // 1.024 MHz conversion clock + _mmode = MEAS_MODE_CMD; // Command/One Shot Mode. + _conversionTime = TIME_64MS; // 64 ms conversion time. + _dividerRange = DIV_2; // Predivider 2x. +} diff --git a/src/sfeAS7331.h b/src/sfeAS7331.h new file mode 100644 index 0000000..a441ccf --- /dev/null +++ b/src/sfeAS7331.h @@ -0,0 +1,697 @@ +/* + SparkFun Spectral UV Sensor - AS7331 + + Qwiic 1x1 + https://www.sparkfun.com/products/23517 + Qwiic Mini + https://www.sparkfun.com/products/23518 + + Repository + https://github.com/sparkfun/SparkFun_AS7331_Arduino_Library + + SPDX-License-Identifier: MIT + + Copyright (c) 2023 SparkFun Electronics + + Name: sfeAS7331.h + + Description: + SfeAS7331Driver is a comms-agnostic driver for the AS7331 Spectral UV + sensor that uses the SparkFun Toolkit. The SfeAS7331ArdI2C class defines + the Arduino specific behavior for initializing and interadcting with devices. + +*/ + +#pragma once + +#include +#include + +/////////////////////////////////////////////////////////////////////////////// +// I2C Addressing +/////////////////////////////////////////////////////////////////////////////// +// 7-bit address defined as [1, 1, 1, 0, 1, A1, A0] where A1/A0 are the +// physical address pins tied high or low +const uint8_t kDefaultAS7331Addr = 0x74; // A1 = 0, A0 = 0 +const uint8_t kSecondaryAS7331Addr = 0x75; // A1 = 0, A1 = 1 +const uint8_t kTertiaryAS7331Addr = 0x76; // A1 = 1, A0 = 0 +const uint8_t kQuaternaryAS7331Addr = 0x77; // A1 = 1, A0 = 1 + +const uint8_t kDefaultAS7331DeviceID = 0x21; // When polling the AGEN register, this should be returned on boot. +const uint8_t kAS7331DeviceIDTopNibble = 0x2; // Top nibble of the AGEN byte, always the same. + +/////////////////////////////////////////////////////////////////////////////// +// Enum Definitions +/////////////////////////////////////////////////////////////////////////////// + +// Device Operating Mode +typedef enum +{ + // 0b00X invalid + DEVICE_MODE_CFG = 0x2, + DEVICE_MODE_MEAS = 0x3 + // 0b1XX invalid +} as7331_dev_op_state_t; + +// Sensor gain, able to be read as (1 << (11 - gain)) aka 2^(11-gain). +typedef enum +{ + GAIN_2048 = 0x0000, + GAIN_1024, + GAIN_512, + GAIN_256, + GAIN_128, + GAIN_64, + GAIN_32, + GAIN_16, + GAIN_8, + GAIN_4, + GAIN_2, + GAIN_1 +} as7331_gain_t; + +// Conversion Clock Frequency available settings, read as (1024 * (1 << cclk)) +// aka 1024*2^cclk. +typedef enum +{ + CCLK_1_024_MHZ = 0x00, + CCLK_2_048_MHZ, + CCLK_4_096_MHZ, + CCLK_8_192_MHZ +} as7331_conv_clk_freq_t; + +// Measurement Mode types +typedef enum +{ + MEAS_MODE_CONT = 0x0, // Continuous mode + MEAS_MODE_CMD, // Command/OneShot mode + MEAS_MODE_SYNS, // SYNchronous Start mode + MEAS_MODE_SYND // SYNchronous start and enD mode +} as7331_meas_mode_t; + +// Time conversion values in CONT, CMD, SYNS modes. Read as (1 << tconv) aka +// 2^tconv. +typedef enum +{ + TIME_1MS = 0x0, + TIME_2MS, + TIME_4MS, + TIME_8MS, + TIME_16MS, + TIME_32MS, + TIME_64MS, + TIME_128MS, + TIME_256MS, + TIME_512MS, + TIME_1024MS, + TIME_2048MS, + TIME_4096MS, + TIME_8192MS, + TIME_16384MS +} as7331_conv_time_t; + +// Predivider values. Read as (1 << (1+div)) aka 2^(1+div). +typedef enum +{ + DIV_2 = 0x0, + DIV_4, + DIV_8, + DIV_16, + DIV_32, + DIV_64, + DIV_128, + DIV_256 +} as7331_divider_val_t; + +// Type of UV to pick. +typedef enum +{ + AS7331_UVA, + AS7331_UVB, + AS7331_UVC +} as7331_uv_type; + +/////////////////////////////////////////////////////////////////////////////// +// Configuration Register Descriptions +// +// Can only be accessed in the Configuration operation state. All 8 bits long. +// +// The following registers map to the underlying registers of the device. +/////////////////////////////////////////////////////////////////////////////// + +const uint8_t kSfeAS7331RegCfgOsr = 0x00; // Register address + +// A union is used here so that individual values from the register can be +// accessed or the whole register can be accessed. +typedef union { + struct + { + uint8_t dos : 3; // Device Operating State - OSR[2:0] + uint8_t sw_res : 1; // Software Reset - OSR[3] + uint8_t reserved : 2; // Reserved, don't write. - OSR[4:5] + uint8_t pd : 1; // Power Down Enabled - OSR[6] + uint8_t ss : 1; // Start State - OSR[7] + }; + uint8_t byte; +} sfe_as7331_reg_cfg_osr_t; + +const uint8_t kSfeAS7331RegCfgAgen = 0x02; // Register address + +// A union is used here so that individual values from the register can be +// accessed or the whole register can be accessed. +typedef union { + struct + { + uint8_t mut : 4; // Increments when changes are made to the control + // registers. Defaults to 0b0001 aka 0x1. + uint8_t devid : 4; // Always equals 0b0010 aka 0x2. + }; + uint8_t byte; +} sfe_as7331_reg_cfg_agen_t; + +const uint8_t kSfeAS7331RegCfgCreg1 = 0x06; // Register address + +// A union is used here so that individual values from the register can be +// accessed or the whole register can be accessed. +typedef union { + struct + { + uint8_t time : 4; // Conversion time - CREG1[3:0] + uint8_t gain : 4; // Sensor gain - CREG1[7:4] + }; + uint8_t byte; +} sfe_as7331_reg_cfg_creg1_t; + +const uint8_t kSfeAS7331RegCfgCreg2 = 0x07; // Register address + +// A union is used here so that individual values from the register can be +// accessed or the whole register can be accessed. +typedef union { + struct + { + uint8_t div : 3; // Digital Divider value - CREG2[2:0] + uint8_t en_div : 1; // Whether the digital divider is enabled - CREG2[3] + uint8_t reserved : 2; // Reserved, don't write. - CREG2[5:4] + uint8_t en_tm : 1; // Whether temperature is calculated in SYND mode. - CREG2[6] + uint8_t reserved1 : 1; // Reserved, don't write. - CREG2[7] + }; + uint8_t byte; +} sfe_as7331_reg_cfg_creg2_t; + +const uint8_t kSfeAS7331RegCfgCreg3 = 0x08; // Register Address + +// A union is used here so that individual values from the register can be +// accessed or the whole register can be accessed. +typedef union { + struct + { + uint8_t cclk : 2; // Conversion clock selection. - CREG3[1:0] + uint8_t reserved : 1; // Reserved, don't write. - CREG3[2] + uint8_t rdyod : 1; // Output mode of the ready pin. - CREG3[3] + uint8_t sb : 1; // Standby mode bit. - CREG3[4] + uint8_t reserved1 : 1; // Reserved, don't write. - CREG3[5] + uint8_t mmode : 2; // Measurement mode selection. - CREG3[7:6] + }; + uint8_t byte; +} sfe_as7331_reg_cfg_creg3_t; + +const uint8_t kSfeAS7331RegCfgBreak = 0x09; // Register address, register is a single uint8_t. + +const uint8_t kSfeAS7331RegCfgEdges = 0x0A; // Register address, register is a single uint8_t. + +const uint8_t kSfeAS7331RegCfgOptReg = 0x0B; // Register address + +// A union is used here so that individual values from the register can be +// accessed or the whole register can be accessed. +typedef union { + struct + { + uint8_t init_idx : 1; // I2C repeat start mode flag. - OPTREG[0] + uint8_t reserved : 7; // Reserved, don't write. - OPTREG[7:1] + }; + uint8_t byte; +} sfe_as7331_reg_cfg_optreg_t; + +/////////////////////////////////////////////////////////////////////////////// +// Measurement Register Descriptions +// +// Can only be accessed in the Measure operation state. All 16 bits long. They +// are all read-only except the bottom byte of the OSR/STATUS register. +// +// The following registers map to the underlying registers of the device. +/////////////////////////////////////////////////////////////////////////////// + +const uint8_t kSfeAS7331RegMeasOsrStatus = 0x00; // Register address + +// A union is used here so that individual values from the register can be +// accessed or the whole register can be accessed. +typedef union { + struct + { + sfe_as7331_reg_cfg_osr_t osr; // See OSR configuration register above. - OSRSTAT[7:0] + uint8_t powerstate : 1; // Power down state. - OSRSTAT[8] + uint8_t standbystate : 1; // Standby mode state. - OSRSTAT[9] + uint8_t notready : 1; // Inverted value of the ready pin. - OSRSTAT[10] + uint8_t ndata : 1; // Indicates new data available. - OSRSTAT[11] + uint8_t ldata : 1; // Indicates data overwrite prior to retrieval. - OSRSTAT[12] + uint8_t adcof : 1; // OVF of at least one ADC channel. - OSRSTAT[13] + uint8_t mresof : 1; // OVF of at least one of the MRES registers. - OSRSTAT[14] + uint8_t outconvof : 1; // OVF of the internal 24-bit time reference. - OSRSTAT[15] + }; + uint16_t word; +} sfe_as7331_reg_meas_osr_status_t; + +// Output result registers. 16-bit values unless noted otherwise. +const uint8_t kSfeAS7331RegMeasTemp = 0x01; // 12-bit temperature, MS 4-bits 0. +const uint8_t kSfeAS7331RegMeasMres1 = 0x02; +const uint8_t kSfeAS7331RegMeasMres2 = 0x03; +const uint8_t kSfeAS7331RegMeasMres3 = 0x04; +const uint8_t kSfeAS7331RegMeasOutConvL = 0x05; // First 16-bits of 24-bit OUTCONV. +const uint8_t kSfeAS7331RegMeasOutConvH = 0x06; // LSB is MSB of OUTCONV, MSB is 0. + +/////////////////////////////////////////////////////////////////////////////// + +class SfeAS7331Driver +{ + public: + // Default initialization values based on the datasheet. See SfeAS7331Driver::setDefaultSettings for + // an explanation of the values. + SfeAS7331Driver(uint8_t address = kDefaultAS7331Addr) + : _devAddress{address}, _theBus{nullptr}, _breakTime{25}, _numEdges{1}, _readyPinMode{false}, + _dividerEnabled{false}, _tempConvEnabled{true}, _indexMode{true}, _standbyState{false}, _startState{false}, + _powerDownEnableState{true}, _opMode{DEVICE_MODE_CFG}, _sensorGain{GAIN_2}, _cclk{CCLK_1_024_MHZ}, + _mmode{MEAS_MODE_CMD}, _conversionTime{TIME_64MS}, _dividerRange{DIV_2}, _uva{0.0f}, _uvb{0.0f}, _uvc{0.0f}, + _temperature{0.0f}, _outputConversionTime{0U}, _conversionA{0.0f}, _conversionB{0.0f}, _conversionC{0.0f} + { + } + + /// @brief This method is called to initialize the AS7331 device through the + /// specified bus. + /// @param deviceAddress I2C address for the device. + /// @param theBus Pointer to the bus object. + /// @return True if successful, false if it fails. + bool begin(const uint8_t &deviceAddress = kDefaultAS7331Addr, sfeTkIBus *theBus = nullptr); + + /// @brief Requests the device ID from the sensor. + /// @return The device ID of the sensor. + uint8_t getDeviceID(void); + + /// @brief Sets the communication bus to the specified bus. + /// @param theBus Bus to set as the communication devie. + void setCommunicationBus(sfeTkIBus *theBus); + + /// @brief Sets the address that the bus uses to communicate with the sensor. + /// @param deviceAddress Device address to use. + void setDeviceAddress(const uint8_t &deviceAddress); + + /// @brief Gets the currently configured device address. + /// @return device address. + uint8_t getDeviceAddress(void); + + /// @brief Helper class that sets up the sensor and state in the POR + /// configuration. + /// @param runSoftReset Flag that runs the soft reset function to reset the + /// device. + /// @return True if successful, false otherwise. + bool runDefaultSetup(const bool &runSoftReset = false); + + /// @brief Puts the sensor in the specified measurement mode. + /// @param measMode Measurement mode to enter. + /// @param startMeasure Flag to start measuring immediately if set. + /// @return True if successful, false otherwise. + bool prepareMeasurement(const as7331_meas_mode_t &measMode = MEAS_MODE_CONT, const bool &startMeasure = false); + + /// @brief Performs a soft reset of the sensor. + /// @return True if successful, false otherwise. + bool reset(void); + + /// @brief Reads the sensor's temperature, converts it to a usable form, and + /// saves it to the internal temperature variable. + /// @return 0 if successful, negative if error, positive for warning. + sfeTkError_t readTemp(void); + + /// @brief Reads the sensor's UVA register, converts it to a usable form, and + /// saves it to the internal UVA variable. + /// @return 0 if successful, negative if error, positive for warning. + sfeTkError_t readUVA(void); + + /// @brief Reads the sensor's UVB register, converts it to a usable form, and + /// saves it to the internal UVB variable. + /// @return 0 if successful, negative if error, positive for warning. + sfeTkError_t readUVB(void); + + /// @brief Reads the sensor's UVC register, converts it to a usable form, and + /// saves it to the internal UVC variable. + /// @return 0 if successful, negative if error, positive for warning. + sfeTkError_t readUVC(void); + + /// @brief Read's all three UV registers, converts them to a usable form, then + /// saves them to their respective internal variable. + /// @return 0 if successful, negative if error, positive for warning. + sfeTkError_t readAllUV(void); + + /// @brief Read the sensor's temperature, UV, and external time conversion + /// clock counts, converts them, and then saves them to their respective + /// internal variable. + /// @return 0 if successful, negative if error, positive for warning. + sfeTkError_t readAll(void); + + /// @brief Read the conversion clock counts register and saves it to the + /// internal output conversion time variable. + /// @return 0 if successful, negative if error, positive for warning. + sfeTkError_t readOutConv(void); + + /// @brief Returns the last valid UVA reading. + /// @return A float of the UVA reading. + float getUVA(void); + + /// @brief Returns the last valid UVB reading. + /// @return A float of the UVB reading. + float getUVB(void); + + /// @brief Returns the last valid UVC reading. + /// @return A float of the UVC reading. + float getUVC(void); + + /// @brief Returns the last valid Temperature reading. + /// @return A float of the Temperature reading. + float getTemp(void); + + /// @brief Returns the last valid output conversion. + /// @return The output conversion time in number of clock cycles. + uint32_t getOutConv(void); + + /// @brief Getter for the currently configured gain. + /// @return Sensor's gain expressed as (1 << (11 - gain)). + as7331_gain_t getGainRaw(void); + + /// @brief Getter for the currently configured gain. + /// @return Sensor's gain expressed as a unitless scalar. + uint16_t getGainValue(void); + + /// @brief Sets the UV sensor's gain. + /// @param gain The gain to set the sensor to. + /// @return 0 if successful, negative if error, positive for warning. + sfeTkError_t setGain(const as7331_gain_t &gain); + + /// @brief Getter for the currently configured conversion clock. + /// @return Sensor's conversion clock expressed as 1024*(1 << cclk). + as7331_conv_clk_freq_t getCClkRaw(void); + + /// @brief Getter for the currently configured conversion clock. + /// @return Sensor's conversion clock expressed in kHz. + uint16_t getCClkKHz(void); + + /// @brief Set the sensor's internal clock speed. + /// @param cclk Clock speed to set on the sensor. + /// @return 0 if successful, negative if error, positive for warning. + sfeTkError_t setCClk(const as7331_conv_clk_freq_t &cclk); + + /// @brief Getter for the currently configured conversion time. + /// @return Sensor's conversion time expressed as (1 << time). + as7331_conv_time_t getConversionTimeRaw(void); + + /// @brief Getter for the currently configured conversion time. + /// @return Sensor's conversion time in milliseconds. + uint16_t getConversionTimeMillis(void); + + /// @brief Sets the conversion time that the sensor will run to. + /// @param convTime Conversion time to set the sensor to. + /// @return 0 if successful, negative if error, positive for warning. + sfeTkError_t setConversionTime(const as7331_conv_time_t &convTime); + + /// @brief Getter for the currently configured pin mode. + /// @return False if push-pull, true if open-drain. + bool getReadyPinMode(void); + + /// @brief Sets the ready pin type to push-pull or open-drain. + /// @param pinMode Mode to set the ready pin to. + /// @return 0 if successful, negative if error, positive for warning. + sfeTkError_t setReadyPinMode(const bool &pinMode); + + /// @brief Getter for the currently configured divider status. + /// @return True if Internal predivider is enabled, false otherwise. + bool getDigitalDividerEnabled(void); + + /// @brief Enables or disables the internal UV result divider. + /// @param isEnabled Enable or disable the divder. + /// @return 0 if successful, negative if error, positive for warning. + sfeTkError_t setDigitalDividerEnabled(const bool &isEnabled); + + /// @brief Getter for the currently configured divider range. + /// @return Sensor's internal UV predivider range. + as7331_divider_val_t getDigitalDividerRange(void); + + /// @brief Sets the value of the internal UV result divider. + /// @param divider Divider value to set. + /// @param setEnableDiv Option to turn on the divider if desired. + /// @return 0 if successful, negative if error, positive for warning. + sfeTkError_t setDigitalDividerRange(const as7331_divider_val_t ÷r, const bool &enableDiv = true); + + /// @brief Getter for the SYND temperature conversion status. + /// @return True if temperature conversion is enabled in SYND mode. + bool getSyndTempConversionEnabled(void); + + /// @brief Enables or disables temperature conversion when in SYND mode. + /// @param isEnabled Enable or disable the feature. + /// @return 0 if successful, negative if error, positive for warning. + sfeTkError_t setSyndTempConversionEnabled(const bool &isEnabled); + + /// @brief Getter for the currently configured I2C compatibility mode. + /// @return True if the device will respond to repeat starts, false otherwise. + bool getIndexMode(void); + + /// @brief Set the index mode for compatibility with I2C controllers that + /// don't support repeated start. + /// @param indexMode Simple or standard I2C addressing mode. + /// @return 0 if successful, negative if error, positive for warning. + sfeTkError_t setIndexMode(const bool &indexMode); + + /// @brief Getter for the currently configured minimum break time in CONT, + /// CMD, SYNS modes. + /// @return Sensor's breaktime in 8us steps. + uint8_t getBreakTime(void); + + /// @brief Set the minimum time between measurements in CONT, SYNS, SYND modes. + /// @param breakTime Time between measurements, 8us step time, max 2048us. A 0 + /// value is a minimum of 3 cclk cycles. + /// @return 0 if successful, negative if error, positive for warning. + sfeTkError_t setBreakTime(const uint8_t &breakTime); + + /// @brief Getter for the currently configured minimum number of edges to end + /// conversion when in SYND mode. + /// @return Sensor's minimum number of edges, minimum 1 edge. + uint8_t getNumEdges(void); + + /// @brief Set the minimum number of falling edges required at the SYN input + /// until the conversion is terminated. Only operational in SYND mode. + /// @param numEdges Number of edges prior to terminating conversion in SYND + /// mode. 0 is not allowed, 1 is the minimum. + /// @return 0 if successful, negative if error, positive for warning. + sfeTkError_t setNumEdges(const uint8_t &numEdges); + + /// @brief Getter for the current power state. + /// @return Sensor's power state. + bool getPowerDownState(void); + + /// @brief Sets the power state of the sensor. + /// @param pd Power state to set. + /// @return 0 if successful, negative if error, positive for warning. + sfeTkError_t setPowerDownState(const bool &pd); + + /// @brief Getter for the current operational state. + /// @return Sensor's operational mode. + as7331_dev_op_state_t getOperationMode(void); + + /// @brief Set the sensor's operating mode. + /// @param opMode Operating mode to set. + /// @return 0 if successful, negative if error, positive for warning. + sfeTkError_t setOperationMode(const as7331_dev_op_state_t &opMode); + + /// @brief Getter for the current measurement state. + /// @return Sensor's measurement state. + as7331_meas_mode_t getMeasurementMode(void); + + /// @brief Sets the sensor's measurement mode. + /// @param measMode Measurement mode to set. + /// @return 0 if successful, negative if error, positive for warning. + sfeTkError_t setMeasurementMode(const as7331_meas_mode_t &measMode); + + /// @brief Getter for the current standby state. + /// @return Sensor's standby state. + bool getStandbyState(void); + + /// @brief Sets the sensor's standby mode. + /// @param standby State to set. + /// @return 0 if successful, negative if error, positive for warning. + sfeTkError_t setStandbyState(const bool &standby); + + /// @brief Getter for the current start state. + /// @return Sensor's start state. + bool getStartState(void); + + /// @brief Sets the sensor's start state. This begins measurement. + /// @param startState Start state to set. + /// @return 0 if successful, negative if error, positive for warning. + sfeTkError_t setStartState(const bool &startState); + + /// @brief Gets the sensor's status when in measurement operation mode. + /// @param statusReg Pointer to a register struct to store the sensor's + /// current status. + /// @return 0 if successful, negative if error, positive for warning. + sfeTkError_t getStatus(sfe_as7331_reg_meas_osr_status_t &statusReg); + + /// @brief Gets the operational state register when in configuration operation + /// mode. + /// @param osrReg Pointer to a register struct to store the sensor's current + /// OSR register. + /// @return 0 if successful, negative if error, positive for warning. + sfeTkError_t getOSR(sfe_as7331_reg_cfg_osr_t &osrReg); + + /// @brief Sets the operational state register when in configuration operation + /// mode. + /// @param osrReg Pointer to a register struct that has the new register + /// configuration. + /// @return 0 if successful, negative if error, positive for warning. + sfeTkError_t setOSR(const sfe_as7331_reg_cfg_osr_t &osrReg); + + /// @brief Gets the configuration register #1 when in configuration operation + /// mode. + /// @param creg1 Pointer to a register struct to store the sensor's current + /// creg1 register. + /// @return 0 if successful, negative if error, positive for warning. + sfeTkError_t getCReg1(sfe_as7331_reg_cfg_creg1_t &creg1); + + /// @brief Sets the configuration register #1 when in configuration operation + /// mode. + /// @param creg1 Pointer to a register struct that has the new register + /// configuration. + /// @return 0 if successful, negative if error, positive for warning. + sfeTkError_t setCReg1(const sfe_as7331_reg_cfg_creg1_t &creg1); + + /// @brief Gets the configuration register #2 when in configuration operation + /// mode. + /// @param creg2 Pointer to a register struct to store the sensor's current + /// creg2 register. + /// @return 0 if successful, negative if error, positive for warning. + sfeTkError_t getCReg2(sfe_as7331_reg_cfg_creg2_t &creg2); + + /// @brief Sets the configuration register #2 when in configuration operation + /// mode. + /// @param creg2 Pointer to a register struct that has the new register + /// configuration. + /// @return 0 if successful, negative if error, positive for warning. + sfeTkError_t setCReg2(const sfe_as7331_reg_cfg_creg2_t &creg2); + + /// @brief Gets the configuration register #3 when in configuration operation + /// mode. + /// @param creg3 Pointer to a register struct to store the sensor's current + /// creg3 register. + /// @return 0 if successful, negative if error, positive for warning. + sfeTkError_t getCReg3(sfe_as7331_reg_cfg_creg3_t &creg3); + + /// @brief Sets the configuration register #3 when in configuration operation + /// mode. + /// @param creg3 Pointer to a register struct that has the new register + /// configuration. + /// @return 0 if successful, negative if error, positive for warning. + sfeTkError_t setCReg3(const sfe_as7331_reg_cfg_creg3_t &creg3); + + /// @brief Gets the break register when in configuration operation mode. + /// @param breakReg Pointer to a register struct to store the sensor's current + /// break register. + /// @return 0 if successful, negative if error, positive for warning. + sfeTkError_t getBreak(uint8_t &breakReg); + + /// @brief Sets the break register when in configuration operation mode. + /// @param breakReg Pointer to a register struct that has the new register + /// configuration. + /// @return 0 if successful, negative if error, positive for warning. + sfeTkError_t setBreak(const uint8_t &breakReg); + + /// @brief Gets the edges register when in configuration operation mode. + /// @param edgesReg Pointer to a register struct to store the sensor's current + /// edges register. + /// @return 0 if successful, negative if error, positive for warning. + sfeTkError_t getEdges(uint8_t &edgesReg); + + /// @brief Sets the edges register when in configuration operation mode. + /// @param edgesReg Pointer to a register struct that has the new register + /// configuration. + /// @return 0 if successful, negative if error, positive for warning. + sfeTkError_t setEdges(const uint8_t &edgesReg); + + /// @brief Gets the option register when in configuration operation mode. + /// @param optReg Pointer to a register struct to store the sensor's current + /// option register. + /// @return 0 if successful, negative if error, positive for warning. + sfeTkError_t getOptIndex(sfe_as7331_reg_cfg_optreg_t &optReg); + + /// @brief Sets the option register when in configuration operation mode. + /// @param optReg Pointer to a register struct that has the new register + /// configuration. + /// @return 0 if successful, negative if error, positive for warning. + sfeTkError_t setOptIndex(const sfe_as7331_reg_cfg_optreg_t &optReg); + + private: + /// @brief Reads a UV result register and saves it to the respective internal + /// variable. + /// @param uv_type The type of UV you want to read. + /// @return 0 if successful, negative if error, positive if warning + sfeTkError_t readRawUV(const as7331_uv_type &uv_type); + + /// @brief Converts the raw temperature value to a human readable form. + /// @param inputVal Raw temperature value to convert. + /// @return The converted device temperature in degree C. + float convertRawTempToTempC(const uint16_t &inputVal); + + /// @brief Converts a raw result value and performs a conversion to a human + /// readable format. + /// @param rawVal The raw input value. + /// @param convFactor Conversion factor to multiply the raw input value. + /// @return The calculated conversion result + float convertRawUVVal(const uint16_t &rawVal, const float &convFactor); + + /// @brief Called when changing values that affect the conversion, calculates + /// a new conversion factor to reduce the conversion overhead. + void calculateConversionFactors(void); + + /// @brief Called to reset all local values back to initial conditions. + void setDefaultSettings(void); + + sfeTkIBus *_theBus; // Pointer to bus device. + uint8_t _devAddress; // Device's I2C address. + + uint8_t _breakTime; // Local config value. Value is in us/8. EX: _breakTime = 20 means 20*8 = 160us. + uint8_t _numEdges; // Local config value. Edges seen on SYN pin before ending conversion in SYND mode. + + bool _readyPinMode; // Local config value. False is Push/Pull True is Open/Drain. + bool _dividerEnabled; // Local config value. False is disabled, True is enabled. + bool _tempConvEnabled; // Local config value. False is disabled, True is enabled. + bool _indexMode; // Local config value. False is for controllers without repeat start. + bool _standbyState; // Local state value. False means the device is not in standby mode. + bool _startState; // Local state value. False means the device is not allowed to measure. + bool _powerDownEnableState; // Local state value. False means the device is NOT POWERED DOWN. This is inverse. + + as7331_dev_op_state_t _opMode; // Local state value. Configuration or Measure operating mode. + as7331_gain_t _sensorGain; // Local config value. Sensor gain stored as (1 << (11 - gain)). + as7331_conv_clk_freq_t _cclk; // Local config value. Sensor's conversion clock stored as 1024*(1 << cclk) kHz. + as7331_meas_mode_t _mmode; // Local state value. Details the device's measurement mode as CONT, CMD, SYNS, or SYND. + as7331_conv_time_t _conversionTime; // Local config value. Contains the conversion time stored as (1 << time) ms. + as7331_divider_val_t _dividerRange; // Local config value. Contains the predivider value stored as (1 << 1 + range). + + float _uva; // Last valid UVA result in uW/cm2. + float _uvb; // Last valid UVB result in uW/cm2. + float _uvc; // Last valid UVC result in uW/cm2. + float _temperature; // Last valid temperature result in degC. + + uint32_t _outputConversionTime; // Last valid output conversion time result in of clock cycle count. + + float _conversionA; // Internal conversion factor for the UVA sensor. + float _conversionB; // Internal conversion factor for the UVB sensor. + float _conversionC; // Internal conversion factor for the UVC sensor. + + const float _fsrA = 348160.0; // Full Scale Resolution for the UVA sensor. + const float _fsrB = 387072.0; // Full Scale Resolution for the UVB sensor. + const float _fsrC = 169984.0; // Full Scale Resolution for the UVC sensor. +}; diff --git a/src/sfe_as7331_registers.h b/src/sfe_as7331_registers.h deleted file mode 100644 index 797c948..0000000 --- a/src/sfe_as7331_registers.h +++ /dev/null @@ -1,274 +0,0 @@ -/* - SPDX-License-Identifier: MIT - - Copyright (c) 2023 SparkFun Electronics - -*/ - -#pragma once -#include - -/// I2C addresses -// 7-bit address defined as [1, 1, 1, 0, 1, A1, A0] where A1/A0 are the address pins tied high or low -#define AS7331_ADDR_DEFAULT 0x74 -#define AS7331_ADDR_SEC 0x75 -#define AS7331_ADDR_TER 0x76 -#define AS7331_ADDR_QUA 0x77 - -#define AS7331_DEFAULT_DEV_ID 0x21 -#define AS7331_DEV_ID_HIGH 0x2 - - -/// Enum Settings - -typedef enum { - // 0b00X invalid - DEVICE_MODE_CFG = 0x2, - DEVICE_MODE_MEAS = 0x3 - // 0b1XX invalid -} as7331_device_op_state_t; - -typedef enum { - POWER_DOWN_DISABLE = 0x0, - POWER_DOWN_ENABLE -} as7331_power_state_t; - -typedef enum { - START_STATE_DISABLED = 0x0, - START_STATE_ENABLED -} as7331_startstate_t; - -typedef enum { - GAIN_2048 = 0x0000, - GAIN_1024, - GAIN_512, - GAIN_256, - GAIN_128, - GAIN_64, - GAIN_32, - GAIN_16, - GAIN_8, - GAIN_4, - GAIN_2, - GAIN_1 -} as7331_gain_t; - -typedef enum { - SYN_TEMP_DISABLED = 0x0, - SYN_TEMP_ENABLED -} as7331_ext_syn_temp_meas_t; - -typedef enum { - CCLK_1_024_MHZ = 0x00, - CCLK_2_048_MHZ, - CCLK_4_096_MHZ, - CCLK_8_192_MHZ -} as7331_conv_clk_freq_t; - -typedef enum { - READYPIN_PUSHPULL = 0x0, - READYPIN_OPENDRAIN -} as7331_ready_pin_mode_t; - -typedef enum { - STANDBY_DISABLED = 0x0, - STANDBY_ENABLED -} as7331_standby_mode_t; - -typedef enum { - MEAS_MODE_CONT = 0x0, - MEAS_MODE_CMD, - MEAS_MODE_SYNS, - MEAS_MODE_SYND -} as7331_meas_mode_t; - -typedef enum { - INDEX_NO_REPEAT_START = 0x0, - INDEX_REPEAT_START -} as7331_simple_reg_read_mode_t; - -typedef enum { - TIME_1MS = 0x0, - TIME_2MS, - TIME_4MS, - TIME_8MS, - TIME_16MS, - TIME_32MS, - TIME_64MS, - TIME_128MS, - TIME_256MS, - TIME_512MS, - TIME_1024MS, - TIME_2048MS, - TIME_4096MS, - TIME_8192MS, - TIME_16384MS -} as7331_conv_time_t; - -typedef enum { - DIVIDER_DISABLED = 0x0, - DIVIDER_ENABLED = 0x1 -} as7331_divider_enable_t; - -typedef enum { - DIV_2 = 0x0, - DIV_4, - DIV_8, - DIV_16, - DIV_32, - DIV_64, - DIV_128, - DIV_256 -} as7331_divider_val_t; - -/// Configuration Registers -// These registers can only be accessed in the configuration state, and they -// are all 8 bits long. - -#define SFE_AS7331_REGISTER_CFG_OSR 0x00 -typedef union { - struct { - uint8_t dos : 3; - uint8_t sw_res : 1; - uint8_t reserved : 2; - uint8_t pd : 1; - uint8_t ss : 1; - }; - uint8_t byte; -} sfe_as7331_reg_cfg_osr_t; - -#define SFE_AS7331_REGISTER_CFG_AGEN 0x02 -typedef union { - struct { - uint8_t mut : 4; - uint8_t devid : 4; - }; - uint8_t byte; -} sfe_as7331_reg_cfg_agen_t; - -#define SFE_AS7331_REGISTER_CFG_CREG1 0x06 -typedef union { - struct { - uint8_t time : 4; - uint8_t gain : 4; - }; - uint8_t byte; -} sfe_as7331_reg_cfg_creg1_t; - -#define SFE_AS7331_REGISTER_CFG_CREG2 0x07 -typedef union { - struct { - uint8_t div : 3; - uint8_t en_div : 1; - uint8_t reserved : 2; - uint8_t en_tm : 1; - uint8_t reserved1 : 1; - }; - uint8_t byte; -} sfe_as7331_reg_cfg_creg2_t; - -#define SFE_AS7331_REGISTER_CFG_CREG3 0x08 -typedef union { - struct { - uint8_t cclk : 2; - uint8_t reserved : 1; - uint8_t rdyod : 1; - uint8_t sb : 1; - uint8_t reserved1 : 1; - uint8_t mmode : 2; - }; - uint8_t byte; -} sfe_as7331_reg_cfg_creg3_t; - -#define SFE_AS7331_REGISTER_CFG_BREAK 0x09 -typedef uint8_t sfe_as7331_reg_cfg_break_t; - -#define SFE_AS7331_REGISTER_CFG_EDGES 0x0A -typedef uint8_t sfe_as7331_reg_cfg_edges_t; - -#define SFE_AS7331_REGISTER_CFG_OPTREG 0x0B -typedef union { - struct { - uint8_t init_idx : 1; - uint8_t reserved : 7; - }; - uint8_t byte; -} sfe_as7331_reg_cfg_optreg_t; - - -/// Measurement Registers -// These registers can only be accessed in the measurement state. They are -// read-only and 16 bits long, except OUTCONV, which is 24 bits long. - -#define SFE_AS7331_REGISTER_MEAS_OSR_STATUS 0x00 -typedef union { - struct { - sfe_as7331_reg_cfg_osr_t osr; - uint8_t powerstate : 1; - uint8_t standbystate : 1; - uint8_t notready : 1; - uint8_t ndata : 1; - uint8_t ldata : 1; - uint8_t adcof : 1; - uint8_t mresof : 1; - uint8_t outconvof : 1; - }; - uint16_t word; -} sfe_as7331_reg_meas_osr_status_t; - -#define SFE_AS7331_REGISTER_MEAS_TEMP 0x01 -typedef union { - struct { - uint16_t temp : 12; - uint8_t zeros : 4; - }; - uint16_t word; -} sfe_as7331_reg_meas_temp_t; - -#define SFE_AS7331_REGISTER_MEAS_MRES1 0x02 -typedef union { - struct { - uint8_t res_l; - uint8_t res_h; - }; - uint16_t word; -} sfe_as7331_reg_meas_mres1_t; - -#define SFE_AS7331_REGISTER_MEAS_MRES2 0x03 -typedef union { - struct { - uint8_t res_l; - uint8_t res_h; - }; - uint16_t word; -} sfe_as7331_reg_meas_mres2_t; - - -#define SFE_AS7331_REGISTER_MEAS_MRES3 0x04 -typedef union { - struct { - uint8_t res_l; - uint8_t res_h; - }; - uint16_t word; -} sfe_as7331_reg_meas_mres3_t; - - -#define SFE_AS7331_REGISTER_MEAS_OUTCONV_L 0x05 -typedef union { - struct { - uint8_t outconv_l; - uint8_t outconv_m; - }; - uint16_t word; -} sfe_as7331_reg_meas_outconv_l_t; - - -#define SFE_AS7331_REGISTER_MEAS_OUTCONV_H 0x06 -typedef union { - struct { - uint8_t outconv_h; - uint8_t zeros; - }; - uint16_t word; -} sfe_as7331_reg_meas_outconv_h_t; diff --git a/src/sfe_bus.h b/src/sfe_bus.h deleted file mode 100644 index 0bff2a7..0000000 --- a/src/sfe_bus.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - SPDX-License-Identifier: MIT - - Copyright (c) 2023 SparkFun Electronics - - A pure virtual base class for implementing a common communication interface - in SparkFun products. -*/ - -#pragma once - -#include - -// Error and warning codes -#define SFE_BUS_OK 0 -#define SFE_BUS_E_UNKNOWN -1 -#define SFE_BUS_E_NULL_PTR -2 -#define SFE_BUS_E_TIMEOUT -3 -#define SFE_BUS_E_NO_RESPONSE -4 -#define SFE_BUS_E_DATA_TOO_LONG -5 -#define SFE_BUS_E_NULL_DEV_SETTINGS -6 -#define SFE_BUS_E_NULL_DATA_BUFFER -7 -#define SFE_BUS_W_UNKNOWN 1 -#define SFE_BUS_W_UNDER_READ 2 -#define SFE_BUS_W_NOT_ENABLED 3 - -/// @brief An abstract Bus address class for enabling multiple types of addresses. -class SFEBusDevSettings{}; // Nothing to see here... - -/// @brief An abstract interface for a communication bus -class SFEBus -{ - public: - /// @brief Begin bus. - /// @return 0 for success, negative for failure, positive for warning. - virtual int8_t begin(void) = 0; - - /// @brief End bus. - /// @return 0 for success, negative for failure, positive for warning. - virtual int8_t end(void) = 0; - - /// @brief Writes a number of bytes starting at the given register address. - /// @param devSettings Settings of the device. - /// @param regAddr The first register address to write to. - /// @param data Data buffer to write to registers. - /// @param numBytes Number of bytes to write. - /// @return 0 for success, negative for failure, positive for warning. - virtual int8_t writeRegisterBytes(const SFEBusDevSettings *devSettings, const uint8_t regAddr, const uint8_t *data, const uint32_t numBytes) = 0; - - /// @brief Reads a number of bytes starting at the given register address. - /// @param devSettings Settings of the device. - /// @param regAddr The first register address to read from. - /// @param data Data buffer to read from registers. - /// @param numBytes Number of bytes to read. - /// @return 0 for success, negative for failure, positive for warning. - virtual int8_t readRegisterBytes(const SFEBusDevSettings *devSettings, const uint8_t regAddr, uint8_t *data, const uint32_t numBytes) = 0; - - /// @brief Writes a number of bytes to a device that doesn't use registers for communications. - /// @param devSettings Settings of the device. - /// @param data Data buffer to write from registers. - /// @param numBytes Number of bytes to write. - /// @return 0 for success, negative for failure, positive for warning. - virtual int8_t writeBytes(const SFEBusDevSettings *devSettings, const uint8_t *data, const uint32_t numBytes) = 0; - - /// @brief Reads a number of bytes to a device that doesn't use registers for communications. - /// @param devSettings Settings of the device. - /// @param data Data buffer to read from registers. - /// @param numBytes Number of bytes to read. - /// @return 0 for success, negative for failure, positive for warning. - virtual int8_t readBytes(const SFEBusDevSettings *devSettings, uint8_t *data, const uint32_t numBytes) = 0; -}; diff --git a/src/sfe_i2c.h b/src/sfe_i2c.h deleted file mode 100644 index d30b5b0..0000000 --- a/src/sfe_i2c.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - SPDX-License-Identifier: MIT - - Copyright (c) 2023 SparkFun Electronics -*/ - -#pragma once - -#include "sfe_bus.h" - -#define SFE_BUS_I2C_DEFAULT_ADDRESS 0x00 -#define SFE_BUS_I2C_DEFAULT_I2C_SPEED 100000 -#define SFE_BUS_I2C_BUFFER_SIZE 32 - -// @brief A simple bus address implementation for a generic I2C. -class SFEBusDevSettingsI2C : public SFEBusDevSettings -{ - public: - uint8_t devAddr = SFE_BUS_I2C_DEFAULT_ADDRESS; // Default I2C Address - uint32_t maxDataRate = SFE_BUS_I2C_DEFAULT_I2C_SPEED; // Default I2C Speed -}; - -/// @brief An abstract interface for an I2C communication bus -class SFEBusI2C : public SFEBus -{ - public: - /// @brief Pings I2C device and looks for an ACK response. - /// @param devAddr Address to ping. - /// @return 0 for success, negative for failure, positive for warning. - virtual int8_t ping(const uint8_t devAddr) = 0; - - /// @brief Pings I2C device and looks for an ACK response. - /// @param devSettings Settings of device to ping. - /// @return 0 for success, negative for failure, positive for warning. - virtual int8_t ping(const SFEBusDevSettings *devSettings) = 0; - - /// @brief Changes the I2C buffer size. - /// @param bufferSize New buffer size. - /// @return 0 for success, negative for failure, positive for warning. - virtual int8_t setBufferSize(const uint32_t bufferSize) = 0; - - /// @brief Returns the I2C buffer size. - /// @param bufferSize Buffer to return the size of the transmit buffer. - /// @return 0 for success, negative for failure, positive for warning. - virtual int8_t getBufferSize(uint32_t *bufferSize) = 0; - - /// @brief Changes the Bus transmit frequency. - /// @param frequency New bus frequency. - /// @return 0 for success, negative for failure, positive for warning. - virtual int8_t setBusFrequency(const uint32_t frequency) = 0; - - /// @brief Returns the Bus transmit frequency. - /// @param frequency Buffer to return the frequency. - /// @return 0 for success, negative for failure, positive for warning. - virtual int8_t getBusFrequency(uint32_t *frequency) = 0; - - protected: - uint32_t _i2cBufferSize = SFE_BUS_I2C_BUFFER_SIZE; // Default Buffer Size - uint32_t _busFrequency = SFE_BUS_I2C_DEFAULT_I2C_SPEED; // Default Speed is 100kHz -}; diff --git a/src/sfe_i2c_arduino.cpp b/src/sfe_i2c_arduino.cpp deleted file mode 100644 index cada1ee..0000000 --- a/src/sfe_i2c_arduino.cpp +++ /dev/null @@ -1,302 +0,0 @@ -/* - SPDX-License-Identifier: MIT - - Copyright (c) 2023 SparkFun Electronics -*/ - -#include "sfe_i2c_arduino.h" - -int8_t SFEBusArduinoI2C::begin(void) -{ - return begin(_i2cBus ? _i2cBus : &Wire ); -} - -int8_t SFEBusArduinoI2C::begin(TwoWire &wirePort) -{ - return begin(&wirePort); -} - -int8_t SFEBusArduinoI2C::begin(TwoWire *i2cBus) -{ - if (!i2cBus) - return SFE_BUS_E_NULL_PTR; - - _i2cBus = i2cBus; - - _i2cBus->begin(); - - return SFE_BUS_OK; -} - -int8_t SFEBusArduinoI2C::end(void) -{ - // Null pointer check. - if (!_i2cBus) - return SFE_BUS_E_NULL_PTR; - - _i2cBus->end(); - - return SFE_BUS_OK; -} - -int8_t SFEBusArduinoI2C::ping(const uint8_t devAddr) -{ - // Null pointer check. - if (_i2cBus == nullptr) - return SFE_BUS_E_NULL_PTR; - if (!devAddr) - return SFE_BUS_E_NULL_PTR; - // Begin and end transmission to check for ACK response - _i2cBus->beginTransmission(devAddr); - - return _mapError(_i2cBus->endTransmission()); -} - -int8_t SFEBusArduinoI2C::ping(const SFEBusDevSettings *devSettings) -{ - // Null pointer check. - if (!devSettings) - return SFE_BUS_E_NULL_DEV_SETTINGS; - - SFEBusDevSettingsI2C *pAddr = (SFEBusDevSettingsI2C *)devSettings; - - return ping(pAddr->devAddr); -} - -int8_t SFEBusArduinoI2C::writeRegisterBytes(const SFEBusDevSettings *devSettings, const uint8_t regAddr, - const uint8_t *data, const uint32_t numBytes) -{ - // Null pointer check. - if (!_i2cBus) - return SFE_BUS_E_NULL_PTR; - - // Null pointer check. - if (!devSettings) - return SFE_BUS_E_NULL_DEV_SETTINGS; - - SFEBusDevSettingsI2C *pAddr = (SFEBusDevSettingsI2C *)devSettings; - - uint32_t writeOffset = 0; - uint32_t bytesToSend = numBytes; - int8_t result = 0; - - // Start transmission and send register address. - _i2cBus->beginTransmission(pAddr->devAddr); - _i2cBus->write(regAddr); - - while (bytesToSend > 0) - { - // Limit sendLength to the size of the I2C buffer to send in chunks. - uint8_t sendLength = (bytesToSend > _i2cBufferSize) ? _i2cBufferSize : bytesToSend; - - // Do the write thing. - for (uint8_t i = 0; i < sendLength; i++) - _i2cBus->write(data[writeOffset + i]); - - // If there's still more to send, send a repeat start. - if (bytesToSend > _i2cBufferSize) - { - result = _mapError(_i2cBus->endTransmission(false)); - if (SFE_BUS_OK != result) - return result; - } - - writeOffset += sendLength; - bytesToSend -= sendLength; - } - - return _mapError(_i2cBus->endTransmission()); -} - -int8_t SFEBusArduinoI2C::readRegisterBytes(const SFEBusDevSettings *devSettings, const uint8_t regAddr, uint8_t *data, - const uint32_t numBytes) -{ - // Null pointer check. - if (!_i2cBus) - return SFE_BUS_E_NULL_PTR; - - // Null pointer check. - if (!devSettings) - return SFE_BUS_E_NULL_DEV_SETTINGS; - - // Null pointer check. - if (!data) - return SFE_BUS_E_NULL_DATA_BUFFER; - - SFEBusDevSettingsI2C *pAddr = (SFEBusDevSettingsI2C *)devSettings; - - // Start transmission and send register address. - _i2cBus->beginTransmission(pAddr->devAddr); - _i2cBus->write(regAddr); - - // Repeat start condition, return if there's an error. - int8_t result = _mapError(_i2cBus->endTransmission(false)); - if (SFE_BUS_OK != result) - return result; - - uint32_t bytesLeftToRead = numBytes; - uint32_t readOffset = 0; - - while (bytesLeftToRead > 0) - { - // Limit readLength to the size of the I2C buffer to read in chunks. - uint8_t readLength = (bytesLeftToRead > _i2cBufferSize) ? _i2cBufferSize : bytesLeftToRead; - - // Request bytes, then read them into the data buffer. - uint32_t numRead = _i2cBus->requestFrom(pAddr->devAddr, readLength); - - if (numRead < readLength) - return SFE_BUS_W_UNDER_READ; - - if (_i2cBus->available()) - { - for (uint8_t i = 0; i < readLength; i++) - data[readOffset + i] = _i2cBus->read(); - } - else - return SFE_BUS_E_NO_RESPONSE; - - readOffset += readLength; - bytesLeftToRead -= readLength; - } - - return SFE_BUS_OK; -} - -int8_t SFEBusArduinoI2C::writeBytes(const SFEBusDevSettings *devSettings, const uint8_t *data, uint32_t numBytes) -{ - // Null pointer check. - if (!_i2cBus) - return SFE_BUS_E_NULL_PTR; - - // Null pointer check. - if (!devSettings) - return SFE_BUS_E_NULL_DEV_SETTINGS; - - SFEBusDevSettingsI2C *pAddr = (SFEBusDevSettingsI2C *)devSettings; - - uint32_t writeOffset = 0; - uint32_t bytesToSend = numBytes; - int8_t result = 0; - - // Start transmission. - _i2cBus->beginTransmission(pAddr->devAddr); - - while (bytesToSend > 0) - { - // Limit sendLength to the size of the I2C buffer to send in chunks. - uint8_t sendLength = (bytesToSend > _i2cBufferSize) ? _i2cBufferSize : bytesToSend; - - // Do the write thing. - for (uint8_t i = 0; i < sendLength; i++) - _i2cBus->write(data[writeOffset + i]); - - // If there's still more to send, send a repeat start. - if (bytesToSend > _i2cBufferSize) - { - result = _mapError(_i2cBus->endTransmission(false)); - if (SFE_BUS_OK != result) - return result; - } - - writeOffset += sendLength; - bytesToSend -= sendLength; - } - - return _mapError(_i2cBus->endTransmission()); -} - -int8_t SFEBusArduinoI2C::readBytes(const SFEBusDevSettings *devSettings, uint8_t *data, uint32_t numBytes) -{ - // Null pointer check. - if (!_i2cBus) - return SFE_BUS_E_NULL_PTR; - - // Null pointer check. - if (!devSettings) - return SFE_BUS_E_NULL_DEV_SETTINGS; - - SFEBusDevSettingsI2C *pAddr = (SFEBusDevSettingsI2C *)devSettings; - - // Start transmission. - _i2cBus->beginTransmission(pAddr->devAddr); - - // Repeat start condition, return if there's an error. - int8_t result = _mapError(_i2cBus->endTransmission(false)); - if (SFE_BUS_OK != result) - return result; - - uint32_t bytesLeftToRead = numBytes; - uint32_t readOffset = 0; - - while (bytesLeftToRead > 0) - { - // Limit readLength to the size of the I2C buffer to read in chunks. - uint8_t readLength = (bytesLeftToRead > _i2cBufferSize) ? _i2cBufferSize : bytesLeftToRead; - - // Request bytes, then read them into the data buffer. - uint32_t numRead = _i2cBus->requestFrom(pAddr->devAddr, readLength); - - if (numRead < readLength) - return SFE_BUS_W_UNDER_READ; - - if (_i2cBus->available()) - { - for (uint8_t i = 0; i < readLength; i++) - data[readOffset + i] = _i2cBus->read(); - } - else - return SFE_BUS_E_NO_RESPONSE; - - readOffset += readLength; - bytesLeftToRead -= readLength; - } - - return SFE_BUS_OK; -} - -int8_t SFEBusArduinoI2C::setBufferSize(const uint32_t bufferSize) -{ - _i2cBufferSize = bufferSize; - - return SFE_BUS_OK; -} - -int8_t SFEBusArduinoI2C::getBufferSize(uint32_t *bufferSize) -{ - *bufferSize = _i2cBufferSize; - - return SFE_BUS_OK; -} - -int8_t SFEBusArduinoI2C::setBusFrequency(const uint32_t frequency) -{ - if (!_i2cBus) - return SFE_BUS_E_NULL_PTR; - - _i2cBus->setClock(frequency); - _busFrequency = frequency; - - return SFE_BUS_OK; -} - -int8_t SFEBusArduinoI2C::getBusFrequency(uint32_t *frequency) -{ - *frequency = _busFrequency; - - return SFE_BUS_OK; -} - -int8_t SFEBusArduinoI2C::_mapError(const uint8_t error) -{ - if (!error) - return SFE_BUS_OK; - else if (error == 1) - return SFE_BUS_E_DATA_TOO_LONG; - else if ((error == 2) || (error == 3)) - return SFE_BUS_E_NO_RESPONSE; - else if (error == 5) - return SFE_BUS_E_TIMEOUT; - else - return SFE_BUS_E_UNKNOWN; -} diff --git a/src/sfe_i2c_arduino.h b/src/sfe_i2c_arduino.h deleted file mode 100644 index cad7824..0000000 --- a/src/sfe_i2c_arduino.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - SPDX-License-Identifier: MIT - - Copyright (c) 2023 SparkFun Electronics -*/ - -#pragma once - -#include -#include "sfe_i2c.h" -#include - -/// @brief An I2C communication bus implementation for Arduino -class SFEBusArduinoI2C : public SFEBusI2C -{ - public: - /// @brief Empty Constructor. - SFEBusArduinoI2C(void) : _i2cBus{nullptr}{}; - - /// @brief Passing in a TwoWire Object. - SFEBusArduinoI2C(TwoWire &wirePort) : _i2cBus{&wirePort}{}; - - /// @brief Begin the I2C object with the default Wire object. - /// @return 0 for success, negative for failure, positive for warning. - int8_t begin(void); - - /// @brief Begin the I2C object with the inputted Wire object. - /// @param wirePort I2C object to use for this bus. - /// @return 0 for success, negative for failure, positive for warning. - int8_t begin(TwoWire &wirePort); - - /// @brief Begin the I2C object with the inputted Wire object pointer. - /// @param i2cBus I2C bus pointer. - /// @return 0 for success, negative for failure, positive for warning. - int8_t begin(TwoWire *i2cBus); - - /// @brief End the I2C object. - /// @return 0 for success, negative for failure, positive for warning. - int8_t end(void); - - /// @brief Pings I2C device and looks for an ACK response. - /// @param devAddr Address to ping. - /// @return 0 for success, negative for failure, positive for warning. - int8_t ping(const uint8_t devAddr); - - /// @brief Pings I2C device and looks for an ACK response. - /// @param devSettings Settings object containing the address to ping. - /// @return 0 for success, negative for failure, positive for warning. - int8_t ping(const SFEBusDevSettings *devSettings); - - /// @brief Writes a number of bytes starting at the given register address. - /// @param devSettings I2C Settings object containing the address of the device. - /// @param regAddr The register address to write to. - /// @param data Data buffer to write to registers. - /// @param numBytes Number of bytes to write. - /// @return 0 for success, negative for failure, positive for warning. - int8_t writeRegisterBytes(const SFEBusDevSettings *devSettings, const uint8_t regAddr, const uint8_t *data, const uint32_t numBytes); - - /// @brief Reads a number of bytes starting at the given register address. - /// @param devSettings I2C Settings object containing the address of the device. - /// @param regAddr The first register address to read from. - /// @param data Data buffer to read from registers. - /// @param numBytes Number of bytes to read. - /// @return 0 for success, negative for failure, positive for warning. - int8_t readRegisterBytes(const SFEBusDevSettings *devSettings, const uint8_t regAddr, uint8_t *data, const uint32_t numBytes); - - /// @brief Writes a number of bytes to a device that doesn't use registers for communications. - /// @param devSettings I2C Settings object containing the address of the device. - /// @param data Data buffer to write to registers. - /// @param numBytes Number of bytes to write. - /// @return 0 for success, negative for failure, positive for warning. - int8_t writeBytes(const SFEBusDevSettings *devSettings, const uint8_t *data, const uint32_t numBytes); - - /// @brief Reads a number of bytes to a device that doesn't use registers for communications. - /// @param devSettings I2C Settings object containing the address of the device. - /// @param data Data buffer to read from registers. - /// @param numBytes Number of bytes to read. - /// @return 0 for success, negative for failure, positive for warning. - int8_t readBytes(const SFEBusDevSettings *devSettings, uint8_t *data, const uint32_t numBytes); - - /// @brief Changes the I2C buffer size. - /// @param bufferSize New buffer size. - /// @return 0 for success, negative for failure, positive for warning. - int8_t setBufferSize(const uint32_t bufferSize); - - /// @brief Returns the I2C buffer size. - /// @param bufferSize Buffer to return the buffer... yep. - /// @return 0 for success, negative for failure, positive for warning. - int8_t getBufferSize(uint32_t *bufferSize); - - /// @brief Changes the Bus transmit frequency. - /// @param frequency New bus frequency. - /// @return 0 for success, negative for failure, positive for warning. - int8_t setBusFrequency(const uint32_t frequency); - - /// @brief Returns the Bus transmit frequency. - /// @param frequency Buffer to return the frequency. - /// @return 0 for success, negative for failure, positive for warning. - int8_t getBusFrequency(uint32_t *frequency); - - private: - TwoWire* _i2cBus; - - /// @brief Maps the TwoWire interface error scheme to the common bus error scheme. - /// @param error TwoWire error code. - /// @return 0 for success, negative for failure, positive for warning. - int8_t _mapError(const uint8_t error); -}; pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy