1
0
mirror of https://github.com/kidoman/embd synced 2024-11-11 12:08:53 +01:00
embd/sensor/lsm303/lsm303.go

162 lines
3.3 KiB
Go
Raw Normal View History

2013-12-07 18:41:06 +01:00
// Package lsm303 allows interfacing with the LSM303 magnetometer.
package lsm303
import (
"math"
"sync"
"time"
"github.com/golang/glog"
2014-03-02 20:21:23 +01:00
"github.com/kidoman/embd"
2013-12-07 18:41:06 +01:00
)
const (
magAddress = 0x1E
magConfigRegA = 0x00
2013-12-08 22:19:39 +01:00
MagHz75 = 0x00 // ODR = 0.75 Hz
Mag1Hz5 = 0x04 // ODR = 1.5 Hz
Mag3Hz = 0x08 // ODR = 3 Hz
Mag7Hz5 = 0x0C // ODR = 7.5 Hz
Mag15Hz = 0x10 // ODR = 15 Hz
Mag30Hz = 0x14 // ODR = 30 Hz
Mag75Hz = 0x18 // ODR = 75 Hz
MagNormal = 0x00 // Normal mode
MagPositiveBias = 0x01 // Positive bias mode
MagNegativeBias = 0x02 // Negative bias mode
MagCRADefault = Mag15Hz | MagNormal // 15 Hz and normal mode is the default
2013-12-07 18:41:06 +01:00
magModeReg = 0x02
2013-12-08 22:19:39 +01:00
MagContinuous = 0x00 // Continuous conversion mode
2013-12-08 22:21:15 +01:00
MagSingle = 0x01 // Single conversion mode
2013-12-08 22:19:39 +01:00
MagSleep = 0x03 // Sleep mode
2013-12-07 18:41:06 +01:00
2013-12-08 22:19:39 +01:00
MagMRDefault = MagContinuous // Continuous conversion is the default
2013-12-07 18:41:06 +01:00
magDataSignal = 0x02
magData = 0x03
pollDelay = 250
)
2014-03-23 11:17:58 +01:00
// LSM303 represents a LSM303 magnetometer.
2014-03-02 20:21:23 +01:00
type LSM303 struct {
Bus embd.I2CBus
Poll int
2013-12-07 18:41:06 +01:00
initialized bool
2014-03-02 20:21:23 +01:00
mu sync.RWMutex
2013-12-07 18:41:06 +01:00
headings chan float64
quit chan struct{}
}
// New creates a new LSM303 interface. The bus variable controls
// the I2C bus used to communicate with the device.
2014-03-02 20:21:23 +01:00
func New(bus embd.I2CBus) *LSM303 {
return &LSM303{Bus: bus, Poll: pollDelay}
2013-12-07 18:41:06 +01:00
}
// Initialize the device
2014-03-02 20:21:23 +01:00
func (d *LSM303) setup() error {
2013-12-07 18:41:06 +01:00
d.mu.RLock()
if d.initialized {
d.mu.RUnlock()
2014-03-02 20:21:23 +01:00
return nil
2013-12-07 18:41:06 +01:00
}
d.mu.RUnlock()
d.mu.Lock()
defer d.mu.Unlock()
2014-03-02 20:21:23 +01:00
if err := d.Bus.WriteByteToReg(magAddress, magConfigRegA, MagCRADefault); err != nil {
return err
2013-12-07 18:41:06 +01:00
}
2014-03-02 20:21:23 +01:00
if err := d.Bus.WriteByteToReg(magAddress, magModeReg, MagMRDefault); err != nil {
return err
2013-12-07 18:41:06 +01:00
}
d.initialized = true
2014-03-02 20:21:23 +01:00
return nil
2013-12-07 18:41:06 +01:00
}
2014-03-02 20:21:23 +01:00
func (d *LSM303) measureHeading() (float64, error) {
if err := d.setup(); err != nil {
return 0, err
2013-12-07 18:41:06 +01:00
}
2014-03-02 20:21:23 +01:00
if _, err := d.Bus.ReadByteFromReg(magAddress, magDataSignal); err != nil {
return 0, err
2013-12-07 18:41:06 +01:00
}
data := make([]byte, 6)
2014-03-02 20:21:23 +01:00
if err := d.Bus.ReadFromReg(magAddress, magData, data); err != nil {
return 0, err
2013-12-07 18:41:06 +01:00
}
x := int16(data[0])<<8 | int16(data[1])
y := int16(data[2])<<8 | int16(data[3])
2014-03-02 20:21:23 +01:00
heading := math.Atan2(float64(y), float64(x)) / math.Pi * 180
2013-12-07 18:41:06 +01:00
if heading < 0 {
heading += 360
}
2014-03-02 20:21:23 +01:00
return heading, nil
2013-12-07 18:41:06 +01:00
}
2013-12-08 22:19:39 +01:00
// Heading returns the current heading [0, 360).
2014-03-02 20:21:23 +01:00
func (d *LSM303) Heading() (float64, error) {
2013-12-07 18:41:06 +01:00
select {
2014-03-02 20:21:23 +01:00
case heading := <-d.headings:
return heading, nil
2013-12-07 18:41:06 +01:00
default:
glog.V(2).Infof("lsm303: no headings available... measuring")
2013-12-07 18:41:06 +01:00
return d.measureHeading()
}
}
2013-12-08 22:19:39 +01:00
// Run starts the sensor data acquisition loop.
func (d *LSM303) Run() error {
2013-12-07 18:41:06 +01:00
go func() {
d.quit = make(chan struct{})
2014-03-02 20:21:23 +01:00
timer := time.Tick(time.Duration(d.Poll) * time.Millisecond)
2013-12-07 18:41:06 +01:00
var heading float64
for {
select {
case <-timer:
h, err := d.measureHeading()
if err == nil {
heading = h
}
if err == nil && d.headings == nil {
d.headings = make(chan float64)
}
case d.headings <- heading:
case <-d.quit:
d.headings = nil
return
}
}
}()
return nil
2013-12-07 18:41:06 +01:00
}
// Close the sensor data acquisition loop and put the LSM303 into sleep mode.
2014-03-02 20:21:23 +01:00
func (d *LSM303) Close() error {
2013-12-07 18:41:06 +01:00
if d.quit != nil {
d.quit <- struct{}{}
}
2014-03-02 20:21:23 +01:00
return d.Bus.WriteByteToReg(magAddress, magModeReg, MagSleep)
2013-12-07 18:41:06 +01:00
}