mirror of https://github.com/periph/devices
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
142 lines
3.4 KiB
Go
142 lines
3.4 KiB
Go
// Copyright 2018 The Periph Authors. All rights reserved.
|
|
// Use of this source code is governed under the Apache License, Version 2.0
|
|
// that can be found in the LICENSE file.
|
|
|
|
package sn3218
|
|
|
|
import (
|
|
"errors"
|
|
|
|
"periph.io/x/conn/v3/i2c"
|
|
)
|
|
|
|
const (
|
|
i2cAddress = 0x54
|
|
cmdEnableOutput = 0x00
|
|
cmdSetBrightnessValues = 0x01
|
|
cmdEnableLeds = 0x13
|
|
cmdUpdate = 0x16
|
|
cmdReset = 0x17
|
|
)
|
|
|
|
// Dev is a handler to sn3218 controller.
|
|
type Dev struct {
|
|
i2c i2c.Dev
|
|
on [18]bool
|
|
brightness [18]byte
|
|
}
|
|
|
|
// New returns a handle to a SN3218 LED driver.
|
|
func New(bus i2c.Bus) (*Dev, error) {
|
|
d := &Dev{
|
|
i2c: i2c.Dev{Bus: bus, Addr: i2cAddress},
|
|
}
|
|
if err := d.reset(); err != nil {
|
|
return nil, err
|
|
}
|
|
return d, nil
|
|
}
|
|
|
|
// Halt resets the registers and switches the driver off.
|
|
func (d *Dev) Halt() error {
|
|
return d.reset()
|
|
}
|
|
|
|
// WakeUp returns from sleep mode and switches the channels according to the states in the register of SN3218.
|
|
func (d *Dev) WakeUp() error {
|
|
_, err := d.i2c.Write([]byte{cmdEnableOutput, 0x01})
|
|
return err
|
|
}
|
|
|
|
// Sleep sends SN3218 to sleep mode while keeping the states in the registers.
|
|
func (d *Dev) Sleep() error {
|
|
_, err := d.i2c.Write([]byte{cmdEnableOutput, 0x00})
|
|
return err
|
|
}
|
|
|
|
// GetState returns the state (on/off) and the brightness (0..255) of the
|
|
// Channel 0..17.
|
|
func (d *Dev) GetState(channel int) (bool, byte, error) {
|
|
if channel < 0 || channel >= 18 {
|
|
return false, 0, errors.New("channel number out of range 0..17")
|
|
}
|
|
return d.on[channel], d.brightness[channel], nil
|
|
}
|
|
|
|
// Switch switched the channel (0..18) to state (on/off).
|
|
func (d *Dev) Switch(channel int, state bool) error {
|
|
if channel < 0 || channel >= 18 {
|
|
return errors.New("channel number out of range 0..17")
|
|
}
|
|
d.on[channel] = state
|
|
return d.updateStates()
|
|
}
|
|
|
|
// SwitchAll switches all channels according to the state (on/off).
|
|
func (d *Dev) SwitchAll(state bool) error {
|
|
for i := 0; i < 18; i++ {
|
|
d.on[i] = state
|
|
}
|
|
return d.updateStates()
|
|
}
|
|
|
|
// Brightness sets the brightness of led (0..17) to value (0..255).
|
|
func (d *Dev) Brightness(channel int, value byte) error {
|
|
if channel < 0 || channel >= 18 {
|
|
return errors.New("channel number out of range 0..17")
|
|
}
|
|
d.brightness[channel] = value
|
|
return d.updateBrightness()
|
|
}
|
|
|
|
// BrightnessAll sets the brightness of all channels to the value (0..255).
|
|
func (d *Dev) BrightnessAll(value byte) error {
|
|
for i := 0; i < 18; i++ {
|
|
d.brightness[i] = value
|
|
}
|
|
return d.updateBrightness()
|
|
}
|
|
|
|
// Reset resets the registers to the default values.
|
|
func (d *Dev) reset() error {
|
|
_, err := d.i2c.Write([]byte{cmdReset, 0xFF})
|
|
d.on = [18]bool{}
|
|
d.brightness = [18]byte{}
|
|
return err
|
|
}
|
|
|
|
func (d *Dev) stateArrayToInt() uint {
|
|
var result uint
|
|
for i := uint(0); i < uint(18); i++ {
|
|
state := uint(1)
|
|
if !d.on[i] {
|
|
state = uint(0)
|
|
}
|
|
result |= (state << i)
|
|
}
|
|
return result
|
|
}
|
|
|
|
func (d *Dev) update() error {
|
|
_, err := d.i2c.Write([]byte{cmdUpdate, 0xFF})
|
|
return err
|
|
}
|
|
|
|
func (d *Dev) updateStates() error {
|
|
mask := d.stateArrayToInt()
|
|
cmd := [...]byte{cmdEnableLeds, byte(mask & 0x3F), byte((mask >> 6) & 0x3F), byte((mask >> 12) & 0x3F)}
|
|
if _, err := d.i2c.Write(cmd[:]); err != nil {
|
|
return err
|
|
}
|
|
return d.update()
|
|
}
|
|
|
|
func (d *Dev) updateBrightness() error {
|
|
cmd := [19]byte{cmdSetBrightnessValues}
|
|
copy(cmd[1:], d.brightness[:])
|
|
if _, err := d.i2c.Write(cmd[:]); err != nil {
|
|
return err
|
|
}
|
|
return d.update()
|
|
}
|