From 002ba58bb79efebaab8baa2924ced9fbdd0953bf Mon Sep 17 00:00:00 2001 From: szampardi Date: Thu, 7 Nov 2024 20:52:19 +0100 Subject: [PATCH] re-add changes --- drivers/i2c/veml7700_driver.go | 143 ++++++++++++++++++++++++++++ drivers/i2c/veml7700_driver_test.go | 83 ++++++++++++++++ 2 files changed, 226 insertions(+) create mode 100644 drivers/i2c/veml7700_driver.go create mode 100644 drivers/i2c/veml7700_driver_test.go diff --git a/drivers/i2c/veml7700_driver.go b/drivers/i2c/veml7700_driver.go new file mode 100644 index 000000000..769a02041 --- /dev/null +++ b/drivers/i2c/veml7700_driver.go @@ -0,0 +1,143 @@ +package i2c + +const ( + defaultVEML7700Address = 0x10 +) + +const ( + ALS_GAIN_1 = 0x0 + ALS_GAIN_2 = 0x1 + ALS_GAIN_1_4 = 0x3 + ALS_GAIN_1_8 = 0x2 +) + +const ( + ALS_25MS = 0xC + ALS_50MS = 0x8 + ALS_100MS = 0x0 + ALS_200MS = 0x1 + ALS_400MS = 0x2 + ALS_800MS = 0x3 +) + +type VEML7700Driver struct { + *Driver + gain byte + integrationTime byte +} + +func NewVEML7700Driver(c Connector, options ...func(Config)) *VEML7700Driver { + v := &VEML7700Driver{ + Driver: NewDriver(c, "VEML7700", defaultVEML7700Address), + } + v.afterStart = v.initialize + + for _, option := range options { + option(v) + } + + return v +} + +func (v *VEML7700Driver) initialize() error { + if err := v.setGain(ALS_GAIN_1_8); err != nil { + return err + } + if err := v.setIntegrationTime(ALS_100MS); err != nil { + return err + } + return v.setShutdown(false) +} + +func (v *VEML7700Driver) ReadRawLight() (uint16, error) { + buf := make([]byte, 2) + if err := v.connection.ReadBlockData(0x04, buf); err != nil { + return 0, err + } + return uint16(buf[0]) | (uint16(buf[1]) << 8), nil +} + +func (v *VEML7700Driver) ReadRawWhite() (uint16, error) { + buf := make([]byte, 2) + if err := v.connection.ReadBlockData(0x05, buf); err != nil { + return 0, err + } + return uint16(buf[0]) | (uint16(buf[1]) << 8), nil +} + +func (v *VEML7700Driver) setShutdown(state bool) error { + var shutdown byte + if state { + shutdown = 1 + } else { + shutdown = 0 + } + return v.connection.WriteBlockData(0x00, []byte{shutdown}) +} + +func (v *VEML7700Driver) setGain(gain byte) error { + v.gain = gain + return v.connection.WriteBlockData(0x00, []byte{gain}) +} + +func (v *VEML7700Driver) setIntegrationTime(integrationTime byte) error { + v.integrationTime = integrationTime + return v.connection.WriteBlockData(0x00, []byte{integrationTime}) +} + +func (v *VEML7700Driver) GainValue() float64 { + switch v.gain { + case ALS_GAIN_2: + return 2.0 + case ALS_GAIN_1: + return 1.0 + case ALS_GAIN_1_4: + return 0.25 + case ALS_GAIN_1_8: + return 0.125 + default: + return 1.0 + } +} + +// IntegrationTimeValue returns the current integration time in milliseconds +func (v *VEML7700Driver) IntegrationTimeValue() int { + switch v.integrationTime { + case ALS_25MS: + return 25 + case ALS_50MS: + return 50 + case ALS_100MS: + return 100 + case ALS_200MS: + return 200 + case ALS_400MS: + return 400 + case ALS_800MS: + return 800 + default: + return 100 + } +} + +func (v *VEML7700Driver) Lux() (float64, error) { + light, err := v.ReadRawLight() + if err != nil { + return 0, err + } + resolution := v.resolution() + return resolution * float64(light), nil +} + +func (v *VEML7700Driver) resolution() float64 { + resolutionAtMax := 0.0036 + gainMax := 2.0 + integrationTimeMax := 800.0 + integrationTimeValue := float64(v.IntegrationTimeValue()) + gainValue := v.GainValue() + + if gainValue == gainMax && integrationTimeValue == integrationTimeMax { + return resolutionAtMax + } + return resolutionAtMax * (integrationTimeMax / integrationTimeValue) * (gainMax / gainValue) +} diff --git a/drivers/i2c/veml7700_driver_test.go b/drivers/i2c/veml7700_driver_test.go new file mode 100644 index 000000000..435bc504f --- /dev/null +++ b/drivers/i2c/veml7700_driver_test.go @@ -0,0 +1,83 @@ +package i2c + +import ( + "bytes" + "errors" + "strings" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "gobot.io/x/gobot/v2" +) + +// this ensures that the implementation is based on i2c.Driver, which implements the gobot.Driver +// and tests all implementations, so no further tests needed here for gobot.Driver interface +var _ gobot.Driver = (*VEML7700Driver)(nil) + +func initTestVEML7700DriverWithStubbedAdaptor() (*VEML7700Driver, *i2cTestAdaptor) { + a := newI2cTestAdaptor() + d := NewVEML7700Driver(a) + if err := d.Start(); err != nil { + panic(err) + } + return d, a +} + +func TestNewVEML7700Driver(t *testing.T) { + var di interface{} = NewVEML7700Driver(newI2cTestAdaptor()) + d, ok := di.(*VEML7700Driver) + if !ok { + t.Errorf("NewVEML7700Driver() should have returned a *VEML7700Driver") + } + assert.NotNil(t, d.Driver) + assert.True(t, strings.HasPrefix(d.Name(), "VEML7700")) + assert.Equal(t, 0x10, d.defaultAddress) +} + +func TestVEML7700Options(t *testing.T) { + // This is a general test, that options are applied in constructor by using the common WithBus() option and + // least one of this driver. Further tests for options can also be done by call of "WithOption(val)(d)". + d := NewVEML7700Driver(newI2cTestAdaptor(), WithBus(2)) + assert.Equal(t, 2, d.GetBusOrDefault(1)) +} + +func TestVEML7700Start(t *testing.T) { + d := NewVEML7700Driver(newI2cTestAdaptor()) + require.NoError(t, d.Start()) +} + +func TestVEML7700Halt(t *testing.T) { + d, _ := initTestVEML7700DriverWithStubbedAdaptor() + require.NoError(t, d.Halt()) +} + +func TestVEML7700NullLux(t *testing.T) { + d, _ := initTestVEML7700DriverWithStubbedAdaptor() + lux, _ := d.Lux() + assert.Equal(t, 0.0, lux) +} + +func TestVEML7700Lux(t *testing.T) { + d, a := initTestVEML7700DriverWithStubbedAdaptor() + a.i2cReadImpl = func(b []byte) (int, error) { + buf := new(bytes.Buffer) + buf.Write([]byte{0x05, 0xb0}) + copy(b, buf.Bytes()) + return buf.Len(), nil + } + + lux, _ := d.Lux() + assert.Equal(t, 20764.108799999998, lux) +} + +func TestVEML7700LuxError(t *testing.T) { + d, a := initTestVEML7700DriverWithStubbedAdaptor() + a.i2cReadImpl = func(b []byte) (int, error) { + return 0, errors.New("wrong number of bytes read") + } + + _, err := d.Lux() + require.ErrorContains(t, err, "wrong number of bytes read") +}