/*
 * THIS FILE IS AUTOMATICALLY GENERATED
 *
 * Generator:     sensirion-driver-generator 1.8.0
 * Product:       stc42
 * Model-Version: 1.1.0
 */
/*
 * Copyright (c) 2026, Sensirion AG
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * * Redistributions of source code must retain the above copyright notice, this
 *   list of conditions and the following disclaimer.
 *
 * * Redistributions in binary form must reproduce the above copyright notice,
 *   this list of conditions and the following disclaimer in the documentation
 *   and/or other materials provided with the distribution.
 *
 * * Neither the name of Sensirion AG nor the names of its
 *   contributors may be used to endorse or promote products derived from
 *   this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef SENSIRIONI2CSTC42_H
#define SENSIRIONI2CSTC42_H

#include <SensirionCore.h>
#include <Wire.h>

#define STC42A_I2C_ADDR_29 0x29
#define STC42A_I2C_ADDR_2A 0x2a
#define STC42A_I2C_ADDR_2B 0x2b

typedef enum {
    STC42_READ_PRODUCT_INFO_CMD_ID = 0x365b,
    STC42_START_CONCENTRATION_MEASUREMENT_CMD_ID = 0x2152,
    STC42_READ_MEASUREMENT_TICKS_CMD_ID = 0xec05,
    STC42_STOP_MEASUREMENT_CMD_ID = 0x3ff9,
    STC42_COMPENSATE_TEMPERATURE_WITH_SHT41_CMD_ID = 0x2619,
    STC42_ENABLE_MANUAL_TEMPERATURE_COMPENSATION_CMD_ID = 0x2612,
    STC42_SET_COMPENSATION_TEMPERATURE_TICKS_CMD_ID = 0xe000,
    STC42_COMPENSATE_HUMIDITY_WITH_SHT41_CMD_ID = 0x2657,
    STC42_ENABLE_MANUAL_HUMIDITY_COMPENSATION_CMD_ID = 0x264a,
    STC42_SET_COMPENSATION_HUMIDITY_TICKS_CMD_ID = 0xe00b,
    STC42_ENABLE_MANUAL_PRESSURE_COMPENSATION_CMD_ID = 0x2698,
    STC42_SET_COMPENSATION_PRESSURE_MBAR_CMD_ID = 0xe016,
    STC42_PERFORM_FORCED_RECALIBRATION_TICKS_CMD_ID = 0xe01d,
    STC42_ENABLE_AUTOMATIC_SELF_CALIBRATION_CMD_ID = 0x3f86,
    STC42_DISABLE_AUTOMATIC_SELF_CALIBRATION_CMD_ID = 0x3f07,
    STC42_ENTER_SLEEP_MODE_CMD_ID = 0x36e0,
    STC42_ENABLE_LOW_POWER_MODE_CMD_ID = 0x3f90,
    STC42_EXIT_LOW_POWER_MODE_CMD_ID = 0x3f11,
    STC42_SET_ALERT_UPPER_THRESHOLD_CMD_ID = 0x2f87,
    STC42_SET_ALERT_LOWER_THRESHOLD_CMD_ID = 0x278c,
} STC42CmdId;

typedef union {
    struct {
        uint16_t scaleFactor : 12;
        uint16_t unit : 4;
    };
    uint16_t value;
} STC42ScaleFactorType;

typedef union {
    struct {
        uint16_t padding : 8;
        uint16_t i2cError : 1;
        uint16_t dewPointOutOfRange : 1;
        uint16_t measurementToLow : 1;
        uint16_t vddOutOfRange : 1;
        uint16_t eepromAccessError : 1;
        uint16_t memoryAccessError : 1;
        uint16_t ascBaselineOutOfRange : 1;
        uint16_t ascBaselineWarning : 1;
    };
    uint16_t value;
} STC42ReadErrorFlags;

class SensirionI2cStc42 {
  public:
    SensirionI2cStc42();
    /**
     * @brief Initializes the STC42 class.
     *
     * @param i2cBus Arduino stream object to be used for communication.
     */
    void begin(TwoWire& i2cBus, uint8_t i2cAddress);

    /**
     * @brief Read measurements.
     *
     * Read measurement values and convert them to the appropriate physical
     * units.
     *
     * @param[out] hydrogen H₂ in [vol % in air]
     * @param[out] temperature Temperature in [°C]
     * @param[out] humidity Relative humidity in [%]
     * @param[out] ambientPressure Ambient pressure in [mBar]
     * @param[out] errorFlags Error flags for the read data
     *
     * @return error_code 0 on success, an error code otherwise.
     */
    int16_t readMeasurements(float& hydrogen, float& temperature,
                             float& humidity, uint16_t& ambientPressure,
                             STC42ReadErrorFlags& errorFlags);

    /**
     * @brief performForcedRecalibration
     *
     * Perform an FRC with argument H₂ in [vol % in air].
     *
     * @param[in] h2 H₂ in [vol % in air]
     * @param[in] scaleFactor
     *
     * @return error_code 0 on success, an error code otherwise.
     */
    int16_t performForcedRecalibration(float h2, uint16_t scaleFactor);

    /**
     * @brief setCompensationTemperature
     *
     * Set the temperature compensation with argument T [°C]
     *
     * @param[in] t Temperature T [°C]
     *
     * @return error_code 0 on success, an error code otherwise.
     */
    int16_t setCompensationTemperature(float t);

    /**
     * @brief setCompensationHumidity
     *
     * Set the humidity compensation with argument RH [%]
     *
     * @param[in] rh Relative humidity RH [%]
     *
     * @return error_code 0 on success, an error code otherwise.
     */
    int16_t setCompensationHumidity(float rh);

    /**
     * @brief Read product type and serial number
     *
     * @param[out] productNumber
     * @param[out] serialNumber
     *
     * @return error_code 0 on success, an error code otherwise.
     */
    int16_t readProductInfo(uint32_t& productNumber, int8_t serialNumber[],
                            uint16_t serialNumberSize);

    /**
     * @brief startConcentrationMeasurement
     *
     * Start measuring the hydrogen concentration
     *
     * @param[in] measurementPeriod Defines how the measurement shall be carried
     * out:
     *
     *
     * * measurement_period = 0:
     * * A single shot measurement is done. The measurement value is available
     * after a ``measure-time`` of about 75ms.
     * * measurement_period > 0: Once a measurement is started with
     *   measurement_period > 0, the sensor will repeatedly measure the gas
     *   concentration until the measurement is stopped or the sensor is power
     *   cycled. During this time, the measurement data can be read out using
     * the
     *   ``read_measurement_ticks`` command.
     * * The value measurement_period gives an indication how fast new
     * measurement data is available.
     * * In case ``measurement_period <= the measure-time`` the readout
     * frequency is about ~10Hz. In case ``measurement_period > the
     * measure-time`` the readout frequency is approximated with the formula:
     * * ``Readout frequency in Hz = 1000 / (measurement_period)``
     * * The maximum value for ``measurement_period`` is 65536
     *
     * @return error_code 0 on success, an error code otherwise.
     *
     * Example:
     * --------
     *
     * @code{.cpp}
     *
     *     int16_t localError = 0;
     *
     *     localError = sensor.startConcentrationMeasurement(1000);
     *     if (localError != NO_ERROR) {
     *         return;
     *     }
     *
     * @endcode
     *
     */
    int16_t startConcentrationMeasurement(uint16_t measurementPeriod);

    /**
     * @brief Read the measured values from the sensor
     *
     * Read the measurement values from the sensor. Between the command
     * ``start_concentration_measurement`` and the command
     * ``read_measurement_ticks`` it is required to wait for the maximum value
     * of measure-time ms and measurement_period ms. Otherwise the sensor will
     * NACK the request. The same wait time needs to be observed between two
     * successive calls to ``read_measurement_ticks``.
     *
     * @param[out] gasConcentration The hydrogen concentration as ticks. The
     * returned value can be converted into volume % in air using the following
     * formula:
     *
     * ``H2[vol% in air] = (gas_concentration - 2**14)/2**15 * scale_factor``
     * @param[out] temperature The temperature as ticks. The returned value can
     * be converted into a temperature °C using the following formula:
     *
     * ``T [°C] = -45 + 175*temperature/(2**16-1)``
     * @param[out] relativeHumidity The relative humidity as ticks. The returned
     * value can be converted into relative humidity % using the following
     * formula:
     *
     * ``RH % = -6 + 125*relative_humidity/(2**16-1)``
     * @param[out] ambientPressure The ambient pressure in mBar. No further
     * conversion is required.
     * @param[out] errorFlags Error information for current data reading.
     * @param[out] scaleFactor The first 12 bits contain the factor that needs
     * to be applied to convert the raw value into the physical unit. The bits
     * 12 to 15 contain information about the unit:
     *
     *
     * * 1 = %vol
     * * 2 = ‰vol
     * * 3 = hPa partial pressure
     * * 4 = mmHg partial pressure
     *
     * @note It is not required to read all values. The read can be stopped
     * after each field
     *
     * @return error_code 0 on success, an error code otherwise.
     */
    int16_t readMeasurementTicks(uint16_t& gasConcentration,
                                 uint16_t& temperature,
                                 uint16_t& relativeHumidity,
                                 uint16_t& ambientPressure,
                                 STC42ReadErrorFlags& errorFlags,
                                 STC42ScaleFactorType& scaleFactor);

    /**
     * @brief stopMeasurement
     *
     * The sensor will stop measuring
     *
     * @return error_code 0 on success, an error code otherwise.
     */
    int16_t stopMeasurement(void);

    /**
     * @brief compensateTemperatureWithSht41
     *
     * When using this option the STC4x will read temperature values from an
     * **SHT41A-AD1B** sensor that is attached to the I²C master bus of the STC
     * (Pin 9 and 1).
     *
     * @return error_code 0 on success, an error code otherwise.
     */
    int16_t compensateTemperatureWithSht41(void);

    /**
     * @brief enableManualTemperatureCompensation
     *
     * Allows to write temperature values to the sensor
     *
     * @return error_code 0 on success, an error code otherwise.
     */
    int16_t enableManualTemperatureCompensation(void);

    /**
     * @brief setCompensationTemperatureTicks
     *
     * Write a new temperature value to the sensor. The value is used as
     * temperature compensation value until another value is written to the
     * sensor.
     *
     * @param[in] temperatureTicks Value to be used to compensate temperature as
     * ticks.
     *
     * @return error_code 0 on success, an error code otherwise.
     *
     * Example:
     * --------
     *
     * @code{.cpp}
     *
     *     int16_t localError = 0;
     *
     *     localError = sensor.setCompensationTemperatureTicks(26214);
     *     if (localError != NO_ERROR) {
     *         return;
     *     }
     *
     * @endcode
     *
     */
    int16_t setCompensationTemperatureTicks(uint16_t temperatureTicks);

    /**
     * @brief compensateHumidityWithSht41
     *
     * When using this option the STC4x will read relative humidity values from
     * an
     * **SHT41A-AD1B** sensor that is attached to the I²C master bus of the STC
     * (Pin 9 and 1).
     *
     * @return error_code 0 on success, an error code otherwise.
     */
    int16_t compensateHumidityWithSht41(void);

    /**
     * @brief enableManualHumidityCompensation
     *
     * Enables the option to adjust the readings for humidity impact using
     * values written by application software.
     *
     * @return error_code 0 on success, an error code otherwise.
     */
    int16_t enableManualHumidityCompensation(void);

    /**
     * @brief setCompensationHumidityTicks
     *
     * Write a new relative humidity value to the sensor. The value is used as
     * relative_humidity compensation value until another value is written to
     * the sensor.
     *
     * @param[in] relativeHumidityTicks Value to the as relative humidity
     * compensation value as ticks
     *
     * @return error_code 0 on success, an error code otherwise.
     *
     * Example:
     * --------
     *
     * @code{.cpp}
     *
     *     int16_t localError = 0;
     *
     *     localError = sensor.setCompensationHumidityTicks(29359);
     *     if (localError != NO_ERROR) {
     *         return;
     *     }
     *
     * @endcode
     *
     */
    int16_t setCompensationHumidityTicks(uint16_t relativeHumidityTicks);

    /**
     * @brief enableManualPressureCompensation
     *
     * Enables the option to adjust the readings for pressure impact using
     * values written by application software.
     *
     * @return error_code 0 on success, an error code otherwise.
     */
    int16_t enableManualPressureCompensation(void);

    /**
     * @brief setCompensationPressureMbar
     *
     * Write a new pressure value [mbar] to the sensor. The value is used as
     * pressure compensation value until another value is written to the sensor.
     *
     * @param[in] pressureMbar Pressure compensation value
     *
     * @return error_code 0 on success, an error code otherwise.
     *
     * Example:
     * --------
     *
     * @code{.cpp}
     *
     *     int16_t localError = 0;
     *
     *     localError = sensor.setCompensationPressureMbar(1013);
     *     if (localError != NO_ERROR) {
     *         return;
     *     }
     *
     * @endcode
     *
     */
    int16_t setCompensationPressureMbar(uint16_t pressureMbar);

    /**
     * @brief Triggers a forced recalibration of the STC42
     *
     * Forced recalibration is used to improve the sensor output with a known
     * reference value.
     *
     * Before initiating forced recalibration, the sensor needs to be configured
     * for proper compensation of ambient conditions (temperature, relative
     * humidity and pressure). The effect of FRC takes place immediately after
     * the command is executed and takes effect with the first subsequent
     * measurement.
     *
     * FRC must only be performed when a well-known accurate reference
     * concentration value is available, e.g. in a production facility where
     * only air is present. Sensors can be permanently compromised if FRC is
     * performed with a parameter
     * ``gas_concentration`` that largely deviates from the actual gas
     * concentrations. For the best possible performance, the FRC should be
     * executed close to the median operating temperature, humidity, pressure,
     * and concentration of the end application.
     *
     * Typical applications for FRC:
     *
     *
     * * After soldering and assembly
     * * Before commissioning a product
     * * Before starting a measurement series
     * The forced recalibration requires that the command
     * ``start_concentration_measurement`` was called before with
     * ``measurement_period > 0``. The command is only started if the error-bits
     * ``i2c_error``, ``vdd_out_of_range`` and ``memory_access_error`` are not
     * set.
     *
     * @param[in] gasConcentration The tick value is obtained by the form the
     * formula:
     *
     * ``H₂[vol % in air] * 2**15 / scale_factor + 2**14``
     *
     * Therefore, to compensate to a H₂ concentration in Air with 0 % H₂ we need
     * to set the value to 16384.
     *
     * @return error_code 0 on success, an error code otherwise.
     *
     * Example:
     * --------
     *
     * @code{.cpp}
     *
     *     int16_t localError = 0;
     *
     *     localError = sensor.performForcedRecalibrationTicks(16384);
     *     if (localError != NO_ERROR) {
     *         return;
     *     }
     *
     * @endcode
     *
     */
    int16_t performForcedRecalibrationTicks(uint16_t gasConcentration);

    /**
     * @brief Enables automatic self calibration
     *
     * **Enable automatic self calibration**
     *
     * The sensor runs by default in Automatic Self-Calibration mode. This mode
     * will enhance the accuracy for applications where the target gas is not
     * present for most of the time and is mandatory for long term use. This
     * feature can be disabled and enabled with the following commands.
     *
     * @return error_code 0 on success, an error code otherwise.
     */
    int16_t enableAutomaticSelfCalibration(void);

    /**
     * @brief Disables automatic self calibration
     *
     * **Disable automatic self calibration**
     *
     * Allows to disable automatic self calibration.
     *
     * @return error_code 0 on success, an error code otherwise.
     */
    int16_t disableAutomaticSelfCalibration(void);

    /**
     * @brief Sets the sensor from idle mode into sleep mode.
     *
     * The enter_sleep_mode command sets the sensor to sleep mode through the
     * I2C interface. The written relative humidity, temperature, and pressure
     * compensation values as well as the ASC state will be retained while in
     * sleep mode.
     *
     * @return error_code 0 on success, an error code otherwise.
     */
    int16_t enterSleepMode(void);

    /**
     * @brief Enable the low power mode of the sensor and aktivates interrupt
     * pin.
     *
     * @return error_code 0 on success, an error code otherwise.
     */
    int16_t enableLowPowerMode(void);

    /**
     * @brief Exit the low power mode of the sensor
     *
     * @return error_code 0 on success, an error code otherwise.
     */
    int16_t exitLowPowerMode(void);

    /**
     * @brief Set the upper threshold for interrupt trigger.
     *
     * @param[in] uppperThresholdTicks The value of upper trigger threshold in
     * ticks.
     *
     * @return error_code 0 on success, an error code otherwise.
     *
     * Example:
     * --------
     *
     * @code{.cpp}
     *
     *     int16_t localError = 0;
     *
     *     localError = sensor.setAlertUpperThreshold(19660);
     *     if (localError != NO_ERROR) {
     *         return;
     *     }
     *
     * @endcode
     *
     */
    int16_t setAlertUpperThreshold(uint16_t uppperThresholdTicks);

    /**
     * @brief Set the lower threshold for interrupt trigger.
     *
     * @param[in] lowerThresholdTicks The value of lower trigger threshold in
     * ticks.
     *
     * @return error_code 0 on success, an error code otherwise.
     *
     * Example:
     * --------
     *
     * @code{.cpp}
     *
     *     int16_t localError = 0;
     *
     *     localError = sensor.setAlertLowerThreshold(13107);
     *     if (localError != NO_ERROR) {
     *         return;
     *     }
     *
     * @endcode
     *
     */
    int16_t setAlertLowerThreshold(uint16_t lowerThresholdTicks);

    /**
     * @brief signalHydrogen
     *
     * @param[in] hydrogenTicks
     * @param[in] scaleFactor
     *
     * @return Convert raw measurement value to hydrogen value.
     */
    static float signalHydrogen(uint16_t hydrogenTicks, uint16_t scaleFactor);

    /**
     * @brief signalTemperature
     *
     * @param[in] temperatureTicks
     *
     * @return Convert temperature ticks to temperature celsius
     */
    static float signalTemperature(uint16_t temperatureTicks);

    /**
     * @brief signalRelativeHumidity
     *
     * @param[in] relativeHumidityTicks
     *
     * @return Convert relative humidity ticks to relative humidity %
     */
    static float signalRelativeHumidity(uint16_t relativeHumidityTicks);

  private:
    TwoWire* _i2cBus = nullptr;
    uint8_t _i2cAddress = 0;
};

#endif  // SENSIRIONI2CSTC42_H