diff --git a/experimental/devices/as7262/as7262.go b/experimental/devices/as7262/as7262.go index 79ccf71..e735af5 100644 --- a/experimental/devices/as7262/as7262.go +++ b/experimental/devices/as7262/as7262.go @@ -2,12 +2,9 @@ // 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" @@ -35,34 +32,33 @@ var DefaultOpts = Opts{ // 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() + // The nil or zero values for gain and interrupt are valid return &Dev{ c: &i2c.Dev{Bus: bus, Addr: 0x49}, gain: opts.Gain, interrupt: opts.InterruptPin, - order: binary.BigEndian, + done: make(chan struct{}, 1), 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 + + // Mutable + mu sync.Mutex + gain Gain + done chan struct{} + + // Guards canceled + canceledMu sync.Mutex + canceled bool } -// Spectrum is the reading from the senor including the actual sensor state for +// Spectrum is the reading from the sensor including the actual sensor state for // the readings. type Spectrum struct { Bands []Band @@ -70,7 +66,14 @@ type Spectrum struct { Gain Gain LedDrive physic.ElectricCurrent Integration time.Duration - //TODO:(NeuralSpaz) Pretty Printer. +} + +func (s Spectrum) String() string { + str := fmt.Sprintf("Spectrum: Gain:%s, Led Drive %s, Sense Time: %s", s.Gain, s.LedDrive, s.Integration) + for _, band := range s.Bands { + str += "\n" + band.String() + } + return str } // Band has two types of measurement of relative spectral flux density. @@ -97,6 +100,10 @@ type Band struct { Name string } +func (b Band) String() string { + return fmt.Sprintf("%s Band(%s) %7.1f counts", b.Name, b.Wavelength, b.Value) +} + // Sense preforms a reading of relative spectral radiance of all the sensor // bands. // @@ -118,8 +125,11 @@ func (d *Dev) Sense(ledDrive physic.ElectricCurrent, senseTime time.Duration) (S d.mu.Lock() defer d.mu.Unlock() - d.ctx, d.cancel = context.WithCancel(context.Background()) - defer d.cancel() + done := make(chan struct{}, 1) + d.canceledMu.Lock() + d.done = done + d.canceled = false + d.canceledMu.Unlock() it, integration := calcSenseTime(senseTime) if err := d.writeVirtualRegister(intergrationReg, it); err != nil { @@ -146,7 +156,7 @@ func (d *Dev) Sense(ledDrive physic.ElectricCurrent, senseTime time.Duration) (S if !edge { return Spectrum{}, errPinTimeout } - case <-d.ctx.Done(): + case <-d.done: return Spectrum{}, errHalted } } else { @@ -156,7 +166,7 @@ func (d *Dev) Sense(ledDrive physic.ElectricCurrent, senseTime time.Duration) (S if err := d.pollDataReady(); err != nil { return Spectrum{}, err } - case <-d.ctx.Done(): + case <-d.done: return Spectrum{}, errHalted } @@ -176,19 +186,19 @@ func (d *Dev) Sense(ledDrive physic.ElectricCurrent, senseTime time.Duration) (S 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]) + v := binary.BigEndian.Uint16(raw[0:2]) + b := binary.BigEndian.Uint16(raw[2:4]) + g := binary.BigEndian.Uint16(raw[4:6]) + y := binary.BigEndian.Uint16(raw[6:8]) + o := binary.BigEndian.Uint16(raw[8:10]) + r := binary.BigEndian.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]))) + vcal := float64(math.Float32frombits(binary.BigEndian.Uint32(cal[0:4]))) + bcal := float64(math.Float32frombits(binary.BigEndian.Uint32(cal[4:8]))) + gcal := float64(math.Float32frombits(binary.BigEndian.Uint32(cal[8:12]))) + ycal := float64(math.Float32frombits(binary.BigEndian.Uint32(cal[12:16]))) + ocal := float64(math.Float32frombits(binary.BigEndian.Uint32(cal[16:20]))) + rcal := float64(math.Float32frombits(binary.BigEndian.Uint32(cal[20:24]))) traw := make([]byte, 1) if err := d.readVirtualRegister(deviceTemperatureReg, traw); err != nil { @@ -213,13 +223,18 @@ func (d *Dev) Sense(ledDrive physic.ElectricCurrent, senseTime time.Duration) (S var waitForSensor = time.After -// Halt stops any pending operations +// Halt stops any pending operations. Repeated calls to Halt do nothing. func (d *Dev) Halt() error { - d.cancel() + d.canceledMu.Lock() + defer d.canceledMu.Unlock() + + if !d.canceled { + d.done <- struct{}{} + d.canceled = true + } return nil } -// String implaments the stringer interface func (d *Dev) String() string { return fmt.Sprintf("AMS AS7262 6 channel visible spectrum sensor") } @@ -238,16 +253,42 @@ const ( G64x Gain = 0x30 ) +const ( + _GainG1x = "1x" + _GainG4x = "3.7x" + _GainG16x = "16x" + _GainG64x = "64x" +) + +func (g Gain) String() string { + switch { + case g == 0: + return _GainG1x + case g == 16: + return _GainG4x + case g == 32: + return _GainG16x + case g == 48: + return _GainG64x + default: + return "bad gain value" + } +} + // 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. + if gain != G1x && gain != G4x && gain != G16x && gain != G64x { + return errGainValue + } d.mu.Lock() defer d.mu.Unlock() - d.ctx, d.cancel = context.WithCancel(context.Background()) - defer d.cancel() + done := make(chan struct{}, 1) + d.canceledMu.Lock() + d.done = done + d.canceled = false + d.canceledMu.Unlock() if err := d.writeVirtualRegister(controlReg, uint8(gain)); err != nil { return err @@ -320,8 +361,8 @@ func (d *Dev) readVirtualRegister(register byte, data []byte) error { // 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() + timeout := time.NewTimer(d.timeout) + defer timeout.Stop() for { if err := d.pollStatus(clearBuffer); err != nil { @@ -350,10 +391,10 @@ func (d *Dev) pollDataReady() error { select { case <-time.After(5 * time.Millisecond): // Polling interval. - case <-pollctx.Done(): + case <-timeout.C: // Return error if it takes too long. return errStatusDeadline - case <-d.ctx.Done(): + case <-d.done: return errHalted } } @@ -376,11 +417,11 @@ const ( // 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() + timeout := time.NewTimer(d.timeout) + defer timeout.Stop() // Check if already canceled first select { - case <-d.ctx.Done(): + case <-d.done: return errHalted default: // Proceed. @@ -424,10 +465,10 @@ func (d *Dev) pollStatus(dir direction) error { select { case <-time.After(5 * time.Millisecond): // Polling interval. - case <-pollctx.Done(): + case <-timeout.C: // Return error if it takes too long. return errStatusDeadline - case <-d.ctx.Done(): + case <-d.done: return errHalted } } @@ -489,7 +530,6 @@ type IOError struct { Err error } -// Error implements the Error interface. func (e *IOError) Error() string { if e.Err != nil { return "ioerror while " + e.Op + ": " + e.Err.Error() @@ -501,6 +541,7 @@ 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") + errGainValue = errors.New("invalid gain value") ) const ( diff --git a/experimental/devices/as7262/as7262_test.go b/experimental/devices/as7262/as7262_test.go index 7097f4e..ef4243d 100644 --- a/experimental/devices/as7262/as7262_test.go +++ b/experimental/devices/as7262/as7262_test.go @@ -2,12 +2,9 @@ // 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" @@ -93,13 +90,13 @@ func TestDev_Sense(t *testing.T) { tx: sensorTestCaseInteruptValidRead, }, { - name: "interuptTimeout", + name: "haltBeforeforEdge", opts: Opts{ InterruptPin: intPin, }, waiter: dontwait, sendEdge: false, - wantErr: errPinTimeout, + wantErr: errHalted, want: Spectrum{}, tx: sensorTestCaseInteruptValidRead, }, @@ -172,37 +169,39 @@ func TestDev_Sense(t *testing.T) { }, } 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) - bus := &i2ctest.Playback{ - Ops: tt.tx, - DontPanic: true, - } - d, _ := New(bus, &tt.opts) + waitForSensor = tt.waiter(d) - waitForSensor = tt.waiter(d) + if d.interrupt != nil && tt.sendEdge { + intPin.EdgesChan <- gpio.High + } + if tt.name == "haltBeforeforEdge" { + // Time must be less than senseTime. + time.AfterFunc(time.Millisecond, func() { + d.Halt() + }) + } - if d.interrupt != nil && tt.sendEdge { - intPin.EdgesChan <- gpio.High - } + got, err := d.Sense(physic.MilliAmpere*100, time.Millisecond*3) - 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 _, ok := tt.wantErr.(*IOError); ok { + if _, ok := err.(*IOError); !ok { + t.Errorf("expected IOError but %T", err) } - if !reflect.DeepEqual(got, tt.want) { - t.Errorf("Dev.Sense() = %v, want %v", got, tt.want) + 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) + } } } @@ -222,15 +221,13 @@ func Test_calcSenseTime(t *testing.T) { } 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) - } - }) + 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) + } } } @@ -254,11 +251,9 @@ func Test_calcLed(t *testing.T) { {"-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) - } - }) + if got, _ := calcLed(tt.drive); got != tt.want { + t.Errorf("calcLed() = %v, want %v", got, tt.want) + } } } @@ -372,44 +367,40 @@ func TestDev_pollStatus(t *testing.T) { }, } for _, tt := range tests { + bus := &i2ctest.Playback{ + Ops: tt.tx, + DontPanic: true, + } - 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() - } + d := &Dev{ + c: &i2c.Dev{Bus: bus, Addr: 0x49}, + done: make(chan struct{}, 1), + timeout: tt.timeout, + } + defer d.Halt() + if tt.halt > time.Nanosecond { + go func() { + time.Sleep(tt.halt) + d.Halt() + }() + } else if tt.halt != 0 { + d.Halt() + d.Halt() + } - 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) + 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) + } } } @@ -472,42 +463,37 @@ func TestDev_writeVirtualRegister(t *testing.T) { }, } for _, tt := range tests { + bus := &i2ctest.Playback{ + Ops: tt.tx, + DontPanic: true, + } - 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() - } + d := &Dev{ + c: &i2c.Dev{Bus: bus, Addr: 0x49}, + done: make(chan struct{}, 1), + timeout: tt.timeout, + } + defer d.Halt() + if tt.halt > time.Nanosecond { + go func() { + time.Sleep(tt.halt) + d.Halt() + }() + } else if tt.halt != 0 { + d.Halt() + } - 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) + 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) + } } } @@ -605,42 +591,36 @@ func TestDev_readVirtualRegister(t *testing.T) { }, } for _, tt := range tests { + bus := &i2ctest.Playback{ + Ops: tt.tx, + DontPanic: true, + } + d := &Dev{ + c: &i2c.Dev{Bus: bus, Addr: 0x49}, + done: make(chan struct{}, 1), + timeout: tt.timeout, + } + // defer d.Halt() + if tt.halt > time.Nanosecond { + go func() { + time.Sleep(tt.halt) + d.Halt() + }() + } else if tt.halt != 0 { + d.Halt() + } - t.Run(tt.name, func(t *testing.T) { - bus := &i2ctest.Playback{ - Ops: tt.tx, - DontPanic: true, + got := d.readVirtualRegister(0x04, tt.data) + if _, ok := tt.wantErr.(*IOError); ok { + if _, ok := got.(*IOError); !ok { + t.Errorf("expected IOError but %T", got) } - 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) + 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) + } } } @@ -752,47 +732,41 @@ func TestDev_pollDataReady(t *testing.T) { }, } for _, tt := range tests { + bus := &i2ctest.Playback{ + Ops: tt.tx, + DontPanic: true, + } - 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 := &Dev{ + c: &i2c.Dev{Bus: bus, Addr: 0x49}, + done: make(chan struct{}, 1), + timeout: tt.timeout, + } + defer d.Halt() + 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) + 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 @@ -809,22 +783,19 @@ func TestNew(t *testing.T) { }, } 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) - } - }) + 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) + } } } @@ -833,6 +804,7 @@ func TestDev_Gain(t *testing.T) { name string tx []i2ctest.IO timeout time.Duration + halt bool gain Gain wantErr error }{ @@ -845,6 +817,24 @@ func TestDev_Gain(t *testing.T) { timeout: time.Millisecond * 100, wantErr: &IOError{"reading status register", nil}, }, + { + name: "errHalt", + tx: []i2ctest.IO{ + {Addr: 0x49, W: []byte{statusReg}, R: []byte{0x03}}, + {Addr: 0x49, W: []byte{statusReg}, R: []byte{0x03}}, + {Addr: 0x49, W: []byte{statusReg}, R: []byte{0x03}}, + {Addr: 0x49, W: []byte{statusReg}, R: []byte{0x03}}, + {Addr: 0x49, W: []byte{statusReg}, R: []byte{0x03}}, + }, + halt: true, + timeout: time.Millisecond * 100, + wantErr: errHalted, + }, + { + name: "errGainValue", + gain: Gain(255), + wantErr: errGainValue, + }, { name: "ok", gain: G16x, @@ -859,27 +849,27 @@ func TestDev_Gain(t *testing.T) { }, } for _, tt := range tests { - - t.Run(tt.name, func(t *testing.T) { - bus := &i2ctest.Playback{ - Ops: tt.tx, - DontPanic: true, + bus := &i2ctest.Playback{ + Ops: tt.tx, + DontPanic: true, + } + d, _ := New(bus, &DefaultOpts) + go func() { + time.Sleep(time.Millisecond * 1) + d.Halt() + }() + got := d.Gain(tt.gain) + + if _, ok := tt.wantErr.(*IOError); ok { + if _, ok := got.(*IOError); !ok { + t.Errorf("expected IOError but %T", got) } - 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) + 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) + } } } @@ -891,6 +881,47 @@ func TestDev_String(t *testing.T) { } } +func TestBand_String(t *testing.T) { + want := " Band(0m) 0.0 counts" + d := Band{} + if d.String() != want { + t.Errorf("expected %s but got %s", want, d.String()) + } +} + +func TestSpectrum_String(t *testing.T) { + want := "Spectrum: Gain:1x, Led Drive 100mA, Sense Time: 2.8ms\n" + + "V Band(450nm) 0.2 counts\n" + + "B Band(500nm) 0.2 counts\n" + + "G Band(550nm) 0.2 counts\n" + + "Y Band(570nm) 0.2 counts\n" + + "O Band(600nm) 0.2 counts\n" + + "R Band(650nm) 0.2 counts" + d := validSpectrum + if d.String() != want { + t.Errorf("expected %s but got %s", want, d.String()) + } +} + +func TestGain_String(t *testing.T) { + tests := []struct { + name string + gain Gain + want string + }{ + {"1x", G1x, "1x"}, + {"4x", G4x, "3.7x"}, + {"16x", G16x, "16x"}, + {"64x", G64x, "64x"}, + {"invalid", Gain(255), "bad gain value"}, + } + for _, tt := range tests { + if got := tt.gain.String(); got != tt.want { + t.Errorf("Gain.String() %s expected %s but got %s", tt.name, tt.want, got) + } + } +} + func TestIOError_Error(t *testing.T) { tests := []struct { name string @@ -902,12 +933,27 @@ func TestIOError_Error(t *testing.T) { {"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) - } - }) + e := &IOError{tt.op, tt.err} + got := e.Error() + if tt.want != got { + t.Errorf("expected %s but got %s", tt.want, got) + } + } +} + +func TestIntergration_AfterHalt(t *testing.T) { + bus := &i2ctest.Playback{ + Ops: sensorTestCaseValidRead, + DontPanic: true, + } + d, _ := New(bus, &DefaultOpts) + + d.Halt() + if _, err := d.Sense(physic.MilliAmpere*100, time.Millisecond*3); err == errHalted { + t.Errorf("got %v expected nil", errHalted) + } + d.Halt() + if err := d.Gain(G1x); err == errHalted { + t.Errorf("got %v expected nil", errHalted) } } diff --git a/experimental/devices/as7262/example_test.go b/experimental/devices/as7262/example_test.go index 9e3f6b5..dd72587 100644 --- a/experimental/devices/as7262/example_test.go +++ b/experimental/devices/as7262/example_test.go @@ -2,8 +2,6 @@ // 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 ( diff --git a/experimental/devices/as7262/testdata_test.go b/experimental/devices/as7262/testdata_test.go index b020544..3b7ffd2 100644 --- a/experimental/devices/as7262/testdata_test.go +++ b/experimental/devices/as7262/testdata_test.go @@ -2,8 +2,6 @@ // 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 (