From 2f8171ed6c36d09b83d96aee6ffc1cbf14a0bd0e Mon Sep 17 00:00:00 2001 From: M-A Date: Wed, 27 Dec 2017 18:06:58 -0500 Subject: [PATCH] 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. --- experimental/devices/cap1188/cap1188.go | 580 +++++++++--------- .../devices/cap1188/cap1188_example_test.go | 77 +++ .../devices/cap1188/cap1188_options.go | 67 +- experimental/devices/cap1188/cap1188_test.go | 218 ++----- 4 files changed, 458 insertions(+), 484 deletions(-) create mode 100644 experimental/devices/cap1188/cap1188_example_test.go diff --git a/experimental/devices/cap1188/cap1188.go b/experimental/devices/cap1188/cap1188.go index 1b223d0..42e1e49 100644 --- a/experimental/devices/cap1188/cap1188.go +++ b/experimental/devices/cap1188/cap1188.go @@ -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 - isSPI bool - inputStatuses []TouchStatus - resetAt time.Time + c mmr.Dev8 + opts Opts + isSPI bool + + 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) + } + } + 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 -// 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")) - } + if opts == nil { + opts = DefaultOpts() } - d := &Dev{d: &i2c.Dev{Bus: b, Addr: addr}, isSPI: false} - if d.Debug { - log.Printf("cap1188: Connecting via I2C address: %#X\n", addr) + addr, err := opts.i2cAddr() + if err != nil { + return nil, wrapf("%v", err) } - d.inputStatuses = make([]TouchStatus, nbrOfLEDs) - if err := d.makeDev(opts); err != nil { + d, err := makeDev(&i2c.Dev{Bus: b, Addr: addr}, false, opts) + if err != nil { return nil, err } - // time to communications is 15ms - now := time.Now() - readyAt := d.resetAt.Add(15 * time.Millisecond) - if now.Before(readyAt) { - time.Sleep(readyAt.Sub(now)) - } + 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 - // 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 + // - 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 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 - // 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. + // 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. 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 } -// setBit sets a specific bit on a register -// TODO(mattetti): avoid reading before writing, keep states in memory +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. 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{} diff --git a/experimental/devices/cap1188/cap1188_example_test.go b/experimental/devices/cap1188/cap1188_example_test.go new file mode 100644 index 0000000..f6edc5d --- /dev/null +++ b/experimental/devices/cap1188/cap1188_example_test.go @@ -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") +} diff --git a/experimental/devices/cap1188/cap1188_options.go b/experimental/devices/cap1188/cap1188_options.go index 9bc329e..84eaa49 100644 --- a/experimental/devices/cap1188/cap1188_options.go +++ b/experimental/devices/cap1188/cap1188_options.go @@ -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,10 +119,10 @@ 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 + // CycleTime determines the overall cycle time for all measured channels // during normal operation. All measured channels are sampled at the // beginning of the cycle time. If additional time is remaining, then the // device is placed into a lower power state for the remaining duration of @@ -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{ diff --git a/experimental/devices/cap1188/cap1188_test.go b/experimental/devices/cap1188/cap1188_test.go index af31ab0..31038ca 100644 --- a/experimental/devices/cap1188/cap1188_test.go +++ b/experimental/devices/cap1188/cap1188_test.go @@ -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) + } +}