mirror of
https://github.com/kidoman/embd
synced 2024-12-22 12:50:19 +01:00
- add support for tmp006
- refactor the i2c interface
This commit is contained in:
parent
1a6f97f102
commit
0563d2be5c
146
i2c/i2c.go
146
i2c/i2c.go
@ -22,22 +22,26 @@ const (
|
||||
|
||||
// A Bus implements access to the I2C two wire bus.
|
||||
type Bus interface {
|
||||
// Read a byte from the given address.
|
||||
// ReadByte reads a byte from the given address.
|
||||
ReadByte(addr byte) (value byte, err error)
|
||||
// Write a byte to the given address.
|
||||
// WriteByte writes a byte to the given address.
|
||||
WriteByte(addr, value byte) error
|
||||
// Write a bunch of bytes ot the given address.
|
||||
// WriteBytes writes a slice bytes to the given address.
|
||||
WriteBytes(addr byte, value []byte) error
|
||||
|
||||
// Read a bunch of bytes (len(value)) from the given address and register.
|
||||
ReadFromReg(addr, reg byte, value []byte) (err error)
|
||||
// Read a byte from the given address and register.
|
||||
// ReadFromReg reads n (len(value)) bytes from the given address and register.
|
||||
ReadFromReg(addr, reg byte, value []byte) error
|
||||
// ReadByteFromReg reads a byte from the given address and register.
|
||||
ReadByteFromReg(addr, reg byte) (value byte, err error)
|
||||
// Read a int from the given address and register.
|
||||
ReadInt(addr, reg byte) (value int, err error)
|
||||
// ReadU16FromReg reads a unsigned 16 bit integer from the given address and register.
|
||||
ReadWordFromReg(addr, reg byte) (value uint16, err error)
|
||||
|
||||
// Write a byte to the given address and register.
|
||||
WriteToReg(addr, reg, value byte) error
|
||||
// WriteToReg writes len(value) bytes to the given address and register.
|
||||
WriteToReg(addr, reg byte, value []byte) error
|
||||
// WriteByteToReg writes a byte to the given address and register.
|
||||
WriteByteToReg(addr, reg, value byte) error
|
||||
// WriteU16ToReg
|
||||
WriteWordToReg(addr, reg byte, value uint16) error
|
||||
}
|
||||
|
||||
type i2c_msg struct {
|
||||
@ -108,7 +112,6 @@ func (b *bus) setAddress(addr byte) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// Read a byte from the given address.
|
||||
func (b *bus) ReadByte(addr byte) (value byte, err error) {
|
||||
b.mu.Lock()
|
||||
defer b.mu.Unlock()
|
||||
@ -129,7 +132,6 @@ func (b *bus) ReadByte(addr byte) (value byte, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// Write a byte to the given address.
|
||||
func (b *bus) WriteByte(addr, value byte) (err error) {
|
||||
b.mu.Lock()
|
||||
defer b.mu.Unlock()
|
||||
@ -147,7 +149,6 @@ func (b *bus) WriteByte(addr, value byte) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// Write a bunch of bytes ot the given address.
|
||||
func (b *bus) WriteBytes(addr byte, value []byte) error {
|
||||
b.mu.Lock()
|
||||
defer b.mu.Unlock()
|
||||
@ -172,7 +173,6 @@ func (b *bus) WriteBytes(addr byte, value []byte) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Read a bunch of bytes (len(value)) from the given address and register.
|
||||
func (b *bus) ReadFromReg(addr, reg byte, value []byte) (err error) {
|
||||
b.mu.Lock()
|
||||
defer b.mu.Unlock()
|
||||
@ -206,7 +206,6 @@ func (b *bus) ReadFromReg(addr, reg byte, value []byte) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Read a byte from the given address and register.
|
||||
func (b *bus) ReadByteFromReg(addr, reg byte) (value byte, err error) {
|
||||
buf := make([]byte, 1)
|
||||
if err = b.ReadFromReg(addr, reg, buf); err != nil {
|
||||
@ -216,18 +215,16 @@ func (b *bus) ReadByteFromReg(addr, reg byte) (value byte, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// Read a int from the given address and register.
|
||||
func (b *bus) ReadInt(addr, reg byte) (value int, err error) {
|
||||
var buf = make([]byte, 2)
|
||||
func (b *bus) ReadWordFromReg(addr, reg byte) (value uint16, err error) {
|
||||
buf := make([]byte, 2)
|
||||
if err = b.ReadFromReg(addr, reg, buf); err != nil {
|
||||
return
|
||||
}
|
||||
value = int((int(buf[0]) << 8) | int(buf[1]))
|
||||
value = uint16((uint16(buf[0]) << 8) | uint16(buf[1]))
|
||||
return
|
||||
}
|
||||
|
||||
// Write a byte to the given address and register.
|
||||
func (b *bus) WriteToReg(addr, reg, value byte) (err error) {
|
||||
func (b *bus) WriteToReg(addr, reg byte, value []byte) (err error) {
|
||||
b.mu.Lock()
|
||||
defer b.mu.Unlock()
|
||||
|
||||
@ -235,16 +232,81 @@ func (b *bus) WriteToReg(addr, reg, value byte) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
var outbuf [2]byte
|
||||
outbuf := append([]byte{reg}, value...)
|
||||
|
||||
hdrp := (*reflect.SliceHeader)(unsafe.Pointer(&outbuf))
|
||||
|
||||
var message i2c_msg
|
||||
message.addr = uint16(addr)
|
||||
message.flags = 0
|
||||
message.len = uint16(len(outbuf))
|
||||
message.buf = uintptr(unsafe.Pointer(&hdrp.Data))
|
||||
|
||||
var packets i2c_rdwr_ioctl_data
|
||||
|
||||
packets.msgs = uintptr(unsafe.Pointer(&message))
|
||||
packets.nmsg = 1
|
||||
|
||||
if _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, b.file.Fd(), rdrwCmd, uintptr(unsafe.Pointer(&packets))); errno != 0 {
|
||||
err = syscall.Errno(errno)
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (b *bus) WriteByteToReg(addr, reg, value byte) (err error) {
|
||||
b.mu.Lock()
|
||||
defer b.mu.Unlock()
|
||||
|
||||
if err = b.setAddress(addr); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
outbuf := [...]byte{
|
||||
reg,
|
||||
value,
|
||||
}
|
||||
|
||||
var message i2c_msg
|
||||
message.addr = uint16(addr)
|
||||
message.flags = 0
|
||||
message.len = uint16(len(outbuf))
|
||||
message.buf = uintptr(unsafe.Pointer(&outbuf))
|
||||
|
||||
var packets i2c_rdwr_ioctl_data
|
||||
|
||||
packets.msgs = uintptr(unsafe.Pointer(&message))
|
||||
packets.nmsg = 1
|
||||
|
||||
if _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, b.file.Fd(), rdrwCmd, uintptr(unsafe.Pointer(&packets))); errno != 0 {
|
||||
err = syscall.Errno(errno)
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (b *bus) WriteWordToReg(addr, reg byte, value uint16) (err error) {
|
||||
b.mu.Lock()
|
||||
defer b.mu.Unlock()
|
||||
|
||||
if err = b.setAddress(addr); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
outbuf := [...]byte{
|
||||
reg,
|
||||
byte(value >> 8),
|
||||
byte(value),
|
||||
}
|
||||
|
||||
var messages i2c_msg
|
||||
messages.addr = uint16(addr)
|
||||
messages.flags = 0
|
||||
messages.len = uint16(len(outbuf))
|
||||
messages.buf = uintptr(unsafe.Pointer(&outbuf))
|
||||
|
||||
outbuf[0] = reg
|
||||
outbuf[1] = value
|
||||
|
||||
var packets i2c_rdwr_ioctl_data
|
||||
|
||||
packets.msgs = uintptr(unsafe.Pointer(&messages))
|
||||
@ -258,37 +320,47 @@ func (b *bus) WriteToReg(addr, reg, value byte) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// Read a byte from the given address.
|
||||
// ReadByte reads a byte from the given address.
|
||||
func ReadByte(addr byte) (value byte, err error) {
|
||||
return Default.ReadByte(addr)
|
||||
}
|
||||
|
||||
// Write a byte to the given address.
|
||||
func WriteByte(addr, value byte) (err error) {
|
||||
// WriteByte writes a byte to the given address.
|
||||
func WriteByte(addr, value byte) error {
|
||||
return Default.WriteByte(addr, value)
|
||||
}
|
||||
|
||||
// Write a bunch of bytes ot the given address.
|
||||
// WriteBytes writes a slice bytes to the given address.
|
||||
func WriteBytes(addr byte, value []byte) error {
|
||||
return Default.WriteBytes(addr, value)
|
||||
}
|
||||
|
||||
// Read a bunch of bytes (len(value)) from the given address and register.
|
||||
func ReadFromReg(addr, reg byte, value []byte) (err error) {
|
||||
// ReadFromReg reads n (len(value)) bytes from the given address and register.
|
||||
func ReadFromReg(addr, reg byte, value []byte) error {
|
||||
return Default.ReadFromReg(addr, reg, value)
|
||||
}
|
||||
|
||||
// Read a byte from the given address and register.
|
||||
// ReadByteFromReg reads a byte from the given address and register.
|
||||
func ReadByteFromReg(addr, reg byte) (value byte, err error) {
|
||||
return Default.ReadByteFromReg(addr, reg)
|
||||
}
|
||||
|
||||
// Read a int from the given address and register.
|
||||
func ReadInt(addr, reg byte) (value int, err error) {
|
||||
return Default.ReadInt(addr, reg)
|
||||
// ReadU16FromReg reads a unsigned 16 bit integer from the given address and register.
|
||||
func ReadWordFromReg(addr, reg byte) (value uint16, err error) {
|
||||
return Default.ReadWordFromReg(addr, reg)
|
||||
}
|
||||
|
||||
// Write a byte to the given address and register.
|
||||
func WriteToReg(addr, reg, value byte) (err error) {
|
||||
// WriteToReg writes len(value) bytes to the given address and register.
|
||||
func WriteToReg(addr, reg byte, value []byte) error {
|
||||
return Default.WriteToReg(addr, reg, value)
|
||||
}
|
||||
|
||||
// WriteByteToReg writes a byte to the given address and register.
|
||||
func WriteByteToReg(addr, reg, value byte) error {
|
||||
return Default.WriteByteToReg(addr, reg, value)
|
||||
}
|
||||
|
||||
// WriteU16ToReg
|
||||
func WriteWordToReg(addr, reg byte, value uint16) error {
|
||||
return Default.WriteWordToReg(addr, reg, value)
|
||||
}
|
||||
|
@ -14,11 +14,11 @@ func main() {
|
||||
log.Panic(err)
|
||||
}
|
||||
|
||||
lightingSensor := bh1750fvi.New(bh1750fvi.High, bus)
|
||||
defer lightingSensor.Close()
|
||||
sensor := bh1750fvi.New(bh1750fvi.High, bus)
|
||||
defer sensor.Close()
|
||||
|
||||
for {
|
||||
lighting, err := lightingSensor.Lighting()
|
||||
lighting, err := sensor.Lighting()
|
||||
if err != nil {
|
||||
log.Panic(err)
|
||||
}
|
||||
|
41
samples/tmp006.go
Normal file
41
samples/tmp006.go
Normal file
@ -0,0 +1,41 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"os/signal"
|
||||
|
||||
"github.com/kid0m4n/go-rpi/i2c"
|
||||
"github.com/kid0m4n/go-rpi/sensor/tmp006"
|
||||
)
|
||||
|
||||
func main() {
|
||||
bus, err := i2c.NewBus(1)
|
||||
if err != nil {
|
||||
log.Panic(err)
|
||||
}
|
||||
|
||||
sensor := tmp006.New(bus, 0x40)
|
||||
if status, err := sensor.Present(); err != nil || !status {
|
||||
log.Print("tmp006: not found")
|
||||
log.Print(err)
|
||||
return
|
||||
}
|
||||
defer sensor.Close()
|
||||
|
||||
sensor.Start()
|
||||
|
||||
stop := make(chan os.Signal, 1)
|
||||
signal.Notify(stop, os.Interrupt, os.Kill)
|
||||
|
||||
for {
|
||||
select {
|
||||
case temp := <-sensor.ObjTemps():
|
||||
log.Printf("tmp006: got obj temp %.2f", temp)
|
||||
case temp := <-sensor.RawDieTemps():
|
||||
log.Printf("tmp006: got die temp %.2f", temp)
|
||||
case <-stop:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
@ -90,12 +90,12 @@ func (d *bh1750fvi) measureLighting() (lighting float64, err error) {
|
||||
}
|
||||
time.Sleep(180 * time.Millisecond)
|
||||
|
||||
var sensorReading int
|
||||
if sensorReading, err = d.bus.ReadInt(d.i2cAddr, defReadReg); err != nil {
|
||||
var reading uint16
|
||||
if reading, err = d.bus.ReadWordFromReg(d.i2cAddr, defReadReg); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
lighting = float64(sensorReading) / measurementAcuuracy
|
||||
lighting = float64(int16(reading)) / measurementAcuuracy
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -102,8 +102,8 @@ func (d *bmp085) calibrate() (err error) {
|
||||
defer d.cmu.Unlock()
|
||||
|
||||
readInt16 := func(reg byte) (value int16, err error) {
|
||||
var v int
|
||||
if v, err = d.bus.ReadInt(address, reg); err != nil {
|
||||
var v uint16
|
||||
if v, err = d.bus.ReadWordFromReg(address, reg); err != nil {
|
||||
return
|
||||
}
|
||||
value = int16(v)
|
||||
@ -111,8 +111,8 @@ func (d *bmp085) calibrate() (err error) {
|
||||
}
|
||||
|
||||
readUInt16 := func(reg byte) (value uint16, err error) {
|
||||
var v int
|
||||
if v, err = d.bus.ReadInt(address, reg); err != nil {
|
||||
var v uint16
|
||||
if v, err = d.bus.ReadWordFromReg(address, reg); err != nil {
|
||||
return
|
||||
}
|
||||
value = uint16(v)
|
||||
@ -185,16 +185,13 @@ func (d *bmp085) calibrate() (err error) {
|
||||
}
|
||||
|
||||
func (d *bmp085) readUncompensatedTemp() (temp uint16, err error) {
|
||||
if err = d.bus.WriteToReg(address, control, readTempCmd); err != nil {
|
||||
if err = d.bus.WriteByteToReg(address, control, readTempCmd); err != nil {
|
||||
return
|
||||
}
|
||||
time.Sleep(tempReadDelay)
|
||||
var t int
|
||||
t, err = d.bus.ReadInt(address, tempData)
|
||||
if err != nil {
|
||||
if temp, err = d.bus.ReadWordFromReg(address, tempData); err != nil {
|
||||
return
|
||||
}
|
||||
temp = uint16(t)
|
||||
return
|
||||
}
|
||||
|
||||
@ -250,7 +247,7 @@ func (d *bmp085) Temperature() (temp float64, err error) {
|
||||
}
|
||||
|
||||
func (d *bmp085) readUncompensatedPressure() (pressure uint32, err error) {
|
||||
if err = d.bus.WriteToReg(address, control, byte(readPressureCmd+(d.oss<<6))); err != nil {
|
||||
if err = d.bus.WriteByteToReg(address, control, byte(readPressureCmd+(d.oss<<6))); err != nil {
|
||||
return
|
||||
}
|
||||
time.Sleep(time.Duration(2+(3<<d.oss)) * time.Millisecond)
|
||||
|
@ -102,8 +102,8 @@ func (d *bmp180) calibrate() (err error) {
|
||||
defer d.cmu.Unlock()
|
||||
|
||||
readInt16 := func(reg byte) (value int16, err error) {
|
||||
var v int
|
||||
if v, err = d.bus.ReadInt(address, reg); err != nil {
|
||||
var v uint16
|
||||
if v, err = d.bus.ReadWordFromReg(address, reg); err != nil {
|
||||
return
|
||||
}
|
||||
value = int16(v)
|
||||
@ -111,8 +111,8 @@ func (d *bmp180) calibrate() (err error) {
|
||||
}
|
||||
|
||||
readUInt16 := func(reg byte) (value uint16, err error) {
|
||||
var v int
|
||||
if v, err = d.bus.ReadInt(address, reg); err != nil {
|
||||
var v uint16
|
||||
if v, err = d.bus.ReadWordFromReg(address, reg); err != nil {
|
||||
return
|
||||
}
|
||||
value = uint16(v)
|
||||
@ -185,16 +185,13 @@ func (d *bmp180) calibrate() (err error) {
|
||||
}
|
||||
|
||||
func (d *bmp180) readUncompensatedTemp() (temp uint16, err error) {
|
||||
if err = d.bus.WriteToReg(address, control, readTempCmd); err != nil {
|
||||
if err = d.bus.WriteByteToReg(address, control, readTempCmd); err != nil {
|
||||
return
|
||||
}
|
||||
time.Sleep(tempReadDelay)
|
||||
var t int
|
||||
t, err = d.bus.ReadInt(address, tempData)
|
||||
if err != nil {
|
||||
if temp, err = d.bus.ReadWordFromReg(address, tempData); err != nil {
|
||||
return
|
||||
}
|
||||
temp = uint16(t)
|
||||
return
|
||||
}
|
||||
|
||||
@ -250,7 +247,7 @@ func (d *bmp180) Temperature() (temp float64, err error) {
|
||||
}
|
||||
|
||||
func (d *bmp180) readUncompensatedPressure() (pressure uint32, err error) {
|
||||
if err = d.bus.WriteToReg(address, control, byte(readPressureCmd+(d.oss<<6))); err != nil {
|
||||
if err = d.bus.WriteByteToReg(address, control, byte(readPressureCmd+(d.oss<<6))); err != nil {
|
||||
return
|
||||
}
|
||||
time.Sleep(time.Duration(2+(3<<d.oss)) * time.Millisecond)
|
||||
|
@ -213,10 +213,10 @@ func (d *l3gd20) setup() (err error) {
|
||||
d.mu.Lock()
|
||||
defer d.mu.Unlock()
|
||||
|
||||
if err = d.bus.WriteToReg(address, ctrlReg1, ctrlReg1Default); err != nil {
|
||||
if err = d.bus.WriteByteToReg(address, ctrlReg1, ctrlReg1Default); err != nil {
|
||||
return
|
||||
}
|
||||
if err = d.bus.WriteToReg(address, ctrlReg4, d.rng.value); err != nil {
|
||||
if err = d.bus.WriteByteToReg(address, ctrlReg4, d.rng.value); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
@ -370,5 +370,5 @@ func (d *l3gd20) Close() (err error) {
|
||||
if d.quit != nil {
|
||||
d.quit <- struct{}{}
|
||||
}
|
||||
return d.bus.WriteToReg(address, ctrlReg1, ctrlReg1Finished)
|
||||
return d.bus.WriteByteToReg(address, ctrlReg1, ctrlReg1Finished)
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ type LSM303 interface {
|
||||
|
||||
// Run starts the sensor data acquisition loop.
|
||||
Run() error
|
||||
// Close closes the sensor data acquisition loop and put the LSM303 into sleep mode.
|
||||
// Close closes the sensor data acquisition loop and puts the LSM303 into sleep mode.
|
||||
Close() error
|
||||
}
|
||||
|
||||
@ -91,10 +91,10 @@ func (d *lsm303) setup() (err error) {
|
||||
d.mu.Lock()
|
||||
defer d.mu.Unlock()
|
||||
|
||||
if err = d.bus.WriteToReg(magAddress, magConfigRegA, MagCRADefault); err != nil {
|
||||
if err = d.bus.WriteByteToReg(magAddress, magConfigRegA, MagCRADefault); err != nil {
|
||||
return
|
||||
}
|
||||
if err = d.bus.WriteToReg(magAddress, magModeReg, MagMRDefault); err != nil {
|
||||
if err = d.bus.WriteByteToReg(magAddress, magModeReg, MagMRDefault); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
@ -182,7 +182,7 @@ func (d *lsm303) Close() (err error) {
|
||||
if d.quit != nil {
|
||||
d.quit <- struct{}{}
|
||||
}
|
||||
err = d.bus.WriteToReg(magAddress, magModeReg, MagSleep)
|
||||
err = d.bus.WriteByteToReg(magAddress, magModeReg, MagSleep)
|
||||
return
|
||||
}
|
||||
|
||||
|
336
sensor/tmp006/tmp006.go
Normal file
336
sensor/tmp006/tmp006.go
Normal file
@ -0,0 +1,336 @@
|
||||
package tmp006
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"math"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/kid0m4n/go-rpi/i2c"
|
||||
)
|
||||
|
||||
const (
|
||||
b0 = -0.0000294
|
||||
b1 = -0.00000057
|
||||
b2 = 0.00000000463
|
||||
c2 = 13.4
|
||||
tref = 298.15
|
||||
a2 = -0.00001678
|
||||
a1 = 0.00175
|
||||
s0 = 6.4
|
||||
|
||||
vObjReg = 0x00
|
||||
tempAmbReg = 0x01
|
||||
configReg = 0x02
|
||||
manIdReg = 0xFE
|
||||
manId = 0x5449
|
||||
devIdReg = 0xFF
|
||||
devId = 0x0067
|
||||
|
||||
reset = 0x8000
|
||||
modeOn = 0x7000
|
||||
drdyEn = 0x0100
|
||||
|
||||
configRegDefault = modeOn | drdyEn
|
||||
)
|
||||
|
||||
type SampleRate struct {
|
||||
enabler uint16
|
||||
samples int
|
||||
timeRequired float64
|
||||
}
|
||||
|
||||
var (
|
||||
SR1 = &SampleRate{0x0000, 1, 0.25} // 1 sample, 0.25 second between measurements.
|
||||
SR2 = &SampleRate{0x0200, 2, 0.5} // 2 samples, 0.5 second between measurements.
|
||||
SR4 = &SampleRate{0x0400, 4, 1} // 4 samples, 1 second between measurements.
|
||||
SR8 = &SampleRate{0x0600, 8, 2} // 8 samples, 2 seconds between measurements.
|
||||
SR16 = &SampleRate{0x0800, 16, 4} // 16 samples, 4 seconds between measurements.
|
||||
)
|
||||
|
||||
// Device represents a TMP006 thermopile sensor.
|
||||
type Device struct {
|
||||
// Bus to communicate over.
|
||||
Bus i2c.Bus
|
||||
// Addr of the sensor.
|
||||
Addr byte
|
||||
// Debug turns on additional debug output.
|
||||
Debug bool
|
||||
// SampleRate specifies the sampling rate for the sensor.
|
||||
SampleRate *SampleRate
|
||||
|
||||
initialized bool
|
||||
mu sync.RWMutex
|
||||
|
||||
rawDieTemps chan float64
|
||||
objTemps chan float64
|
||||
closing chan chan struct{}
|
||||
}
|
||||
|
||||
// New creates a new TMP006 sensor.
|
||||
func New(bus i2c.Bus, addr byte) *Device {
|
||||
return &Device{
|
||||
Bus: bus,
|
||||
Addr: addr,
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Device) validate() error {
|
||||
if d.Bus == nil {
|
||||
return errors.New("tmp006: bus is nil")
|
||||
}
|
||||
if d.Addr == 0x00 {
|
||||
return fmt.Errorf("tmp006: %#x is not a valid address", d.Addr)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Close puts the device into low power mode.
|
||||
func (d *Device) Close() (err error) {
|
||||
if err = d.setup(); err != nil {
|
||||
return
|
||||
}
|
||||
if d.closing != nil {
|
||||
waitc := make(chan struct{})
|
||||
d.closing <- waitc
|
||||
<-waitc
|
||||
}
|
||||
if d.Debug {
|
||||
log.Print("tmp006: resetting")
|
||||
}
|
||||
if err = d.Bus.WriteWordToReg(d.Addr, configReg, reset); err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Present checks if the device is present at the given address.
|
||||
func (d *Device) Present() (status bool, err error) {
|
||||
if err = d.validate(); err != nil {
|
||||
return
|
||||
}
|
||||
var mid, did uint16
|
||||
if mid, err = d.Bus.ReadWordFromReg(d.Addr, manIdReg); err != nil {
|
||||
return
|
||||
}
|
||||
if d.Debug {
|
||||
log.Printf("tmp006: got manufacturer id %#04x", mid)
|
||||
}
|
||||
if mid != manId {
|
||||
err = fmt.Errorf("tmp006: not found at %#02x, manufacturer id mismatch", d.Addr)
|
||||
return
|
||||
}
|
||||
if did, err = d.Bus.ReadWordFromReg(d.Addr, devIdReg); err != nil {
|
||||
return
|
||||
}
|
||||
if d.Debug {
|
||||
log.Printf("tmp006: got device id %#04x", did)
|
||||
}
|
||||
if did != devId {
|
||||
err = fmt.Errorf("tmp006: not found at %#02x, device id mismatch", d.Addr)
|
||||
return
|
||||
}
|
||||
|
||||
status = true
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (d *Device) setup() (err error) {
|
||||
d.mu.RLock()
|
||||
if d.initialized {
|
||||
d.mu.RUnlock()
|
||||
return
|
||||
}
|
||||
d.mu.RUnlock()
|
||||
|
||||
d.mu.Lock()
|
||||
defer d.mu.Unlock()
|
||||
|
||||
if err = d.validate(); err != nil {
|
||||
return
|
||||
}
|
||||
if d.SampleRate == nil {
|
||||
if d.Debug {
|
||||
log.Printf("tmp006: sample rate = nil, using SR16")
|
||||
}
|
||||
d.SampleRate = SR16
|
||||
}
|
||||
if d.Debug {
|
||||
log.Printf("tmp006: configuring with %#04x", configRegDefault|d.SampleRate.enabler)
|
||||
}
|
||||
if err = d.Bus.WriteWordToReg(d.Addr, configReg, configRegDefault|d.SampleRate.enabler); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
d.initialized = true
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (d *Device) measureRawDieTemp() (temp float64, err error) {
|
||||
if err = d.setup(); err != nil {
|
||||
return
|
||||
}
|
||||
var raw uint16
|
||||
if raw, err = d.Bus.ReadWordFromReg(d.Addr, tempAmbReg); err != nil {
|
||||
return
|
||||
}
|
||||
raw >>= 2
|
||||
if d.Debug {
|
||||
log.Printf("tmp006: raw die temp %#04x", raw)
|
||||
}
|
||||
|
||||
temp = float64(int16(raw)) * 0.03125
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (d *Device) measureRawVoltage() (volt int16, err error) {
|
||||
if err = d.setup(); err != nil {
|
||||
return
|
||||
}
|
||||
var vlt uint16
|
||||
if vlt, err = d.Bus.ReadWordFromReg(d.Addr, vObjReg); err != nil {
|
||||
return
|
||||
}
|
||||
volt = int16(vlt)
|
||||
if d.Debug {
|
||||
log.Printf("tmp006: raw voltage %#04x", volt)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (d *Device) measureObjTemp() (temp float64, err error) {
|
||||
if err = d.setup(); err != nil {
|
||||
return
|
||||
}
|
||||
tDie, err := d.measureRawDieTemp()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if d.Debug {
|
||||
log.Printf("tmp006: tdie = %.2f C", tDie)
|
||||
}
|
||||
tDie += 273.15 // Convert to K
|
||||
vo, err := d.measureRawVoltage()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
vObj := float64(vo)
|
||||
vObj *= 156.25 // 156.25 nV per LSB
|
||||
vObj /= 1000 // nV -> uV
|
||||
if d.Debug {
|
||||
log.Printf("tmp006: vObj = %.5f uV", vObj)
|
||||
}
|
||||
vObj /= 1000 // uV -> mV
|
||||
vObj /= 1000 // mV -> V
|
||||
|
||||
tdie_tref := tDie - tref
|
||||
s := 1 + a1*tdie_tref + a2*tdie_tref*tdie_tref
|
||||
s *= s0
|
||||
s /= 10000000
|
||||
s /= 10000000
|
||||
|
||||
Vos := b0 + b1*tdie_tref + b2*tdie_tref*tdie_tref
|
||||
fVobj := (vObj - Vos) + c2*(vObj-Vos)*(vObj-Vos)
|
||||
|
||||
temp = math.Sqrt(math.Sqrt(tDie*tDie*tDie*tDie + fVobj/s))
|
||||
temp -= 273.15
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// RawDieTemp returns the current raw die temp reading.
|
||||
func (d *Device) RawDieTemp() (temp float64, err error) {
|
||||
select {
|
||||
case temp = <-d.rawDieTemps:
|
||||
return
|
||||
default:
|
||||
return d.measureRawDieTemp()
|
||||
}
|
||||
}
|
||||
|
||||
// RawDieTemps returns a channel to get future raw die temps from.
|
||||
func (d *Device) RawDieTemps() <-chan float64 {
|
||||
return d.rawDieTemps
|
||||
}
|
||||
|
||||
// ObjTemp returns the current obj temp reading.
|
||||
func (d *Device) ObjTemp() (temp float64, err error) {
|
||||
select {
|
||||
case temp = <-d.objTemps:
|
||||
return
|
||||
default:
|
||||
return d.measureObjTemp()
|
||||
}
|
||||
}
|
||||
|
||||
// ObjTemps returns a channel to fetch obj temps from.
|
||||
func (d *Device) ObjTemps() <-chan float64 {
|
||||
return d.objTemps
|
||||
}
|
||||
|
||||
// Start starts the data acquisition loop.
|
||||
func (d *Device) Start() (err error) {
|
||||
if err = d.setup(); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
d.rawDieTemps = make(chan float64)
|
||||
d.objTemps = make(chan float64)
|
||||
|
||||
go func() {
|
||||
var rawDieTemp, objTemp float64
|
||||
var rdtAvlb, otAvlb bool
|
||||
var err error
|
||||
var timer <-chan time.Time
|
||||
resetTimer := func() {
|
||||
timer = time.After(time.Duration(d.SampleRate.timeRequired*1000) * time.Millisecond)
|
||||
}
|
||||
resetTimer()
|
||||
|
||||
for {
|
||||
var rawDieTemps, objTemps chan float64
|
||||
|
||||
if rdtAvlb {
|
||||
rawDieTemps = d.rawDieTemps
|
||||
}
|
||||
if otAvlb {
|
||||
objTemps = d.objTemps
|
||||
}
|
||||
|
||||
select {
|
||||
case <-timer:
|
||||
var rdt float64
|
||||
if rdt, err = d.measureRawDieTemp(); err != nil {
|
||||
log.Printf("tmp006: %v", err)
|
||||
} else {
|
||||
rawDieTemp = rdt
|
||||
rdtAvlb = true
|
||||
}
|
||||
var ot float64
|
||||
if ot, err = d.measureObjTemp(); err != nil {
|
||||
log.Printf("tmp006: %v", err)
|
||||
} else {
|
||||
objTemp = ot
|
||||
otAvlb = true
|
||||
}
|
||||
resetTimer()
|
||||
case rawDieTemps <- rawDieTemp:
|
||||
rdtAvlb = false
|
||||
case objTemps <- objTemp:
|
||||
otAvlb = false
|
||||
case waitc := <-d.closing:
|
||||
waitc <- struct{}{}
|
||||
close(d.rawDieTemps)
|
||||
close(d.objTemps)
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
return
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user