Examples

Simple Test

Ensure your device works with this simple test.

examples/cirque_pinnacle_simpletest.py
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
"""
A simple test example. This example also works with glidepoint_lite.py
"""
import time
import struct
import board
from digitalio import DigitalInOut

# if running this on a ATSAMD21 M0 based board
# from circuitpython_cirque_pinnacle import glidepoint_lite as glidepoint
from circuitpython_cirque_pinnacle import glidepoint

dr_pin = DigitalInOut(board.D2)
# NOTE The dr_pin is an optional keyword argument to the
# constructor when using Absolute or Relative modes

# if using a trackpad configured for SPI
spi = board.SPI()
ss_pin = DigitalInOut(board.D7)
t_pad = glidepoint.PinnacleTouchSPI(spi, ss_pin)
# if using a trackpad configured for I2C
# i2c = board.I2C()
# t_pad = glidepoint.PinnacleTouchI2C(i2c)

t_pad.data_mode = glidepoint.ABSOLUTE  # ensure Absolute mode is enabled
t_pad.absolute_mode_config(z_idle_count=1)  # limit idle packet count to 1


def print_data(timeout=6):
    """Print available data reports from the Pinnacle touch controller
    until there's no input for a period of ``timeout`` seconds."""
    if t_pad.data_mode == glidepoint.RELATIVE:
        print("using Relative mode")
    elif t_pad.data_mode == glidepoint.ABSOLUTE:
        print("using Absolute mode")
    start = time.monotonic()
    while time.monotonic() - start < timeout:
        if dr_pin.value:  # is there new data?
            data = t_pad.read()

            if t_pad.data_mode == glidepoint.ABSOLUTE and data[3]:
                # NOTE ``and data[3]`` means only when Z-axis is > 0
                # specification sheet recommends clamping absolute position data of
                # X & Y axis for reliability
                data[1] = max(128, min(1920, data[1]))  # X-axis
                data[2] = max(64, min(1472, data[2]))  # Y-axis
            elif t_pad.data_mode == glidepoint.RELATIVE:
                # convert 2's compliment form into natural numbers
                data = struct.unpack("Bbbb", data)
            print(data)
            start = time.monotonic()

USB Mouse example

This example uses CircuitPython’s built-in usb_hid API to emulate a mouse with the Cirque circle trackpad.

examples/cirque_pinnacle_usb_mouse.py
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
"""
This example uses CircuitPython's built-in `usb_hid` API
to emulate a mouse with the Cirque circle trackpad
"""
import time
import board
from digitalio import DigitalInOut
import usb_hid

# if running this on a ATSAMD21 M0 based board
# from circuitpython_cirque_pinnacle import glidepoint_lite as glidepoint
from circuitpython_cirque_pinnacle import glidepoint

dr_pin = DigitalInOut(board.D2)
# NOTE Specifying the optional keyword argument ``dr_pin`` to the
# constructor expedites ``read()`` when using Absolute or Relative modes

# if using a trackpad configured for SPI
spi = board.SPI()
ss_pin = DigitalInOut(board.D7)
t_pad = glidepoint.PinnacleTouchSPI(spi, ss_pin, dr_pin=dr_pin)
# if using a trackpad configured for I2C
# i2c = board.I2C()
# t_pad = glidepoint.PinnacleTouchI2C(i2c, dr_pin=dr_pin)

t_pad.data_mode = glidepoint.RELATIVE  # ensure mouse mode is enabled

mouse = None
for dev in usb_hid.devices:
    # be sure we're grabbing the mouse singleton
    if dev.usage == 2 and dev.usage_page == 1:
        mouse = dev
# mouse.send_report() takes a 4 byte buffer in which
#   byte0 = buttons in which
#       bit5 = back, bit4 = forward, bit2 = middle, bit1 = right, bit0 = left
#   byte1 = delta x-axis
#   byte2 = delta y-axis
#   byte3 = delta scroll wheel
if mouse is None:
    raise OSError("mouse HID device not available.")


def move(timeout=10):
    """Send mouse X & Y reported data from the Pinnacle touch controller
    until there's no input for a period of ``timeout`` seconds."""
    start = time.monotonic()
    while time.monotonic() - start < timeout:
        data = t_pad.read()  # only returns fresh data (if any)
        if data:  # is there fresh data?
            mouse.send_report(data)  # no scrolling or backward/forward
            start = time.monotonic()
    mouse.send_report(b"\x00" * 4)  # release buttons (just in case)

AnyMeas mode example

This example uses the Pinnacle touch controller’s AnyMeas mode to fetch raw ADC values.

examples/cirque_pinnacle_anymeas_test.py
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
"""
A test example using SPI to read ADC measurements from the Pinnacle touch
controller in "AnyMeas" mode
"""
import time
import struct
import board
from digitalio import DigitalInOut

# This example does NOT work with glidepoint_lite.py
from circuitpython_cirque_pinnacle import glidepoint

try:
    from typing import List
except ImportError:
    pass

dr_pin = DigitalInOut(board.D2)
# NOTE The dr_pin is a required keyword argument to the
# constructor when using AnyMeas mode

# if using a trackpad configured for SPI
spi = board.SPI()
ss_pin = DigitalInOut(board.D7)
t_pad = glidepoint.PinnacleTouchSPI(spi, ss_pin, dr_pin=dr_pin)
# if using a trackpad configured for I2C
# i2c = board.I2C()
# t_pad = glidepoint.PinnacleTouchI2C(i2c, dr_pin=dr_pin)

# if dr_pin was not specified upon instantiation.
# this command will raise an AttributeError exception
t_pad.data_mode = glidepoint.ANYMEAS

# setup toggle and polarity bits for measuring with PNP gate muxing
class MeasVector:  # pylint: disable=too-few-public-methods
    """A blueprint matrix used to manipulate the measurements' vector"""

    def __init__(self, toggle: int, polarity: int):
        self.toggle = toggle
        self.polarity = polarity


vectors: List[MeasVector] = []
# This toggles Y0 only and toggles it positively
vectors.append(MeasVector(0x00010000, 0x00010000))
# This toggles Y0 only and toggles it negatively
vectors.append(MeasVector(0x00010000, 0x00000000))
# This toggles X0 only and toggles it positively
vectors.append(MeasVector(0x00000001, 0x00000000))
# This toggles X16 only and toggles it positively
vectors.append(MeasVector(0x00008000, 0x00000000))
# This toggles Y0-Y7 negative and X0-X7 positive
vectors.append(MeasVector(0x00FF00FF, 0x000000FF))

idle_vectors = [0] * len(vectors)


def compensate(count=5):
    """take ``count`` measurements, then average them together"""
    for i, vector in enumerate(vectors):
        idle_vectors[i] = 0
        for _ in range(count):
            result = struct.unpack(
                "h", t_pad.measure_adc(vector.toggle, vector.polarity)
            )[0]
            idle_vectors[i] += result
        idle_vectors[i] /= count
        print("compensation {}: {}".format(i, idle_vectors[i]))


def take_measurements(timeout=10):
    """read ``len(vectors)`` number of measurements and print results for
    ``timeout`` number of seconds."""
    start = time.monotonic()
    while time.monotonic() - start < timeout:
        for i, vector in enumerate(vectors):
            result = struct.unpack(
                "h", t_pad.measure_adc(vector.toggle, vector.polarity)
            )[0]
            print("vector{}: {}".format(i, result - idle_vectors[i]), end="\t")
        print()