bmp180: promote to stable; fix bug in bme280 (#152)

- bme280: fix hang in Halt() if SenseContinuous() listener is hung.
- bmp180: Add unit tests; increase test coverage to 96%.
- bmp180: Remove Reset(). There's no known use case.
- bmp180: Implement SenseContinuous().
- Consistently wrap errors in both packages.
- Various typos.
pull/1/head
M-A 9 years ago committed by GitHub
parent e235d09bc8
commit 70fd9082bb

@ -36,7 +36,7 @@ type Oversampling uint8
// Possible oversampling values.
//
// The higher the more time and power it takes to take a measurement. Even at
// 16x for all 3 sensor, it is less than 100ms albeit increased power
// 16x for all 3 sensors, it is less than 100ms albeit increased power
// consumption may increase the temperature reading.
const (
Off Oversampling = 0
@ -103,6 +103,7 @@ type Dev struct {
mu sync.Mutex
stop chan struct{}
wg sync.WaitGroup
}
func (d *Dev) String() string {
@ -116,19 +117,19 @@ func (d *Dev) Sense(env *devices.Environment) error {
d.mu.Lock()
defer d.mu.Unlock()
if d.stop != nil {
return errors.New("bme280: already sensing continuously")
return wrap(errors.New("already sensing continuously"))
}
err := d.writeCommands([]byte{
// ctrl_meas
0xF4, byte(d.opts.Temperature)<<5 | byte(d.opts.Pressure)<<2 | byte(forced),
})
if err != nil {
return err
return wrap(err)
}
time.Sleep(d.measDelay)
for idle := false; !idle; {
if idle, err = d.isIdle(); err != nil {
return err
return wrap(err)
}
}
return d.sense(env)
@ -149,6 +150,7 @@ func (d *Dev) SenseContinuous(interval time.Duration) (<-chan devices.Environmen
// Don't send the stop command to the device.
close(d.stop)
d.stop = nil
d.wg.Wait()
}
s := chooseStandby(interval - d.measDelay)
err := d.writeCommands([]byte{
@ -158,18 +160,21 @@ func (d *Dev) SenseContinuous(interval time.Duration) (<-chan devices.Environmen
0xF4, byte(d.opts.Temperature)<<5 | byte(d.opts.Pressure)<<2 | byte(normal),
})
if err != nil {
return nil, err
return nil, wrap(err)
}
sensing := make(chan devices.Environment)
d.stop = make(chan struct{})
d.wg.Add(1)
go func() {
defer d.wg.Done()
defer close(sensing)
d.sensingContinuous(interval, sensing, d.stop)
}()
return sensing, nil
}
// Halt stops the bme280 from acquiring measurements as initiated by Sense().
// Halt stops the bme280 from acquiring measurements as initiated by
// SenseContinuous().
//
// It is recommended to call this function before terminating the process to
// reduce idle power usage.
@ -181,6 +186,7 @@ func (d *Dev) Halt() error {
}
close(d.stop)
d.stop = nil
d.wg.Wait()
// Page 27 (for register) and 12~13 section 3.3.
return d.writeCommands([]byte{
// config
@ -254,7 +260,7 @@ func NewI2C(b i2c.Bus, opts *Opts) (*Dev, error) {
case 0x00:
// do not do anything
default:
return nil, errors.New("bme280: given address not supported by device")
return nil, wrap(errors.New("given address not supported by device"))
}
}
d := &Dev{d: &i2c.Dev{Bus: b, Addr: addr}, isSPI: false}
@ -273,12 +279,12 @@ func NewI2C(b i2c.Bus, opts *Opts) (*Dev, error) {
// When using SPI, the CS line must be used.
func NewSPI(p spi.Port, opts *Opts) (*Dev, error) {
if opts != nil && opts.Address != 0 {
return nil, errors.New("bme280: do not use Address in SPI")
return nil, wrap(errors.New("do not use Address in SPI"))
}
// It works both in Mode0 and Mode3.
c, err := p.Connect(10000000, spi.Mode3, 8)
if err != nil {
return nil, err
return nil, wrap(err)
}
d := &Dev{d: c, isSPI: true}
if err := d.makeDev(opts); err != nil {
@ -294,7 +300,7 @@ func (d *Dev) makeDev(opts *Opts) error {
opts = &defaults
}
if opts.Temperature == Off {
return errors.New("temperature measurement is required, use at least O1x")
return wrap(errors.New("temperature measurement is required, use at least O1x"))
}
d.opts = *opts
d.measDelay = d.opts.delayTypical()
@ -308,7 +314,7 @@ func (d *Dev) makeDev(opts *Opts) error {
return err
}
if chipID[0] != 0x60 {
return fmt.Errorf("bme280: unexpected chip id %x; is this a BME280?", chipID[0])
return wrap(fmt.Errorf("unexpected chip id %x; is this a BME280?", chipID[0]))
}
// TODO(maruel): We may want to wait for isIdle().
@ -387,8 +393,11 @@ func (d *Dev) sensingContinuous(interval time.Duration, sensing chan<- devices.E
log.Printf("bme280: failed to sense: %v", err)
return
}
sensing <- e
select {
case sensing <- e:
case <-stop:
return
}
select {
case <-stop:
return
@ -416,12 +425,15 @@ func (d *Dev) readReg(reg uint8, b []byte) error {
// Rest of the write buffer is ignored.
write[0] = reg
if err := d.d.Tx(write, read); err != nil {
return err
return wrap(err)
}
copy(b, read[1:])
return nil
}
return d.d.Tx([]byte{reg}, b)
if err := d.d.Tx([]byte{reg}, b); err != nil {
return wrap(err)
}
return nil
}
// writeCommands writes a command to the bme280.
@ -434,7 +446,10 @@ func (d *Dev) writeCommands(b []byte) error {
b[i] &^= 0x80
}
}
return d.d.Tx(b, nil)
if err := d.d.Tx(b, nil); err != nil {
return wrap(err)
}
return nil
}
//
@ -620,6 +635,10 @@ func (c *calibration) compensateHumidityInt(raw, tFine int32) uint32 {
return uint32(x >> 12)
}
func wrap(err error) error {
return fmt.Errorf("bme280: %v", err)
}
var _ devices.Environmental = &Dev{}
var _ devices.Device = &Dev{}
var _ fmt.Stringer = &Dev{}

@ -47,7 +47,7 @@ func TestSPISense_success(t *testing.T) {
s := spitest.Playback{
Playback: conntest.Playback{
Ops: []conntest.IO{
// Chipd ID detection.
// Chip ID detection.
{
W: []byte{0xD0, 0x00},
R: []byte{0x00, 0x60},
@ -123,7 +123,7 @@ func TestNewSPI_fail_len(t *testing.T) {
Playback: conntest.Playback{
Ops: []conntest.IO{
{
// Chipd ID detection.
// Chip ID detection.
W: []byte{0xD0, 0x00},
R: []byte{0x00},
},
@ -146,7 +146,7 @@ func TestNewSPI_fail_chipid(t *testing.T) {
Playback: conntest.Playback{
Ops: []conntest.IO{
{
// Chipd ID detection.
// Chip ID detection.
W: []byte{0xD0, 0x00},
R: []byte{0x00, 0xFF},
},
@ -164,7 +164,7 @@ func TestNewSPI_fail_chipid(t *testing.T) {
func TestNewI2C_fail_io(t *testing.T) {
bus := i2ctest.Playback{
Ops: []i2ctest.IO{
// Chipd ID detection.
// Chip ID detection.
{Addr: 0x76, W: []byte{0xd0}},
},
DontPanic: true,
@ -182,7 +182,7 @@ func TestNewI2C_fail_io(t *testing.T) {
func TestNewI2C_fail_chipid(t *testing.T) {
bus := i2ctest.Playback{
Ops: []i2ctest.IO{
// Chipd ID detection.
// Chip ID detection.
{Addr: 0x76, W: []byte{0xd0}, R: []byte{0x60}},
},
DontPanic: true,
@ -198,7 +198,7 @@ func TestNewI2C_fail_chipid(t *testing.T) {
func TestNewI2C_calib1(t *testing.T) {
bus := i2ctest.Playback{
Ops: []i2ctest.IO{
// Chipd ID detection.
// Chip ID detection.
{Addr: 0x76, W: []byte{0xd0}, R: []byte{0x60}},
// Calibration data.
{
@ -221,7 +221,7 @@ func TestNewI2C_calib1(t *testing.T) {
func TestNewI2C_calib2(t *testing.T) {
bus := i2ctest.Playback{
Ops: []i2ctest.IO{
// Chipd ID detection.
// Chip ID detection.
{Addr: 0x76, W: []byte{0xd0}, R: []byte{0x60}},
// Calibration data.
{
@ -267,7 +267,7 @@ func TestI2COpts(t *testing.T) {
func TestI2CSense_fail(t *testing.T) {
bus := i2ctest.Playback{
Ops: []i2ctest.IO{
// Chipd ID detection.
// Chip ID detection.
{Addr: 0x76, W: []byte{0xd0}, R: []byte{0x60}},
// Calibration data.
{
@ -302,7 +302,7 @@ func TestI2CSense_fail(t *testing.T) {
func TestI2CSense_success(t *testing.T) {
bus := i2ctest.Playback{
Ops: []i2ctest.IO{
// Chipd ID detection.
// Chip ID detection.
{Addr: 0x76, W: []byte{0xd0}, R: []byte{0x60}},
// Calibration data.
{
@ -355,7 +355,7 @@ func TestI2CSense_success(t *testing.T) {
func TestI2CSense_idle_fail(t *testing.T) {
bus := i2ctest.Playback{
Ops: []i2ctest.IO{
// Chipd ID detection.
// Chip ID detection.
{Addr: 0x76, W: []byte{0xd0}, R: []byte{0x60}},
// Calibration data.
{
@ -389,7 +389,7 @@ func TestI2CSense_idle_fail(t *testing.T) {
func TestI2CSense_command_fail(t *testing.T) {
bus := i2ctest.Playback{
Ops: []i2ctest.IO{
// Chipd ID detection.
// Chip ID detection.
{Addr: 0x76, W: []byte{0xd0}, R: []byte{0x60}},
// Calibration data.
{
@ -425,7 +425,7 @@ func TestI2CSense_command_fail(t *testing.T) {
func TestI2CSenseContinuous_success(t *testing.T) {
bus := i2ctest.Playback{
Ops: []i2ctest.IO{
// Chipd ID detection.
// Chip ID detection.
{Addr: 0x76, W: []byte{0xd0}, R: []byte{0x60}},
// Calibration data.
{
@ -524,6 +524,9 @@ func TestI2CSenseContinuous_success(t *testing.T) {
if err := dev.Halt(); err != nil {
t.Fatal(err)
}
if _, ok := <-c2; ok {
t.Fatal("c2 should be closed")
}
if err := bus.Close(); err != nil {
t.Fatal(err)
}
@ -532,7 +535,7 @@ func TestI2CSenseContinuous_success(t *testing.T) {
func TestI2CSenseContinuous_command_fail(t *testing.T) {
bus := i2ctest.Playback{
Ops: []i2ctest.IO{
// Chipd ID detection.
// Chip ID detection.
{Addr: 0x76, W: []byte{0xd0}, R: []byte{0x60}},
// Calibration data.
{
@ -564,7 +567,7 @@ func TestI2CSenseContinuous_sense_fail(t *testing.T) {
}
bus := i2ctest.Playback{
Ops: []i2ctest.IO{
// Chipd ID detection.
// Chip ID detection.
{Addr: 0x76, W: []byte{0xd0}, R: []byte{0x60}},
// Calibration data.
{

@ -6,11 +6,9 @@
//
// Datasheet
//
// The official data sheet can be found here:
//
// https://ae-bst.resource.bosch.com/media/_tech/media/datasheets/BST-BMP180-DS000-121.pdf
//
// The font the official datasheet on page 15 is unreadable, a copy with
// The font the official datasheet on page 15 is hard to read, a copy with
// readable text can be found here:
//
// https://cdn-shop.adafruit.com/datasheets/BST-BMP180-DS000-09.pdf
@ -27,6 +25,8 @@ import (
"encoding/binary"
"errors"
"fmt"
"log"
"sync"
"time"
"periph.io/x/periph/conn/i2c"
@ -37,50 +37,38 @@ import (
// Oversampling affects how much time is taken to measure pressure.
type Oversampling uint8
// Possible oversampling values.
//
// The higher the more time and power it takes to take a measurement. Even at
// 8x for pressure sensor, it is less than 30ms albeit at small increased power
// consumption, which may increase the temperature reading.
const (
// Possible oversampling values
No Oversampling = 0
O1x Oversampling = 0
O2x Oversampling = 1
O4x Oversampling = 2
O8x Oversampling = 3
)
// bit offsets in regCtrlMeas
ctrlMeasurementControlShift = 0
ctrlStartConversionShift = 5
ctrlOversamplingShift = 6
// commands
cmdStartTempConv uint8 = (1 << ctrlStartConversionShift) | (0x0E << ctrlMeasurementControlShift)
cmdStartPressureConv uint8 = (1 << ctrlStartConversionShift) | (0x14 << ctrlMeasurementControlShift)
chipAddress = 0x77 // the address of a BMP180 is fixed at 0x77
chipID = 0x55 // contents of the ID register, always 0x55
// registers
regChipID = 0xD0 // register contains the chip id
regCalibrationStart = 0xAA // first calibration register address
regSoftReset = 0xE0 // soft reset register
regCtrlMeas = 0xF4 // control measurement
regOut = 0xF6 // 3 bytes register with measurement data
softResetValue = 0xB6
const oversamplingName = "1x2x4x8x"
tempConvTime = 4500 * time.Microsecond // maximum conversion time for temperature
)
var oversamplingIndex = [...]uint8{0, 2, 4, 6, 8}
// maximum conversion time for pressure
var pressureConvTime = [...]time.Duration{
4500 * time.Microsecond,
7500 * time.Microsecond,
13500 * time.Microsecond,
25500 * time.Microsecond,
func (i Oversampling) String() string {
if i >= Oversampling(len(oversamplingIndex)-1) {
return fmt.Sprintf("Oversampling(%d)", i)
}
return oversamplingName[oversamplingIndex[i]:oversamplingIndex[i+1]]
}
// Dev is a handle to a bmp180.
type Dev struct {
dev mmr.Dev8
cal calibration
os Oversampling
cal calibration
mu sync.Mutex
stop chan struct{}
wg sync.WaitGroup
}
func (d *Dev) String() string {
@ -89,104 +77,142 @@ func (d *Dev) String() string {
// Sense returns measurements as °C and kPa.
func (d *Dev) Sense(env *devices.Environment) error {
// start conversion for temperature
if err := d.dev.WriteUint8(regCtrlMeas, cmdStartTempConv); err != nil {
return err
d.mu.Lock()
defer d.mu.Unlock()
if d.stop != nil {
return wrap(errors.New("already sensing continuously"))
}
return d.sense(env)
}
// SenseContinuous implements devices.Environmental.
func (d *Dev) SenseContinuous(interval time.Duration) (<-chan devices.Environment, error) {
d.mu.Lock()
defer d.mu.Unlock()
if d.stop != nil {
close(d.stop)
d.stop = nil
d.wg.Wait()
}
sensing := make(chan devices.Environment)
d.stop = make(chan struct{})
d.wg.Add(1)
go func() {
defer d.wg.Done()
defer close(sensing)
d.sensingContinuous(interval, sensing, d.stop)
}()
return sensing, nil
}
// Halt stops continuous reading.
func (d *Dev) Halt() error {
d.mu.Lock()
defer d.mu.Unlock()
if d.stop != nil {
close(d.stop)
d.stop = nil
d.wg.Wait()
}
return nil
}
time.Sleep(tempConvTime)
// New returns an object that communicates over I²C to BMP180 environmental
// sensor.
//
// The I²C bus frequency can be up to 3.4MHz.
func New(b i2c.Bus, os Oversampling) (d *Dev, err error) {
bus := &i2c.Dev{Bus: b, Addr: 0x77}
d = &Dev{dev: mmr.Dev8{Conn: bus, Order: binary.BigEndian}, os: os}
// read value
ut, err := d.dev.ReadUint16(regOut)
// Confirm the chip ID.
id, err := d.dev.ReadUint8(0xD0)
if err != nil {
return err
return nil, wrap(err)
}
if id != 0x55 {
return nil, wrap(fmt.Errorf("unexpected chip id 0x%x; is this a BMP180?", id))
}
temp := d.cal.compensateTemp(ut)
// Read calibration data.
if err := d.dev.ReadStruct(0xAA, &d.cal); err != nil {
return nil, wrap(err)
}
if !d.cal.isValid() {
return nil, wrap(errors.New("calibration data is invalid"))
}
return d, nil
}
// start conversion for pressure
cmd := cmdStartPressureConv
cmd |= uint8(d.os) << ctrlOversamplingShift
//
if err := d.dev.WriteUint8(regCtrlMeas, cmd); err != nil {
return err
func (d *Dev) sense(env *devices.Environment) error {
// Request temperature convertion and read measurement.
if err := d.dev.WriteUint8(0xF4, 0x20|0x0E); err != nil {
return wrap(err)
}
time.Sleep(4500 * time.Microsecond)
ut, err := d.dev.ReadUint16(0xF6)
if err != nil {
return wrap(err)
}
temp := d.cal.compensateTemp(ut)
// Request pressure conversion and read measurement.
if err := d.dev.WriteUint8(0xF4, 0x20|0x14|(uint8(d.os)<<6)); err != nil {
return wrap(err)
}
time.Sleep(pressureConvTime[d.os])
// read value
var pressureBuf [3]byte
if err := d.dev.ReadStruct(regOut, pressureBuf[:]); err != nil {
return err
if err := d.dev.ReadStruct(0xF6, pressureBuf[:]); err != nil {
return wrap(err)
}
up := (int32(pressureBuf[0])<<16 + int32(pressureBuf[1])<<8 | int32(pressureBuf[2])) >> (8 - d.os)
pressure := d.cal.compensatePressure(up, int32(ut), d.os)
env.Temperature = devices.Celsius(temp * 100)
env.Pressure = devices.KPascal(pressure)
return nil
}
// SenseContinuous implements devices.Environmental.
func (d *Dev) SenseContinuous(interval time.Duration) (<-chan devices.Environment, error) {
// TODO(maruel): Manually poll in a loop via time.NewTicker.
return nil, errors.New("not implemented")
}
// Halt is a noop for the BMP180.
func (d *Dev) Halt() error {
return nil
}
// Reset issues a soft reset to the device.
func (d *Dev) Reset() error {
// issue soft reset to initialize device
if err := d.dev.WriteUint8(regSoftReset, softResetValue); err != nil {
return err
}
// wait for restart
time.Sleep(10 * time.Millisecond)
return nil
}
// New returns an object that communicates over I²C to BMP180 environmental
// sensor. The frequency for the bus can be up to 3.4MHz.
func New(b i2c.Bus, os Oversampling) (d *Dev, err error) {
bus := &i2c.Dev{Bus: b, Addr: chipAddress}
d = &Dev{
os: os,
dev: mmr.Dev8{
Conn: bus,
Order: binary.BigEndian,
},
}
func (d *Dev) sensingContinuous(interval time.Duration, sensing chan<- devices.Environment, stop <-chan struct{}) {
t := time.NewTicker(interval)
defer t.Stop()
id, err := d.dev.ReadUint8(regChipID)
for {
// Do one initial sensing right away.
var e devices.Environment
d.mu.Lock()
err := d.sense(&e)
d.mu.Unlock()
if err != nil {
return nil, err
log.Printf("bmp180: failed to sense: %v", err)
return
}
if id != chipID {
return nil, fmt.Errorf("bmp180: unexpected chip id 0x%x; is this a BMP180?", id)
select {
case sensing <- e:
case <-stop:
return
}
// read calibration data from internal EEPROM, 11 registers with two bytes each
if err := d.dev.ReadStruct(regCalibrationStart, &d.cal); err != nil {
return nil, err
select {
case <-stop:
return
case <-t.C:
}
if !d.cal.isValid() {
return nil, errors.New("calibration data is invalid")
}
}
return d, nil
//
// Maximum conversion time for pressure.
var pressureConvTime = [...]time.Duration{
4500 * time.Microsecond,
7500 * time.Microsecond,
13500 * time.Microsecond,
25500 * time.Microsecond,
}
// calibration data read from the internal EEPROM (datasheet page 13)
// calibration data read from the internal EEPROM (datasheet page 13).
type calibration struct {
AC1, AC2, AC3 int16
AC4, AC5, AC6 uint16
@ -249,6 +275,10 @@ func (c *calibration) compensatePressure(up, ut int32, os Oversampling) uint32 {
return uint32(p)
}
func wrap(err error) error {
return fmt.Errorf("bmp180: %v", err)
}
var _ devices.Environmental = &Dev{}
var _ devices.Device = &Dev{}
var _ fmt.Stringer = &Dev{}

@ -0,0 +1,362 @@
// Copyright 2017 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 bmp180
import (
"testing"
"time"
"periph.io/x/periph/conn/i2c/i2ctest"
"periph.io/x/periph/devices"
)
func TestNew_fail_read_chipid(t *testing.T) {
bus := i2ctest.Playback{
Ops: []i2ctest.IO{
// Chip ID detection read fail.
},
DontPanic: true,
}
if _, err := New(&bus, O1x); err == nil {
t.Fatal("can't read chip ID")
}
}
func TestNew_bad_chipid(t *testing.T) {
bus := i2ctest.Playback{
Ops: []i2ctest.IO{
// Bad Chip ID detection.
{Addr: 0x77, W: []byte{0xd0}, R: []byte{0x60}},
},
}
if _, err := New(&bus, O1x); err == nil {
t.Fatal("bad chip ID")
}
}
func TestNew_fail_calib(t *testing.T) {
bus := i2ctest.Playback{
Ops: []i2ctest.IO{
// Chip ID detection.
{Addr: 0x77, W: []byte{0xd0}, R: []byte{0x55}},
// Fail to read calibration data.
},
DontPanic: true,
}
if _, err := New(&bus, O1x); err == nil {
t.Fatal("can't read calibration")
}
}
func TestNew_bad_calib(t *testing.T) {
bus := i2ctest.Playback{
Ops: []i2ctest.IO{
// Chip ID detection.
{Addr: 0x77, W: []byte{0xd0}, R: []byte{0x55}},
// Calibration data.
{
Addr: 0x77,
W: []byte{0xaa},
R: []byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
},
},
DontPanic: true,
}
if _, err := New(&bus, O1x); err == nil {
t.Fatal("bad calibration")
}
}
func TestSense_success(t *testing.T) {
bus := i2ctest.Playback{
Ops: []i2ctest.IO{
// Chip ID detection.
{Addr: 0x77, W: []byte{0xd0}, R: []byte{0x55}},
// Calibration data.
{
Addr: 0x77,
W: []byte{0xaa},
R: []byte{35, 136, 251, 103, 199, 169, 135, 91, 98, 137, 80, 22, 25, 115, 0, 46, 128, 0, 209, 246, 10, 123},
},
// Request temperature.
{Addr: 0x77, W: []byte{0xF4, 0x2E}},
// Read temperature.
{Addr: 0x77, W: []byte{0xF6}, R: []byte{0x71, 0xBf}},
// Request pressure.
{Addr: 0x77, W: []byte{0xF4, 0x34}},
// Read pressure.
{Addr: 0x77, W: []byte{0xF6}, R: []byte{0xAb, 0x96, 0}},
},
}
dev, err := New(&bus, O1x)
if err != nil {
t.Fatal(err)
}
if s := dev.String(); s != "BMP180{playback(119)}" {
t.Fatal(s)
}
env := devices.Environment{}
if err := dev.Sense(&env); err != nil {
t.Fatal(err)
}
if env.Temperature != 25300 {
t.Fatalf("temp %d", env.Temperature)
}
if env.Pressure != 100567 {
t.Fatalf("pressure %d", env.Pressure)
}
if env.Humidity != 0 {
t.Fatalf("humidity %d", env.Humidity)
}
if err := dev.Halt(); err != nil {
t.Fatal(err)
}
if err := bus.Close(); err != nil {
t.Fatal(err)
}
}
func TestSense_fail_1(t *testing.T) {
bus := i2ctest.Playback{
Ops: []i2ctest.IO{
// Chip ID detection.
{Addr: 0x77, W: []byte{0xd0}, R: []byte{0x55}},
// Calibration data.
{
Addr: 0x77,
W: []byte{0xaa},
R: []byte{35, 136, 251, 103, 199, 169, 135, 91, 98, 137, 80, 22, 25, 115, 0, 46, 128, 0, 209, 246, 10, 123},
},
// Request temperature fail.
},
DontPanic: true,
}
dev, err := New(&bus, O1x)
if err != nil {
t.Fatal(err)
}
env := devices.Environment{}
if dev.Sense(&env) == nil {
t.Fatal("sensing should have failed")
}
if err := bus.Close(); err != nil {
t.Fatal(err)
}
}
func TestSense_fail_2(t *testing.T) {
bus := i2ctest.Playback{
Ops: []i2ctest.IO{
// Chip ID detection.
{Addr: 0x77, W: []byte{0xd0}, R: []byte{0x55}},
// Calibration data.
{
Addr: 0x77,
W: []byte{0xaa},
R: []byte{35, 136, 251, 103, 199, 169, 135, 91, 98, 137, 80, 22, 25, 115, 0, 46, 128, 0, 209, 246, 10, 123},
},
// Request temperature.
{Addr: 0x77, W: []byte{0xF4, 0x2E}},
// Read temperature fail.
},
DontPanic: true,
}
dev, err := New(&bus, O1x)
if err != nil {
t.Fatal(err)
}
env := devices.Environment{}
if dev.Sense(&env) == nil {
t.Fatal("sensing should have failed")
}
if err := bus.Close(); err != nil {
t.Fatal(err)
}
}
func TestSense_fail_3(t *testing.T) {
bus := i2ctest.Playback{
Ops: []i2ctest.IO{
// Chip ID detection.
{Addr: 0x77, W: []byte{0xd0}, R: []byte{0x55}},
// Calibration data.
{
Addr: 0x77,
W: []byte{0xaa},
R: []byte{35, 136, 251, 103, 199, 169, 135, 91, 98, 137, 80, 22, 25, 115, 0, 46, 128, 0, 209, 246, 10, 123},
},
// Request temperature.
{Addr: 0x77, W: []byte{0xF4, 0x2E}},
// Read temperature fail.
{Addr: 0x77, W: []byte{0xF6}, R: []byte{0x71, 0xBf}},
// Request pressure fail.
},
DontPanic: true,
}
dev, err := New(&bus, O1x)
if err != nil {
t.Fatal(err)
}
env := devices.Environment{}
if dev.Sense(&env) == nil {
t.Fatal("sensing should have failed")
}
if err := bus.Close(); err != nil {
t.Fatal(err)
}
}
func TestSense_fail_4(t *testing.T) {
bus := i2ctest.Playback{
Ops: []i2ctest.IO{
// Chip ID detection.
{Addr: 0x77, W: []byte{0xd0}, R: []byte{0x55}},
// Calibration data.
{
Addr: 0x77,
W: []byte{0xaa},
R: []byte{35, 136, 251, 103, 199, 169, 135, 91, 98, 137, 80, 22, 25, 115, 0, 46, 128, 0, 209, 246, 10, 123},
},
// Request temperature.
{Addr: 0x77, W: []byte{0xF4, 0x2E}},
// Read temperature fail.
{Addr: 0x77, W: []byte{0xF6}, R: []byte{0x71, 0xBf}},
// Request pressure.
{Addr: 0x77, W: []byte{0xF4, 0x34}},
// Read pressure fail.
},
DontPanic: true,
}
dev, err := New(&bus, O1x)
if err != nil {
t.Fatal(err)
}
env := devices.Environment{}
if dev.Sense(&env) == nil {
t.Fatal("sensing should have failed")
}
if err := bus.Close(); err != nil {
t.Fatal(err)
}
}
func TestSenseContinuous_success(t *testing.T) {
bus := i2ctest.Playback{
Ops: []i2ctest.IO{
// Chip ID detection.
{Addr: 0x77, W: []byte{0xd0}, R: []byte{0x55}},
// Calibration data.
{
Addr: 0x77,
W: []byte{0xaa},
R: []byte{35, 136, 251, 103, 199, 169, 135, 91, 98, 137, 80, 22, 25, 115, 0, 46, 128, 0, 209, 246, 10, 123},
},
// Request temperature.
{Addr: 0x77, W: []byte{0xF4, 0x2E}},
// Read temperature.
{Addr: 0x77, W: []byte{0xF6}, R: []byte{0x71, 0xBf}},
// Request pressure.
{Addr: 0x77, W: []byte{0xF4, 0x34}},
// Read pressure.
{Addr: 0x77, W: []byte{0xF6}, R: []byte{0xAb, 0x96, 0}},
// Request temperature.
{Addr: 0x77, W: []byte{0xF4, 0x2E}},
// Read temperature.
{Addr: 0x77, W: []byte{0xF6}, R: []byte{0x71, 0xBf}},
// Request pressure.
{Addr: 0x77, W: []byte{0xF4, 0x34}},
// Read pressure.
{Addr: 0x77, W: []byte{0xF6}, R: []byte{0xAb, 0x96, 0}},
},
DontPanic: true,
}
dev, err := New(&bus, O1x)
if err != nil {
t.Fatal(err)
}
c, err := dev.SenseContinuous(time.Minute)
if err != nil {
t.Fatal(err)
}
env := <-c
if env.Temperature != 25300 {
t.Fatalf("temp %d", env.Temperature)
}
if env.Pressure != 100567 {
t.Fatalf("pressure %d", env.Pressure)
}
if env.Humidity != 0 {
t.Fatalf("humidity %d", env.Humidity)
}
if dev.Sense(&env) == nil {
t.Fatal("Sense() should have failed")
}
c2, err := dev.SenseContinuous(time.Minute)
if err != nil {
t.Fatal(err)
}
env = <-c2
if _, ok := <-c; ok {
t.Fatal("c should be closed")
}
if err := dev.Halt(); err != nil {
t.Fatal(err)
}
if _, ok := <-c2; ok {
t.Fatal("c2 should be closed")
}
if err := bus.Close(); err != nil {
t.Fatal(err)
}
}
func TestOversampling(t *testing.T) {
data := []struct {
o Oversampling
v int
s string
}{
{O1x, 1, "1x"},
{O2x, 2, "2x"},
{O4x, 4, "4x"},
{O8x, 8, "8x"},
{Oversampling(100), 0, "Oversampling(100)"},
}
for i, line := range data {
if s := line.o.String(); s != line.s {
t.Fatalf("#%d %s != %s", i, s, line.s)
}
}
}
func TestCompensate(t *testing.T) {
c := calibration{
AC1: 408,
AC2: -72,
AC3: -14383,
AC4: 32741,
AC5: 32757,
AC6: 23153,
B1: 6190,
B2: 4,
MB: -32768,
MC: -8711,
MD: 2868,
}
if temp := c.compensateTemp(27898); temp != 150 {
t.Errorf("temperature is wrong, want %v, got %v", 150, temp)
}
if pressure := c.compensatePressure(23843, 27898, 0); pressure != 69964 {
t.Errorf("pressure is wrong, want %v, got %v", 69964, pressure)
}
}

@ -1,31 +0,0 @@
// Copyright 2017 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 bmp180
import "testing"
func TestCompensate(t *testing.T) {
c := calibration{
AC1: 408,
AC2: -72,
AC3: -14383,
AC4: 32741,
AC5: 32757,
AC6: 23153,
B1: 6190,
B2: 4,
MB: -32768,
MC: -8711,
MD: 2868,
}
if temp := c.compensateTemp(27898); temp != 150 {
t.Errorf("temperature is wrong, want %v, got %v", 150, temp)
}
if pressure := c.compensatePressure(23843, 27898, 0); pressure != 69964 {
t.Errorf("pressure is wrong, want %v, got %v", 69964, pressure)
}
}
Loading…
Cancel
Save