Skip to content

Commit c2f8978

Browse files
committed
Initial commit
0 parents  commit c2f8978

2 files changed

Lines changed: 368 additions & 0 deletions

File tree

‎touch.py‎

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
# MicroPython Trill Sensor library
2+
# Copyright (C) 2021 H. Groefsema
3+
#
4+
# This program is free software: you can redistribute it and/or modify
5+
# it under the terms of the GNU General Public License as published by
6+
# the Free Software Foundation, either version 3 of the License, or
7+
# (at your option) any later version.
8+
#
9+
# This program is distributed in the hope that it will be useful,
10+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
# GNU General Public License for more details.
13+
#
14+
# You should have received a copy of the GNU General Public License
15+
# along with this program. If not, see <https://www.gnu.org/licenses/>.
16+
17+
# Implements a helper class to obtain Trill sensor touches
18+
# Generic Touches class
19+
class Touches(object):
20+
21+
# Converts data read using MODE_CENTROID to a list of touches
22+
# Please instantiate subclasses only
23+
def __init__(self, data):
24+
self.touches = []
25+
26+
# Returns a list of touches as tuples, with
27+
# (vertical position, touch size) in case of one-directional data, or
28+
# (horizontal position, vertical position, horizontal size, vertical size)
29+
# in case of two-directional data
30+
def getTouches(self):
31+
return self.touches
32+
33+
# Returns the number of touches
34+
def getNumTouches(self):
35+
return len(self.touches)
36+
37+
# Returns the touch at index as a tuple
38+
def getTouch(self, index):
39+
touch = None
40+
if index < len(self.touches):
41+
touch = self.touches[index]
42+
return touch
43+
44+
45+
# Touches given one-directional data, e.g., using Bar, Ring, or Craft
46+
class Touches1D(Touches):
47+
48+
def __init__(self, data):
49+
super(Touches1D, self).__init__(data)
50+
51+
verticalLocations = data[:int(len(data)/2)]
52+
verticalSizes = data[int(len(data)/2):]
53+
54+
self.touches = []
55+
for i in range[0:len(verticalLocations)]:
56+
if verticalLocations[i] is not -1:
57+
self.touches.append((verticalLocations[i], verticalSizes[i]))
58+
59+
60+
# Touches given two-directional data, e.g., using Square or Hex
61+
class Touches2D(Touches):
62+
63+
def __init__(self, data):
64+
super(Touches2D, self).__init__(data)
65+
66+
vertical = data[:int(len(data)/2)]
67+
horizontal = data[int(len(data)/2):]
68+
69+
verticalLocations = vertical[:int(len(vertical)/2)]
70+
verticalSizes = vertical[int(len(vertical)/2):]
71+
72+
horizontalLocations = horizontal[:int(len(horizontal)/2)]
73+
horizontalSizes = horizontal[int(len(horizontal)/2):]
74+
75+
self.touches = []
76+
for i in range(0,len(verticalLocations)):
77+
if verticalLocations[i] is not -1:
78+
self.touches.append((horizontalLocations[i], verticalLocations[i], horizontalSizes[i], verticalSizes[i]))
79+

‎trill.py‎

Lines changed: 289 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,289 @@
1+
# MicroPython Trill Sensor library
2+
# Copyright (C) 2021 H. Groefsema
3+
#
4+
# This program is free software: you can redistribute it and/or modify
5+
# it under the terms of the GNU General Public License as published by
6+
# the Free Software Foundation, either version 3 of the License, or
7+
# (at your option) any later version.
8+
#
9+
# This program is distributed in the hope that it will be useful,
10+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
# GNU General Public License for more details.
13+
#
14+
# You should have received a copy of the GNU General Public License
15+
# along with this program. If not, see <https://www.gnu.org/licenses/>.
16+
17+
# Implements an I2C Trill sensor
18+
import time
19+
import struct
20+
21+
REG_COMMAND = 0x00
22+
REG_DATA = 0x04
23+
24+
COMMAND_NONE = 0x00
25+
COMMAND_MODE = 0x01
26+
COMMAND_SCAN_SETTINGS = 0x02
27+
COMMAND_PRESCALER = 0x03
28+
COMMAND_NOISE_THRESHOLD = 0x04
29+
COMMAND_IDAC = 0x05
30+
COMMAND_BASELINE_UPDATE = 0x06
31+
COMMAND_MINIMUM_SIZE = 0x07
32+
COMMAND_AUTO_SCAN_INTERVAL = 0x10
33+
COMMAND_IDENTIFY = 0xFF
34+
35+
MODE_CENTROID = 0x00
36+
MODE_RAW = 0x01
37+
MODE_BASELINE = 0x02
38+
MODE_DIFF = 0x03
39+
40+
TYPES = ["Unknown", "Bar", "Square", "Craft", "Ring", "Hex", "Flex"]
41+
42+
# Class that represents a generic Trill device
43+
class TrillSensor(object):
44+
45+
# Initialize a generic Trill sensor, with
46+
# i2c being an I2C bus instance
47+
# address being the I2C address of the sensor,
48+
# mode being the sensor mode, and
49+
# sleep being the delay to use between I2C bus communication
50+
def __init__(self, i2c, address=0x00, mode=None, sleep=10):
51+
self.i2c = i2c
52+
self.address=address
53+
self.mode = mode
54+
self.sleep = sleep
55+
self.type = 0
56+
self.identifiedType = 0
57+
self.firmware = None
58+
self.size = (1, 1)
59+
self.channels = 0
60+
self.maxTouches = 0
61+
self.directions = 0
62+
63+
def identify(self):
64+
self.i2c.writeto(self.address, struct.pack("1B", REG_DATA))
65+
time.sleep_ms(10)
66+
self.i2c.writeto_mem(self.address, REG_COMMAND, struct.pack("1B", COMMAND_IDENTIFY))
67+
time.sleep_ms(self.sleep + 15)
68+
(_, self.identifiedType, self.firmware) = self.i2c.readfrom(self.address, 3)
69+
print("Trill type", TYPES[self.identifiedType], "with firmware version", self.firmware)
70+
if self.type is not self.identifiedType:
71+
print("Warning: connected Trill device does not identify as", TYPES[self.type], "!!!")
72+
73+
# Get the sensor type
74+
def getType(self):
75+
if self.identifiedType is 0:
76+
self.identify()
77+
return TYPES[self.identifiedType]
78+
79+
# Get the sensor firmware version
80+
def getFirmwareVersion(self):
81+
if self.firmware is None:
82+
self.identify()
83+
return self.firmware
84+
85+
# Get the size of the sensor as a tuple (x, y)
86+
def getSize(self):
87+
return self.size
88+
89+
# Get the number of channels of the sensor
90+
def getNumChannels(self):
91+
return self.channels
92+
93+
# Read the latest scan value from the sensor
94+
def read(self):
95+
self.i2c.writeto(self.address, struct.pack("1B", REG_DATA))
96+
time.sleep_ms(self.sleep)
97+
98+
# Set the sensor mode
99+
def setMode(self, mode):
100+
self.mode = mode
101+
self.i2c.writeto_mem(self.address, REG_COMMAND, struct.pack("2B", COMMAND_MODE, mode))
102+
time.sleep_ms(self.sleep)
103+
104+
# Get the sensor mode
105+
# Returns None if mode hasn't been set
106+
def getMode(self):
107+
return self.mode
108+
109+
# Set the scan speed and resolution (numBits) of the sensor, with
110+
# speed being a value from 0 to 3, and
111+
# resolution being a value from 9 to 16
112+
def setScanSettings(self, speed=0, resolution=12):
113+
if speed < 0:
114+
speed = 0
115+
elif speed > 3:
116+
speed = 3
117+
else:
118+
speed = speed
119+
120+
if resolution < 9:
121+
resolution = 9
122+
elif resolution > 16:
123+
resolution = 16
124+
else:
125+
resolution = resolution
126+
127+
self.i2c.writeto_mem(self.address, REG_COMMAND, struct.pack("3B", COMMAND_SCAN_SETTINGS, speed, resolution))
128+
time.sleep_ms(self.sleep)
129+
130+
# Update the baseline capacitance values of the sensor
131+
def updateBaseline(self):
132+
self.i2c.writeto_mem(self.address, REG_COMMAND, struct.pack("1B", COMMAND_BASELINE_UPDATE))
133+
time.sleep_ms(self.sleep)
134+
135+
# Set the prescaler of the sensor, with
136+
# prescaler being a value from 1 to 8
137+
def setPrescaler(self, prescaler=8):
138+
self.i2c.writeto_mem(self.address, REG_COMMAND, struct.pack("2B", COMMAND_PRESCALER, prescaler))
139+
time.sleep_ms(self.sleep)
140+
141+
# Set the noise threshold for the MODE_CENTROID and MODE_DIFF modes, with
142+
# threshold being a value from 0 to 255
143+
def setNoiseThreshold(self, threshold):
144+
self.i2c.writeto_mem(self.address, REG_COMMAND, struct.pack("2B", COMMAND_NOISE_THRESHOLD, threshold))
145+
time.sleep_ms(self.sleep)
146+
147+
# Set the IDAC value of the sensor, with
148+
# value being a value from 0 to 255
149+
def setIDACValue(self, value):
150+
self.i2c.writeto_mem(self.address, REG_COMMAND, struct.pack("2B", COMMAND_IDAC, value))
151+
time.sleep_ms(self.sleep)
152+
153+
# Set the minimum registered touch size
154+
def setMinimumTouchSize(self, minSize):
155+
self.i2c.writeto_mem(self.address, REG_COMMAND, struct.pack("BH", COMMAND_MINIMUM_SIZE, minSize))
156+
time.sleep_ms(self.sleep)
157+
158+
# Set the automatic scan interval (used with the EVT pin)
159+
def setAutoScanInterval(self, interval):
160+
self.i2c.writeto_mem(self.address, REG_COMMAND, struct.pack("BH", COMMAND_AUTO_SCAN_INTERVAL, interval))
161+
time.sleep_ms(self.sleep)
162+
163+
# Returns True if the sensor is one-directional
164+
def is1D(self):
165+
return self.directions is 1
166+
167+
# Returns True if the sensor is two-directional
168+
def is2D(self):
169+
return self.directions is 2
170+
171+
172+
# Class representing a Trill Bar
173+
class Bar(TrillSensor):
174+
175+
def __init__(self, i2c, address=0x20, mode=MODE_CENTROID, sleep=10):
176+
super(Bar, self).__init__(i2c, address, mode, sleep)
177+
self.type = 1
178+
self.size = (1, 3200)
179+
self.channels = 26
180+
self.maxTouches = 5
181+
self.directions = 1
182+
183+
self.setMode(mode)
184+
self.setScanSettings()
185+
self.updateBaseline()
186+
187+
def read(self):
188+
super(Bar, self).read()
189+
data = None
190+
191+
if self.mode is MODE_CENTROID:
192+
data = struct.unpack(">10h", self.i2c.readfrom_mem(self.address, REG_DATA, 4 * self.maxTouches))
193+
else:
194+
data = struct.unpack(">26h", self.i2c.readfrom_mem(self.address, REG_DATA, 2 * self.channels))
195+
196+
return data
197+
198+
199+
# Class representing a Trill Square
200+
class Square(TrillSensor):
201+
202+
def __init__(self, i2c, address=0x28, mode=MODE_CENTROID, sleep=10):
203+
super(Square, self).__init__(i2c, address, mode, sleep)
204+
self.type = 2
205+
self.size = (1792, 1792)
206+
self.channels = 30
207+
self.maxTouches = 4
208+
self.directions = 2
209+
210+
self.setMode(mode)
211+
self.setScanSettings()
212+
self.updateBaseline()
213+
214+
def read(self):
215+
super(Square, self).read()
216+
data = None
217+
218+
if self.mode is MODE_CENTROID:
219+
data = struct.unpack(">16h", self.i2c.readfrom_mem(self.address, REG_DATA, 4 * self.directions * self.maxTouches))
220+
else:
221+
data = struct.unpack(">30h", self.i2c.readfrom_mem(self.address, REG_DATA, 2 * self.channels))
222+
223+
return data
224+
225+
226+
# Class representing a Trill Craft
227+
class Craft(Bar):
228+
229+
def __init__(self, i2c, address=0x30, mode=MODE_CENTROID, sleep=10):
230+
super(Craft, self).__init__(i2c, address, mode, sleep)
231+
self.type = 3
232+
self.size = (1, 4096)
233+
self.channels = 30
234+
235+
def read(self):
236+
super(Craft, self).read()
237+
data = None
238+
239+
if self.mode is MODE_CENTROID:
240+
data = struct.unpack(">10h", self.i2c.readfrom_mem(self.address, REG_DATA, 4 * self.maxTouches))
241+
else:
242+
data = struct.unpack(">26h", self.i2c.readfrom_mem(self.address, REG_DATA, 2 * self.channels))
243+
244+
return data
245+
246+
247+
# Class representing a Trill Ring
248+
class Ring(Bar):
249+
250+
def __init__(self, i2c, address=0x38, mode=MODE_CENTROID, sleep=10):
251+
super(Ring, self).__init__(i2c, address, mode, sleep)
252+
self.type = 4
253+
self.size = (1, 3584)
254+
self.channels = 28
255+
256+
def read(self):
257+
super(Ring, self).read()
258+
data = None
259+
260+
if self.mode is MODE_CENTROID:
261+
data = struct.unpack(">10h", self.i2c.readfrom_mem(self.address, REG_DATA, 4 * self.maxTouches))
262+
else:
263+
data = struct.unpack(">28h", self.i2c.readfrom_mem(self.address, REG_DATA, 2 * self.channels))
264+
265+
return data
266+
267+
268+
# Class representing a Trill Hex
269+
class Hex(Square):
270+
271+
def __init__(self, i2c, address=0x40, mode=MODE_CENTROID, sleep=10):
272+
super(Hex, self).__init__(i2c, address, mode, sleep)
273+
self.type = 5
274+
self.size = (1664, 1920)
275+
276+
self.setMode(mode)
277+
self.setScanSettings()
278+
self.updateBaseline()
279+
280+
def read(self):
281+
super(Hex, self).read()
282+
data = None
283+
284+
if self.mode is MODE_CENTROID:
285+
data = struct.unpack(">16h", self.i2c.readfrom_mem(self.address, REG_DATA, 4 * self.directions * self.maxTouches))
286+
else:
287+
data = struct.unpack(">30h", self.i2c.readfrom_mem(self.address, REG_DATA, 2 * self.channels))
288+
289+
return data

0 commit comments

Comments
 (0)