hybridgroup.gobot/drivers/i2c/mpl115a2_driver.go

160 lines
3.6 KiB
Go

package i2c
import (
"gobot.io/x/gobot/v2"
"bytes"
"encoding/binary"
"time"
)
const mpl115a2DefaultAddress = 0x60
const (
mpl115A2Reg_PressureMSB = 0x00 // first ADC register
mpl115A2Reg_PressureLSB = 0x01
mpl115A2Reg_TempMSB = 0x02
mpl115A2Reg_TempLSB = 0x03
mpl115A2Reg_A0_MSB = 0x04 // first coefficient register
mpl115A2Reg_A0_LSB = 0x05
mpl115A2Reg_B1_MSB = 0x06
mpl115A2Reg_B1_LSB = 0x07
mpl115A2Reg_B2_MSB = 0x08
mpl115A2Reg_B2_LSB = 0x09
mpl115A2Reg_C12_MSB = 0x0A
mpl115A2Reg_C12_LSB = 0x0B
mpl115A2Reg_StartConversion = 0x12
)
// MPL115A2Driver is a Gobot Driver for the MPL115A2 I2C digital pressure/temperature sensor.
// datasheet:
// https://www.nxp.com/docs/en/data-sheet/MPL115A2.pdf
//
// reference implementations:
// * https://github.com/adafruit/Adafruit_MPL115A2
type MPL115A2Driver struct {
*Driver
gobot.Eventer
a0 float32
b1 float32
b2 float32
c12 float32
}
// NewMPL115A2Driver creates a new Gobot Driver for an MPL115A2
// I2C Pressure/Temperature sensor.
//
// Params:
//
// c Connector - the Adaptor to use with this Driver
//
// Optional params:
//
// i2c.WithBus(int): bus to use with this driver
// i2c.WithAddress(int): address to use with this driver
func NewMPL115A2Driver(c Connector, options ...func(Config)) *MPL115A2Driver {
d := &MPL115A2Driver{
Driver: NewDriver(c, "MPL115A2", mpl115a2DefaultAddress),
Eventer: gobot.NewEventer(),
}
d.afterStart = d.initialization
for _, option := range options {
option(d)
}
// TODO: add commands to API
d.AddEvent(Error)
return d
}
// Pressure fetches the latest data from the MPL115A2, and returns the pressure in kPa
func (d *MPL115A2Driver) Pressure() (p float32, err error) {
d.mutex.Lock()
defer d.mutex.Unlock()
p, _, err = d.getData()
return
}
// Temperature fetches the latest data from the MPL115A2, and returns the temperature in °C
func (d *MPL115A2Driver) Temperature() (t float32, err error) {
d.mutex.Lock()
defer d.mutex.Unlock()
_, t, err = d.getData()
return
}
func (d *MPL115A2Driver) initialization() error {
data := make([]byte, 8)
if err := d.connection.ReadBlockData(mpl115A2Reg_A0_MSB, data); err != nil {
return err
}
var coA0 int16
var coB1 int16
var coB2 int16
var coC12 int16
buf := bytes.NewBuffer(data)
if err := binary.Read(buf, binary.BigEndian, &coA0); err != nil {
return err
}
if err := binary.Read(buf, binary.BigEndian, &coB1); err != nil {
return err
}
if err := binary.Read(buf, binary.BigEndian, &coB2); err != nil {
return err
}
if err := binary.Read(buf, binary.BigEndian, &coC12); err != nil {
return err
}
coC12 = coC12 >> 2
d.a0 = float32(coA0) / 8.0
d.b1 = float32(coB1) / 8192.0
d.b2 = float32(coB2) / 16384.0
d.c12 = float32(coC12) / 4194304.0
return nil
}
// getData fetches the latest data from the MPL115A2
func (d *MPL115A2Driver) getData() (p, t float32, err error) {
var temperature uint16
var pressure uint16
var pressureComp float32
if err = d.connection.WriteByteData(mpl115A2Reg_StartConversion, 0); err != nil {
return 0, 0, err
}
time.Sleep(5 * time.Millisecond)
data := []byte{0, 0, 0, 0}
if err = d.connection.ReadBlockData(mpl115A2Reg_PressureMSB, data); err != nil {
return
}
buf := bytes.NewBuffer(data)
if err := binary.Read(buf, binary.BigEndian, &pressure); err != nil {
return 0, 0, err
}
if err := binary.Read(buf, binary.BigEndian, &temperature); err != nil {
return 0, 0, err
}
temperature = temperature >> 6
pressure = pressure >> 6
pressureComp = d.a0 + (d.b1+d.c12*float32(temperature))*float32(pressure) + d.b2*float32(temperature)
p = (65.0/1023.0)*pressureComp + 50.0
t = ((float32(temperature) - 498.0) / -5.35) + 25.0
return
}