gobot.io/x/gobot@v1.16.0/drivers/i2c/bmp180_driver.go (about)

     1  package i2c
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/binary"
     6  	"time"
     7  
     8  	"gobot.io/x/gobot"
     9  )
    10  
    11  const bmp180Address = 0x77
    12  
    13  const bmp180RegisterAC1MSB = 0xAA
    14  
    15  const bmp180RegisterCtl = 0xF4
    16  const bmp180CmdTemp = 0x2E
    17  const bmp180RegisterTempMSB = 0xF6
    18  const bmp180CmdPressure = 0x34
    19  const bmp180RegisterPressureMSB = 0xF6
    20  
    21  const (
    22  	// BMP180UltraLowPower is the lowest oversampling mode of the pressure measurement.
    23  	BMP180UltraLowPower BMP180OversamplingMode = iota
    24  	// BMP180Standard is the standard oversampling mode of the pressure measurement.
    25  	BMP180Standard
    26  	// BMP180HighResolution is a high oversampling mode of the pressure measurement.
    27  	BMP180HighResolution
    28  	// BMP180UltraHighResolution is the highest oversampling mode of the pressure measurement.
    29  	BMP180UltraHighResolution
    30  )
    31  
    32  // BMP180OversamplingMode is the oversampling ratio of the pressure measurement.
    33  type BMP180OversamplingMode uint
    34  
    35  type calibrationCoefficients struct {
    36  	ac1 int16
    37  	ac2 int16
    38  	ac3 int16
    39  	ac4 uint16
    40  	ac5 uint16
    41  	ac6 uint16
    42  	b1  int16
    43  	b2  int16
    44  	mb  int16
    45  	mc  int16
    46  	md  int16
    47  }
    48  
    49  // BMP180Driver is the gobot driver for the Bosch pressure sensor BMP180.
    50  // Device datasheet: https://cdn-shop.adafruit.com/datasheets/BST-BMP180-DS000-09.pdf
    51  type BMP180Driver struct {
    52  	name       string
    53  	Mode       BMP180OversamplingMode
    54  	connector  Connector
    55  	connection Connection
    56  	Config
    57  	calibrationCoefficients *calibrationCoefficients
    58  }
    59  
    60  // NewBMP180Driver creates a new driver with the i2c interface for the BMP180 device.
    61  // Params:
    62  //		conn Connector - the Adaptor to use with this Driver
    63  //
    64  // Optional params:
    65  //		i2c.WithBus(int):	bus to use with this driver
    66  //		i2c.WithAddress(int):	address to use with this driver
    67  //
    68  func NewBMP180Driver(c Connector, options ...func(Config)) *BMP180Driver {
    69  	b := &BMP180Driver{
    70  		name:                    gobot.DefaultName("BMP180"),
    71  		connector:               c,
    72  		Mode:                    BMP180UltraLowPower,
    73  		Config:                  NewConfig(),
    74  		calibrationCoefficients: &calibrationCoefficients{},
    75  	}
    76  
    77  	for _, option := range options {
    78  		option(b)
    79  	}
    80  
    81  	// TODO: expose commands to API
    82  	return b
    83  }
    84  
    85  // Name returns the name of the device.
    86  func (d *BMP180Driver) Name() string {
    87  	return d.name
    88  }
    89  
    90  // SetName sets the name of the device.
    91  func (d *BMP180Driver) SetName(n string) {
    92  	d.name = n
    93  }
    94  
    95  // Connection returns the connection of the device.
    96  func (d *BMP180Driver) Connection() gobot.Connection {
    97  	return d.connector.(gobot.Connection)
    98  }
    99  
   100  // Start initializes the BMP180 and loads the calibration coefficients.
   101  func (d *BMP180Driver) Start() (err error) {
   102  	bus := d.GetBusOrDefault(d.connector.GetDefaultBus())
   103  	address := d.GetAddressOrDefault(bmp180Address)
   104  
   105  	if d.connection, err = d.connector.GetConnection(address, bus); err != nil {
   106  		return err
   107  	}
   108  	if err := d.initialization(); err != nil {
   109  		return err
   110  	}
   111  	return nil
   112  }
   113  
   114  func (d *BMP180Driver) initialization() (err error) {
   115  	var coefficients []byte
   116  	// read the 11 calibration coefficients.
   117  	if coefficients, err = d.read(bmp180RegisterAC1MSB, 22); err != nil {
   118  		return err
   119  	}
   120  	buf := bytes.NewBuffer(coefficients)
   121  	binary.Read(buf, binary.BigEndian, &d.calibrationCoefficients.ac1)
   122  	binary.Read(buf, binary.BigEndian, &d.calibrationCoefficients.ac2)
   123  	binary.Read(buf, binary.BigEndian, &d.calibrationCoefficients.ac3)
   124  	binary.Read(buf, binary.BigEndian, &d.calibrationCoefficients.ac4)
   125  	binary.Read(buf, binary.BigEndian, &d.calibrationCoefficients.ac5)
   126  	binary.Read(buf, binary.BigEndian, &d.calibrationCoefficients.ac6)
   127  	binary.Read(buf, binary.BigEndian, &d.calibrationCoefficients.b1)
   128  	binary.Read(buf, binary.BigEndian, &d.calibrationCoefficients.b2)
   129  	binary.Read(buf, binary.BigEndian, &d.calibrationCoefficients.mb)
   130  	binary.Read(buf, binary.BigEndian, &d.calibrationCoefficients.mc)
   131  	binary.Read(buf, binary.BigEndian, &d.calibrationCoefficients.md)
   132  
   133  	return nil
   134  }
   135  
   136  // Halt halts the device.
   137  func (d *BMP180Driver) Halt() (err error) {
   138  	return nil
   139  }
   140  
   141  // Temperature returns the current temperature, in celsius degrees.
   142  func (d *BMP180Driver) Temperature() (temp float32, err error) {
   143  	var rawTemp int16
   144  	if rawTemp, err = d.rawTemp(); err != nil {
   145  		return 0, err
   146  	}
   147  	return d.calculateTemp(rawTemp), nil
   148  }
   149  
   150  // Pressure returns the current pressure, in pascals.
   151  func (d *BMP180Driver) Pressure() (pressure float32, err error) {
   152  	var rawTemp int16
   153  	var rawPressure int32
   154  	if rawTemp, err = d.rawTemp(); err != nil {
   155  		return 0, err
   156  	}
   157  	if rawPressure, err = d.rawPressure(d.Mode); err != nil {
   158  		return 0, err
   159  	}
   160  	return d.calculatePressure(rawTemp, rawPressure, d.Mode), nil
   161  }
   162  
   163  func (d *BMP180Driver) rawTemp() (int16, error) {
   164  	if _, err := d.connection.Write([]byte{bmp180RegisterCtl, bmp180CmdTemp}); err != nil {
   165  		return 0, err
   166  	}
   167  	time.Sleep(5 * time.Millisecond)
   168  	ret, err := d.read(bmp180RegisterTempMSB, 2)
   169  	if err != nil {
   170  		return 0, err
   171  	}
   172  	buf := bytes.NewBuffer(ret)
   173  	var rawTemp int16
   174  	binary.Read(buf, binary.BigEndian, &rawTemp)
   175  	return rawTemp, nil
   176  }
   177  
   178  func (d *BMP180Driver) read(address byte, n int) ([]byte, error) {
   179  	if _, err := d.connection.Write([]byte{address}); err != nil {
   180  		return nil, err
   181  	}
   182  	buf := make([]byte, n)
   183  	bytesRead, err := d.connection.Read(buf)
   184  	if bytesRead != n || err != nil {
   185  		return nil, err
   186  	}
   187  	return buf, nil
   188  }
   189  
   190  func (d *BMP180Driver) calculateTemp(rawTemp int16) float32 {
   191  	b5 := d.calculateB5(rawTemp)
   192  	t := (b5 + 8) >> 4
   193  	return float32(t) / 10
   194  }
   195  
   196  func (d *BMP180Driver) calculateB5(rawTemp int16) int32 {
   197  	x1 := (int32(rawTemp) - int32(d.calibrationCoefficients.ac6)) * int32(d.calibrationCoefficients.ac5) >> 15
   198  	x2 := int32(d.calibrationCoefficients.mc) << 11 / (x1 + int32(d.calibrationCoefficients.md))
   199  	return x1 + x2
   200  }
   201  
   202  func (d *BMP180Driver) rawPressure(mode BMP180OversamplingMode) (rawPressure int32, err error) {
   203  	if _, err = d.connection.Write([]byte{bmp180RegisterCtl, bmp180CmdPressure + byte(mode<<6)}); err != nil {
   204  		return 0, err
   205  	}
   206  	time.Sleep(pauseForReading(mode))
   207  	var ret []byte
   208  	if ret, err = d.read(bmp180RegisterPressureMSB, 3); err != nil {
   209  		return 0, err
   210  	}
   211  	rawPressure = (int32(ret[0])<<16 + int32(ret[1])<<8 + int32(ret[2])) >> (8 - uint(mode))
   212  	return rawPressure, nil
   213  }
   214  
   215  func (d *BMP180Driver) calculatePressure(rawTemp int16, rawPressure int32, mode BMP180OversamplingMode) float32 {
   216  	b5 := d.calculateB5(rawTemp)
   217  	b6 := b5 - 4000
   218  	x1 := (int32(d.calibrationCoefficients.b2) * (b6 * b6 >> 12)) >> 11
   219  	x2 := (int32(d.calibrationCoefficients.ac2) * b6) >> 11
   220  	x3 := x1 + x2
   221  	b3 := (((int32(d.calibrationCoefficients.ac1)*4 + x3) << uint(mode)) + 2) >> 2
   222  	x1 = (int32(d.calibrationCoefficients.ac3) * b6) >> 13
   223  	x2 = (int32(d.calibrationCoefficients.b1) * ((b6 * b6) >> 12)) >> 16
   224  	x3 = ((x1 + x2) + 2) >> 2
   225  	b4 := (uint32(d.calibrationCoefficients.ac4) * uint32(x3+32768)) >> 15
   226  	b7 := (uint32(rawPressure-b3) * (50000 >> uint(mode)))
   227  	var p int32
   228  	if b7 < 0x80000000 {
   229  		p = int32((b7 << 1) / b4)
   230  	} else {
   231  		p = int32((b7 / b4) << 1)
   232  	}
   233  	x1 = (p >> 8) * (p >> 8)
   234  	x1 = (x1 * 3038) >> 16
   235  	x2 = (-7357 * p) >> 16
   236  	return float32(p + ((x1 + x2 + 3791) >> 4))
   237  }
   238  
   239  func pauseForReading(mode BMP180OversamplingMode) time.Duration {
   240  	var d time.Duration
   241  	switch mode {
   242  	case BMP180UltraLowPower:
   243  		d = 5 * time.Millisecond
   244  	case BMP180Standard:
   245  		d = 8 * time.Millisecond
   246  	case BMP180HighResolution:
   247  		d = 14 * time.Millisecond
   248  	case BMP180UltraHighResolution:
   249  		d = 26 * time.Millisecond
   250  	}
   251  	return d
   252  }