diff --git a/samples/.gitignore b/samples/.gitignore index af9b180..5a92db3 100644 --- a/samples/.gitignore +++ b/samples/.gitignore @@ -8,6 +8,7 @@ gpio gpiodetect gpiodirect gpioshort +isl29125 l3gd20 led ledshort diff --git a/samples/isl29125.go b/samples/isl29125.go new file mode 100644 index 0000000..0603da1 --- /dev/null +++ b/samples/isl29125.go @@ -0,0 +1,35 @@ +// +build ignore + +package main + +import ( + "fmt" + "time" + + "github.com/kidoman/embd" + _ "github.com/kidoman/embd/host/all" + "github.com/kidoman/embd/sensor/isl29125" +) + +func main() { + + if err := embd.InitI2C(); err != nil { + panic(err) + } + defer embd.CloseI2C() + + bus := embd.NewI2CBus(1) + + isl := isl29125.New(isl29125.DefaultConfig, bus) + defer isl.Close() + + for { + r, err := isl.Reading() + if err != nil { + panic(err) + } + fmt.Printf("%v", r) + + time.Sleep(500 * time.Millisecond) + } +} diff --git a/sensor/isl29125/isl29125.go b/sensor/isl29125/isl29125.go new file mode 100644 index 0000000..da36d48 --- /dev/null +++ b/sensor/isl29125/isl29125.go @@ -0,0 +1,252 @@ +// Package isl29125 allows interfacing with the ISL29125 RGB light sensor +// Datasheet: http://www.intersil.com/content/dam/Intersil/documents/isl2/isl29125.pdf +package isl29125 + +/* + + TODO: + - add support for the following: + - config register 2 and 3 + - lux calculation + - powerdown / power up + - interupt config / monitor +*/ + +import ( + "fmt" + "time" + + "github.com/golang/glog" + "github.com/kidoman/embd" +) + +const ( + pollDelay = 250 +) + +const ( + ModePowerDown = 0x00 + ModeGreenOnly = 0x01 + ModeRedOnly = 0x02 + ModeBlueOnly = 0x03 + ModeStandBy = 0x04 + ModeRGB = 0x05 + ModeRG = 0x06 + ModeGB = 0x07 +) + +const ( + LuxRange375 = 0x00 + LuxRange10k = 0x08 +) + +const ( + IRAdjustLow = 0x00 + IRAdjustMed = 0x20 + IRAdjustHigh = 0x3f +) + +const ( + Resolution16Bit = 0x00 + Resolution12Bit = 0x10 +) + +const ( + SyncStartOnWrite = 0x00 + SyncStartOnInt = 0x20 +) + +const ( + RegisterDeviceID = 0x00 + RegisterConfig1 = 0x01 + RegisterConfig2 = 0x02 + RegisterConfig3 = 0x03 + RegisterFlags = 0x08 + RegisterGreenLow = 0x09 + RegisterGreenHigh = 0x0a + RegisterRedLow = 0x0b + RegisterRedHigh = 0x0c + RegisterBlueLow = 0x0d + RegisterBlueHigh = 0x0e +) + +const ( + FlagReady = 0x00 + FlagInterrupt = 0x01 + FlagConversion = 0x02 + FlagPowerDownOrBrownOut = 0x04 + FlagGreenConverting = 0x10 + FlagRedConverting = 0x20 + FlagBlueConverting = 0x30 +) + +const ( + DefaultConfig = ModeRGB | LuxRange375 | Resolution16Bit | SyncStartOnWrite +) + +const ( + SensorAddr = 0x44 + DeviceID = 0x7d +) + +const ( + CmdGetStatus = 0x08 + CmdReset = 0x46 +) + +// Reading represents a single reading from an RGB light sensor. +type Reading struct { + Red uint16 + Green uint16 + Blue uint16 + Lux uint16 + LuxRange int + Resolution int +} + +// ISL29125 represents an RGB light sensor. +type ISL29125 struct { + Bus embd.I2CBus + Poll int + + readings chan *Reading + quit chan bool + + mode uint8 + initialized bool +} + +// New returns an ISL29125 for a given config. +func New(config uint8, bus embd.I2CBus) *ISL29125 { + glog.V(1).Info("Creating new ISL29125") + return &ISL29125{Bus: bus, Poll: pollDelay, mode: config} +} + +// Setup initializes the sensor. +func (i *ISL29125) setup() error { + + if i.initialized { + return nil + } + + // verify that i2c device is reachable on specified bus and that it reports back the correct ID + id, err := i.Bus.ReadByteFromReg(SensorAddr, RegisterDeviceID) + if err != nil { + return err + } + if DeviceID != id { + return fmt.Errorf("Invalid device id. Expected [%x] but device reports [%x]", DeviceID, id) + } + + // power down device ( don't know current state; assume it's running ) + err = i.Bus.WriteByteToReg(SensorAddr, RegisterConfig1, ModePowerDown) + if err != nil { + return err + } + time.Sleep(100 * time.Millisecond) + + // reset device + err = i.Bus.WriteByteToReg(SensorAddr, DeviceID, CmdReset) + if err != nil { + return err + } + time.Sleep(100 * time.Millisecond) + + // verify status after reset is ready + status, err := i.Bus.ReadByteFromReg(SensorAddr, CmdGetStatus) + + if err != nil { + return err + } + + if status != FlagReady { + return fmt.Errorf("Invalid device status. Expected [%x] but device reports [%x]", FlagReady, status) + } + + // set config 1 to user specified mode + if err = i.Bus.WriteByteToReg(SensorAddr, RegisterConfig1, i.mode); err != nil { + return err + } + // set config 2 to fixed value + if err = i.Bus.WriteByteToReg(SensorAddr, RegisterConfig2, IRAdjustHigh); err != nil { + return err + } + + // set config 3 to fixed value + if err = i.Bus.WriteByteToReg(SensorAddr, RegisterConfig3, 0x0); err != nil { + return err + } + + i.initialized = true + return nil + +} + +func (i *ISL29125) getReading() (*Reading, error) { + if err := i.setup(); err != nil { + return nil, err + } + + glog.V(1).Info("Getting reading") + red, err := i.Bus.ReadWordFromReg(SensorAddr, RegisterRedLow) + if err != nil { + return nil, err + } + green, err := i.Bus.ReadWordFromReg(SensorAddr, RegisterGreenLow) + if err != nil { + return nil, err + } + blue, err := i.Bus.ReadWordFromReg(SensorAddr, RegisterBlueLow) + if err != nil { + return nil, err + } + + return &Reading{Red: red, Green: green, Blue: blue}, nil +} + +// Reading returns a single sensor reading. +func (i *ISL29125) Reading() (*Reading, error) { + select { + case r := <-i.readings: + return r, nil + default: + return i.getReading() + } +} + +// Run starts continuous sensor data acquisition loop. +func (i *ISL29125) Run() { + glog.V(1).Info("Running sensor") + go func() { + i.quit = make(chan bool) + i.readings = make(chan *Reading) + ticker := time.NewTicker(time.Duration(i.Poll) * time.Millisecond) + defer ticker.Stop() + + var reading *Reading + + for { + select { + case i.readings <- reading: + case <-ticker.C: + r, err := i.getReading() + if err == nil { + reading = r + } + case <-i.quit: + i.readings = nil + return + } + } + }() + return +} + +// Close down sensor. +func (i *ISL29125) Close() { + glog.V(1).Info("Closing sensor") + if i.quit != nil { + i.quit <- true + } + return +}