mirror of https://github.com/periph/devices
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
parent
fb97d9d25d
commit
38804e4864
@ -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…
Reference in New Issue