-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathTrill.h
324 lines (277 loc) · 8.35 KB
/
Trill.h
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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
/*
* Trill library for Arduino
* (c) 2020 bela.io
*
* This library communicates with the Trill sensors
* using I2C.
*
* BSD license
*/
#ifndef TRILL_H
#define TRILL_H
#if (ARDUINO >= 100)
#include "Arduino.h"
#else
#include "WProgram.h"
#endif
#include "Wire.h"
#define TRILL_SPEED_ULTRA_FAST 0
#define TRILL_SPEED_FAST 1
#define TRILL_SPEED_NORMAL 2
#define TRILL_SPEED_SLOW 3
class Touches
{
public:
Touches() { num_touches = 0; };
typedef uint16_t TouchData_t;
/* How many touches? */
uint8_t getNumTouches() const;
/* Location and size of a particular touch, ranging from 0 to N-1.
Returns -1 if no such touch exists. */
int touchLocation(uint8_t touch_num) const;
int touchSize(uint8_t touch_num) const;
void processCentroids(uint8_t maxCentroids);
TouchData_t const* centroids;
TouchData_t const* sizes;
uint8_t num_touches;/* Number of touches. Updated by processCentroids() */
};
class Touches2D : public Touches
{
public:
unsigned int getNumHorizontalTouches();
int touchHorizontalLocation(uint8_t touch_num);
int touchHorizontalSize(uint8_t touch_num);
protected:
Touches2D() {};
Touches horizontal;
};
class Trill : public Touches2D
{
public:
Trill();
enum Mode {
AUTO = -1,
CENTROID = 0,
RAW = 1,
BASELINE = 2,
DIFF = 3,
NUM_MODES = 5
};
enum Device {
TRILL_NONE = -1,
TRILL_UNKNOWN = 0,
TRILL_BAR = 1,
TRILL_SQUARE = 2,
TRILL_CRAFT = 3,
TRILL_RING = 4,
TRILL_HEX = 5,
TRILL_FLEX = 6,
TRILL_NUM_DEVICES = 7
};
struct TrillDefaults
{
Trill::Device device;
Trill::Mode mode;
uint8_t address;
};
struct TrillDefaults trillDefaults[TRILL_NUM_DEVICES + 1] = {
{TRILL_NONE, AUTO, 0xFF},
{TRILL_UNKNOWN, AUTO, 0xFF},
{TRILL_BAR, CENTROID, 0x20},
{TRILL_SQUARE, CENTROID, 0x28},
{TRILL_CRAFT, DIFF, 0x30},
{TRILL_RING, CENTROID, 0x38},
{TRILL_HEX, CENTROID, 0x40},
{TRILL_FLEX, DIFF, 0x48},
};
static constexpr uint8_t interCommandDelay = 15;
/**
* An array containing the valid values for the speed parameter
* in setScanSettings()
*/
static constexpr uint8_t speedValues[4] = {0, 1, 2, 3};
/**
* The maximum value for the setPrescaler() method
*/
static constexpr uint8_t prescalerMax = 8;
/* Initialise the hardware */
int begin(Device device, uint8_t i2c_address = 255, TwoWire* wire = &Wire);
/* Initialise the hardware, it's the same as begin() */
int setup(Device device, uint8_t i2c_address = 255, TwoWire* wire = &Wire) { return begin(device, i2c_address, wire); }
/* --- Main communication --- */
/* Return the type of device attached, or 0 if none is attached.
Same as begin(), but without re-initialising the system. */
int identify();
/**
* Does the device have one axis of position sensing?
*
* @return `true` if the device has one axis of position sensing
* and is set in #CENTROID mode, `false`
* otherwise.
*/
bool is1D();
/**
* Does the device have two axes of position sensing?
*
* @return `true` if the device has two axes of position sensing
* and is set in #CENTROID mode, `false`
* otherwise.
*/
bool is2D();
static Device probe(uint8_t i2c_address) {
Trill t;
/* Start I2C */
t.begin(Trill::TRILL_UNKNOWN, i2c_address);
/* Check the type of device attached */
if(t.identify() != 0) {
// Unable to identify device
return Trill::TRILL_NONE;
}
return t.deviceType();
}
/* Return the device type already identified */
Device deviceType() { return device_type_; };
/* Get the name of a given device */
static const char* getNameFromDevice(Device device);
/* Return firmware version */
int firmwareVersion() { return firmware_version_; }
/* Get the mode that the device is currently in */
Mode getMode() { return mode_; }
/* Get the current address of the device */
uint8_t getAddress() { return i2c_address_; }
/* Get the number of capacitive channels on the device */
unsigned int getNumChannels();
/* Return the number of "button" channels on the device */
unsigned int getNumButtons() { return 2 * (getMode() == CENTROID && TRILL_RING == deviceType());};
/* Read the latest scan value from the sensor. Returns true on success. */
boolean read();
/* Update the baseline value on the sensor */
void updateBaseline();
/* --- Data processing --- */
/* Button value for Ring? */
int getButtonValue(uint8_t button_num);
/* --- Raw data handling --- */
/* Request raw data; wrappers for Wire */
boolean requestRawData(uint8_t max_length = 0xFF);
int rawDataAvailable();
int rawDataRead();
/* --- Scan configuration settings --- */
void setMode(Mode mode);
void setScanSettings(uint8_t speed, uint8_t num_bits);
void setPrescaler(uint8_t prescaler);
void setNoiseThreshold(uint8_t threshold);
void setIDACValue(uint8_t value);
void setMinimumTouchSize(uint16_t size);
void setAutoScanInterval(uint16_t interval);
private:
void prepareForDataRead();
enum {
kCommandNone = 0,
kCommandMode = 1,
kCommandScanSettings = 2,
kCommandPrescaler = 3,
kCommandNoiseThreshold = 4,
kCommandIdac = 5,
kCommandBaselineUpdate = 6,
kCommandMinimumSize = 7,
kCommandAutoScanInterval = 16,
kCommandIdentify = 255
};
enum {
kOffsetCommand = 0,
kOffsetData = 4
};
enum {
kMaxTouchNum1D = 5,
kMaxTouchNum2D = 4
};
enum {
kCentroidLengthDefault = 20,
kCentroidLengthRing = 24,
kCentroidLength2D = 32,
kRawLength = 60
};
enum {
kNumChannelsBar = 26,
kNumChannelsRing = 30,
kNumChannelsMax = 30
};
enum {
kRawLengthBar = 52,
kRawLengthHex = 60,
kRawLengthRing = 56
};
TwoWire* wire_;
uint8_t i2c_address_; /* Address of this slider on I2C bus */
Device device_type_; /* Which type of device is connected, if any */
uint8_t firmware_version_; /* Firmware version running on the device */
Mode mode_; /* Which mode the device is in */
uint8_t last_read_loc_; /* Which byte reads will begin from on the device */
uint8_t raw_bytes_left_; /* How many bytes still remaining to request? */
uint16_t buffer_[kCentroidLength2D * 2];/* Buffer for centroid response */
};
// first template argument is the max num of centroids
// the second argument is the number of readings that will be processed at the
// same time. This should be 0 if the data passed to process() is already ordered
template <uint8_t _maxNumCentroids, uint8_t _numReadings>
class CentroidDetection : public Touches
{
public:
typedef uint16_t WORD;
CentroidDetection() {};
CentroidDetection(const unsigned int* order);
int begin(const uint8_t* order, unsigned int numReadings) {
return setup(order, numReadings);
}
// pass nullptr if the data passed to process() is already ordered.
int setup(const uint8_t* order, unsigned int orderLength) {
this->order = order;
Touches::centroids = this->centroids;
Touches::sizes = this->sizes;
num_touches = 0;
this->orderLength = orderLength;
if(orderLength > _numReadings)
return -1; // cannot work with more than _numReadings
return 0;
}
void process(const WORD* rawData) {
uint8_t nMax = _numReadings < orderLength ? _numReadings : orderLength;
if(order) {
for(unsigned int n = 0; n < nMax; ++n) {
data[n] = rawData[order[n]];
}
cc.CSD_waSnsDiff = data;
} else {
// no reordering needed
cc.CSD_waSnsDiff = rawData;
}
cc.calculateCentroids(centroids, sizes, _maxNumCentroids, 0, nMax, nMax);
processCentroids(_maxNumCentroids);
}
void setMinimumTouchSize(TouchData_t minSize) {
cc.wMinimumCentroidSize = minSize;
}
private:
// a small helper class, whose main purpose is to wrap the #include
// and make all the variables related to it private and multi-instance safe
class CalculateCentroids
{
public:
typedef uint8_t BYTE;
WORD const * CSD_waSnsDiff;
WORD wMinimumCentroidSize = 0;
BYTE SLIDER_BITS = 7;
WORD wAdjacentCentroidNoiseThreshold = 400; // Trough between peaks needed to identify two centroids
//WORD calculateCentroids(WORD *centroidBuffer, WORD *sizeBuffer, BYTE maxNumCentroids, BYTE minSensor, BYTE maxSensor, BYTE numSensors);
// calculateCentroids is defined here:
#include "calculateCentroids.h"
};
TouchData_t centroids[_maxNumCentroids];
TouchData_t sizes[_maxNumCentroids * 2];
const uint8_t* order;
unsigned int orderLength;
WORD data[_numReadings];
CalculateCentroids cc;
};
class CustomSlider : public CentroidDetection<5, 30> {};
#endif /* TRILL_H */