code review changes and bug fixes

This commit is contained in:
Adam Bright 2016-09-21 17:49:09 +00:00
parent eb44392b0a
commit d938e007ff
2 changed files with 156 additions and 181 deletions

View File

@ -10,18 +10,15 @@ import (
"github.com/kidoman/embd"
_ "github.com/kidoman/embd/host/rpi"
"github.com/kidoman/embd/sensor/mcp9808"
"github.com/stianeikeland/go-rpio"
)
func main() {
if err := embd.InitI2C(); err != nil {
panic(err)
}
bus := embd.NewI2CBus(1)
defer embd.CloseI2C()
bus := embd.NewI2CBus(1)
therm := mcp9808.New(bus)
// set sensor to low power mode when we're done
defer therm.SetShutdownMode(true)
if id, err := therm.ManufacturerID(); err == nil {
fmt.Printf("Manufacturer ID: 0x%x\n", id)
@ -32,51 +29,36 @@ func main() {
}
therm.SetShutdownMode(false)
//therm.SetWindowTempLock(false)
// therm.SetCriticalTempLock(false)
config, err := therm.WriteConfig()
if err != nil {
panic(err)
}
fmt.Printf("New Config: %b\n", config)
therm.SetAlertMode(true)
therm.SetInterruptClear(true)
therm.SetAlertStatus(true)
therm.SetAlertControl(true)
//therm.SetInterruptClear(true)
//therm.SetAlertStatus(true)
//therm.SetAlertSelect(false)
//therm.SetAlertPolarity(true)
//therm.SetAlertMode(true)
config, err = therm.WriteConfig()
if err != nil {
therm.SetAlertSelect(false)
therm.SetAlertPolarity(false)
config, _ := therm.Config()
fmt.Printf("New Config: %b\n", config)
if err := therm.SetCriticalTemp(TempFToC(90)); err != nil {
panic(err)
}
fmt.Printf("New Config: %b\n", config)
if err := therm.SetWindowTempUpper(TempFToC(80)); err != nil {
panic(err)
}
fmt.Printf("Set upper temp to %fC\n", TempFToC(80))
temp, err := therm.AmbientTemp()
upperTemp, _ := therm.WindowTempUpper()
fmt.Printf("Upper Temp Limit set to: %fC\n", upperTemp)
alert, err := embd.NewDigitalPin(23)
if err != nil {
panic(err)
}
fmt.Printf("Temp is %f\n", TempCToF(temp.CelsiusDeg))
if err := embd.InitGPIO(); err != nil {
panic(err)
}
if err := rpio.Open(); err != nil {
log.Fatalf("Error: %v\n", err)
}
defer rpio.Close()
defer embd.CloseGPIO()
alert := rpio.Pin(4)
alert.Input()
alert.PullDown()
timer := time.Tick(time.Duration(5) * time.Second)
alert.SetDirection(embd.In)
alert.PullUp()
cancel := make(chan bool)
go func() {
@ -84,17 +66,26 @@ func main() {
reader.ReadString('\n')
cancel <- true
}()
timer := time.Tick(time.Duration(5) * time.Second)
for {
select {
case <-timer:
temp, err := therm.AmbientTemp()
if err == nil {
fmt.Printf("Ambient temp is: %f\n", TempCToF(temp.CelsiusDeg))
if err != nil {
fmt.Printf("Error reading temp: %s\n", err.Error())
} else {
fmt.Printf("Current temp is: %fF (%fC), Window Alert: %v, Critical Alert: %v\n",
TempCToF(temp.CelsiusDeg), temp.CelsiusDeg, temp.AboveUpper || temp.BelowLower, temp.AboveCritical)
}
status, err := alert.Read()
if err != nil {
log.Printf("Error reading pin: %s\n", err.Error())
continue
}
status := alert.Read()
fmt.Printf("Status: %d\n\n", status)
if status == rpio.High {
fmt.Println("Alert temp has been reached.")
if status == embd.High {
fmt.Println("Alert temp has been reached!")
return
}
case <-cancel:

View File

@ -4,9 +4,8 @@
package mcp9808
import (
"log"
"math"
"sync"
"time"
"github.com/kidoman/embd"
)
@ -16,14 +15,14 @@ const (
address = 0x18
// Register addresses.
regConfig = 0x01
regUpperTemp = 0x02
regLowerTemp = 0x03
regCriticalTemp = 0x04
regAmbientTemp = 0x05
regManufID = 0x06
regDeviceID = 0x07
regResolution = 0x08
regConfig = iota // starts at 1, this is what we want
regUpperTemp
regLowerTemp
regCriticalTemp
regAmbientTemp
regManufID
regDeviceID
regResolution
)
const (
@ -40,20 +39,14 @@ const (
// MCP9808 represents a MCP9808 temperature sensor.
type MCP9808 struct {
Bus embd.I2CBus
Poll time.Duration
cmu sync.RWMutex
Bus embd.I2CBus
cmu sync.Mutex
config uint16
synced bool
temps chan uint16
}
// New returns a handle to a MCP9808 sensor.
func New(bus embd.I2CBus) *MCP9808 {
return &MCP9808{Bus: bus, Poll: time.Second, synced: false}
return &MCP9808{Bus: bus}
}
// ManufacturerID reads the device manufacturer ID
@ -79,48 +72,41 @@ func (d *MCP9808) DeviceID() (uint8, uint8, error) {
// Config returns the current word value of the sensor config struct and whether
// that value reflects what is set on the sensor
func (d *MCP9808) Config() (uint16, bool) {
return d.config, d.synced
func (d *MCP9808) Config() (uint16, error) {
return d.readConfig()
}
// ReadConfig reads the config word from the device and writes it to the config attribute
// this overwrites any changes that may have been made to the config attribute
func (d *MCP9808) ReadConfig() (uint16, error) {
d.cmu.RLock()
defer d.cmu.RUnlock()
func (d *MCP9808) readConfig() (uint16, error) {
config, err := d.Bus.ReadWordFromReg(address, regConfig)
if err != nil {
return 0, err
}
d.config = config
d.synced = true
return d.config, nil
}
// WriteConfig writes the sensor's config word to the device and returns the resulting config
func (d *MCP9808) WriteConfig() (uint16, error) {
d.cmu.Lock()
if err := d.Bus.WriteWordToReg(address, regConfig, d.config); err != nil {
return 0, err
}
d.cmu.Unlock()
// read the config after write in case some changes were invalid
return d.ReadConfig()
func (d *MCP9808) writeConfig() error {
return d.Bus.WriteWordToReg(address, regConfig, d.config)
}
// flipConfig bit sets (1, set = true) or clears (0, set = false) a bit within the config word
func (d *MCP9808) flipConfigBit(val uint16, set bool) {
func (d *MCP9808) flipConfigBit(val uint16, set bool) error {
d.cmu.Lock()
defer d.cmu.Unlock()
if set {
d.config |= val
} else {
d.config &= ^val
}
d.synced = false
return d.writeConfig()
}
func (d *MCP9808) readConfigValue(val uint16) bool {
return !(d.config&(1<<val) == 0)
func (d *MCP9808) readConfigValue(val uint16) (bool, error) {
_, err := d.readConfig()
return !(d.config&(1<<val) == 0), err
}
// Hysteresis applies for decreasing temperature only (hot to cold) or as temperature
@ -145,8 +131,9 @@ const (
// 11 = +6.0°C
// The hysteresis applies for decreasing temperature only (hot to cold) or as temperature
// drifts below the specified limit.
func (d *MCP9808) TempHysteresis() Hysteresis {
return Hysteresis(d.config >> 9)
func (d *MCP9808) TempHysteresis() (Hysteresis, error) {
_, err := d.readConfig()
return Hysteresis(d.config >> 9), err
}
// SetTempHysteresis - TUPPER and TLOWER Limit Hysteresis bits
@ -158,16 +145,19 @@ func (d *MCP9808) TempHysteresis() Hysteresis {
// drifts below the specified limit.
// This bit can not be altered when either of the Lock bits are set (bit 6 and bit 7).
// Thi s bit can be programmed in Shutdown mode.
func (d *MCP9808) SetTempHysteresis(val Hysteresis) {
func (d *MCP9808) SetTempHysteresis(val Hysteresis) error {
d.cmu.Lock()
defer d.cmu.Unlock()
d.config = d.config - d.config&^(d.config>>9) + uint16(val)<<9
d.synced = false
return d.writeConfig()
}
// ShutdownMode bit
// 0 (false) = Continuous conversion (power-up default)
// 1 (true) = Shutdown (Low-Power mode)
// In shutdown, all power-consuming activities are disabled, though all registers can be written to or read.
func (d *MCP9808) ShutdownMode() bool {
func (d *MCP9808) ShutdownMode() (bool, error) {
return d.readConfigValue(configShutDown)
}
@ -177,15 +167,15 @@ func (d *MCP9808) ShutdownMode() bool {
// In shutdown, all power-consuming activities are disabled, though all registers can be written to or read.
// This bit cannot be set to 1 when either of the Lock bits is set (bit 6 and bit 7). However, it can be
// cleared to 0 for continuous conversion while locked
func (d *MCP9808) SetShutdownMode(set bool) {
d.flipConfigBit(configShutDown, set)
func (d *MCP9808) SetShutdownMode(set bool) error {
return d.flipConfigBit(configShutDown, set)
}
// CriticalTempLock - TCRIT Lock bit
// 0 (false) = Unlocked. TCRIT register can be written (power-up default)
// 1 (true) = Locked. TCRIT register can not be written
// When enabled, this bit remains set to 1 or locked until cleared by an internal Reset
func (d *MCP9808) CriticalTempLock() bool {
func (d *MCP9808) CriticalTempLock() (bool, error) {
return d.readConfigValue(configCriticalTempLock)
}
@ -194,31 +184,31 @@ func (d *MCP9808) CriticalTempLock() bool {
// 1 (true) = Locked. TCRIT register can not be written
// When enabled, this bit remains set to 1 or locked until cleared by an internal Reset
// This bit can be programmed in Shutdown mode.
func (d *MCP9808) SetCriticalTempLock(locked bool) {
d.flipConfigBit(configCriticalTempLock, locked)
func (d *MCP9808) setCriticalTempLock(locked bool) error {
return d.flipConfigBit(configCriticalTempLock, locked)
}
// WindowTempLock - TUPPER and TLOWER Window Lock bit
// 0 (false) = Unlocked; TUPPER and TLOWER registers can be written (power-up default)
// 1 (true) = Locked; TUPPER and TLOWER registers can not be written
// When enabled, this bit remains set to 1 or locked until cleared by a Power-on Reset
func (d *MCP9808) WindowTempLock() bool {
func (d *MCP9808) WindowTempLock() (bool, error) {
return d.readConfigValue(configWindowTempLock)
}
// SetWindowTempLock - TUPPER and TLOWER Window Lock bit
// setWindowTempLock - TUPPER and TLOWER Window Lock bit
// 0 (false) = Unlocked; TUPPER and TLOWER registers can be written (power-up default)
// 1 (true) = Locked; TUPPER and TLOWER registers can not be written
// When enabled, this bit remains set to 1 or locked until cleared by a Power-on Reset
// This bit can be programmed in Shutdown mode.
func (d *MCP9808) SetWindowTempLock(locked bool) {
d.flipConfigBit(configWindowTempLock, locked)
func (d *MCP9808) setWindowTempLock(locked bool) error {
return d.flipConfigBit(configWindowTempLock, locked)
}
// InterruptClear - Interrupt Clear bit
// 0 (false) = No effect (power-up default)
// 1 (true) = Clear interrupt output; when read, this bit returns to 0
func (d *MCP9808) InterruptClear() bool {
func (d *MCP9808) InterruptClear() (bool, error) {
return d.readConfigValue(configInterruptClear)
}
@ -227,14 +217,14 @@ func (d *MCP9808) InterruptClear() bool {
// 1 (true) = Clear interrupt output; when read, this bit returns to 0
// This bit can not be set to 1 in Shutdown mode, but it can be cleared after the device enters Shutdown
// mode.
func (d *MCP9808) SetInterruptClear(set bool) {
d.flipConfigBit(configInterruptClear, set)
func (d *MCP9808) SetInterruptClear(set bool) error {
return d.flipConfigBit(configInterruptClear, set)
}
// AlertStatus Alert Output Status bit
// 0 (false) = Alert output is not asserted by the device (power-up default)
// 1 (true) = Alert output is asserted as a comparator/Interrupt or critical temperature output
func (d *MCP9808) AlertStatus() bool {
func (d *MCP9808) AlertStatus() (bool, error) {
return d.readConfigValue(configAlertStatus)
}
@ -244,14 +234,14 @@ func (d *MCP9808) AlertStatus() bool {
// This bit can not be set to 1 or cleared to 0 in Shutdown mode. However, if the Alert output is configured
// as Interrupt mode, and if the host controller clears to 0, the interrupt, using bit 5 while the device
// is in Shutdown mode, then this bit will also be cleared 0.
func (d *MCP9808) SetAlertStatus(set bool) {
d.flipConfigBit(configAlertStatus, set)
func (d *MCP9808) SetAlertStatus(set bool) error {
return d.flipConfigBit(configAlertStatus, set)
}
// AlertControl - Alert Output Control bit
// 0 (false) = Disabled (power-up default)
// 1 (true) = Enabled
func (d *MCP9808) AlertControl() bool {
func (d *MCP9808) AlertControl() (bool, error) {
return d.readConfigValue(configAlertControl)
}
@ -260,14 +250,14 @@ func (d *MCP9808) AlertControl() bool {
// 1 (true) = Enabled
// This bit can not be altered when either of the Lock bits are set (bit 6 and bit 7).
// This bit can be programmed in Shutdown mode, but the Alert output will not assert or deassert.
func (d *MCP9808) SetAlertControl(set bool) {
d.flipConfigBit(configAlertControl, set)
func (d *MCP9808) SetAlertControl(set bool) error {
return d.flipConfigBit(configAlertControl, set)
}
// AlertSelect - Alert Output Select bit
// 0 (false) = Alert output for TUPPER, TLOWER and TCRIT (power-up default)
// 1 (true) = TA > TCRIT only (TUPPER and TLOWER temperature boundaries are disabled)
func (d *MCP9808) AlertSelect() bool {
func (d *MCP9808) AlertSelect() (bool, error) {
return d.readConfigValue(configAlertSelect)
}
@ -276,14 +266,14 @@ func (d *MCP9808) AlertSelect() bool {
// 1 (true) = TA > TCRIT only (TUPPER and TLOWER temperature boundaries are disabled)
// When the Alarm Window Lock bit is set, this bit cannot be altered until unlocked (bit 6).
// This bit can be programmed in Shutdown mode, but the Alert output will not assert or deassert.
func (d *MCP9808) SetAlertSelect(set bool) {
d.flipConfigBit(configAlertSelect, set)
func (d *MCP9808) SetAlertSelect(set bool) error {
return d.flipConfigBit(configAlertSelect, set)
}
// AlertPolarity - Alert Output Polarity bit
// 0 (false) = Active-low (power-up default; pull-up resistor required)
// 1 (true) = Active-high
func (d *MCP9808) AlertPolarity() bool {
func (d *MCP9808) AlertPolarity() (bool, error) {
return d.readConfigValue(configAlertPolarity)
}
@ -292,14 +282,14 @@ func (d *MCP9808) AlertPolarity() bool {
// 1 (true) = Active-high
// This bit cannot be altered when either of the Lock bits are set (bit 6 and bit 7).
// This bit can be programmed in Shutdown mode, but the Alert output will not assert or deassert.
func (d *MCP9808) SetAlertPolarity(set bool) {
d.flipConfigBit(configAlertPolarity, set)
func (d *MCP9808) SetAlertPolarity(set bool) error {
return d.flipConfigBit(configAlertPolarity, set)
}
// AlertMode - Alert Output Mode bit
// 0 (false) = Comparator output (power-up default)
// 1 (true) = Interrupt output
func (d *MCP9808) AlertMode() bool {
func (d *MCP9808) AlertMode() (bool, error) {
return d.readConfigValue(configAlertMode)
}
@ -308,8 +298,8 @@ func (d *MCP9808) AlertMode() bool {
// 1 (true) = Interrupt output
// This bit cannot be altered when either of the Lock bits are set (bit 6 and bit 7).
// This bit can be programmed in Shutdown mode, but the Alert output will not assert or deassert.
func (d *MCP9808) SetAlertMode(set bool) {
d.flipConfigBit(configAlertMode, set)
func (d *MCP9808) SetAlertMode(set bool) error {
return d.flipConfigBit(configAlertMode, set)
}
// Temperature contains the ambient temperature along with alert values.
@ -318,6 +308,60 @@ type Temperature struct {
AboveCritical, AboveUpper, BelowLower bool
}
// readTempC reads from the reg temperature register and returns the current temperature value in celsius
func (d *MCP9808) readTempC(reg byte) (float64, error) {
temp, err := d.Bus.ReadWordFromReg(address, reg)
if err != nil {
return 0, err
}
return convertWordToTempC(temp), nil
}
func convertWordToTempC(temp uint16) float64 {
wholeNum := float64(temp&0xFF0) / 16.0
fraction := float64(temp&0xF) * .0625
tempRead := wholeNum + fraction
if !(temp&(1<<12) == 0) { // read sign bit
tempRead *= -1
}
return tempRead
}
func (d *MCP9808) setTemp(reg byte, newTemp float64) error {
d.cmu.Lock()
defer d.cmu.Unlock()
var signBit uint16
if newTemp < 0 {
newTemp *= -1
signBit = 0x1000
}
wholeNum, fraction := math.Modf(newTemp)
var roundedFrac uint16
switch {
case fraction < .125:
roundedFrac = 0
case fraction < .375:
roundedFrac = 1
case fraction < .625:
roundedFrac = 2
case fraction < .875:
roundedFrac = 3
default:
roundedFrac = 4
}
newTempWord := signBit + uint16(wholeNum)*16 + roundedFrac*4
if err := d.Bus.WriteWordToReg(address, reg, newTempWord); err != nil {
return err
}
return nil
}
// AmbientTemp reads the current sensor value along with the flags denoting what boundaries the
// current temperature exceeds.
func (d *MCP9808) AmbientTemp() (*Temperature, error) {
@ -326,57 +370,15 @@ func (d *MCP9808) AmbientTemp() (*Temperature, error) {
return nil, err
}
tempC := temp &^ 0xF000
wholeNum := float64(tempC&^0xF) / 16.0
fraction := tempC &^ 0xFF0
tempResult := &Temperature{
AboveCritical: !(temp&(1<<15) == 0),
AboveUpper: !(temp&(1<<14) == 0),
BelowLower: !(temp&(1<<13) == 0)}
tempResult.CelsiusDeg = wholeNum + (float64(fraction) / 10000.0)
if !(temp&(1<<12) == 0) { // read sign bit
tempResult.CelsiusDeg *= -1
}
tempResult.CelsiusDeg = convertWordToTempC(temp)
return tempResult, nil
}
// readTempC reads from the ambient temperature register and returns the current temperature value in celsius
func (d *MCP9808) readTempC(reg byte) (float64, error) {
temp, err := d.Bus.ReadWordFromReg(address, reg)
if err != nil {
return 0, err
}
log.Printf("\nTA vs TCrit: %v\nTA vs TUpper: %v\nTA vs TLower: %v\n", !(temp&(1<<15) == 0), !(temp&(1<<14) == 0), !(temp&(1<<13) == 0))
wholeTempC := temp &^ 0xF000
wholeNum := float64(wholeTempC&^0xF) / 16.0
fraction := wholeTempC &^ 0xFF0
tempRead := wholeNum + (float64(fraction) / 10000.0)
if !(temp&(1<<12) == 0) { // read sign bit
tempRead *= -1
}
return tempRead, nil
}
func (d *MCP9808) setTemp(reg byte, newTemp float64) error {
var signBit uint16
if newTemp < 0 {
newTemp *= -1
signBit = 0x1000
}
newTempWord := uint16(newTemp)*15 + uint16(newTemp*16) + signBit
if err := d.Bus.WriteWordToReg(address, reg, newTempWord); err != nil {
return err
}
return nil
}
// CriticalTempUpper reads the current temperature set in the critical temperature register.
func (d *MCP9808) CriticalTempUpper() (float64, error) {
return d.readTempC(regCriticalTemp)
@ -385,11 +387,7 @@ func (d *MCP9808) CriticalTempUpper() (float64, error) {
// SetCriticalTemp when the temperature goes above the set value the alert will be
// triggered if enabled.
func (d *MCP9808) SetCriticalTemp(newTemp float64) error {
d.cmu.Lock()
defer d.cmu.Unlock()
d.SetCriticalTempLock(false)
if _, err := d.WriteConfig(); err != nil {
if err := d.setCriticalTempLock(false); err != nil {
return err
}
@ -397,9 +395,7 @@ func (d *MCP9808) SetCriticalTemp(newTemp float64) error {
return err
}
d.SetCriticalTempLock(true)
_, err := d.WriteConfig()
return err
return d.setCriticalTempLock(true)
}
// WindowTempUpper reads the current temperature set in the upper window temperature register.
@ -410,11 +406,7 @@ func (d *MCP9808) WindowTempUpper() (float64, error) {
// SetWindowTempUpper when the temperature goes above the set value the alert will be
// triggered if enabled.
func (d *MCP9808) SetWindowTempUpper(newTemp float64) error {
d.cmu.Lock()
defer d.cmu.Unlock()
d.SetWindowTempLock(false)
if _, err := d.WriteConfig(); err != nil {
if err := d.setWindowTempLock(false); err != nil {
return err
}
@ -422,9 +414,7 @@ func (d *MCP9808) SetWindowTempUpper(newTemp float64) error {
return err
}
d.SetWindowTempLock(true)
_, err := d.WriteConfig()
return err
return d.setWindowTempLock(true)
}
// WindowTempLower reads the current temperature set in the lower window temperature register.
@ -435,11 +425,7 @@ func (d *MCP9808) WindowTempLower() (float64, error) {
// SetWindowTempLower when the temperature goes below the set value the alert will be
// triggered if enabled.
func (d *MCP9808) SetWindowTempLower(newTemp float64) error {
d.cmu.Lock()
defer d.cmu.Unlock()
d.SetWindowTempLock(false)
if _, err := d.WriteConfig(); err != nil {
if err := d.setWindowTempLock(false); err != nil {
return err
}
@ -447,9 +433,7 @@ func (d *MCP9808) SetWindowTempLower(newTemp float64) error {
return err
}
d.SetWindowTempLock(true)
_, err := d.WriteConfig()
return err
return d.setWindowTempLock(true)
}
// TempResolution reads the current temperature accuracy from the sensor (affects temperature read speed)