CCS811 use ReadBlockData()
This commit is contained in:
commit
91f94d9d4e
|
@ -4,8 +4,6 @@ import (
|
|||
"fmt"
|
||||
"math"
|
||||
"time"
|
||||
|
||||
"gobot.io/x/gobot"
|
||||
)
|
||||
|
||||
// CCS811DriveMode type
|
||||
|
@ -22,7 +20,7 @@ const (
|
|||
|
||||
const (
|
||||
|
||||
//DefaultAddress is the default I2C address for the ccs811
|
||||
//the default I2C address for the ccs811 applies for ADDR to GND, for ADDR to VDD it will be 0x5B
|
||||
ccs811DefaultAddress = 0x5A
|
||||
|
||||
//Registers, all definitions have been taken from the datasheet
|
||||
|
@ -74,7 +72,7 @@ type CCS811Status struct {
|
|||
FwMode byte
|
||||
}
|
||||
|
||||
//NewCCS811Status returns a new instance of the package ccs811 status definiton
|
||||
//NewCCS811Status returns a new instance of the package ccs811 status definition
|
||||
func NewCCS811Status(data uint8) *CCS811Status {
|
||||
return &CCS811Status{
|
||||
HasError: data & 0x01,
|
||||
|
@ -88,16 +86,16 @@ func NewCCS811Status(data uint8) *CCS811Status {
|
|||
//The following definitions were taken from the bit fields of the ccs811RegMeasMode defined in
|
||||
//https://ams.com/documents/20143/36005/CCS811_DS000459_6-00.pdf/c7091525-c7e5-37ac-eedb-b6c6828b0dcf#page=16
|
||||
type CCS811MeasMode struct {
|
||||
//If intThresh is 1 a data measurement will only be taken when the sensor value mets the threshold constraint.
|
||||
//If intThresh is 1 a data measurement will only be taken when the sensor value meets the threshold constraint.
|
||||
//The threshold value is set in the threshold register (0x10)
|
||||
intThresh uint8
|
||||
//If intDataRdy is 1, the nINT signal (pin 3 of the device) will be driven low when new data is avaliable.
|
||||
//If intDataRdy is 1, the nINT signal (pin 3 of the device) will be driven low when new data is available.
|
||||
intDataRdy uint8
|
||||
//driveMode represents the sampling rate of the sensor. If the value is 0, the measurement process is idle.
|
||||
driveMode CCS811DriveMode
|
||||
}
|
||||
|
||||
//NewCCS811MeasMode returns a new instance of the package ccs811 measurement mode configuration. This represents the desired intial
|
||||
//NewCCS811MeasMode returns a new instance of the package ccs811 measurement mode configuration. This represents the desired initial
|
||||
//state of the measurement mode register.
|
||||
func NewCCS811MeasMode() *CCS811MeasMode {
|
||||
return &CCS811MeasMode{
|
||||
|
@ -115,30 +113,26 @@ func (mm *CCS811MeasMode) GetMeasMode() byte {
|
|||
|
||||
//CCS811Driver is the Gobot driver for the CCS811 (air quality sensor) Adafruit breakout board
|
||||
type CCS811Driver struct {
|
||||
name string
|
||||
connector Connector
|
||||
connection Connection
|
||||
*Driver
|
||||
measMode *CCS811MeasMode
|
||||
ntcResistanceValue uint32
|
||||
Config
|
||||
}
|
||||
|
||||
//NewCCS811Driver creates a new driver for the CCS811 (air quality sensor)
|
||||
func NewCCS811Driver(a Connector, options ...func(Config)) *CCS811Driver {
|
||||
l := &CCS811Driver{
|
||||
name: gobot.DefaultName("CCS811"),
|
||||
connector: a,
|
||||
func NewCCS811Driver(c Connector, options ...func(Config)) *CCS811Driver {
|
||||
d := &CCS811Driver{
|
||||
Driver: NewDriver(c, "CCS811", ccs811DefaultAddress),
|
||||
measMode: NewCCS811MeasMode(),
|
||||
//Recommended resistance value is 100,000
|
||||
ntcResistanceValue: 100000,
|
||||
Config: NewConfig(),
|
||||
}
|
||||
d.afterStart = d.initialize
|
||||
|
||||
for _, option := range options {
|
||||
option(l)
|
||||
option(d)
|
||||
}
|
||||
|
||||
return l
|
||||
return d
|
||||
}
|
||||
|
||||
//WithCCS811MeasMode sets the sampling rate of the device
|
||||
|
@ -158,32 +152,11 @@ func WithCCS811NTCResistance(val uint32) func(Config) {
|
|||
}
|
||||
}
|
||||
|
||||
//Start initializes the sensor
|
||||
func (d *CCS811Driver) Start() (err error) {
|
||||
bus := d.GetBusOrDefault(d.connector.GetDefaultBus())
|
||||
address := d.GetAddressOrDefault(ccs811DefaultAddress)
|
||||
|
||||
if d.connection, err = d.connector.GetConnection(address, bus); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return d.initialize()
|
||||
}
|
||||
|
||||
//Name returns the Name for the Driver
|
||||
func (d *CCS811Driver) Name() string { return d.name }
|
||||
|
||||
//SetName sets the Name for the Driver
|
||||
func (d *CCS811Driver) SetName(n string) { d.name = n }
|
||||
|
||||
//Connection returns the connection for the Driver
|
||||
func (d *CCS811Driver) Connection() gobot.Connection { return d.connector.(gobot.Connection) }
|
||||
|
||||
//Halt returns true if devices is halted successfully
|
||||
func (d *CCS811Driver) Halt() (err error) { return }
|
||||
|
||||
//GetHardwareVersion returns the hardware version of the device in the form of 0x1X
|
||||
func (d *CCS811Driver) GetHardwareVersion() (uint8, error) {
|
||||
d.mutex.Lock()
|
||||
defer d.mutex.Unlock()
|
||||
|
||||
v, err := d.connection.ReadByteData(ccs811RegHwVersion)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
|
@ -194,6 +167,9 @@ func (d *CCS811Driver) GetHardwareVersion() (uint8, error) {
|
|||
|
||||
//GetFirmwareBootVersion returns the bootloader version
|
||||
func (d *CCS811Driver) GetFirmwareBootVersion() (uint16, error) {
|
||||
d.mutex.Lock()
|
||||
defer d.mutex.Unlock()
|
||||
|
||||
v, err := d.connection.ReadWordData(ccs811RegFwBootVersion)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
|
@ -204,6 +180,9 @@ func (d *CCS811Driver) GetFirmwareBootVersion() (uint16, error) {
|
|||
|
||||
//GetFirmwareAppVersion returns the app code version
|
||||
func (d *CCS811Driver) GetFirmwareAppVersion() (uint16, error) {
|
||||
d.mutex.Lock()
|
||||
defer d.mutex.Unlock()
|
||||
|
||||
v, err := d.connection.ReadWordData(ccs811RegFwAppVersion)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
|
@ -214,6 +193,9 @@ func (d *CCS811Driver) GetFirmwareAppVersion() (uint16, error) {
|
|||
|
||||
//GetStatus returns the current status of the device
|
||||
func (d *CCS811Driver) GetStatus() (*CCS811Status, error) {
|
||||
d.mutex.Lock()
|
||||
defer d.mutex.Unlock()
|
||||
|
||||
s, err := d.connection.ReadByteData(ccs811RegStatus)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -226,8 +208,11 @@ func (d *CCS811Driver) GetStatus() (*CCS811Status, error) {
|
|||
//GetTemperature returns the device temperature in celcius.
|
||||
//If you do not have an NTC resistor installed, this function should not be called
|
||||
func (d *CCS811Driver) GetTemperature() (float32, error) {
|
||||
d.mutex.Lock()
|
||||
defer d.mutex.Unlock()
|
||||
|
||||
buf, err := d.read(ccs811RegNtc, 4)
|
||||
buf := make([]byte, 4)
|
||||
err := d.connection.ReadBlockData(ccs811RegNtc, buf)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
@ -248,8 +233,11 @@ func (d *CCS811Driver) GetTemperature() (float32, error) {
|
|||
//GetGasData returns the data for the gas sensor.
|
||||
//eco2 is returned in ppm and tvoc is returned in ppb
|
||||
func (d *CCS811Driver) GetGasData() (uint16, uint16, error) {
|
||||
d.mutex.Lock()
|
||||
defer d.mutex.Unlock()
|
||||
|
||||
data, err := d.read(ccs811RegAlgResultData, 4)
|
||||
data := make([]byte, 4)
|
||||
err := d.connection.ReadBlockData(ccs811RegAlgResultData, data)
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
|
@ -261,7 +249,7 @@ func (d *CCS811Driver) GetGasData() (uint16, uint16, error) {
|
|||
return eco2, tvoC, nil
|
||||
}
|
||||
|
||||
//HasData returns true if the device has not errored and temperature/gas data is avaliable
|
||||
//HasData returns true if the device has not errored and temperature/gas data is available
|
||||
func (d *CCS811Driver) HasData() (bool, error) {
|
||||
s, err := d.GetStatus()
|
||||
if err != nil {
|
||||
|
@ -277,35 +265,22 @@ func (d *CCS811Driver) HasData() (bool, error) {
|
|||
|
||||
//EnableExternalInterrupt enables the external output hardware interrupt pin 3.
|
||||
func (d *CCS811Driver) EnableExternalInterrupt() error {
|
||||
d.mutex.Lock()
|
||||
defer d.mutex.Unlock()
|
||||
|
||||
d.measMode.intDataRdy = 1
|
||||
return d.connection.WriteByteData(ccs811RegMeasMode, d.measMode.GetMeasMode())
|
||||
}
|
||||
|
||||
//DisableExternalInterrupt disables the external output hardware interrupt pin 3.
|
||||
func (d *CCS811Driver) DisableExternalInterrupt() error {
|
||||
d.mutex.Lock()
|
||||
defer d.mutex.Unlock()
|
||||
|
||||
d.measMode.intDataRdy = 0
|
||||
return d.connection.WriteByteData(ccs811RegMeasMode, d.measMode.GetMeasMode())
|
||||
}
|
||||
|
||||
//updateMeasMode writes the current value of measMode to the measurement mode register.
|
||||
func (d *CCS811Driver) updateMeasMode() error {
|
||||
return d.connection.WriteByteData(ccs811RegMeasMode, d.measMode.GetMeasMode())
|
||||
}
|
||||
|
||||
//ResetDevice does a software reset of the device. After this operation is done,
|
||||
//the user must start the app code before the sensor can take any measurements
|
||||
func (d *CCS811Driver) resetDevice() error {
|
||||
return d.connection.WriteBlockData(ccs811RegSwReset, ccs811SwResetSequence)
|
||||
}
|
||||
|
||||
//startApp starts the app code in the device. This operation has to be done after a
|
||||
//software reset to start taking sensor measurements.
|
||||
func (d *CCS811Driver) startApp() error {
|
||||
//Write without data is needed to start the app code
|
||||
_, err := d.connection.Write([]byte{ccs811RegAppStart})
|
||||
return err
|
||||
}
|
||||
|
||||
func (d *CCS811Driver) initialize() error {
|
||||
deviceID, err := d.connection.ReadByteData(ccs811RegHwID)
|
||||
if err != nil {
|
||||
|
@ -335,15 +310,21 @@ func (d *CCS811Driver) initialize() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// An implementation of the ReadBlockData i2c operation. This code was copied from the BMP280Driver code
|
||||
func (d *CCS811Driver) read(reg byte, n int) ([]byte, error) {
|
||||
if _, err := d.connection.Write([]byte{reg}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
buf := make([]byte, n)
|
||||
bytesRead, err := d.connection.Read(buf)
|
||||
if bytesRead != n || err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return buf, nil
|
||||
//ResetDevice does a software reset of the device. After this operation is done,
|
||||
//the user must start the app code before the sensor can take any measurements
|
||||
func (d *CCS811Driver) resetDevice() error {
|
||||
return d.connection.WriteBlockData(ccs811RegSwReset, ccs811SwResetSequence)
|
||||
}
|
||||
|
||||
//startApp starts the app code in the device. This operation has to be done after a
|
||||
//software reset to start taking sensor measurements.
|
||||
func (d *CCS811Driver) startApp() error {
|
||||
//Write without data is needed to start the app code
|
||||
_, err := d.connection.Write([]byte{ccs811RegAppStart})
|
||||
return err
|
||||
}
|
||||
|
||||
//updateMeasMode writes the current value of measMode to the measurement mode register.
|
||||
func (d *CCS811Driver) updateMeasMode() error {
|
||||
return d.connection.WriteByteData(ccs811RegMeasMode, d.measMode.GetMeasMode())
|
||||
}
|
||||
|
|
|
@ -2,87 +2,57 @@ package i2c
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"gobot.io/x/gobot"
|
||||
"gobot.io/x/gobot/gobottest"
|
||||
)
|
||||
|
||||
// The CCS811 Meets the Driver Definition
|
||||
// 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 = (*CCS811Driver)(nil)
|
||||
|
||||
// --------- HELPERS
|
||||
func initTestCCS811Driver() (driver *CCS811Driver) {
|
||||
driver, _ = initTestCCS811DriverWithStubbedAdaptor()
|
||||
return
|
||||
func initTestCCS811WithStubbedAdaptor() (*CCS811Driver, *i2cTestAdaptor) {
|
||||
a := newI2cTestAdaptor()
|
||||
return NewCCS811Driver(a), a
|
||||
}
|
||||
|
||||
func initTestCCS811DriverWithStubbedAdaptor() (*CCS811Driver, *i2cTestAdaptor) {
|
||||
adaptor := newI2cTestAdaptor()
|
||||
return NewCCS811Driver(adaptor), adaptor
|
||||
}
|
||||
|
||||
// --------- BASE TESTS
|
||||
func TestNewCCS811Driver(t *testing.T) {
|
||||
// Does it return a pointer to an instance of CCS811Driver?
|
||||
var c interface{} = NewCCS811Driver(newI2cTestAdaptor())
|
||||
_, ok := c.(*CCS811Driver)
|
||||
var di interface{} = NewCCS811Driver(newI2cTestAdaptor())
|
||||
d, ok := di.(*CCS811Driver)
|
||||
if !ok {
|
||||
t.Errorf("NewCCS811Driver() should have returned a *CCS811Driver")
|
||||
}
|
||||
gobottest.Refute(t, d.Driver, nil)
|
||||
gobottest.Assert(t, strings.HasPrefix(d.Name(), "CCS811"), true)
|
||||
gobottest.Assert(t, d.defaultAddress, 0x5A)
|
||||
gobottest.Refute(t, d.measMode, nil)
|
||||
gobottest.Assert(t, d.ntcResistanceValue, uint32(100000))
|
||||
}
|
||||
|
||||
func TestCCS811DriverSetName(t *testing.T) {
|
||||
// Does it change the name of the driver
|
||||
d := initTestCCS811Driver()
|
||||
d.SetName("TESTME")
|
||||
gobottest.Assert(t, d.Name(), "TESTME")
|
||||
}
|
||||
|
||||
func TestCCS811Connection(t *testing.T) {
|
||||
// Does it create an instance of gobot.Connection
|
||||
ccs811 := initTestCCS811Driver()
|
||||
gobottest.Refute(t, ccs811.Connection(), nil)
|
||||
}
|
||||
|
||||
// // --------- CONFIG OVERIDE TESTS
|
||||
|
||||
func TestCCS811DriverWithBus(t *testing.T) {
|
||||
// Can it update the bus
|
||||
d := NewCCS811Driver(newI2cTestAdaptor(), WithBus(2))
|
||||
func TestCCS811Options(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 := NewCCS811Driver(newI2cTestAdaptor(), WithBus(2), WithAddress(0xFF), WithCCS811NTCResistance(0xFF))
|
||||
gobottest.Assert(t, d.GetBusOrDefault(1), 2)
|
||||
}
|
||||
|
||||
func TestCCS811DriverWithAddress(t *testing.T) {
|
||||
// Can it update the address
|
||||
d := NewCCS811Driver(newI2cTestAdaptor(), WithAddress(0xFF))
|
||||
gobottest.Assert(t, d.GetAddressOrDefault(0x5a), 0xFF)
|
||||
gobottest.Assert(t, d.ntcResistanceValue, uint32(0xFF))
|
||||
}
|
||||
|
||||
func TestCCS811DriverWithCCS811MeasMode(t *testing.T) {
|
||||
// Can it update the measurement mode
|
||||
func TestCCS811WithCCS811MeasMode(t *testing.T) {
|
||||
d := NewCCS811Driver(newI2cTestAdaptor(), WithCCS811MeasMode(CCS811DriveMode10Sec))
|
||||
gobottest.Assert(t, d.measMode.driveMode, CCS811DriveMode(CCS811DriveMode10Sec))
|
||||
}
|
||||
|
||||
func TestCCS811DriverWithCCS811NTCResistance(t *testing.T) {
|
||||
// Can it update the ntc resitor value used for temp calcuations
|
||||
d := NewCCS811Driver(newI2cTestAdaptor(), WithCCS811NTCResistance(0xFF))
|
||||
gobottest.Assert(t, d.ntcResistanceValue, uint32(0xFF))
|
||||
}
|
||||
|
||||
// // --------- DRIVER SPECIFIC TESTS
|
||||
|
||||
func TestCCS811DriverGetGasData(t *testing.T) {
|
||||
|
||||
cases := []struct {
|
||||
func TestCCS811GetGasData(t *testing.T) {
|
||||
var tests = map[string]struct {
|
||||
readReturn func([]byte) (int, error)
|
||||
eco2 uint16
|
||||
tvoc uint16
|
||||
err error
|
||||
}{
|
||||
// Can it compute the gas data with ideal values taken from the bus
|
||||
{
|
||||
"ideal values taken from the bus": {
|
||||
readReturn: func(b []byte) (int, error) {
|
||||
copy(b, []byte{1, 156, 0, 86})
|
||||
return 4, nil
|
||||
|
@ -91,8 +61,7 @@ func TestCCS811DriverGetGasData(t *testing.T) {
|
|||
tvoc: 86,
|
||||
err: nil,
|
||||
},
|
||||
// Can it compute the gas data with the max values possible taken from the bus
|
||||
{
|
||||
"max values possible taken from the bus": {
|
||||
readReturn: func(b []byte) (int, error) {
|
||||
copy(b, []byte{255, 255, 255, 255})
|
||||
return 4, nil
|
||||
|
@ -101,8 +70,7 @@ func TestCCS811DriverGetGasData(t *testing.T) {
|
|||
tvoc: 65535,
|
||||
err: nil,
|
||||
},
|
||||
// Does it return an error when the i2c operation fails
|
||||
{
|
||||
"error when the i2c operation fails": {
|
||||
readReturn: func(b []byte) (int, error) {
|
||||
copy(b, []byte{255, 255, 255, 255})
|
||||
return 4, errors.New("Error")
|
||||
|
@ -112,31 +80,31 @@ func TestCCS811DriverGetGasData(t *testing.T) {
|
|||
err: errors.New("Error"),
|
||||
},
|
||||
}
|
||||
|
||||
d, adaptor := initTestCCS811DriverWithStubbedAdaptor()
|
||||
for name, tc := range tests {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
// arrange
|
||||
d, a := initTestCCS811WithStubbedAdaptor()
|
||||
// Create stub function as it is needed by read submethod in driver code
|
||||
adaptor.i2cWriteImpl = func([]byte) (int, error) { return 0, nil }
|
||||
|
||||
a.i2cWriteImpl = func([]byte) (int, error) { return 0, nil }
|
||||
d.Start()
|
||||
for _, c := range cases {
|
||||
adaptor.i2cReadImpl = c.readReturn
|
||||
a.i2cReadImpl = tc.readReturn
|
||||
// act
|
||||
eco2, tvoc, err := d.GetGasData()
|
||||
gobottest.Assert(t, eco2, c.eco2)
|
||||
gobottest.Assert(t, tvoc, c.tvoc)
|
||||
gobottest.Assert(t, err, c.err)
|
||||
// assert
|
||||
gobottest.Assert(t, eco2, tc.eco2)
|
||||
gobottest.Assert(t, tvoc, tc.tvoc)
|
||||
gobottest.Assert(t, err, tc.err)
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestCCS811DriverGetTemperature(t *testing.T) {
|
||||
|
||||
cases := []struct {
|
||||
func TestCCS811GetTemperature(t *testing.T) {
|
||||
var tests = map[string]struct {
|
||||
readReturn func([]byte) (int, error)
|
||||
temp float32
|
||||
err error
|
||||
}{
|
||||
// Can it compute the temperature data with ideal values taken from the bus
|
||||
{
|
||||
"ideal values taken from the bus": {
|
||||
readReturn: func(b []byte) (int, error) {
|
||||
copy(b, []byte{10, 197, 0, 248})
|
||||
return 4, nil
|
||||
|
@ -144,8 +112,7 @@ func TestCCS811DriverGetTemperature(t *testing.T) {
|
|||
temp: 27.811005,
|
||||
err: nil,
|
||||
},
|
||||
// Can it compute the temperature data without bus values overflowing
|
||||
{
|
||||
"without bus values overflowing": {
|
||||
readReturn: func(b []byte) (int, error) {
|
||||
copy(b, []byte{129, 197, 10, 248})
|
||||
return 4, nil
|
||||
|
@ -153,8 +120,7 @@ func TestCCS811DriverGetTemperature(t *testing.T) {
|
|||
temp: 29.48822,
|
||||
err: nil,
|
||||
},
|
||||
// Can it compute a negative temperature
|
||||
{
|
||||
"negative temperature": {
|
||||
readReturn: func(b []byte) (int, error) {
|
||||
copy(b, []byte{255, 255, 255, 255})
|
||||
return 4, nil
|
||||
|
@ -162,8 +128,7 @@ func TestCCS811DriverGetTemperature(t *testing.T) {
|
|||
temp: -25.334152,
|
||||
err: nil,
|
||||
},
|
||||
// Does it return an error if the i2c bus errors
|
||||
{
|
||||
"error if the i2c bus errors": {
|
||||
readReturn: func(b []byte) (int, error) {
|
||||
copy(b, []byte{129, 197, 0, 248})
|
||||
return 4, errors.New("Error")
|
||||
|
@ -172,30 +137,30 @@ func TestCCS811DriverGetTemperature(t *testing.T) {
|
|||
err: errors.New("Error"),
|
||||
},
|
||||
}
|
||||
|
||||
d, adaptor := initTestCCS811DriverWithStubbedAdaptor()
|
||||
for name, tc := range tests {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
// arrange
|
||||
d, a := initTestCCS811WithStubbedAdaptor()
|
||||
// Create stub function as it is needed by read submethod in driver code
|
||||
adaptor.i2cWriteImpl = func([]byte) (int, error) { return 0, nil }
|
||||
|
||||
a.i2cWriteImpl = func([]byte) (int, error) { return 0, nil }
|
||||
d.Start()
|
||||
for _, c := range cases {
|
||||
adaptor.i2cReadImpl = c.readReturn
|
||||
a.i2cReadImpl = tc.readReturn
|
||||
// act
|
||||
temp, err := d.GetTemperature()
|
||||
gobottest.Assert(t, temp, c.temp)
|
||||
gobottest.Assert(t, err, c.err)
|
||||
// assert
|
||||
gobottest.Assert(t, temp, tc.temp)
|
||||
gobottest.Assert(t, err, tc.err)
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestCCS811DriverHasData(t *testing.T) {
|
||||
|
||||
cases := []struct {
|
||||
func TestCCS811HasData(t *testing.T) {
|
||||
var tests = map[string]struct {
|
||||
readReturn func([]byte) (int, error)
|
||||
result bool
|
||||
err error
|
||||
}{
|
||||
// Does it return true for HasError = 0 and DataRdy = 1
|
||||
{
|
||||
"true for HasError=0 and DataRdy=1": {
|
||||
readReturn: func(b []byte) (int, error) {
|
||||
copy(b, []byte{0x08})
|
||||
return 1, nil
|
||||
|
@ -203,8 +168,7 @@ func TestCCS811DriverHasData(t *testing.T) {
|
|||
result: true,
|
||||
err: nil,
|
||||
},
|
||||
// Does it return false for HasError = 1 and DataRdy = 1
|
||||
{
|
||||
"false for HasError=1 and DataRdy=1": {
|
||||
readReturn: func(b []byte) (int, error) {
|
||||
copy(b, []byte{0x09})
|
||||
return 1, nil
|
||||
|
@ -212,8 +176,7 @@ func TestCCS811DriverHasData(t *testing.T) {
|
|||
result: false,
|
||||
err: nil,
|
||||
},
|
||||
// Does it return false for HasError = 1 and DataRdy = 0
|
||||
{
|
||||
"false for HasError=1 and DataRdy=0": {
|
||||
readReturn: func(b []byte) (int, error) {
|
||||
copy(b, []byte{0x01})
|
||||
return 1, nil
|
||||
|
@ -221,8 +184,7 @@ func TestCCS811DriverHasData(t *testing.T) {
|
|||
result: false,
|
||||
err: nil,
|
||||
},
|
||||
// Does it return false for HasError = 0 and DataRdy = 0
|
||||
{
|
||||
"false for HasError=0 and DataRdy=0": {
|
||||
readReturn: func(b []byte) (int, error) {
|
||||
copy(b, []byte{0x00})
|
||||
return 1, nil
|
||||
|
@ -230,8 +192,7 @@ func TestCCS811DriverHasData(t *testing.T) {
|
|||
result: false,
|
||||
err: nil,
|
||||
},
|
||||
// Does it return an error when the i2c read operation fails
|
||||
{
|
||||
"error when the i2c read operation fails": {
|
||||
readReturn: func(b []byte) (int, error) {
|
||||
copy(b, []byte{0x00})
|
||||
return 1, errors.New("Error")
|
||||
|
@ -240,17 +201,67 @@ func TestCCS811DriverHasData(t *testing.T) {
|
|||
err: errors.New("Error"),
|
||||
},
|
||||
}
|
||||
|
||||
d, adaptor := initTestCCS811DriverWithStubbedAdaptor()
|
||||
for name, tc := range tests {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
// arrange
|
||||
d, a := initTestCCS811WithStubbedAdaptor()
|
||||
// Create stub function as it is needed by read submethod in driver code
|
||||
adaptor.i2cWriteImpl = func([]byte) (int, error) { return 0, nil }
|
||||
|
||||
a.i2cWriteImpl = func([]byte) (int, error) { return 0, nil }
|
||||
d.Start()
|
||||
for _, c := range cases {
|
||||
adaptor.i2cReadImpl = c.readReturn
|
||||
a.i2cReadImpl = tc.readReturn
|
||||
// act
|
||||
result, err := d.HasData()
|
||||
gobottest.Assert(t, result, c.result)
|
||||
gobottest.Assert(t, err, c.err)
|
||||
// assert
|
||||
gobottest.Assert(t, result, tc.result)
|
||||
gobottest.Assert(t, err, tc.err)
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestCCS811_initialize(t *testing.T) {
|
||||
// sequence for initialization the device on Start()
|
||||
// * write hardware ID register (0x20)
|
||||
// * read the ID
|
||||
// * prepare software reset register content: a sequence of four bytes must
|
||||
// be written to this register in a single I²C sequence: 0x11, 0xE5, 0x72, 0x8A
|
||||
// * write software reset register content (0xFF)
|
||||
// * write application start register (0xF4)
|
||||
// * prepare measurement mode register content
|
||||
// * INT_THRESH = 0 (normal mode)
|
||||
// * INT_DATARDY = 0 (disable interrupt mode)
|
||||
// * DRIVE_MODE = 0x01 (constant power, value every 1 sec)
|
||||
// * write measure mode register content (0x01)
|
||||
//
|
||||
// arrange
|
||||
d, a := initTestCCS811WithStubbedAdaptor()
|
||||
a.written = []byte{} // reset writes of former test
|
||||
const (
|
||||
wantChipIDReg = uint8(0x20)
|
||||
wantChipIDRegVal = uint8(0x20)
|
||||
wantResetReg = uint8(0xFF)
|
||||
wantAppStartReg = uint8(0xF4)
|
||||
wantMeasReg = uint8(0x01)
|
||||
wantMeasRegVal = uint8(0x10)
|
||||
)
|
||||
wantResetRegSequence := []byte{0x11, 0xE5, 0x72, 0x8A}
|
||||
// arrange reads
|
||||
numCallsRead := 0
|
||||
a.i2cReadImpl = func(b []byte) (int, error) {
|
||||
numCallsRead++
|
||||
// chip ID
|
||||
b[0] = 0x81
|
||||
return len(b), nil
|
||||
}
|
||||
// arrange, act - initialize() must be called on Start()
|
||||
err := d.Start()
|
||||
// assert
|
||||
gobottest.Assert(t, err, nil)
|
||||
gobottest.Assert(t, numCallsRead, 1)
|
||||
gobottest.Assert(t, len(a.written), 9)
|
||||
gobottest.Assert(t, a.written[0], wantChipIDReg)
|
||||
gobottest.Assert(t, a.written[1], wantResetReg)
|
||||
gobottest.Assert(t, a.written[2:6], wantResetRegSequence)
|
||||
gobottest.Assert(t, a.written[6], wantAppStartReg)
|
||||
gobottest.Assert(t, a.written[7], wantMeasReg)
|
||||
gobottest.Assert(t, a.written[8], wantMeasRegVal)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue