From bf8a4be4d9c311b5b0a65d90aea5e086d96b44e9 Mon Sep 17 00:00:00 2001 From: Karan Misra Date: Sun, 23 Mar 2014 06:25:32 +0530 Subject: [PATCH] led: support led functionality on the bbb --- bbb.go | 10 +++ descriptor.go | 12 +++- gpio.go | 4 ++ i2c.go | 4 ++ led.go | 59 +++++++++++++++ leddriver.go | 172 ++++++++++++++++++++++++++++++++++++++++++++ samples/.gitignore | 2 + samples/led.go | 44 ++++++++++++ samples/ledshort.go | 18 +++++ 9 files changed, 322 insertions(+), 3 deletions(-) create mode 100644 led.go create mode 100644 leddriver.go create mode 100644 samples/led.go create mode 100644 samples/ledshort.go diff --git a/bbb.go b/bbb.go index fb76ed6..4c82f85 100644 --- a/bbb.go +++ b/bbb.go @@ -16,6 +16,9 @@ func init() { return newGPIODriver(bbbPins, newDigitalPin, newBBBAnalogPin) }, I2C: newI2CDriver, + LEDDriver: func() LEDDriver { + return newLEDDriver(bbbLEDMap) + }, } } } @@ -88,6 +91,13 @@ var bbbPins = PinMap{ &PinDesc{ID: "P9_40", Aliases: []string{"1", "AIN1"}, Caps: CapAnalog, AnalogLogical: 1}, } +var bbbLEDMap = LEDMap{ + "beaglebone:green:usr0": []string{"0", "USR0", "usr0"}, + "beaglebone:green:usr1": []string{"1", "USR1", "usr1"}, + "beaglebone:green:usr2": []string{"2", "USR2", "usr2"}, + "beaglebone:green:usr3": []string{"3", "USR3", "usr3"}, +} + type bbbAnalogPin struct { n int diff --git a/descriptor.go b/descriptor.go index 3001acb..fbbc5a7 100644 --- a/descriptor.go +++ b/descriptor.go @@ -1,10 +1,14 @@ package embd -import "fmt" +import ( + "errors" + "fmt" +) type Descriptor struct { - GPIO func() GPIO - I2C func() I2C + GPIO func() GPIO + I2C func() I2C + LEDDriver func() LEDDriver } type Describer func(rev int) *Descriptor @@ -24,3 +28,5 @@ func DescribeHost() (*Descriptor, error) { return describer(rev), nil } + +var ErrFeatureNotSupport = errors.New("embd: feature is not supported") diff --git a/gpio.go b/gpio.go index b27fe64..8b13134 100644 --- a/gpio.go +++ b/gpio.go @@ -51,6 +51,10 @@ func InitGPIO() error { return err } + if desc.GPIO == nil { + return ErrFeatureNotSupport + } + gpioInstance = desc.GPIO() return nil diff --git a/i2c.go b/i2c.go index 85060c2..fa43702 100644 --- a/i2c.go +++ b/i2c.go @@ -37,6 +37,10 @@ func InitI2C() error { return err } + if desc.I2C == nil { + return ErrFeatureNotSupport + } + i2cInstance = desc.I2C() return nil diff --git a/led.go b/led.go new file mode 100644 index 0000000..59dcfdd --- /dev/null +++ b/led.go @@ -0,0 +1,59 @@ +package embd + +type LED interface { + On() error + Off() error + + Toggle() error + + Close() error +} + +type LEDDriver interface { + LED(key interface{}) (LED, error) + + Close() error +} + +var ledDriverInstance LEDDriver + +func InitLED() error { + desc, err := DescribeHost() + if err != nil { + return err + } + + if desc.LEDDriver == nil { + return ErrFeatureNotSupport + } + + ledDriverInstance = desc.LEDDriver() + + return nil +} + +func CloseLED() error { + return ledDriverInstance.Close() +} + +func NewLED(key interface{}) (LED, error) { + return ledDriverInstance.LED(key) +} + +func LEDOn(key interface{}) error { + led, err := NewLED(key) + if err != nil { + return err + } + + return led.On() +} + +func LEDOff(key interface{}) error { + led, err := NewLED(key) + if err != nil { + return err + } + + return led.Off() +} diff --git a/leddriver.go b/leddriver.go new file mode 100644 index 0000000..513901d --- /dev/null +++ b/leddriver.go @@ -0,0 +1,172 @@ +package embd + +import ( + "errors" + "fmt" + "io/ioutil" + "os" + "strconv" + "strings" +) + +type LEDMap map[string][]string + +type ledDriver struct { + ledMap LEDMap + + initializedLEDs map[string]LED +} + +func newLEDDriver(ledMap LEDMap) LEDDriver { + return &ledDriver{ + ledMap: ledMap, + initializedLEDs: map[string]LED{}, + } +} + +func (d *ledDriver) lookup(k interface{}) (string, error) { + var ks string + switch key := k.(type) { + case int: + ks = strconv.Itoa(key) + case string: + ks = key + case fmt.Stringer: + ks = key.String() + default: + return "", errors.New("led: invalid key type") + } + + for id := range d.ledMap { + for _, alias := range d.ledMap[id] { + if alias == ks { + return id, nil + } + } + } + + return "", fmt.Errorf("led: no match found for %q", k) +} + +func (d *ledDriver) LED(k interface{}) (LED, error) { + id, err := d.lookup(k) + if err != nil { + return nil, err + } + + led := newLED(id) + d.initializedLEDs[id] = led + + return led, nil +} + +func (d *ledDriver) Close() error { + for _, led := range d.initializedLEDs { + if err := led.Close(); err != nil { + return err + } + } + + return nil +} + +type led struct { + id string + + brightness *os.File + + initialized bool +} + +func newLED(id string) LED { + return &led{id: id} +} + +func (l *led) init() error { + if l.initialized { + return nil + } + + var err error + if l.brightness, err = l.brightnessFile(); err != nil { + return err + } + + l.initialized = true + + return nil +} + +func (l *led) brightnessFilePath() string { + return fmt.Sprintf("/sys/class/leds/%v/brightness", l.id) +} + +func (l *led) openFile(path string) (*os.File, error) { + return os.OpenFile(path, os.O_RDWR, os.ModeExclusive) +} + +func (l *led) brightnessFile() (*os.File, error) { + return l.openFile(l.brightnessFilePath()) +} + +func (l *led) On() error { + if err := l.init(); err != nil { + return err + } + + _, err := l.brightness.WriteString("1") + return err +} + +func (l *led) Off() error { + if err := l.init(); err != nil { + return err + } + + _, err := l.brightness.WriteString("0") + return err +} + +func (l *led) isOn() (bool, error) { + l.brightness.Seek(0, 0) + bytes, err := ioutil.ReadAll(l.brightness) + if err != nil { + return false, err + } + str := string(bytes) + str = strings.TrimSpace(str) + if str == "1" { + return true, nil + } + return false, nil +} + +func (l *led) Toggle() error { + if err := l.init(); err != nil { + return err + } + + state, err := l.isOn() + if err != nil { + return err + } + + if state { + return l.Off() + } + return l.On() +} + +func (l *led) Close() error { + if !l.initialized { + return nil + } + + if err := l.brightness.Close(); err != nil { + return err + } + + l.initialized = false + + return nil +} diff --git a/samples/.gitignore b/samples/.gitignore index 14dd75b..69e2a06 100644 --- a/samples/.gitignore +++ b/samples/.gitignore @@ -8,6 +8,8 @@ gpiodetect gpiodirect gpioshort l3gd20 +led +ledshort lsm303 mcp4725 pca9685 diff --git a/samples/led.go b/samples/led.go new file mode 100644 index 0000000..1c1d68f --- /dev/null +++ b/samples/led.go @@ -0,0 +1,44 @@ +// +build ignore + +package main + +import ( + "fmt" + "os" + "os/signal" + "time" + + "github.com/kidoman/embd" +) + +func main() { + if err := embd.InitLED(); err != nil { + panic(err) + } + defer embd.CloseLED() + + led, err := embd.NewLED(3) + if err != nil { + panic(err) + } + defer func() { + led.Off() + led.Close() + }() + + quit := make(chan os.Signal, 1) + signal.Notify(quit, os.Interrupt, os.Kill) + defer signal.Stop(quit) + + for { + select { + case <-time.After(500 * time.Millisecond): + if err := led.Toggle(); err != nil { + panic(err) + } + fmt.Printf("Toggled\n") + case <-quit: + return + } + } +} diff --git a/samples/ledshort.go b/samples/ledshort.go new file mode 100644 index 0000000..eb1b0f2 --- /dev/null +++ b/samples/ledshort.go @@ -0,0 +1,18 @@ +// +build ignore + +package main + +import ( + "time" + + "github.com/kidoman/embd" +) + +func main() { + embd.InitLED() + defer embd.CloseLED() + + embd.LEDOn(3) + time.Sleep(1 * time.Second) + embd.LEDOff(3) +}