gobot.io/x/gobot/v2@v2.1.0/drivers/i2c/sht3x_driver.go (about)

     1  /*
     2   * Copyright (c) 2016-2017 Weston Schmidt <weston_schmidt@alumni.purdue.edu>
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   * http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package i2c
    18  
    19  // SHT3xDriver is a driver for the SHT3x-D based devices.
    20  //
    21  // This module was tested with AdaFruit Sensiron SHT32-D Breakout.
    22  // https://www.adafruit.com/products/2857
    23  
    24  import (
    25  	"errors"
    26  	"time"
    27  
    28  	"github.com/sigurn/crc8"
    29  )
    30  
    31  // SHT3xAddressA is the default address of device
    32  const SHT3xAddressA = 0x44
    33  
    34  // SHT3xAddressB is the optional address of device
    35  const SHT3xAddressB = 0x45
    36  
    37  // SHT3xAccuracyLow is the faster, but lower accuracy sample setting
    38  const SHT3xAccuracyLow = 0x16
    39  
    40  // SHT3xAccuracyMedium is the medium accuracy and speed sample setting
    41  const SHT3xAccuracyMedium = 0x0b
    42  
    43  // SHT3xAccuracyHigh is the high accuracy and slowest sample setting
    44  const SHT3xAccuracyHigh = 0x00
    45  
    46  var (
    47  	crc8Params = crc8.Params{
    48  		Poly: 0x31, Init: 0xff, RefIn: false, RefOut: false, XorOut: 0x00, Check: 0xf7, Name: "CRC-8/SENSIRON",
    49  	}
    50  	ErrInvalidAccuracy = errors.New("Invalid accuracy")
    51  	ErrInvalidCrc      = errors.New("Invalid crc")
    52  	ErrInvalidTemp     = errors.New("Invalid temperature units")
    53  )
    54  
    55  // SHT3xDriver is a Driver for a SHT3x humidity and temperature sensor
    56  type SHT3xDriver struct {
    57  	*Driver
    58  	Units    string
    59  	accuracy byte
    60  	delay    time.Duration
    61  	crcTable *crc8.Table
    62  }
    63  
    64  // NewSHT3xDriver creates a new driver with specified i2c interface
    65  // Params:
    66  //		c Connector - the Adaptor to use with this Driver
    67  //
    68  // Optional params:
    69  //		i2c.WithBus(int):	bus to use with this driver
    70  //		i2c.WithAddress(int):	address to use with this driver
    71  //
    72  func NewSHT3xDriver(c Connector, options ...func(Config)) *SHT3xDriver {
    73  	s := &SHT3xDriver{
    74  		Driver:   NewDriver(c, "SHT3x", SHT3xAddressA),
    75  		Units:    "C",
    76  		crcTable: crc8.MakeTable(crc8Params),
    77  	}
    78  	s.SetAccuracy(SHT3xAccuracyHigh)
    79  
    80  	for _, option := range options {
    81  		option(s)
    82  	}
    83  
    84  	return s
    85  }
    86  
    87  // Accuracy returns the accuracy of the sampling
    88  func (s *SHT3xDriver) Accuracy() byte { return s.accuracy }
    89  
    90  // SetAccuracy sets the accuracy of the sampling
    91  func (s *SHT3xDriver) SetAccuracy(a byte) (err error) {
    92  	switch a {
    93  	case SHT3xAccuracyLow:
    94  		s.delay = 5 * time.Millisecond // Actual max is 4, wait 1 ms longer
    95  	case SHT3xAccuracyMedium:
    96  		s.delay = 7 * time.Millisecond // Actual max is 6, wait 1 ms longer
    97  	case SHT3xAccuracyHigh:
    98  		s.delay = 16 * time.Millisecond // Actual max is 15, wait 1 ms longer
    99  	default:
   100  		err = ErrInvalidAccuracy
   101  		return
   102  	}
   103  
   104  	s.accuracy = a
   105  
   106  	return
   107  }
   108  
   109  // SerialNumber returns the serial number of the chip
   110  func (s *SHT3xDriver) SerialNumber() (sn uint32, err error) {
   111  	ret, err := s.sendCommandDelayGetResponse([]byte{0x37, 0x80}, nil, 2)
   112  	if nil == err {
   113  		sn = (uint32(ret[0]) << 16) | uint32(ret[1])
   114  	}
   115  
   116  	return
   117  }
   118  
   119  // Heater returns true if the heater is enabled
   120  func (s *SHT3xDriver) Heater() (status bool, err error) {
   121  	sr, err := s.getStatusRegister()
   122  	if err == nil {
   123  		if (1 << 13) == (sr & (1 << 13)) {
   124  			status = true
   125  		}
   126  	}
   127  	return
   128  }
   129  
   130  // SetHeater enables or disables the heater on the device
   131  func (s *SHT3xDriver) SetHeater(enabled bool) (err error) {
   132  	out := []byte{0x30, 0x66}
   133  	if enabled {
   134  		out[1] = 0x6d
   135  	}
   136  	_, err = s.connection.Write(out)
   137  	return
   138  }
   139  
   140  // Sample returns the temperature in celsius and relative humidity for one sample
   141  func (s *SHT3xDriver) Sample() (temp float32, rh float32, err error) {
   142  	ret, err := s.sendCommandDelayGetResponse([]byte{0x24, s.accuracy}, &s.delay, 2)
   143  	if nil != err {
   144  		return
   145  	}
   146  
   147  	// From the datasheet:
   148  	// RH = 100 * Srh / (2^16 - 1)
   149  	rhSample := uint64(ret[1])
   150  	rh = float32((uint64(1000000)*rhSample)/uint64(0xffff)) / 10000.0
   151  
   152  	tempSample := uint64(ret[0])
   153  	switch s.Units {
   154  	case "C":
   155  		// From the datasheet:
   156  		// T[C] = -45 + 175 * (St / (2^16 - 1))
   157  		temp = float32((uint64(1750000)*tempSample)/uint64(0xffff)-uint64(450000)) / 10000.0
   158  	case "F":
   159  		// From the datasheet:
   160  		// T[F] = -49 + 315 * (St / (2^16 - 1))
   161  		temp = float32((uint64(3150000)*tempSample)/uint64(0xffff)-uint64(490000)) / 10000.0
   162  	default:
   163  		err = ErrInvalidTemp
   164  	}
   165  
   166  	return
   167  }
   168  
   169  // getStatusRegister returns the device status register
   170  func (s *SHT3xDriver) getStatusRegister() (status uint16, err error) {
   171  	ret, err := s.sendCommandDelayGetResponse([]byte{0xf3, 0x2d}, nil, 1)
   172  	if nil == err {
   173  		status = ret[0]
   174  	}
   175  	return
   176  }
   177  
   178  // sendCommandDelayGetResponse is a helper function to reduce duplicated code
   179  func (s *SHT3xDriver) sendCommandDelayGetResponse(send []byte, delay *time.Duration, expect int) (read []uint16, err error) {
   180  	if _, err = s.connection.Write(send); err != nil {
   181  		return
   182  	}
   183  
   184  	if nil != delay {
   185  		time.Sleep(*delay)
   186  	}
   187  
   188  	buf := make([]byte, 3*expect)
   189  	got, err := s.connection.Read(buf)
   190  	if err != nil {
   191  		return
   192  	}
   193  	if got != (3 * expect) {
   194  		err = ErrNotEnoughBytes
   195  		return
   196  	}
   197  
   198  	read = make([]uint16, expect)
   199  	for i := 0; i < expect; i++ {
   200  		crc := crc8.Checksum(buf[i*3:i*3+2], s.crcTable)
   201  		if buf[i*3+2] != crc {
   202  			err = ErrInvalidCrc
   203  			return
   204  		}
   205  		read[i] = uint16(buf[i*3])<<8 | uint16(buf[i*3+1])
   206  	}
   207  
   208  	return
   209  }