@ -3,19 +3,18 @@
// that can be found in the LICENSE file.
// that can be found in the LICENSE file.
// Package cap1188 controls a Microchip cap1188 device over I²C.
// Package cap1188 controls a Microchip cap1188 device over I²C.
// The device is a 8 Channel Capacitive Touch Sensor with 8 LED Drivers
//
// The cap1188 device is a 8 channel capacitive touch sensor with 8 LED drivers.
//
//
// Datasheet
// Datasheet
//
//
// The official data sheet can be found here:
// The official data sheet can be found here:
//
//
// http://ww1.microchip.com/downloads/en/DeviceDoc/CAP1188.pdf
// http://ww1.microchip.com/downloads/en/DeviceDoc/CAP1188.pdf
//
package cap1188
package cap1188
import (
import (
"encoding/binary"
"encoding/binary"
"errors"
"fmt"
"fmt"
"log"
"log"
"time"
"time"
@ -24,71 +23,48 @@ import (
"periph.io/x/periph/conn/gpio"
"periph.io/x/periph/conn/gpio"
"periph.io/x/periph/conn/i2c"
"periph.io/x/periph/conn/i2c"
"periph.io/x/periph/conn/mmr"
"periph.io/x/periph/conn/mmr"
"periph.io/x/periph/conn/spi"
"periph.io/x/periph/devices"
"periph.io/x/periph/devices"
)
)
// TouchStatus is the status of an input sensor
// TouchStatus is the status of an input sensor .
type TouchStatus int8
type TouchStatus int8
func ( t TouchStatus ) String ( ) string {
switch t {
case OffStatus :
return strOffStatus
case PressedStatus :
return strPressedStatus
case HeldStatus :
return strHeldStatus
case ReleasedStatus :
return strReleasedStatus
default :
return "Unknown"
}
}
const (
const (
// OffStatus indicates that the input sensor isn't being activated
// OffStatus indicates that the input sensor isn't being activated.
OffStatus TouchStatus = iota
OffStatus TouchStatus = iota
// PressedStatus indicates that the input sensor is currently pressed
// PressedStatus indicates that the input sensor is currently pressed.
PressedStatus
PressedStatus
// HeldStatus indicates that the input sensor was pressed and is still held pressed
// HeldStatus indicates that the input sensor was pressed and is still held
// pressed.
HeldStatus
HeldStatus
// ReleasedStatus indicates that the input sensor was pressed and is being released
// ReleasedStatus indicates that the input sensor was pressed and is being
// released.
ReleasedStatus
ReleasedStatus
)
)
const (
const touchStatusName = "OffStatusPressedStatusHeldStatusReleasedStatus"
nbrOfLEDs = 8
strOffStatus = "Off"
strPressedStatus = "Pressed"
strHeldStatus = "Held"
strReleasedStatus = "Released"
)
const (
var touchStatusIndex = [ ... ] uint8 { 0 , 9 , 22 , 32 , 46 }
// regLEDLinking - The Sensor Input LED Linking register controls whether a
// capacitive touch sensor input is linked to an LED output. If the
func ( i TouchStatus ) String ( ) string {
// corresponding bit is set, then the appropriate LED output will change
if i < 0 || i >= TouchStatus ( len ( touchStatusIndex ) - 1 ) {
// states defined by the LED Behavior controls in response to the capacitive
return fmt . Sprintf ( "TouchStatus(%d)" , i )
// touch sensor input.
}
regLEDLinking = 0x72
return touchStatusName [ touchStatusIndex [ i ] : touchStatusIndex [ i + 1 ] ]
// regLEDOutputControl - The LED Output Control Register controls the output
}
// state of the LED pins that are not linked to sensor inputs.
regLEDOutputControl = 0x74
)
// Dev is a handle to a cap1188.
// Dev is a handle to a cap1188.
type Dev struct {
type Dev struct {
Opts
c mmr . Dev8
d conn . Conn
opts Opts
regWrapper mmr . Dev8
isSPI bool
isSPI bool
inputStatuses [ ] TouchStatus
inputStatuses [ 8 ] TouchStatus
resetAt time . Time
lastReset time . Time
}
}
func ( d * Dev ) String ( ) string {
func ( d * Dev ) String ( ) string {
return fmt . Sprintf ( "cap1188{%s}" , d . regWrapper . Conn )
return fmt . Sprintf ( "cap1188{%s}" , d . c . Conn )
}
}
// Halt is a noop for the cap1188.
// Halt is a noop for the cap1188.
@ -96,49 +72,40 @@ func (d *Dev) Halt() error {
return nil
return nil
}
}
// InputStatus reads and returns the status of the 8 inputs as an array where
// InputStatus reads and returns the status of the 8 inputs.
// each entry indicates a touch event or not.
func ( d * Dev ) InputStatus ( ) ( [ 8 ] TouchStatus , error ) {
func ( d * Dev ) InputStatus ( ) ( [ ] TouchStatus , error ) {
d . resetSinceAtLeast ( 200 * time . Millisecond )
// first check that we are ready
// Read inputs.
now := time . Now ( )
status , err := d . c . ReadUint8 ( 0x3 )
readyAt := d . resetAt . Add ( 200 * time . Millisecond )
if now . Before ( readyAt ) {
time . Sleep ( readyAt . Sub ( now ) )
}
// read inputs
status , err := d . regWrapper . ReadUint8 ( 0x3 )
if err != nil {
if err != nil {
return d . inputStatuses , wrap ( fmt . Errorf ( "failed to read the input values - %s" , err ) )
return d . inputStatuses , wrapf ( "failed to read the input values: %v" , err )
}
}
// read deltas (in two's complement, capped at -128 to 127)
// Read deltas (in two's complement, capped at -128 to 127).
deltasB := [ nbrOfLEDs ] byte { }
//deltasB := [len(d.inputStatuses)]byte{}
if err = d . regWrapper . ReadStruct ( 0x10 , & deltasB ) ; err != nil {
//if err = d.c.ReadStruct(0x10, &deltasB); err != nil {
return d . inputStatuses , wrap ( fmt . Errorf ( "failed to read the delta values - %s" , err ) )
// return d.inputStatuses, wrapf("failed to read the delta values: %v", err)
}
//}
deltas := [ nbrOfLEDs ] int { }
//deltas := [len(d.inputStatuses)]int{}
for i , b := range deltasB {
//for i, b := range deltasB {
deltas [ i ] = int ( int8 ( b ) )
// deltas[i] = int(int8(b))
}
//}
// Read thresholds.
// read threshold
//thresholds := [len(d.inputStatuses)]byte{}
thresholds := [ nbrOfLEDs ] byte { }
//if err = d.c.ReadStruct(0x30, &thresholds); err != nil {
if err = d . regWrapper . ReadStruct ( 0x30 , & thresholds ) ; err != nil {
// return d.inputStatuses, wrapf("failed to read the threshold values: %v", err)
return d . inputStatuses , wrap ( fmt . Errorf ( "failed to read the threshold values - %s" , err ) )
//}
}
// Convert the data into a sensor state.
// convert the data into a sensor state
var touched bool
for i := uint8 ( 0 ) ; i < uint8 ( len ( d . inputStatuses ) ) ; i ++ {
for i := uint8 ( 0 ) ; i < uint8 ( len ( d . inputStatuses ) ) ; i ++ {
// check if the bit is set.
// Check if the bit is set.
touched = ( status >> ( 7 - i ) ) & 1 == 1
// TODO(mattetti): check if the event is passed the threshold:
// TODO(mattetti): check if the event is passed the threshold:
// deltas[i] > int(thresholds[i])
// deltas[i] > int(thresholds[i])
if touched {
// If the bit is set, it was touched.
if status & ( 1 << ( 7 - i ) ) != 0 {
if d . inputStatuses [ i ] == PressedStatus {
if d . inputStatuses [ i ] == PressedStatus {
if d . RetriggerOnHold {
if d . opts. RetriggerOnHold {
d . inputStatuses [ i ] = HeldStatus
d . inputStatuses [ i ] = HeldStatus
}
}
continue
continue
@ -156,369 +123,396 @@ func (d *Dev) InputStatus() ([]TouchStatus, error) {
// Doing so, disabled the option for the host to set specific LEDs on/off.
// Doing so, disabled the option for the host to set specific LEDs on/off.
func ( d * Dev ) LinkLEDs ( on bool ) error {
func ( d * Dev ) LinkLEDs ( on bool ) error {
if on {
if on {
if err := d . regWrapper . WriteUint8 ( regLEDLinking , 0xff ) ; err != nil {
if err := d . c . WriteUint8 ( regLEDLinking , 0xff ) ; err != nil {
return wrap ( fmt . Errorf ( "failed to link LEDs - %s" , err ) )
return wrap f( "failed to link LEDs: %v" , err )
}
}
} else {
} else {
if err := d . regWrapper . WriteUint8 ( regLEDLinking , 0x00 ) ; err != nil {
if err := d . c . WriteUint8 ( regLEDLinking , 0x00 ) ; err != nil {
return wrap ( fmt . Errorf ( "failed to unlink LEDs - %s" , err ) )
return wrap f( "failed to unlink LEDs: %v" , err )
}
}
}
}
d . LinkedLEDs = on
d . opts. LinkedLEDs = on
return nil
return nil
}
}
// AllLEDs turns all the LEDs on or off.
// AllLEDs turns all the LEDs on or off.
//
//
// This is quite more efficient than looping through each led and turn them on/off.
// This is quite more efficient than looping through each LED and turn them
// on/off.
func ( d * Dev ) AllLEDs ( on bool ) error {
func ( d * Dev ) AllLEDs ( on bool ) error {
if d . LinkedLEDs {
if d . opts. LinkedLEDs {
return wrap ( fmt . Error f( "can't manually set LEDs when they are linked to sensors" ) )
return wrap f( "can't manually set LEDs when they are linked to sensors" )
}
}
if on {
if on {
return d . regWrapper . WriteUint8 ( regLEDOutputControl , 0xff )
if err := d . c . WriteUint8 ( regLEDOutputControl , 0xff ) ; err != nil {
return wrapf ( "failed to turn all LEDs on: %v" , err )
}
}
}
if err := d . c . WriteUint8 ( regLEDOutputControl , 0x00 ) ; err != nil {
return d . regWrapper . WriteUint8 ( regLEDOutputControl , 0x00 )
return wrapf ( "failed to turn all LEDs off: %v" , err )
}
return nil
}
}
// SetLED sets the state of a LED as on or off
// SetLED sets the state of a LED as on or off.
//
// Only works if the LEDs are not linked to the sensors
// Only works if the LEDs are not linked to the sensors
func ( d * Dev ) SetLED ( idx int , state bool ) error {
func ( d * Dev ) SetLED ( idx int , state bool ) error {
if d . LinkedLEDs {
if d . opts. LinkedLEDs {
return wrap ( fmt . Error f( "can't manually set LEDs when they are linked to sensors" ) )
return wrap f( "can't manually set LEDs when they are linked to sensors" )
}
}
if idx > 7 || idx < 0 {
if idx > 7 || idx < 0 {
return wrap ( fmt . Error f( "invalid led idx %d" , idx ) )
return wrap f( "invalid led idx %d" , idx )
}
}
if d . Debug {
if d . opts. Debug {
log . Printf ( " Set LED state %d - %t\n ", idx , state )
log . Printf ( " cap1188: Set LED state %d - %t", idx , state )
}
}
if state {
if state {
return d . setBit ( regLEDOutputControl , idx )
if err := d . setBit ( regLEDOutputControl , idx ) ; err != nil {
return wrapf ( "failed to set LED #%d to %t: %v" , idx , state , err )
}
}
if err := d . clearBit ( regLEDOutputControl , idx ) ; err != nil {
return wrapf ( "failed to set LED #%d to %t: %v" , idx , state , err )
}
}
return d . clearBit ( regLEDOutputControl , idx )
return nil
}
}
// Reset issues a soft reset to the device using the reset pin
// Reset issues a soft reset to the device using the reset pin if available.
// if available.
func ( d * Dev ) Reset ( ) error {
func ( d * Dev ) Reset ( ) error {
if err := d . ClearInterrupt ( ) ; err != nil {
if err := d . ClearInterrupt ( ) ; err != nil {
return err
return err
}
}
if d != nil && d . ResetPin != nil {
if d . opts . ResetPin != nil {
if d . Debug {
if d . opts. Debug {
log . Println ( "cap1188: Resetting the device using the reset pin" )
log . Println ( "cap1188: Resetting the device using the reset pin" )
}
}
if err := d . ResetPin. Out ( gpio . Low ) ; err != nil {
if err := d . opts. ResetPin. Out ( gpio . Low ) ; err != nil {
return err
return wrapf ( "failed to set reset pin low: %v" , err )
}
}
time . S leep( 1 * time . Microsecond )
s leep( 1 * time . Microsecond )
if err := d . ResetPin. Out ( gpio . High ) ; err != nil {
if err := d . opts. ResetPin. Out ( gpio . High ) ; err != nil {
return err
return wrapf ( "failed to set reset pin high: %v" , err )
}
}
time . S leep( 10 * time . Millisecond )
s leep( 10 * time . Millisecond )
if err := d . ResetPin. Out ( gpio . Low ) ; err != nil {
if err := d . opts. ResetPin. Out ( gpio . Low ) ; err != nil {
return err
return wrapf ( "failed to set reset pin low: %v" , err )
}
}
}
}
// Track the reset time since the device won't be ready for up to 15ms
// Track the reset time since the device won't be ready for up to 15ms and
// and won't be ready for first conversion for up to 200ms.
// won't be ready for first conversion for up to 200ms.
d . resetAt = time . Now ( )
d . lastReset = time . Now ( )
// Time to communications is 15ms.
sleep ( 15 * time . Millisecond )
return nil
return nil
}
}
// ClearInterrupt resets the interrupt flag
// ClearInterrupt resets the interrupt flag .
func ( d * Dev ) ClearInterrupt ( ) error {
func ( d * Dev ) ClearInterrupt ( ) error {
// clear the main control bit
// Clear the main control bit.
return d . clearBit ( 0x0 , 0 )
if err := d . clearBit ( 0x0 , 0 ) ; err != nil {
return wrapf ( "failed to clean interrupt: %v" )
}
return nil
}
}
// NewI2C returns a new device that communicates over I²C to cap1188.
// NewI2C returns a new device that communicates over I²C to cap1188.
//
// Use default options if nil is used.
func NewI2C ( b i2c . Bus , opts * Opts ) ( * Dev , error ) {
func NewI2C ( b i2c . Bus , opts * Opts ) ( * Dev , error ) {
addr := uint16 ( 0x28 ) // default address
if opts == nil {
if opts != nil {
opts = DefaultOpts ( )
switch opts . Address {
case 0x28 , 0x29 , 0x2a , 0x2b , 0x2c :
addr = opts . Address
case 0x00 :
// do not do anything
default :
return nil , wrap ( errors . New ( "given address not supported by device" ) )
}
}
}
d := & Dev { d : & i2c . Dev { Bus : b , Addr : addr } , isSPI : false }
addr , err := opts . i2cAddr ( )
if d. Debug {
if err != nil {
log . Printf ( "cap1188: Connecting via I2C address: %#X\n" , add r)
return nil , wrapf ( "%v" , err )
}
}
d .inputStatuses = make ( [ ] TouchStatus , nbrOfLED s)
d , err := makeDev ( & i2c . Dev { Bus : b , Addr : addr } , false , opts )
if err := d . makeDev ( opts ) ; err != nil {
if err != nil {
return nil , err
return nil , err
}
}
// time to communications is 15ms
log . Printf ( "cap1188: Connected via I²C address: %#x" , addr )
now := time . Now ( )
readyAt := d . resetAt . Add ( 15 * time . Millisecond )
if now . Before ( readyAt ) {
time . Sleep ( readyAt . Sub ( now ) )
}
return d , nil
return d , nil
}
}
/ *
// NewSPI returns an object that communicates over SPI to cap1188 environmental
// NewSPI returns an object that communicates over SPI to cap1188 environmental
// sensor.
// sensor.
//
// TODO(mattetti): Expose once implemented and tested.
func NewSPI ( p spi . Port , opts * Opts ) ( * Dev , error ) {
func NewSPI ( p spi . Port , opts * Opts ) ( * Dev , error ) {
return nil , fmt . Errorf ( "not implemented" )
return nil , fmt . Errorf ( " cap1188: not implemented")
}
}
* /
func ( d * Dev ) makeDev ( opts * Opts ) error {
//
// Use default options if none are passed.
if opts == nil {
func makeDev ( c conn . Conn , isSPI bool , opts * Opts ) ( * Dev , error ) {
opts = DefaultOpts ( )
d := & Dev {
opts : * opts ,
isSPI : isSPI ,
c : mmr . Dev8 { Conn : c , Order : binary . LittleEndian } ,
}
}
d . Opts = * opts
d . regWrapper = mmr . Dev8 { Conn : d . d , Order : binary . LittleEndian }
var productID byte
var err error
// Read the product id to confirm it matches our expectations.
// Read the product id to confirm it matches our expectations.
if productID , err = d . regWrapper . ReadUint8 ( 0xFD ) ; err != nil {
if productID , err := d . c . ReadUint8 ( 0xFD ) ; err != nil {
return fmt . Errorf ( "failed to read product id - %s" , err )
return nil , wrapf ( "failed to read product id: %v" , err )
}
} else if productID != 0x50 {
if productID != 0x50 {
return nil , wrapf ( "unexpected chip id %x; is this a cap1188?" , productID )
return fmt . Errorf ( "cap1188: unexpected chip id %x; is this a cap1188?" , productID )
}
}
// manufacturer ID on 0xFE, should be 0x5D
// manufacturer ID on 0xFE, should be 0x5D
// revision ID on 0xFF, should be 0x83
// revision ID on 0xFF, should be 0x83
// reset the device
// Reset the device.
if err = d . Reset ( ) ; err != nil {
if err : = d . Reset ( ) ; err != nil {
return fmt . Errorf ( "failed to reset the device - %s" , err )
return nil , err
}
}
var recalFlag byte
var recalFlag byte
if opts. EnableRecalibration {
if d. opts. EnableRecalibration {
recalFlag = 1
recalFlag = 1
}
}
var intOnRel byte
var intOnRel byte
if ! opts. InterruptOnRelease {
if ! d. opts. InterruptOnRelease {
intOnRel = 1 // 0 = trigger on release
intOnRel = 1 // 0 = trigger on release
}
}
// enable all inputs
// Enable all inputs.
if err = d . regWrapper . WriteUint8 ( 0x21 , 0xff ) ; err != nil {
if err := d . c . WriteUint8 ( 0x21 , 0xff ) ; err != nil {
return wrap ( fmt . Errorf ( "failed to enable all inputs - %s" , err ) )
return nil , wrapf ( "failed to enable all inputs: %v" , err )
}
}
// enable interrupts
// Enable interrupts.
if err = d . regWrapper . WriteUint8 ( 0x27 , 0xff ) ; err != nil {
if err := d . c . WriteUint8 ( 0x27 , 0xff ) ; err != nil {
return wrap ( fmt . Errorf ( "failed to enable interrupts - %s" , err ) )
return nil , wrapf ( "failed to enable interrupts: %v" , err )
}
}
// enable/disable repeats
// Enable/disable repeats.
// TODO(mattetti): make it an option
// TODO(mattetti): make it an option .
if err = d . regWrapper . WriteUint8 ( 0x28 , 0xff ) ; err != nil {
if err := d . c . WriteUint8 ( 0x28 , 0xff ) ; err != nil {
return fmt . Errorf ( "failed to disable repeats - %s ", err )
return nil , wrapf ( "failed to disable repeats: %v ", err )
}
}
// enable multitouch
// Enable multitouch.
multitouchConfig := (
multitouchConfig := (
// Enables the multiple button blocking circuitry.
// Enables the multiple button blocking circuitry.
// ‘ 0’ - The multiple touch circuitry is disabled. The device will not
// - 0: The multiple touch circuitry is disabled. The device will not block
// block multiple touches.
// multiple touches.
// ‘ 1’ (default) - The multiple touch circuitry is enabled. The device
// - 1 (default): The multiple touch circuitry is enabled. The device will
// will flag the number of touches equal to programmed multiple touch
// flag the number of touches equal to programmed multiple touch threshold
// threshold and block all others. It will remember which sensor inputs
// and block all others. It will remember which sensor inputs are valid and
// are valid and block all others until that sensor pad has been
// block all others until that sensor pad has been released. Once a sensor
// released. Once a sensor pad has been released, the N detected touches
// pad has been released, the N detected touches (determined via the cycle
// (determined via the cycle order of CS1 - CS8) will be flagged and all
// order of CS1 - CS8) will be flagged and all others blocked.
// others blocked.
byte ( 0 ) << 7 |
byte ( 0 ) << 7 |
byte ( 0 ) << 6 | byte ( 0 ) << 5 | byte ( 0 ) << 4 |
byte ( 0 ) << 6 | byte ( 0 ) << 5 | byte ( 0 ) << 4 |
// Determines the number of simultaneous touches on all sensor pads
// Determines the number of simultaneous touches on all sensor pads before
// before a Multiple Touch Event is detected and sensor inputs are blocked.
// a Multiple Touch Event is detected and sensor inputs are blocked.
// set to 2
// Set to 2.
byte ( 0 ) << 3 | byte ( 1 ) << 2 |
byte ( 0 ) << 3 | byte ( 1 ) << 2 |
byte ( 0 ) << 1 | byte ( 0 ) << 0 )
byte ( 0 ) << 1 | byte ( 0 ) << 0 )
if err = d . regWrapper . WriteUint8 ( 0x2a , multitouchConfig ) ; err != nil {
if err := d . c . WriteUint8 ( 0x2a , multitouchConfig ) ; err != nil {
return wrap ( fmt . Errorf ( "failed to enable multitouch - %s" , err ) )
return nil , fmt . Errorf ( "failed to enable multitouch: %v" , err )
}
}
// Averaging and Sampling Config
// Averaging and Sampling Config .
samplingConfig := ( byte ( 0 ) << 7 |
samplingConfig := ( byte ( 0 ) << 7 |
// number of samples taken per measurement
// Number of samples taken per measurement.
// TODO(mattetti): use opts.SamplesPerMeasurement
// TODO(mattetti): use d. opts.SamplesPerMeasurement
byte ( 0 ) << 6 |
byte ( 0 ) << 6 |
byte ( 0 ) << 5 |
byte ( 0 ) << 5 |
byte ( 0 ) << 4 |
byte ( 0 ) << 4 |
// sample time
// Sample time.
// TODO(mattetti): use opts.SamplingTime
// TODO(mattetti): use d. opts.SamplingTime
byte ( 1 ) << 3 |
byte ( 1 ) << 3 |
byte ( 0 ) << 2 |
byte ( 0 ) << 2 |
// overall cycle time
// Overall cycle time.
// TODO(mattetti): use opts.CycleTime
// TODO(mattetti): use d. opts.CycleTime
byte ( 0 ) << 1 |
byte ( 0 ) << 1 |
byte ( 0 ) << 0 )
byte ( 0 ) << 0 )
if d . Debug {
if d . opts. Debug {
log . Printf ( "cap1188: Sampling config mask: %08b \n ", samplingConfig )
log . Printf ( "cap1188: Sampling config mask: %08b ", samplingConfig )
}
}
if err = d . regWrapper . WriteUint8 ( 0x24 , samplingConfig ) ; err != nil {
if err := d . c . WriteUint8 ( 0x24 , samplingConfig ) ; err != nil {
return fmt . Errorf ( "failed to enable multitouch - %s ", err )
return nil , wrapf ( "failed to enable multitouch: %v ", err )
}
}
// customize sensitivity (TODO)
// Customize sensitivity.
sensitivity := ( byte ( 0 ) << 7 |
sensitivity := ( byte ( 0 ) << 7 |
// Controls the sensitivity of a touch detection. The sensitivity settings act
// Controls the sensitivity of a touch detection. The sensitivity settings
// to scale the relative delta count value higher or lower based on the system parameters. A setting of
// act to scale the relative delta count value higher or lower based on the
// 000b is the most sensitive while a setting of 111b is the least sensitive. At the more sensitive settings,
// system parameters. A setting of 000b is the most sensitive while a
// touches are detected for a smaller delta capacitance corresponding to a “lighter” touch. These settings
// setting of 111b is the least sensitive. At the more sensitive settings,
// are more sensitive to noise, however, and a noisy environment may flag more false touches with higher
// touches are detected for a smaller delta capacitance corresponding to a
// “lighter” touch. These settings are more sensitive to noise, however,
// and a noisy environment may flag more false touches with higher
// sensitivity levels.
// sensitivity levels.
// Set to 4x
// Set to 4x .
// TODO(mattetti): make that configurable.
// TODO(mattetti): make that configurable.
byte ( 1 ) << 6 | byte ( 0 ) << 5 | byte ( 1 ) << 4 |
byte ( 1 ) << 6 | byte ( 0 ) << 5 | byte ( 1 ) << 4 |
byte ( 0 ) << 3 | byte ( 0 ) << 2 | byte ( 0 ) << 1 | byte ( 0 ) << 0 )
byte ( 0 ) << 3 | byte ( 0 ) << 2 | byte ( 0 ) << 1 | byte ( 0 ) << 0 )
if d . Debug {
if d . opts. Debug {
log . Printf ( "cap1188: Sensitivity mask: %08b \n ", sensitivity )
log . Printf ( "cap1188: Sensitivity mask: %08b ", sensitivity )
}
}
if err = d . regWrapper . WriteUint8 ( 0x1F , sensitivity ) ; err != nil {
if err := d . c . WriteUint8 ( 0x1F , sensitivity ) ; err != nil {
return fmt . Errorf ( "failed to set sensitivity - %s ", err )
return nil , wrapf ( "failed to set sensitivity: %v ", err )
}
}
if opts. LinkedLEDs {
if d. opts. LinkedLEDs {
if err = d . LinkLEDs ( true ) ; err != nil {
if err : = d . LinkLEDs ( true ) ; err != nil {
return err
return nil , err
}
}
}
}
if opts. RetriggerOnHold {
if d. opts. RetriggerOnHold {
if err = d . regWrapper . WriteUint8 ( 0x28 , 0xff ) ; err != nil {
if err := d . c . WriteUint8 ( 0x28 , 0xff ) ; err != nil {
return fmt . Errorf ( "failed to set retrigger on hold - %s ", err )
return nil , wrapf ( "failed to set retrigger on hold: %v ", err )
}
}
} else {
} else {
if err = d . regWrapper . WriteUint8 ( 0x28 , 0x00 ) ; err != nil {
if err := d . c . WriteUint8 ( 0x28 , 0x00 ) ; err != nil {
return fmt . Errorf ( "failed to turn off retrigger on hold - %s ", err )
return nil , wrapf ( "failed to turn off retrigger on hold: %v ", err )
}
}
}
}
// page 47 - configuration registers
// page 47 - configuration registers
config := (
config := (
// Timeout: Enables the timeout and idle functionality of the SMBus protocol.
// Timeout: Enables the timeout and idle functionality of the SMBus protocol.
// default 0 : The SMBus timeout and idle functionality are disabled. The
// - 0 (default) : The SMBus timeout and idle functionality are disabled. The
// SMBus interface will not time out if the clock line is held low.
// SMBus interface will not time out if the clock line is held low.
// Likewise, it will not reset if both data and clock lines are held
// Likewise, it will not reset if both data and clock lines are held high
// high for longer than 200us
// for longer than 200us
byte ( 0 ) << 7 |
byte ( 0 ) << 7 |
// Configures the operation of the WAKE pin.
// Configures the operation of the WAKE pin.
// default 0 : The WAKE pin is not asserted when a touch is detected while the
// - 0 (default) : The WAKE pin is not asserted when a touch is detected
// device is in Standby. It will still be used to wake the device from
// while the device is in Standby. It will still be used to wake the
// Deep Sleep when driven high.
// device from Deep Sleep when driven high.
byte ( 0 ) << 6 |
byte ( 0 ) << 6 |
// digital noise threshold
// Digital noise threshold.
// Determines whether the digital noise threshold is used by the device.
// Determines whether the digital noise threshold is used by the device.
// default 1: The noise threshold is disabled. Any delta count that
// - 1 (default): The noise threshold is disabled. Any delta count that is
// is less than the touch threshold is used for the automatic
// less than the touch threshold is used for the automatic re-calibration
// re-calibration routine.
// routine.
byte ( 1 ) << 5 |
byte ( 1 ) << 5 |
// analog noise filter
// Analog noise filter.
// default 0: Determines whether the analog noise filter is enabled. Setting this
// - 0 (default): The analog noise filter is enabled.
// bit d isables the feature.
// - 1: D isables the feature.
byte ( 1 ) << 4 |
byte ( 1 ) << 4 |
// maximum duration recalibration
// Maximum duration recalibration.
// Determines whether the maximum duration recalibration is enabled.
// Determines whether the maximum duration recalibration is enabled.
//
// - 0: The maximum duration recalibration functionality is disabled. A
// if 0, the maximum duration recalibration functionality is
// touch may be held indefinitely and no re-calibration will be performed
// disabled. A touch may be held indefinitely and no re-calibration
// on any sensor input.
// will be performed on any sensor input.
// - 1: The maximum duration recalibration functionality is enabled. If a
//
// touch is held for longer than the d.opts.MaxTouchDuration, then the
// if 1, The maximum duration recalibration functionality is
// re-calibration routine will be restarted.
// enabled. If a touch is held for longer than the
// opts.MaxTouchDuration, then the re-calibration routine will be
// restarted
recalFlag << 3 |
recalFlag << 3 |
byte ( 0 ) << 2 |
byte ( 0 ) << 2 |
byte ( 0 ) << 1 |
byte ( 0 ) << 1 |
byte ( 0 ) << 0 )
byte ( 0 ) << 0 )
if d . Debug {
if d . opts. Debug {
log . Printf ( "cap1188: Config mask: %08b \n ", config )
log . Printf ( "cap1188: Config mask: %08b ", config )
}
}
if err = d . regWrapper . WriteUint8 ( 0x20 , config ) ; err != nil {
if err := d . c . WriteUint8 ( 0x20 , config ) ; err != nil {
return fmt . Errorf ( "failed to set the device configuration - %s ", err )
return nil , wrapf ( "failed to set the device configuration: %v ", err )
}
}
config2 := (
config2 := (
// Linked LED Transition controls
// Linked LED Transition controls .
// default 0 : The Linked LED Transition controls set the min duty
// - 0 (default) : The Linked LED Transition controls set the min duty cycle
// cycle equal to the max duty cycle
// equal to the max duty cycle.
byte ( 0 ) << 7 |
byte ( 0 ) << 7 |
// Determines the ALERT# pin polarity and behavior.
// Determines the ALERT# pin polarity and behavior.
// default 1: t he ALERT# pin is active low and open drain.
// - 1 (default): T he ALERT# pin is active low and open drain.
byte ( 1 ) << 6 |
byte ( 1 ) << 6 |
// Determines whether the device will reduce power consumption
// Determines whether the device will reduce power consumption while
// w hile w aiting between conversion time completion and the end of
// w aiting between conversion time completion and the end of the polling
// the polling cycle.
// cycle.
// default 0 : The device will always power down as much as possible
// - 0 (default) : The device will always power down as much as possible
// during the time between the end of the last conversion and the
// during the time between the end of the last conversion and the end of
// end of the polling cycle.
// the polling cycle.
byte ( 1 ) << 5 |
byte ( 1 ) << 5 |
// Determines whether the LED Mirror Control register bits are
// Determines whether the LED Mirror Control register bits are linked to
// linked to the LED Polarity bits. Setting this bit blocks the
// the LED Polarity bits. Setting this bit blocks the normal behavior which
// normal behavior which is to automatically set and clear the LED
// is to automatically set and clear the LED Mirror Control bits when the
// Mirror Control bits when the LED Polarity bits are set or
// LED Polarity bits are set or cleared.
// cleared.
// - 0 (default): When the LED Polarity controls are set, the corresponding
// default 0: When the LED Polarity controls are set, the
// LED Mirror control is automatically set. Likewise, when the LED
// corresponding LED Mirror control is automatically set. Likewise,
// Polarity controls are cleared, the corresponding LED Mirror control is
// when the LED Polarity controls are cleared, the corresponding
// also cleared.
// LED Mirror control is also cleared.
byte ( 0 ) << 4 |
byte ( 0 ) << 4 |
// Determines whether the Noise Status bits will show RF Noise as
// Determines whether the Noise Status bits will show RF Noise as the only
// the only input source.
// input source.
// default 0 : The Noise Status registers will show both RF noise and
// - 0 (default) : The Noise Status registers will show both RF noise and low
// low frequency EMI noise if either is detected on a capacitive
// frequency EMI noise if either is detected on a capacitive touch sensor
// touch sensor input.
// input.
byte ( 0 ) << 3 |
byte ( 0 ) << 3 |
// Determines whether the RF noise filter is enabled.
// Determines whether the RF noise filter is enabled.
// default 0: If RF noise is detected by the analog block, the
// - 0 (default): If RF noise is detected by the analog block, the delta
// delta count on the corresponding channel is set to 0. Note that
// count on the corresponding channel is set to 0. Note that this does
// this does not require that Noise Status bits be set.
// not require that Noise Status bits be set.
byte ( 0 ) << 2 |
byte ( 0 ) << 2 |
byte ( 0 ) << 1 |
byte ( 0 ) << 1 |
// Controls the interrupt behavior when a release is detected on a button.
// Controls the interrupt behavior when a release is detected on a button.
// when 0: An interrupt is generated when a press is detected and
// - 0: An interrupt is generated when a press is detected and again when a
// again when a release is detected and at the repeat rate (if enabled)
// release is detected and at the repeat rate (if enabled)
// when 1: An interrupt is generated when a press is detected and
// - 1: An interrupt is generated when a press is detected and at the
// at the repeat rate but not when a release is detected.
// repeat rate but not when a release is detected.
intOnRel << 0 )
intOnRel << 0 )
if d . Debug {
if d . opts. Debug {
log . Printf ( "cap1188: Config2 mask: %08b \n ", config2 )
log . Printf ( "cap1188: Config2 mask: %08b ", config2 )
}
}
if err = d . regWrapper . WriteUint8 ( 0x44 , config2 ) ; err != nil {
if err := d . c . WriteUint8 ( 0x44 , config2 ) ; err != nil {
return fmt . Errorf ( "failed to set the device configuration 2 - %s ", err )
return nil , wrapf ( "failed to set the device configuration 2: %v ", err )
}
}
return nil
return d , nil
}
}
// setBit sets a specific bit on a register
func ( d * Dev ) resetSinceAtLeast ( t time . Duration ) {
// TODO(mattetti): avoid reading before writing, keep states in memory
readyAt := d . lastReset . Add ( t )
if now := time . Now ( ) ; now . Before ( readyAt ) {
sleep ( readyAt . Sub ( now ) )
}
}
// setBit sets a specific bit on a register.
//
// TODO(mattetti): avoid reading before writing, keep states in memory.
func ( d * Dev ) setBit ( regID uint8 , idx int ) error {
func ( d * Dev ) setBit ( regID uint8 , idx int ) error {
v , err := d . regWrapper . ReadUint8 ( regID )
v , err := d . c . ReadUint8 ( regID )
if err != nil {
if err != nil {
return err
return err
}
}
v |= ( 1 << uint8 ( idx ) )
v |= ( 1 << uint8 ( idx ) )
return d . regWrapper . WriteUint8 ( regID , v )
return d . c . WriteUint8 ( regID , v )
}
}
// clearBit clears a specific bit on a register
// clearBit clears a specific bit on a register.
// TODO(mattetti): avoid reading before writing, keep states in memory
//
// TODO(mattetti): avoid reading before writing, keep states in memory.
func ( d * Dev ) clearBit ( regID uint8 , idx int ) error {
func ( d * Dev ) clearBit ( regID uint8 , idx int ) error {
v , err := d . regWrapper . ReadUint8 ( regID )
v , err := d . c . ReadUint8 ( regID )
if err != nil {
if err != nil {
return err
return err
}
}
v &= ^ ( 1 << uint8 ( idx ) )
v &= ^ ( 1 << uint8 ( idx ) )
return d . regWrapper . WriteUint8 ( regID , v )
return d . c . WriteUint8 ( regID , v )
}
}
func wrap ( err error ) error {
//
return fmt . Errorf ( "cap1188: %v" , err )
const (
// regLEDLinking is the Sensor Input LED Linking register controls whether a
// capacitive touch sensor input is linked to an LED output. If the
// corresponding bit is set, then the appropriate LED output will change
// states defined by the LED Behavior controls in response to the capacitive
// touch sensor input.
regLEDLinking = 0x72
// regLEDOutputControl is the LED Output Control Register controls the output
// state of the LED pins that are not linked to sensor inputs.
regLEDOutputControl = 0x74
)
var sleep = time . Sleep
func wrapf ( format string , a ... interface { } ) error {
return fmt . Errorf ( "cap1188: " + format , a ... )
}
}
var _ devices . Device = & Dev { }
var _ devices . Device = & Dev { }