as7262: initial experimental support for AMS AS7262 Spectral ID i2c sensor (#300)

Add initial support for AMS 6 visible colour spectral ID sensor.
pull/1/head
NeuralSpaz 8 years ago committed by M-A
parent fb97d9d25d
commit 38804e4864

@ -6,8 +6,10 @@
Cássio Botaro <cassiobotaro@gmail.com> Cássio Botaro <cassiobotaro@gmail.com>
Fractal Industries, Inc Fractal Industries, Inc
Google Inc. Google Inc.
Josh Gardiner
Matt Aimonetti <mattaimonetti@gmail.com> Matt Aimonetti <mattaimonetti@gmail.com>
Max Ekman <max@looplab.se> Max Ekman <max@looplab.se>
Rifiniti, Inc Rifiniti, Inc
Stephan Sperber Stephan Sperber
Thorsten von Eicken <tve@voneicken.com> Thorsten von Eicken <tve@voneicken.com>

@ -29,6 +29,7 @@
Cássio Botaro <cassiobotaro@gmail.com> Cássio Botaro <cassiobotaro@gmail.com>
Eugene Dzhurynsky <jdevelop@gmail.com> Eugene Dzhurynsky <jdevelop@gmail.com>
Hidetoshi Shimokawa <smkwhdts@gmail.com> Hidetoshi Shimokawa <smkwhdts@gmail.com>
Josh Gardiner <josh@zool.com>
Marc-Antoine Ruel <maruel@chromium.org> <maruel@gmail.com> Marc-Antoine Ruel <maruel@chromium.org> <maruel@gmail.com>
Matt Aimonetti <mattaimonetti@gmail.com> Matt Aimonetti <mattaimonetti@gmail.com>
Max Ekman <max@looplab.se> Max Ekman <max@looplab.se>
@ -36,3 +37,4 @@ Matias Insaurralde <matias@insaurral.de>
Seán C McCord <ulexus@gmail.com> <scm@cycoresys.com> Seán C McCord <ulexus@gmail.com> <scm@cycoresys.com>
Stephan Sperber <sperberstephan@googlemail.com> Stephan Sperber <sperberstephan@googlemail.com>
Thorsten von Eicken <tve@voneicken.com> Thorsten von Eicken <tve@voneicken.com>

@ -0,0 +1,532 @@
// Copyright 2018 The Periph Authors. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.
// +build go1.7
package as7262
import (
"context"
"encoding/binary"
"errors"
"fmt"
"math"
"sync"
"time"
"periph.io/x/periph/conn"
"periph.io/x/periph/conn/gpio"
"periph.io/x/periph/conn/i2c"
"periph.io/x/periph/conn/physic"
)
// Opts holds the configuration options.
type Opts struct {
InterruptPin gpio.PinIn
Gain Gain
}
// DefaultOpts are the recommended default options.
var DefaultOpts = Opts{
InterruptPin: nil,
Gain: G1x,
}
// New opens a handle to an AS7262 sensor.
func New(bus i2c.Bus, opts *Opts) (*Dev, error) {
ctx, cancel := context.WithCancel(context.Background())
cancel()
<-ctx.Done()
return &Dev{
c: &i2c.Dev{Bus: bus, Addr: 0x49},
gain: opts.Gain,
interrupt: opts.InterruptPin,
order: binary.BigEndian,
timeout: 200 * time.Millisecond,
cancel: cancel,
ctx: ctx,
}, nil
}
// Dev is a handle to the as7262 sensor.
type Dev struct {
mu sync.Mutex
c conn.Conn
timeout time.Duration
interrupt gpio.PinIn
// A new context should be provided for long running operations.
cancel context.CancelFunc
ctx context.Context
gain Gain
order binary.ByteOrder
}
// Spectrum is the reading from the senor including the actual sensor state for
// the readings.
type Spectrum struct {
Bands []Band
SensorTemperature physic.Temperature
Gain Gain
LedDrive physic.ElectricCurrent
Integration time.Duration
//TODO:(NeuralSpaz) Pretty Printer.
}
// Band has two types of measurement of relative spectral flux density.
//
// Value
//
// Value are the calibrated readings. The accuracy of the channel counts/μW/cm2
// is ±12%.
//
// Counts
//
// Counts are the raw readings, there are approximately 45 counts/μW/cm2 with a
// gain of 16 (Gx16).
//
// Wavelength
//
// Wavelength is the nominal center of a band, with a ±40nm bandwidth around the
// center. Wavelengths for the as7262 are: 450nm, 500nm, 550nm, 570nm, 600nm and
// 650nm.
type Band struct {
Wavelength physic.Distance
Value float64
Counts uint16
Name string
}
// Sense preforms a reading of relative spectral radiance of all the sensor
// bands.
//
// Led Drive Current
//
// The AS7262 provides a current limated intergated led drive circuit. Valid
// limits for the drive current are 0mA, 12.5mA, 25mA, 50mA and 100mA. If non
// valid values are given the next lowest valid value is used.
//
// Resolution
//
// For best resolution it is recommended that for a specific led drive
// current that the senseTime or gain is increased until at least one of the
// bands returns a count above 10000. The maximum senseTime time is 714ms
// senseTime will be quantised into intervals of of 2.8ms. Actual time taken to
// make a reading is twice the senseTime.
func (d *Dev) Sense(ledDrive physic.ElectricCurrent, senseTime time.Duration) (Spectrum, error) {
d.mu.Lock()
defer d.mu.Unlock()
d.ctx, d.cancel = context.WithCancel(context.Background())
defer d.cancel()
it, integration := calcSenseTime(senseTime)
if err := d.writeVirtualRegister(intergrationReg, it); err != nil {
return Spectrum{}, err
}
led, drive := calcLed(ledDrive)
if err := d.writeVirtualRegister(ledControlReg, led); err != nil {
return Spectrum{}, err
}
if err := d.writeVirtualRegister(controlReg, uint8(allOneShot)|uint8(d.gain)); err != nil {
return Spectrum{}, err
}
if d.interrupt != nil {
isEdge := make(chan bool)
go func() {
// TODO(NeuralSpaz): Test on hardware.
isEdge <- d.interrupt.WaitForEdge(integration*2 + d.timeout)
}()
select {
case edge := <-isEdge:
if !edge {
return Spectrum{}, errPinTimeout
}
case <-d.ctx.Done():
return Spectrum{}, errHalted
}
} else {
select {
// WaitForSensor is time.After().
case <-waitForSensor(integration * 2):
if err := d.pollDataReady(); err != nil {
return Spectrum{}, err
}
case <-d.ctx.Done():
return Spectrum{}, errHalted
}
}
if err := d.writeVirtualRegister(ledControlReg, 0x00); err != nil {
return Spectrum{}, err
}
raw := make([]byte, 12)
if err := d.readVirtualRegister(rawBase, raw); err != nil {
return Spectrum{}, err
}
cal := make([]byte, 24)
if err := d.readVirtualRegister(calBase, cal); err != nil {
return Spectrum{}, err
}
v := d.order.Uint16(raw[0:2])
b := d.order.Uint16(raw[2:4])
g := d.order.Uint16(raw[4:6])
y := d.order.Uint16(raw[6:8])
o := d.order.Uint16(raw[8:10])
r := d.order.Uint16(raw[10:12])
vcal := float64(math.Float32frombits(d.order.Uint32(cal[0:4])))
bcal := float64(math.Float32frombits(d.order.Uint32(cal[4:8])))
gcal := float64(math.Float32frombits(d.order.Uint32(cal[8:12])))
ycal := float64(math.Float32frombits(d.order.Uint32(cal[12:16])))
ocal := float64(math.Float32frombits(d.order.Uint32(cal[16:20])))
rcal := float64(math.Float32frombits(d.order.Uint32(cal[20:24])))
traw := make([]byte, 1)
if err := d.readVirtualRegister(deviceTemperatureReg, traw); err != nil {
return Spectrum{}, err
}
temperature := physic.Temperature(int8(traw[0]))*physic.Kelvin + physic.ZeroCelsius
return Spectrum{
Bands: []Band{
{Wavelength: 450 * physic.NanoMetre, Counts: v, Value: vcal, Name: "V"},
{Wavelength: 500 * physic.NanoMetre, Counts: b, Value: bcal, Name: "B"},
{Wavelength: 550 * physic.NanoMetre, Counts: g, Value: gcal, Name: "G"},
{Wavelength: 570 * physic.NanoMetre, Counts: y, Value: ycal, Name: "Y"},
{Wavelength: 600 * physic.NanoMetre, Counts: o, Value: ocal, Name: "O"},
{Wavelength: 650 * physic.NanoMetre, Counts: r, Value: rcal, Name: "R"},
},
SensorTemperature: temperature,
Gain: d.gain,
LedDrive: drive,
Integration: integration,
}, nil
}
var waitForSensor = time.After
// Halt stops any pending operations
func (d *Dev) Halt() error {
d.cancel()
return nil
}
// String implaments the stringer interface
func (d *Dev) String() string {
return fmt.Sprintf("AMS AS7262 6 channel visible spectrum sensor")
}
// Gain is the sensor gain for all bands
type Gain int
const (
// G1x is gain of 1
G1x Gain = 0x00
// G4x is gain of 3.7
G4x Gain = 0x10
// G16x is a gain of 16
G16x Gain = 0x20
// G64x us a gain of 64
G64x Gain = 0x30
)
// Gain sets the gain of the sensor. There are four levels of gain 1x, 3.7x, 16x,
// and 64x.
func (d *Dev) Gain(gain Gain) error {
// TODO(NeuralSpaz): check that value is valid before writing. Currently
// a client could cast any int as Gain.
d.mu.Lock()
defer d.mu.Unlock()
d.ctx, d.cancel = context.WithCancel(context.Background())
defer d.cancel()
if err := d.writeVirtualRegister(controlReg, uint8(gain)); err != nil {
return err
}
d.gain = gain
return nil
}
// AS7262 i2c protocol uses virtual registers. To write to a given register the
// MSB of the register must be set when writing the register to the write
// register, also status register must be checked for pending writes or data may
// be discarded.
func (d *Dev) writeVirtualRegister(register, data byte) error {
// Check for pending writes.
if err := d.pollStatus(writing); err != nil {
return err
}
// Set virtual register that is being written to.
if err := d.c.Tx([]byte{writeReg, register | 0x80}, nil); err != nil {
return &IOError{"setting virtual register", err}
}
// Check for pending writes again.
if err := d.pollStatus(writing); err != nil {
return err
}
// Write data to register that is being written to.
if err := d.c.Tx([]byte{writeReg, data}, nil); err != nil {
return &IOError{"writing virtual register", err}
}
return nil
}
// AS7262 protocol uses virtual registers. To read a virtual register the
// pointer to the virtual register must be written to the write register. Status
// register must be checked for any pending reads or data may be invalid, then
// data maybe read from the read register.
func (d *Dev) readVirtualRegister(register byte, data []byte) error {
rx := make([]byte, 1)
for i := 0; i < len(data); i++ {
// Check for pending reads.
if err := d.pollStatus(clearBuffer); err != nil {
return err
}
// Set virtual register that is being read from plus offset.
if err := d.c.Tx([]byte{writeReg, register + byte(i)}, nil); err != nil {
return &IOError{"setting virtual register", err}
}
// Check if read buffer is ready.
if err := d.pollStatus(reading); err != nil {
return err
}
// Read byte from register that is being read from into our buffer with
// offset.
if err := d.c.Tx([]byte{readReg}, rx); err != nil {
return &IOError{"reading virtual register", err}
}
data[i] = rx[0]
}
return nil
}
// Polls the data ready bit in the control register(virtual)
func (d *Dev) pollDataReady() error {
pollctx, cancel := context.WithTimeout(context.Background(), d.timeout)
defer cancel()
for {
if err := d.pollStatus(clearBuffer); err != nil {
return err
}
// Set virtual register that is being read from plus offset.
if err := d.c.Tx([]byte{writeReg, controlReg}, nil); err != nil {
return &IOError{"setting virtual register", err}
}
// Check if read buffer is ready.
if err := d.pollStatus(reading); err != nil {
return err
}
// Read byte from register that is being read from into our buffer with
// offset.
data := make([]byte, 1)
if err := d.c.Tx([]byte{readReg}, data); err != nil {
return &IOError{"reading virtual register", err}
}
if data[0]&0x02 > 0 {
return nil
}
select {
case <-time.After(5 * time.Millisecond):
// Polling interval.
case <-pollctx.Done():
// Return error if it takes too long.
return errStatusDeadline
case <-d.ctx.Done():
return errHalted
}
}
}
type direction byte
const (
// Reading is a bit mask for the status register.
reading direction = 1
// Writing is a bit mask for the status register.
writing direction = 2
// ClearBuffer clears any data left in the buffer and then checks the reading
clearBuffer direction = 3
)
// The as7262 registers are implemented as virtual registers pollStatus
// provides a way to repeatedly check if there are any pending reads or writes
// in the relevent buffer before a transaction while with a timeout.
// Direction is used to set which buffer is being polled to be ready.
func (d *Dev) pollStatus(dir direction) error {
pollctx, cancel := context.WithTimeout(context.Background(), d.timeout)
defer cancel()
// Check if already canceled first
select {
case <-d.ctx.Done():
return errHalted
default:
// Proceed.
}
status := make([]byte, 1)
for {
// Read status register.
err := d.c.Tx([]byte{statusReg}, status)
if err != nil {
return &IOError{"reading status register", err}
}
switch dir {
case reading:
// Bit 0: rx valid bit.
// 0 → No data is ready to be read in READ register.
// 1 → Data byte available in READ register.
if status[0]&byte(dir) == 1 {
return nil
}
case writing:
// Bit 1: tx valid bit.
// 0 → New data may be written to WRITE register.
// 1 → WRITE register occupied. Do NOT write.
if status[0]&byte(dir) == 0 {
return nil
}
case clearBuffer:
// If there is data left in the buffer read it.
if status[0]&byte(reading) == 1 {
discard := make([]byte, 1)
if err := d.c.Tx([]byte{readReg}, discard); err != nil {
return &IOError{"clearing buffer", err}
}
}
if status[0]&byte(reading) == 0 {
return nil
}
}
select {
case <-time.After(5 * time.Millisecond):
// Polling interval.
case <-pollctx.Done():
// Return error if it takes too long.
return errStatusDeadline
case <-d.ctx.Done():
return errHalted
}
}
}
const (
maxSenseTime time.Duration = 714 * time.Millisecond
minSenseTime = 2800 * time.Microsecond
)
// calculateIntergrationTime converts a time.Duration into a value between 0 and
// 256
func calcSenseTime(t time.Duration) (uint8, time.Duration) {
if t > maxSenseTime {
return 255, maxSenseTime
}
if t < minSenseTime {
return 1, minSenseTime
}
// Minimum step is 2.8ms
quantizedTime := t / minSenseTime
return uint8(quantizedTime), quantizedTime * minSenseTime
}
func calcLed(drive physic.ElectricCurrent) (uint8, physic.ElectricCurrent) {
switch {
case drive < 12500*physic.MicroAmpere:
return 0x00, 0
case drive >= 12500*physic.MicroAmpere && drive < 25*physic.MilliAmpere:
return 0x08, 12500 * physic.MicroAmpere
case drive >= 25*physic.MilliAmpere && drive < 50*physic.MilliAmpere:
return 0x18, 25 * physic.MilliAmpere
case drive >= 50*physic.MilliAmpere && drive < 100*physic.MilliAmpere:
return 0x28, 50 * physic.MilliAmpere
default:
return 0x38, 100 * physic.MilliAmpere
}
}
type mode uint8
const (
// Bank 1 consists of data from the V, G, B, Y photodiodes.
bank1 mode = 0x00
// Bank 2 consists of data from the G, Y, O, R photodiodes.
bank2 mode = 0x04
// AllContinuously gets data from both banks continuously, requires 2x
// the intergration time.
allContinuously mode = 0x08
// AllOneShot gets data from both banks once, and set the data ready bit in
// the status control register when complete requires 2x the intergration
// time.
allOneShot mode = 0x0c
)
// IOError is a I/O specific error.
type IOError struct {
Op string
Err error
}
// Error implements the Error interface.
func (e *IOError) Error() string {
if e.Err != nil {
return "ioerror while " + e.Op + ": " + e.Err.Error()
}
return "ioerror while " + e.Op
}
var (
errStatusDeadline = errors.New("deadline exceeded reading status register")
errPinTimeout = errors.New("timeout waiting for interrupt signal on pin")
errHalted = errors.New("received halt command")
)
const (
statusReg = 0x00
writeReg = 0x01
readReg = 0x02
hardwareVersion = 0x00
firmwareVersion = 0x02
controlReg = 0x04
intergrationReg = 0x05
deviceTemperatureReg = 0x06
ledControlReg = 0x07
// RawBase used as base for reading uint16 values, data must be sequentially.
rawBase = 0x08
rawVReg = 0x08
rawBReg = 0x0a
rawGReg = 0x0c
rawYReg = 0x0e
rawOReg = 0x10
rawRReg = 0x12
// CalBase used as base for reading float32 values, data must be sequentially.
calBase = 0x14
calibratedVReg = 0x14
calibratedBReg = 0x18
calibratedGReg = 0x1c
calibratedYReg = 0x20
calibratedOReg = 0x24
calibratedRReg = 0x28
)

@ -0,0 +1,913 @@
// Copyright 2018 The Periph Authors. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.
// +build go1.7
package as7262
import (
"context"
"reflect"
"testing"
"time"
"periph.io/x/periph/conn/gpio"
"periph.io/x/periph/conn/gpio/gpiotest"
"periph.io/x/periph/conn/i2c"
"periph.io/x/periph/conn/i2c/i2ctest"
"periph.io/x/periph/conn/physic"
)
func TestDev_Sense(t *testing.T) {
type timefunc func(*Dev) func(time.Duration) <-chan time.Time
defer func() {
waitForSensor = time.After
}()
haltit := func(dev *Dev) func(time.Duration) <-chan time.Time {
return func(d time.Duration) <-chan time.Time {
t := make(chan time.Time, 1)
dev.Halt()
return t
}
}
dontwait := func(dev *Dev) func(time.Duration) <-chan time.Time {
return func(d time.Duration) <-chan time.Time {
t := make(chan time.Time, 1)
t <- time.Now()
dev.timeout = time.Millisecond * 1
return t
}
}
intPin := &gpiotest.Pin{N: "GPIO1", Num: 1, Fn: "NotRealPin", EdgesChan: make(chan gpio.Level, 1)}
tests := []struct {
name string
tx []i2ctest.IO
opts Opts
waiter timefunc
want Spectrum
sendEdge bool
wantErr error
}{
{
name: "validRead",
opts: DefaultOpts,
waiter: dontwait,
wantErr: nil,
want: validSpectrum,
tx: sensorTestCaseValidRead,
},
{
name: "errHalted",
opts: DefaultOpts,
waiter: haltit,
wantErr: errHalted,
want: Spectrum{},
tx: sensorTestCaseValidRead,
},
{
name: "interuptValid",
opts: Opts{
InterruptPin: intPin,
},
waiter: dontwait,
sendEdge: true,
wantErr: nil,
want: validSpectrum,
tx: sensorTestCaseInteruptValidRead,
},
{
name: "interuptTimeout",
opts: Opts{
InterruptPin: intPin,
},
waiter: dontwait,
sendEdge: false,
wantErr: errPinTimeout,
want: Spectrum{},
tx: sensorTestCaseInteruptValidRead,
},
{
name: "interuptTimeout",
opts: Opts{
InterruptPin: intPin,
},
waiter: dontwait,
sendEdge: false,
wantErr: errPinTimeout,
want: Spectrum{},
tx: sensorTestCaseInteruptValidRead,
},
{
name: "ioErrorWritingIntergrationReg",
opts: Opts{
InterruptPin: intPin,
},
waiter: dontwait,
sendEdge: false,
wantErr: &IOError{"reading status register", nil},
want: Spectrum{},
tx: nil,
},
{
name: "ioErrorWritingLedControlReg",
opts: DefaultOpts,
waiter: dontwait,
wantErr: &IOError{"reading status register", nil},
want: Spectrum{},
tx: sensorTestCaseValidRead[:4],
},
{
name: "ioErrorWritingControlReg",
opts: DefaultOpts,
waiter: dontwait,
wantErr: &IOError{"reading status register", nil},
want: Spectrum{},
tx: sensorTestCaseValidRead[:8],
},
{
name: "ioErrorPollDataReady",
opts: DefaultOpts,
waiter: dontwait,
wantErr: &IOError{"reading status register", nil},
want: Spectrum{},
tx: sensorTestCaseValidRead[:12],
},
{
name: "ioErrorWritingLedControlReg2",
opts: DefaultOpts,
waiter: dontwait,
wantErr: &IOError{"reading status register", nil},
want: Spectrum{},
tx: sensorTestCaseValidRead[:16],
},
{
name: "ioErrorReadingRawBase",
opts: DefaultOpts,
waiter: dontwait,
wantErr: &IOError{"reading status register", nil},
want: Spectrum{},
tx: sensorTestCaseValidRead[:32],
},
{
name: "ioErrorReadingCalBase",
opts: DefaultOpts,
waiter: dontwait,
wantErr: &IOError{"reading status register", nil},
want: Spectrum{},
tx: sensorTestCaseValidRead[:82],
},
{
name: "ioErrorReadingTemperature",
opts: DefaultOpts,
waiter: dontwait,
wantErr: &IOError{"reading status register", nil},
want: Spectrum{},
tx: sensorTestCaseValidRead[:164],
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
bus := &i2ctest.Playback{
Ops: tt.tx,
DontPanic: true,
}
d, _ := New(bus, &tt.opts)
waitForSensor = tt.waiter(d)
if d.interrupt != nil && tt.sendEdge {
intPin.EdgesChan <- gpio.High
}
got, err := d.Sense(physic.MilliAmpere*100, time.Millisecond*3)
if _, ok := tt.wantErr.(*IOError); ok {
if _, ok := err.(*IOError); !ok {
t.Errorf("expected IOError but %T", err)
}
if err.(*IOError).Op != tt.wantErr.(*IOError).Op {
t.Errorf("expected %s, but got %s", tt.wantErr.(*IOError).Op, err.(*IOError).Op)
}
} else if err != tt.wantErr {
t.Errorf("expected error: %v but got: %v", tt.wantErr, got)
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("Dev.Sense() = %v, want %v", got, tt.want)
}
})
}
}
func Test_calcSenseTime(t *testing.T) {
var tests = []struct {
name string
t time.Duration
want1 uint8
want2 time.Duration
}{
{"0", 2800 * time.Microsecond, 1, 2800 * time.Microsecond},
{"2.8ms", 0, 1, 2800 * time.Microsecond},
{"3ms", 3 * time.Millisecond, 1, 2800 * time.Microsecond},
{"500ms", 500 * time.Millisecond, 178, 498400 * time.Microsecond},
{"1hour", 1 * time.Hour, 255, 714 * time.Millisecond},
{"-1hour", -1 * time.Hour, 1, 2800 * time.Microsecond},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
got1, got2 := calcSenseTime(test.t)
if got1 != test.want1 {
t.Errorf("calcSenseTime() expected %v but got %v", test.want1, got1)
}
if got2 != test.want2 {
t.Errorf("calcSenseTime() expected %v but got %v", test.want2, got2)
}
})
}
}
func Test_calcLed(t *testing.T) {
tests := []struct {
name string
drive physic.ElectricCurrent
want uint8
}{
{"Off", 0 * physic.Ampere, 0x00},
{"12.5", 12500 * physic.MicroAmpere, 0x08},
{"25", 25 * physic.MilliAmpere, 0x18},
{"50", 50 * physic.MilliAmpere, 0x28},
{"100", 100 * physic.MilliAmpere, 0x38},
{"10", 10 * physic.MilliAmpere, 0x00},
{"20", 20 * physic.MilliAmpere, 0x08},
{"30", 30 * physic.MilliAmpere, 0x18},
{"40", 40 * physic.MilliAmpere, 0x18},
{"60", 60 * physic.MilliAmpere, 0x28},
{"110", 110 * physic.MilliAmpere, 0x38},
{"-1", -1 * physic.MilliAmpere, 0x00},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got, _ := calcLed(tt.drive); got != tt.want {
t.Errorf("calcLed() = %v, want %v", got, tt.want)
}
})
}
}
func TestDev_pollStatus(t *testing.T) {
tests := []struct {
name string
tx []i2ctest.IO
dir direction
timeout time.Duration
halt time.Duration
wantErr error
}{
{
name: "errStatusIO",
tx: []i2ctest.IO{
{Addr: 0x49, W: []byte{statusReg}, R: []byte{}},
},
dir: reading,
timeout: time.Millisecond * 1,
wantErr: &IOError{"reading status register", nil},
},
{
name: "errStatusDeadline",
tx: []i2ctest.IO{
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
},
dir: reading,
timeout: time.Millisecond * 1,
wantErr: errStatusDeadline,
},
{
name: "errHalted",
tx: []i2ctest.IO{
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
},
dir: reading,
timeout: time.Millisecond * 1000,
halt: time.Nanosecond,
wantErr: errHalted,
},
{
name: "ReadReady",
tx: []i2ctest.IO{
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
},
dir: reading,
timeout: time.Millisecond * 1000,
wantErr: nil,
},
{
name: "WriteReady",
tx: []i2ctest.IO{
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
},
dir: writing,
timeout: time.Millisecond * 1000,
wantErr: nil,
},
{
name: "CleanBuffer",
tx: []i2ctest.IO{
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
},
dir: clearBuffer,
timeout: time.Millisecond * 1000,
wantErr: nil,
},
{
name: "ClearBuffer",
tx: []i2ctest.IO{
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
},
dir: clearBuffer,
timeout: time.Millisecond * 1000,
wantErr: nil,
},
{
name: "errClearingBuffer",
tx: []i2ctest.IO{
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{}},
},
dir: clearBuffer,
timeout: time.Millisecond * 1000,
wantErr: &IOError{"clearing buffer", nil},
},
{
name: "retry1",
tx: []i2ctest.IO{
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
},
dir: reading,
timeout: time.Millisecond * 100,
wantErr: nil,
},
{
name: "retrywithHalt",
tx: []i2ctest.IO{
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
},
dir: reading,
timeout: time.Millisecond * 100,
halt: time.Millisecond * 3,
wantErr: errHalted,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
bus := &i2ctest.Playback{
Ops: tt.tx,
DontPanic: true,
}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
d := &Dev{
c: &i2c.Dev{Bus: bus, Addr: 0x49},
cancel: cancel,
ctx: ctx,
timeout: tt.timeout,
}
if tt.halt > time.Nanosecond {
go func() {
time.Sleep(tt.halt)
cancel()
}()
} else if tt.halt != 0 {
cancel()
}
got := d.pollStatus(tt.dir)
// t.Errorf("expected error: %v but got: %v", tt.wantErr, got)
if _, ok := tt.wantErr.(*IOError); ok {
if _, ok := got.(*IOError); !ok {
t.Errorf("expected IOError but %T", got)
}
if got.(*IOError).Op != tt.wantErr.(*IOError).Op {
t.Errorf("expected %s, but got %s", tt.wantErr.(*IOError).Op, got.(*IOError).Op)
}
} else if got != tt.wantErr {
t.Errorf("expected error: %v but got: %v", tt.wantErr, got)
}
})
}
}
func TestDev_writeVirtualRegister(t *testing.T) {
tests := []struct {
name string
tx []i2ctest.IO
timeout time.Duration
halt time.Duration
wantErr error
}{
{
name: "errHalted",
tx: []i2ctest.IO{
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x02}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x02}},
},
timeout: time.Millisecond * 100,
halt: time.Nanosecond,
wantErr: errHalted,
},
{
name: "errSettingVirtualRegister",
tx: []i2ctest.IO{
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{}, R: []byte{}},
},
timeout: time.Millisecond * 100,
wantErr: &IOError{"setting virtual register", nil},
},
{
name: "errStatusIO",
tx: []i2ctest.IO{
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x84}, R: []byte{}},
},
timeout: time.Millisecond * 100,
wantErr: &IOError{"reading status register", nil},
},
{
name: "errWritingVirtualRegister",
tx: []i2ctest.IO{
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x84}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
},
timeout: time.Millisecond * 100,
wantErr: &IOError{"writing virtual register", nil},
},
{
name: "writeOk",
tx: []i2ctest.IO{
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x84}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0xFF}, R: []byte{}},
},
timeout: time.Millisecond * 100,
wantErr: nil,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
bus := &i2ctest.Playback{
Ops: tt.tx,
DontPanic: true,
}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
d := &Dev{
c: &i2c.Dev{Bus: bus, Addr: 0x49},
cancel: cancel,
ctx: ctx,
timeout: tt.timeout,
}
if tt.halt > time.Nanosecond {
go func() {
time.Sleep(tt.halt)
cancel()
}()
} else if tt.halt != 0 {
cancel()
}
got := d.writeVirtualRegister(0x04, 0xFF)
if _, ok := tt.wantErr.(*IOError); ok {
if _, ok := got.(*IOError); !ok {
t.Errorf("expected IOError but %T", got)
}
if got.(*IOError).Op != tt.wantErr.(*IOError).Op {
t.Errorf("expected %s, but got %s", tt.wantErr.(*IOError).Op, got.(*IOError).Op)
}
} else if got != tt.wantErr {
t.Errorf("expected error: %v but got: %v", tt.wantErr, got)
}
})
}
}
func TestDev_readVirtualRegister(t *testing.T) {
tests := []struct {
name string
tx []i2ctest.IO
timeout time.Duration
data []byte
halt time.Duration
wantErr error
}{
{
name: "nodata",
timeout: time.Millisecond * 100,
wantErr: nil,
},
{
name: "errHalted",
tx: []i2ctest.IO{},
data: []byte{0x00},
halt: time.Nanosecond,
timeout: time.Millisecond * 100,
wantErr: errHalted,
},
{
name: "errClearingBuffer",
tx: []i2ctest.IO{
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
// {Addr: 0x49, W: []byte{statusReg}, R: []byte{0x02}},
},
data: []byte{0x00},
timeout: time.Millisecond * 100,
wantErr: &IOError{"clearing buffer", nil},
},
{
name: "errSettingVirtualRegister",
tx: []i2ctest.IO{
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg}, R: []byte{}},
},
data: []byte{0x00},
timeout: time.Millisecond * 100,
wantErr: &IOError{"setting virtual register", nil},
},
{
name: "errStatusIO",
tx: []i2ctest.IO{
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x04}, R: []byte{}},
},
data: []byte{0x00},
timeout: time.Millisecond * 100,
wantErr: &IOError{"reading status register", nil},
},
{
name: "errReadingVirtualRegister",
tx: []i2ctest.IO{
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x04}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{}},
},
data: []byte{0x00},
timeout: time.Millisecond * 100,
wantErr: &IOError{"reading virtual register", nil},
},
{
name: "readSingleByteOk",
tx: []i2ctest.IO{
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x04}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0x00}},
},
data: []byte{0x00},
timeout: time.Millisecond * 100,
wantErr: nil,
},
{
name: "readTwoBytesOk",
tx: []i2ctest.IO{
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x04}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x05}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0x00}},
},
data: []byte{0x00, 0x00},
timeout: time.Millisecond * 100,
wantErr: nil,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
bus := &i2ctest.Playback{
Ops: tt.tx,
DontPanic: true,
}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
d := &Dev{
c: &i2c.Dev{Bus: bus, Addr: 0x49},
cancel: cancel,
ctx: ctx,
timeout: tt.timeout,
}
if tt.halt > time.Nanosecond {
go func() {
time.Sleep(tt.halt)
cancel()
}()
} else if tt.halt != 0 {
cancel()
}
got := d.readVirtualRegister(0x04, tt.data)
if _, ok := tt.wantErr.(*IOError); ok {
if _, ok := got.(*IOError); !ok {
t.Errorf("expected IOError but %T", got)
}
if got.(*IOError).Op != tt.wantErr.(*IOError).Op {
t.Errorf("expected %s, but got %s", tt.wantErr.(*IOError).Op, got.(*IOError).Op)
}
} else if got != tt.wantErr {
t.Errorf("expected error: %v but got: %v", tt.wantErr, got)
}
})
}
}
func TestDev_pollDataReady(t *testing.T) {
tests := []struct {
name string
tx []i2ctest.IO
timeout time.Duration
halt time.Duration
wantErr error
}{
{
name: "errHalted",
tx: []i2ctest.IO{},
halt: time.Nanosecond,
timeout: time.Millisecond * 100,
wantErr: errHalted,
},
{
name: "errStatusIO",
tx: []i2ctest.IO{
{Addr: 0x49, W: []byte{statusReg}, R: []byte{}},
},
timeout: time.Millisecond * 100,
wantErr: &IOError{"reading status register", nil},
},
{
name: "errSettingVirtualRegister",
tx: []i2ctest.IO{
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg}, R: []byte{}},
},
timeout: time.Millisecond * 100,
wantErr: &IOError{"setting virtual register", nil},
},
{
name: "errStatusIO2",
tx: []i2ctest.IO{
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, controlReg}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
},
timeout: time.Millisecond * 100,
wantErr: &IOError{"reading status register", nil},
},
{
name: "errReadingVirtualRegister",
tx: []i2ctest.IO{
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, controlReg}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{}, R: []byte{}},
},
timeout: time.Millisecond * 100,
wantErr: &IOError{"reading virtual register", nil},
},
{
name: "errStatusDeadline",
tx: []i2ctest.IO{
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, controlReg}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0x00}},
},
timeout: 1 * time.Nanosecond,
wantErr: errStatusDeadline,
},
{
name: "ok",
tx: []i2ctest.IO{
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, controlReg}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0x03}},
},
timeout: time.Millisecond * 100,
wantErr: nil,
},
{
name: "retryOk",
tx: []i2ctest.IO{
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, controlReg}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, controlReg}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0x03}},
},
timeout: time.Millisecond * 100,
wantErr: nil,
},
{
name: "errHalted2",
tx: []i2ctest.IO{
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, controlReg}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, controlReg}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0x03}},
},
halt: time.Millisecond * 2,
timeout: time.Millisecond * 100,
wantErr: errHalted,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
bus := &i2ctest.Playback{
Ops: tt.tx,
DontPanic: true,
}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
d := &Dev{
c: &i2c.Dev{Bus: bus, Addr: 0x49},
cancel: cancel,
ctx: ctx,
timeout: tt.timeout,
}
if tt.halt > time.Nanosecond {
go func() {
time.Sleep(tt.halt)
d.Halt()
}()
} else if tt.halt != 0 {
d.Halt()
}
got := d.pollDataReady()
if _, ok := tt.wantErr.(*IOError); ok {
if _, ok := got.(*IOError); !ok {
t.Errorf("expected IOError but %T", got)
}
if got.(*IOError).Op != tt.wantErr.(*IOError).Op {
t.Errorf("expected %s, but got %s", tt.wantErr.(*IOError).Op, got.(*IOError).Op)
}
} else if got != tt.wantErr {
t.Errorf("expected error: %v but got: %v", tt.wantErr, got)
}
})
}
}
func TestNew(t *testing.T) {
// _, cancel := context.WithCancel(context.Background())
tests := []struct {
name string
opts Opts
want1 Gain
want2 gpio.PinIn
wantErr bool
}{
{name: "defautls",
opts: DefaultOpts,
want1: G1x,
want2: nil,
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
bus := &i2ctest.Playback{DontPanic: true}
d, err := New(bus, &tt.opts)
if err != nil != tt.wantErr {
t.Errorf("New() error = %v, wantErr %v", err, tt.wantErr)
return
}
if tt.want1 != d.gain {
t.Errorf("New() wanted %v but got %v", tt.want1, d.gain)
}
if tt.want2 != d.interrupt {
t.Errorf("New() wanted %v but got %v", tt.want2, d.interrupt)
}
})
}
}
func TestDev_Gain(t *testing.T) {
tests := []struct {
name string
tx []i2ctest.IO
timeout time.Duration
gain Gain
wantErr error
}{
{
name: "errStatusIO",
tx: []i2ctest.IO{
{Addr: 0x49, W: []byte{statusReg}, R: []byte{}},
// {Addr: 0x49, W: []byte{writeReg}, R: []byte{}},
},
timeout: time.Millisecond * 100,
wantErr: &IOError{"reading status register", nil},
},
{
name: "ok",
gain: G16x,
tx: []i2ctest.IO{
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x84}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x20}, R: []byte{}},
},
timeout: time.Millisecond * 100,
wantErr: nil,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
bus := &i2ctest.Playback{
Ops: tt.tx,
DontPanic: true,
}
d, _ := New(bus, &DefaultOpts)
got := d.Gain(tt.gain)
if _, ok := tt.wantErr.(*IOError); ok {
if _, ok := got.(*IOError); !ok {
t.Errorf("expected IOError but %T", got)
}
if got.(*IOError).Op != tt.wantErr.(*IOError).Op {
t.Errorf("expected %s, but got %s", tt.wantErr.(*IOError).Op, got.(*IOError).Op)
}
} else if got != tt.wantErr {
t.Errorf("expected error: %v but got: %v", tt.wantErr, got)
}
})
}
}
func TestDev_String(t *testing.T) {
want := "AMS AS7262 6 channel visible spectrum sensor"
d := &Dev{}
if d.String() != want {
t.Errorf("expected %s but got %s", want, d.String())
}
}
func TestIOError_Error(t *testing.T) {
tests := []struct {
name string
op string
err error
want string
}{
{"nil", "doing nothing", nil, "ioerror while doing nothing"},
{"errTimeoutPin", "", errPinTimeout, "ioerror while : timeout waiting for interrupt signal on pin"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
e := &IOError{tt.op, tt.err}
got := e.Error()
if tt.want != got {
t.Errorf("expected %s but got %s", tt.want, got)
}
})
}
}

@ -0,0 +1,12 @@
// Copyright 2018 The Periph Authors. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.
// Package as7262 controls an AMS 6 channel visible spectral sensor via an i2c
// interface. The as7262 features 6 spectral channels spaced at 450, 500, 550,
// 570, 600, 650 nm and includes 2 integrated LED drivers.
//
// Datasheet
//
// https://ams.com/documents/20143/36005/AS7262_DS000486_2-00.pdf
package as7262

@ -0,0 +1,48 @@
// Copyright 2018 The Periph Authors. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.
// +build go1.7
package as7262_test
import (
"fmt"
"log"
"time"
"periph.io/x/periph/conn/physic"
"periph.io/x/periph/conn/i2c/i2creg"
"periph.io/x/periph/experimental/devices/as7262"
"periph.io/x/periph/host"
)
func Example() {
// Make sure periph is initialized.
if _, err := host.Init(); err != nil {
log.Fatal(err)
}
// Open default I²C bus.
bus, err := i2creg.Open("")
if err != nil {
log.Fatalf("failed to open I²C: %v", err)
}
defer bus.Close()
// Create a new spectrum sensor.
sensor, err := as7262.New(bus, &as7262.DefaultOpts)
if err != nil {
log.Fatalln(err)
}
// Read values from sensor.
spectrum, err := sensor.Sense(25*physic.MilliAmpere, 500*time.Millisecond)
if err != nil {
log.Fatalln(err)
}
fmt.Println(spectrum)
}

@ -0,0 +1,372 @@
// Copyright 2018 The Periph Authors. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.
// +build go1.7
package as7262
import (
"time"
"periph.io/x/periph/conn/i2c/i2ctest"
"periph.io/x/periph/conn/physic"
)
// Expected response from sensorTestCaseValidRead or
// sensorTestCaseInteruptValidRead.
var validSpectrum = Spectrum{
Bands: []Band{
{450 * physic.NanoMetre, 0.15625, 43707, "V"},
{500 * physic.NanoMetre, 0.15625, 43707, "B"},
{550 * physic.NanoMetre, 0.15625, 43707, "G"},
{570 * physic.NanoMetre, 0.15625, 43707, "Y"},
{600 * physic.NanoMetre, 0.15625, 43707, "O"},
{650 * physic.NanoMetre, 0.15625, 43707, "R"},
},
SensorTemperature: physic.ZeroCelsius,
LedDrive: physic.MilliAmpere * 100,
Integration: 2800 * time.Microsecond,
}
// Sequence of i2c traffic that yeilds validSpectrum.
var sensorTestCaseValidRead = []i2ctest.IO{
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x85}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x01}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x87}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x38}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x84}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x0c}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x04}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0x02}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x87}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x00}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x08}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0xAA}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x09}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0xBB}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x0a}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0xAA}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x0b}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0xBB}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x0c}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0xAA}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x0d}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0xBB}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x0e}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0xAA}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x0f}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0xBB}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x10}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0xAA}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x11}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0xBB}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x12}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0xAA}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x13}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0xBB}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x14}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0x3e}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x15}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0x20}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x16}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x17}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x18}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0x3e}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x19}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0x20}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x1a}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x1b}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x1c}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0x3e}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x1d}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0x20}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x1e}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x1f}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x20}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0x3e}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x21}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0x20}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x22}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x23}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x24}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0x3e}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x25}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0x20}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x26}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x27}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x28}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0x3e}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x29}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0x20}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x2a}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x2b}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x06}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
}
// Same as sensorTestCaseValidRead but omiting polling for data ready.
var sensorTestCaseInteruptValidRead = []i2ctest.IO{
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x85}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x01}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x87}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x38}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x84}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x0c}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x87}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x00}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x08}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0xAA}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x09}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0xBB}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x0a}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0xAA}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x0b}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0xBB}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x0c}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0xAA}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x0d}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0xBB}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x0e}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0xAA}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x0f}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0xBB}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x10}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0xAA}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x11}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0xBB}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x12}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0xAA}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x13}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0xBB}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x14}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0x3e}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x15}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0x20}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x16}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x17}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x18}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0x3e}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x19}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0x20}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x1a}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x1b}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x1c}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0x3e}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x1d}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0x20}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x1e}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x1f}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x20}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0x3e}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x21}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0x20}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x22}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x23}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x24}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0x3e}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x25}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0x20}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x26}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x27}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x28}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0x3e}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x29}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0x20}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x2a}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x2b}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{writeReg, 0x06}, R: []byte{}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x01}},
{Addr: 0x49, W: []byte{readReg}, R: []byte{0x00}},
{Addr: 0x49, W: []byte{statusReg}, R: []byte{0x00}},
}
Loading…
Cancel
Save