From 2352b96bc1dc52d1dea13134350db0dc34f7ed58 Mon Sep 17 00:00:00 2001 From: NeuralSpaz <6887502+NeuralSpaz@users.noreply.github.com> Date: Thu, 1 Nov 2018 03:50:19 +1100 Subject: [PATCH] as7262: Remove requirement for go1.7 (#301) Refactor to remove context.Context Remove usage of t.Run. Adds test case for Sense for 100% coverage Removed signal.Notify's as signals do not always get delivered. Fix documentation copy paste error. Add Band stringer test. Add Spectrum stringer test Add Gain stringer test. Add Gain stringer. Add Spectrum stringer. Add Band stringer. Add check for gain value. Add more test for Halt() conditions. Move done channel creation within cancel mutex. --- experimental/devices/as7262/as7262.go | 141 ++++-- experimental/devices/as7262/as7262_test.go | 484 ++++++++++--------- experimental/devices/as7262/example_test.go | 2 - experimental/devices/as7262/testdata_test.go | 2 - 4 files changed, 356 insertions(+), 273 deletions(-) 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 (