cap1188: refactor a bit. (#203)

- Make errors consistents.
- Standardize comments.
- Make unit test much faster by not sleeping.
- Reduce the number of properties of Dev.
  - Do not export Opts.
- Commented out I/O for unused data.
- Slightly reduce memory usage.
- Comment out NewSPI() since it is not implemented.
- Remove verbosity by default.
pull/1/head
M-A 8 years ago committed by GitHub
parent b46e37feba
commit 2f8171ed6c

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

@ -0,0 +1,77 @@
// Copyright 2017 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 cap1188_test
import (
"fmt"
"log"
"periph.io/x/periph/conn/gpio"
"periph.io/x/periph/conn/gpio/gpioreg"
"periph.io/x/periph/conn/i2c/i2creg"
"periph.io/x/periph/experimental/devices/cap1188"
)
func Example() {
// Open the I²C bus to which the cap1188 is connected.
i2cBus, err := i2creg.Open("")
if err != nil {
log.Fatal(err)
}
defer i2cBus.Close()
// We need to set an alert ping that will let us know when a touch event
// occurs. The alert pin is the pin connected to the IRQ/interrupt pin.
alertPin := gpioreg.ByName("GPIO25")
if alertPin == nil {
log.Fatal("invalid alert GPIO pin number")
}
// We set the alert pin to monitor for interrupts.
if err := alertPin.In(gpio.PullUp, gpio.BothEdges); err != nil {
log.Fatalf("Can't monitor the alert pin")
}
// Optionally but highly recommended, we can also set a reset pin to
// start/leave things in a clean state.
resetPin := gpioreg.ByName("GPIO21")
if resetPin == nil {
log.Fatal("invalid reset GPIO pin number")
}
// We will configure the cap1188 by setting some options, we can start by the
// defaults.
opts := cap1188.DefaultOpts()
opts.AlertPin = alertPin
opts.ResetPin = resetPin
// Open the device so we can detect touch events.
dev, err := cap1188.NewI2C(i2cBus, opts)
if err != nil {
log.Fatalf("couldn't open cap1188: %v", err)
}
fmt.Println("Monitoring for touch events")
maxTouches := 42 // Stop the program after 42 touches.
for maxTouches > 0 {
if alertPin.WaitForEdge(-1) {
maxTouches--
statuses, err := dev.InputStatus()
if err != nil {
fmt.Printf("Error reading inputs: %v\n", err)
continue
}
// print the status of each sensor
for i, st := range statuses {
fmt.Printf("#%d: %s\t", i, st)
}
fmt.Println()
// we need to clear the interrupt so it can be triggered again
if err := dev.ClearInterrupt(); err != nil {
fmt.Println(err, "while clearing the interrupt")
}
}
}
fmt.Print("\n")
}

@ -4,25 +4,28 @@
package cap1188
import "periph.io/x/periph/conn/gpio"
import (
"errors"
// SamplingTime determines the time to take a single sample
"periph.io/x/periph/conn/gpio"
)
// SamplingTime determines the time to make a single sample.
type SamplingTime uint8
// Possible sampling time values (written as 2 bits)
// Possible sampling time values. (written as 2 bits)
const (
S320us SamplingTime = 0
S640us SamplingTime = 1
// S1_28ms represents 1.28ms sampling time, which is the default.
S1_28ms SamplingTime = 2 // default
S1_28ms SamplingTime = 2
S2_56ms SamplingTime = 3
)
// AvgSampling set the number of samples per measurement that get
// averaged
// AvgSampling set the number of samples per measurement that get averaged.
type AvgSampling uint8
// possible average sampling values. (written as 3 bits)
// Possible average sampling values. (written as 3 bits)
const (
// Avg1 means that 1 sample is taken per measurement
Avg1 AvgSampling = iota // 0
@ -39,7 +42,7 @@ const (
// normal operation.
type CycleTime uint8
// possible cycle time values. (written as 2 bits)
// Possible cycle time values. (written as 2 bits)
const (
C35ms CycleTime = iota // 0
C70ms // default
@ -51,7 +54,7 @@ const (
// recalibration.
type MaxDur uint8
// possible touch duration values. (written as 4 bits)
// Possible touch duration values. (written as 4 bits)
const (
MaxDur560ms MaxDur = iota
MaxDur840ms
@ -71,28 +74,26 @@ const (
MaxDur11200ms
)
// Opts is optional options to pass to the constructor.
//
// Address is only used on creation of an I²C-device. Its default value is 0x28.
// It can be set to other values (0x29, 0x2a, 0x2b, 0x2c) depending on the HW
// configuration of the ADDR_COMM pin. This has no effect with NewSPI()
// Opts is options to pass to the constructor.
type Opts struct {
// Address is the I2C slave address to use
Address uint16
// Debug turns on extra logging capabilities
// Debug turns on extra logging capabilities.
Debug bool
// I2CAddr is the I²C slave address to use. It can only used on creation of
// an I²C-device. Its default value is 0x28. It can be set to other values
// (0x29, 0x2a, 0x2b, 0x2c) depending on the HW configuration of the
// ADDR_COMM pin. Must not be set when used over SPI.
I2CAddr uint16
// LinkedLEDs indicates if the LEDs should be activated automatically
// when their sensors detect a touch event.
LinkedLEDs bool
// MaxTouchDuration sets the touch duration threshold. It is possible that a
// “stuck button” occurs when something is placed on a button which causes a
// touch to be detected for a long period. By setting this value,
// a recalibration can be forced when a touch is held on a button for longer
// touch to be detected for a long period. By setting this value, a
// recalibration can be forced when a touch is held on a button for longer
// than the duration specified.
MaxTouchDuration MaxDur
// EnableRecalibration is used to force the recalibration if a touch event lasts
// longer than MaxTouchDuration.
// EnableRecalibration is used to force the recalibration if a touch event
// lasts longer than MaxTouchDuration.
EnableRecalibration bool
// AlertPin is the pin receiving the interrupt when a touch event is detected
@ -105,11 +106,11 @@ type Opts struct {
// interrupt on the AlertPin when a release event is detected.
InterruptOnRelease bool
// RetriggerOnHold forces a retrigger of the interrupt when a sensor is pressed
// for longer than MaxTouchDuration
// RetriggerOnHold forces a retrigger of the interrupt when a sensor is
// pressed for longer than MaxTouchDuration
RetriggerOnHold bool
// Averaging and Sampling Configuration Register
// Averaging and Sampling Configuration Register.
// SamplesPerMeasurement is the number of samples taken per measurement. All
// samples are taken consecutively on the same channel before the next
@ -118,7 +119,7 @@ type Opts struct {
// Available options: 1, 2, 4, 8 (default), 16, 32, 64, 128
SamplesPerMeasurement AvgSampling
// SamplingTime Determines the time to take a single sample as shown
// SamplingTime Determines the time to take a single sample as shown.
SamplingTime SamplingTime
// CycleTime determines the overall cycle time for all measured channels
@ -129,6 +130,18 @@ type Opts struct {
CycleTime CycleTime
}
func (o *Opts) i2cAddr() (uint16, error) {
switch o.I2CAddr {
case 0:
// Default address.
return 0x28, nil
case 0x28, 0x29, 0x2a, 0x2b, 0x2c:
return o.I2CAddr, nil
default:
return 0, errors.New("given address not supported by device")
}
}
// DefaultOpts returns a pointer to a new Opts with the default option values.
func DefaultOpts() *Opts {
return &Opts{

@ -2,86 +2,20 @@
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.
package cap1188_test
package cap1188
import (
"fmt"
"flag"
"io/ioutil"
"log"
"reflect"
"testing"
"time"
"periph.io/x/periph/conn/gpio"
"periph.io/x/periph/conn/gpio/gpioreg"
"periph.io/x/periph/conn/i2c"
"periph.io/x/periph/conn/i2c/i2creg"
"periph.io/x/periph/conn/i2c/i2ctest"
"periph.io/x/periph/experimental/devices/cap1188"
)
func Example() {
// Open the I²C bus to which the cap1188 is connected.
i2cBus, err := i2creg.Open("")
if err != nil {
log.Fatal(err)
}
defer i2cBus.Close()
// We will configure the cap1188 by setting some options, we can start by the defaults.
opts := cap1188.DefaultOpts()
// We need to set an alert ping that will let us know when a touch event
// occurs. The alert pin is the pin connected to the IRQ/interrupt pin.
alertPin := gpioreg.ByName("GPIO25")
if alertPin == nil {
log.Fatal("invalid alert GPIO pin number")
}
// We set the alert pin to monitor for interrupts
if err := alertPin.In(gpio.PullUp, gpio.BothEdges); err != nil {
log.Fatalf("Can't monitor the alert pin")
}
// Optionally but highly recommended, we can also set a reset pin to
// start/leave things in a clean state.
resetPin := gpioreg.ByName("GPIO21")
if resetPin == nil {
log.Fatal("invalid reset GPIO pin number")
}
opts.AlertPin = alertPin
opts.ResetPin = resetPin
// open the device so we can detect touch events
dev, err := cap1188.NewI2C(i2cBus, opts)
if err != nil {
log.Fatalf("couldn't open cap1188 - %s", err)
}
time.Sleep(200 * time.Millisecond)
fmt.Println("Monitoring for touch events")
maxTouches := 42 // stop the program after 42 touches
for maxTouches > 0 {
if alertPin.WaitForEdge(-1) {
maxTouches--
statuses, err := dev.InputStatus()
if err != nil {
fmt.Printf("Error reading inputs: %s\n", err)
continue
}
// print the status of each sensor
for i, st := range statuses {
fmt.Printf("#%d: %s\t", i, st)
}
fmt.Println()
// we need to clear the interrupt so it can be triggered again
if err := dev.ClearInterrupt(); err != nil {
fmt.Println(err, "while clearing the interrupt")
}
}
}
fmt.Print("\n")
}
func TestNewI2C(t *testing.T) {
bus := i2ctest.Playback{
Ops: []i2ctest.IO{
@ -110,7 +44,7 @@ func TestNewI2C(t *testing.T) {
{Addr: 40, W: []byte{0x44, 0x61}, R: nil},
},
}
d, err := cap1188.NewI2C(&bus, &cap1188.Opts{Debug: true})
d, err := NewI2C(&bus, &Opts{Debug: true})
if err != nil {
t.Fatal(err)
}
@ -129,8 +63,7 @@ func TestDev_InputStatus(t *testing.T) {
tests := []struct {
name string
bus i2c.Bus
opts *cap1188.Opts
want []cap1188.TouchStatus
want [8]TouchStatus
}{
{name: "all off",
bus: &i2ctest.Playback{
@ -138,128 +71,77 @@ func TestDev_InputStatus(t *testing.T) {
// status
{Addr: 40, W: []byte{0x3}, R: []byte{0x0}},
// deltas
{Addr: 40, W: []byte{0x10}, R: []byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}},
//{Addr: 40, W: []byte{0x10}, R: []byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}},
// thresholds
{Addr: 40, W: []byte{0x30}, R: []byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}},
//{Addr: 40, W: []byte{0x30}, R: []byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}},
}...),
},
opts: cap1188.DefaultOpts(),
want: []cap1188.TouchStatus{cap1188.OffStatus, cap1188.OffStatus, cap1188.OffStatus, cap1188.OffStatus, cap1188.OffStatus, cap1188.OffStatus, cap1188.OffStatus, cap1188.OffStatus},
want: [8]TouchStatus{OffStatus, OffStatus, OffStatus, OffStatus, OffStatus, OffStatus, OffStatus, OffStatus},
},
{name: "all pressed",
bus: &i2ctest.Playback{
Ops: append(setupPlaybackIO(), []i2ctest.IO{
{Addr: 40, W: []byte{0x3}, R: []byte{0xff}},
{Addr: 40, W: []byte{0x10}, R: []byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}},
{Addr: 40, W: []byte{0x30}, R: []byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}},
//{Addr: 40, W: []byte{0x10}, R: []byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}},
//{Addr: 40, W: []byte{0x30}, R: []byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}},
}...),
},
opts: cap1188.DefaultOpts(),
want: []cap1188.TouchStatus{cap1188.PressedStatus, cap1188.PressedStatus, cap1188.PressedStatus, cap1188.PressedStatus, cap1188.PressedStatus, cap1188.PressedStatus, cap1188.PressedStatus, cap1188.PressedStatus},
want: [8]TouchStatus{PressedStatus, PressedStatus, PressedStatus, PressedStatus, PressedStatus, PressedStatus, PressedStatus, PressedStatus},
},
{name: "first pressed",
bus: &i2ctest.Playback{
Ops: append(setupPlaybackIO(), []i2ctest.IO{
{Addr: 40, W: []byte{0x3}, R: []byte{1 << 7}},
{Addr: 40, W: []byte{0x10}, R: []byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}},
{Addr: 40, W: []byte{0x30}, R: []byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}},
{Addr: 40, W: []byte{0x3}, R: []byte{0x80}},
//{Addr: 40, W: []byte{0x10}, R: []byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}},
//{Addr: 40, W: []byte{0x30}, R: []byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}},
}...),
},
opts: cap1188.DefaultOpts(),
want: []cap1188.TouchStatus{cap1188.PressedStatus, cap1188.OffStatus, cap1188.OffStatus, cap1188.OffStatus, cap1188.OffStatus, cap1188.OffStatus, cap1188.OffStatus, cap1188.OffStatus},
want: [8]TouchStatus{PressedStatus, OffStatus, OffStatus, OffStatus, OffStatus, OffStatus, OffStatus, OffStatus},
},
{name: "second pressed",
bus: &i2ctest.Playback{
Ops: append(setupPlaybackIO(), []i2ctest.IO{
{Addr: 40, W: []byte{0x3}, R: []byte{1 << 6}},
{Addr: 40, W: []byte{0x10}, R: []byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}},
{Addr: 40, W: []byte{0x30}, R: []byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}},
{Addr: 40, W: []byte{0x3}, R: []byte{0x40}},
//{Addr: 40, W: []byte{0x10}, R: []byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}},
//{Addr: 40, W: []byte{0x30}, R: []byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}},
}...),
},
opts: cap1188.DefaultOpts(),
want: []cap1188.TouchStatus{cap1188.OffStatus, cap1188.PressedStatus, cap1188.OffStatus, cap1188.OffStatus, cap1188.OffStatus, cap1188.OffStatus, cap1188.OffStatus, cap1188.OffStatus},
want: [8]TouchStatus{OffStatus, PressedStatus, OffStatus, OffStatus, OffStatus, OffStatus, OffStatus, OffStatus},
},
{name: "third pressed",
bus: &i2ctest.Playback{
Ops: append(setupPlaybackIO(), []i2ctest.IO{
{Addr: 40, W: []byte{0x3}, R: []byte{1 << 5}},
{Addr: 40, W: []byte{0x10}, R: []byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}},
{Addr: 40, W: []byte{0x30}, R: []byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}},
}...),
},
opts: cap1188.DefaultOpts(),
want: []cap1188.TouchStatus{cap1188.OffStatus, cap1188.OffStatus, cap1188.PressedStatus, cap1188.OffStatus, cap1188.OffStatus, cap1188.OffStatus, cap1188.OffStatus, cap1188.OffStatus},
},
{name: "forth pressed",
bus: &i2ctest.Playback{
Ops: append(setupPlaybackIO(), []i2ctest.IO{
{Addr: 40, W: []byte{0x3}, R: []byte{1 << 4}},
{Addr: 40, W: []byte{0x10}, R: []byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}},
{Addr: 40, W: []byte{0x30}, R: []byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}},
}...),
},
opts: cap1188.DefaultOpts(),
want: []cap1188.TouchStatus{cap1188.OffStatus, cap1188.OffStatus, cap1188.OffStatus, cap1188.PressedStatus, cap1188.OffStatus, cap1188.OffStatus, cap1188.OffStatus, cap1188.OffStatus},
},
{name: "fifth pressed",
bus: &i2ctest.Playback{
Ops: append(setupPlaybackIO(), []i2ctest.IO{
{Addr: 40, W: []byte{0x3}, R: []byte{1 << 3}},
{Addr: 40, W: []byte{0x10}, R: []byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}},
{Addr: 40, W: []byte{0x30}, R: []byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}},
}...),
},
opts: cap1188.DefaultOpts(),
want: []cap1188.TouchStatus{cap1188.OffStatus, cap1188.OffStatus, cap1188.OffStatus, cap1188.OffStatus, cap1188.PressedStatus, cap1188.OffStatus, cap1188.OffStatus, cap1188.OffStatus},
},
{name: "sixth pressed",
bus: &i2ctest.Playback{
Ops: append(setupPlaybackIO(), []i2ctest.IO{
{Addr: 40, W: []byte{0x3}, R: []byte{1 << 2}},
{Addr: 40, W: []byte{0x10}, R: []byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}},
{Addr: 40, W: []byte{0x30}, R: []byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}},
{Addr: 40, W: []byte{0x3}, R: []byte{0x20}},
//{Addr: 40, W: []byte{0x10}, R: []byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}},
//{Addr: 40, W: []byte{0x30}, R: []byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}},
}...),
},
opts: cap1188.DefaultOpts(),
want: []cap1188.TouchStatus{cap1188.OffStatus, cap1188.OffStatus, cap1188.OffStatus, cap1188.OffStatus, cap1188.OffStatus, cap1188.PressedStatus, cap1188.OffStatus, cap1188.OffStatus},
},
{name: "seventh pressed",
bus: &i2ctest.Playback{
Ops: append(setupPlaybackIO(), []i2ctest.IO{
{Addr: 40, W: []byte{0x3}, R: []byte{1 << 1}},
{Addr: 40, W: []byte{0x10}, R: []byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}},
{Addr: 40, W: []byte{0x30}, R: []byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}},
}...),
},
opts: cap1188.DefaultOpts(),
want: []cap1188.TouchStatus{cap1188.OffStatus, cap1188.OffStatus, cap1188.OffStatus, cap1188.OffStatus, cap1188.OffStatus, cap1188.OffStatus, cap1188.PressedStatus, cap1188.OffStatus},
want: [8]TouchStatus{OffStatus, OffStatus, PressedStatus, OffStatus, OffStatus, OffStatus, OffStatus, OffStatus},
},
{name: "eighth pressed",
bus: &i2ctest.Playback{
Ops: append(setupPlaybackIO(), []i2ctest.IO{
{Addr: 40, W: []byte{0x3}, R: []byte{1 << 0}},
{Addr: 40, W: []byte{0x10}, R: []byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}},
{Addr: 40, W: []byte{0x30}, R: []byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}},
{Addr: 40, W: []byte{0x3}, R: []byte{0x1}},
//{Addr: 40, W: []byte{0x10}, R: []byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}},
//{Addr: 40, W: []byte{0x30}, R: []byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}},
}...),
},
opts: cap1188.DefaultOpts(),
want: []cap1188.TouchStatus{cap1188.OffStatus, cap1188.OffStatus, cap1188.OffStatus, cap1188.OffStatus, cap1188.OffStatus, cap1188.OffStatus, cap1188.OffStatus, cap1188.PressedStatus},
want: [8]TouchStatus{OffStatus, OffStatus, OffStatus, OffStatus, OffStatus, OffStatus, OffStatus, PressedStatus},
},
{name: "3 pressed",
bus: &i2ctest.Playback{
Ops: append(setupPlaybackIO(), []i2ctest.IO{
{Addr: 40, W: []byte{0x3}, R: []byte{(1 << 7) ^ (1 << 4) ^ (1 << 0)}},
{Addr: 40, W: []byte{0x10}, R: []byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}},
{Addr: 40, W: []byte{0x30}, R: []byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}},
{Addr: 40, W: []byte{0x3}, R: []byte{0x91}},
//{Addr: 40, W: []byte{0x10}, R: []byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}},
//{Addr: 40, W: []byte{0x30}, R: []byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}},
}...),
},
opts: cap1188.DefaultOpts(),
want: []cap1188.TouchStatus{cap1188.PressedStatus, cap1188.OffStatus, cap1188.OffStatus, cap1188.PressedStatus, cap1188.OffStatus, cap1188.OffStatus, cap1188.OffStatus, cap1188.PressedStatus},
want: [8]TouchStatus{PressedStatus, OffStatus, OffStatus, PressedStatus, OffStatus, OffStatus, OffStatus, PressedStatus},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
d, err := cap1188.NewI2C(tt.bus, tt.opts)
d, err := NewI2C(tt.bus, DefaultOpts())
if err != nil {
t.Fatal(err)
}
@ -276,25 +158,25 @@ func TestDev_InputStatus(t *testing.T) {
t.Run("held touch sensors", func(t *testing.T) {
bus := &i2ctest.Playback{
Ops: append(setupPlaybackIO(), []i2ctest.IO{
{Addr: 40, W: []byte{0x3}, R: []byte{1 << 7}},
{Addr: 40, W: []byte{0x10}, R: []byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}},
{Addr: 40, W: []byte{0x30}, R: []byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}},
{Addr: 40, W: []byte{0x3}, R: []byte{0x80}},
//{Addr: 40, W: []byte{0x10}, R: []byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}},
//{Addr: 40, W: []byte{0x30}, R: []byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}},
// repeat call to get status (still pressed)
{Addr: 40, W: []byte{0x3}, R: []byte{1 << 7}},
{Addr: 40, W: []byte{0x10}, R: []byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}},
{Addr: 40, W: []byte{0x30}, R: []byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}},
{Addr: 40, W: []byte{0x3}, R: []byte{0x80}},
//{Addr: 40, W: []byte{0x10}, R: []byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}},
//{Addr: 40, W: []byte{0x30}, R: []byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}},
// finall call
{Addr: 40, W: []byte{0x3}, R: []byte{0x0}},
{Addr: 40, W: []byte{0x10}, R: []byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}},
{Addr: 40, W: []byte{0x30}, R: []byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}},
//{Addr: 40, W: []byte{0x10}, R: []byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}},
//{Addr: 40, W: []byte{0x30}, R: []byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}},
}...),
}
// set the recorded response to have the retrigger option on
// Set the recorded response to have the retrigger option on.
bus.Ops[10] = i2ctest.IO{Addr: 40, W: []byte{0x28, 0xff}, R: nil}
opts := cap1188.DefaultOpts()
// following option needs to be true so we can get the held status
opts := DefaultOpts()
// Following option needs to be true so we can get the held status.
opts.RetriggerOnHold = true
d, err := cap1188.NewI2C(bus, opts)
d, err := NewI2C(bus, opts)
if err != nil {
t.Fatal(err)
}
@ -303,7 +185,7 @@ func TestDev_InputStatus(t *testing.T) {
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(got, []cap1188.TouchStatus{cap1188.PressedStatus, cap1188.OffStatus, cap1188.OffStatus, cap1188.OffStatus, cap1188.OffStatus, cap1188.OffStatus, cap1188.OffStatus, cap1188.OffStatus}) {
if !reflect.DeepEqual(got, [8]TouchStatus{PressedStatus, OffStatus, OffStatus, OffStatus, OffStatus, OffStatus, OffStatus, OffStatus}) {
t.Fatalf("expected to have the first sensor touched but instead got %v", got)
}
// 2nd check
@ -311,7 +193,7 @@ func TestDev_InputStatus(t *testing.T) {
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(got, []cap1188.TouchStatus{cap1188.HeldStatus, cap1188.OffStatus, cap1188.OffStatus, cap1188.OffStatus, cap1188.OffStatus, cap1188.OffStatus, cap1188.OffStatus, cap1188.OffStatus}) {
if !reflect.DeepEqual(got, [8]TouchStatus{HeldStatus, OffStatus, OffStatus, OffStatus, OffStatus, OffStatus, OffStatus, OffStatus}) {
t.Fatalf("expected to have the first sensor touched but instead got %v", got)
}
})
@ -346,3 +228,11 @@ func setupPlaybackIO() []i2ctest.IO {
{Addr: 40, W: []byte{0x44, 0x61}, R: nil},
}
}
func init() {
sleep = func(time.Duration) {}
flag.Parse()
if !testing.Verbose() {
log.SetOutput(ioutil.Discard)
}
}

Loading…
Cancel
Save