#pragma once #include namespace ocularium { namespace veml { enum class Reg: uint8_t { CONFIG = 0x0, THRS_HIGH = 0x1, THRS_LOW = 0x2, POWER = 0x3, LUX = 0x4, WHITE = 0x5, INT_STATUS = 0x6, CHIPID = 0x7, }; enum class AmbientLightGain: uint8_t { Unity = 0b00, TwoX = 0b01, Quarter = 0b11, Eighth = 0b10, }; enum class IntegrationTime: uint8_t { Ms25 = 0b1100, Ms50 = 0b1000, Ms100 = 0b0000, Ms200 = 0b0001, Ms400 = 0b0010, Ms800 = 0b0011, }; enum class PowerMode: uint8_t { Mode1 = 0b00, Mode2 = 0b01, Mode3 = 0b10, Mode4 = 0b11, }; struct Config { bool shutdown = false; bool interrupt = false; AmbientLightGain gain = AmbientLightGain::Eighth; IntegrationTime integration = IntegrationTime::Ms100; [[nodiscard]] uint16_t to_reg() const; [[nodiscard]] int32_t gain_factor() const { int32_t gain = 0; switch (this->gain) { case AmbientLightGain::TwoX: gain = 1; break; case AmbientLightGain::Unity: gain = 2; break; case AmbientLightGain::Eighth: gain = 8; break; case AmbientLightGain::Quarter: gain = 16; break; default: return -1; } int32_t integ = 0; switch (integration) { case IntegrationTime::Ms800: integ = 1; break; case IntegrationTime::Ms400: integ = 2; break; case IntegrationTime::Ms200: integ = 4; break; case IntegrationTime::Ms100: integ = 8; break; case IntegrationTime::Ms50: integ = 16; break; case IntegrationTime::Ms25: integ = 32; break; default: return -1; } return integ * gain; } }; struct VEML { static constexpr uint8_t ADDR = 0x10; static constexpr uint16_t CHIPID = 0xc481; explicit VEML(TwoWire& wire) : wire(wire) {} bool init(const Config& config = Config{}); [[nodiscard]] uint16_t chipid() const; [[nodiscard]] float lux() const; void set_config(const Config& config); private: TwoWire& wire; Config config = Config{}; void write_reg(Reg reg, uint16_t val) const; uint16_t read_reg(Reg reg) const; }; } using veml::VEML; }