blob: f5e0fc59d82704cdf218949873f8df34ce1ef6c5 [file] [log] [blame]
Erik Gilling3edead52011-03-08 15:59:23 -08001#include <Wire.h>
2#include <Servo.h>
3
Erik Gilling9c16e962011-03-16 17:27:09 -07004#include <Max3421e.h>
5#include <Usb.h>
6#include <AndroidAccessory.h>
Erik Gilling3edead52011-03-08 15:59:23 -08007
Erik Gillingccfe9392011-04-04 10:21:14 -07008#include <CapSense.h>
9
Erik Gilling3edead52011-03-08 15:59:23 -080010#define LED3_RED 2
Erik Gillingea909002011-03-16 15:07:07 -070011#define LED3_GREEN 4
12#define LED3_BLUE 3
Erik Gilling3edead52011-03-08 15:59:23 -080013
14#define LED2_RED 5
Erik Gillingea909002011-03-16 15:07:07 -070015#define LED2_GREEN 7
16#define LED2_BLUE 6
Erik Gilling3edead52011-03-08 15:59:23 -080017
18#define LED1_RED 8
Erik Gillingea909002011-03-16 15:07:07 -070019#define LED1_GREEN 10
20#define LED1_BLUE 9
Erik Gilling3edead52011-03-08 15:59:23 -080021
22#define SERVO1 11
23#define SERVO2 12
24#define SERVO3 13
25
Erik Gillingccfe9392011-04-04 10:21:14 -070026#define TOUCH_RECV 14
27#define TOUCH_SEND 15
Erik Gilling3edead52011-03-08 15:59:23 -080028
29#define RELAY1 A0
30#define RELAY2 A1
31
32#define LIGHT_SENSOR A2
33#define TEMP_SENSOR A3
34
35#define BUTTON1 A6
36#define BUTTON2 A7
37#define BUTTON3 A8
38
39#define JOY_SWITCH A9 // pulls line down when pressed
40#define JOY_nINT A10 // active low interrupt input
41#define JOY_nRESET A11 // active low reset output
42
Erik Gilling9c16e962011-03-16 17:27:09 -070043AndroidAccessory acc("Google, Inc.",
44 "DemoKit",
45 "DemoKit Arduino Board",
46 "1.0",
47 "http://www.android.com",
48 "0000000012345678");
Erik Gilling3edead52011-03-08 15:59:23 -080049Servo servos[3];
50
Erik Gillingccfe9392011-04-04 10:21:14 -070051CapSense touch_robot = CapSense(TOUCH_SEND, TOUCH_RECV); // 10M ohm resistor on demo shield
52
Erik Gilling3edead52011-03-08 15:59:23 -080053void setup();
54void loop();
55
Erik Gilling3edead52011-03-08 15:59:23 -080056void init_buttons()
57{
58 pinMode( BUTTON1, INPUT );
59 pinMode( BUTTON2, INPUT );
60 pinMode( BUTTON3, INPUT );
61
62 digitalWrite( BUTTON1, HIGH ); // enable the internal pullups
63 digitalWrite( BUTTON2, HIGH );
64 digitalWrite( BUTTON3, HIGH );
65}
66
67
68void init_relays()
69{
70 pinMode( RELAY1, OUTPUT );
71 pinMode( RELAY2, OUTPUT );
72}
73
74
75void init_leds()
76{
77 digitalWrite( LED1_RED, 1 );
78 digitalWrite( LED1_GREEN, 1 );
79 digitalWrite( LED1_BLUE, 1 );
80
81 pinMode( LED1_RED, OUTPUT );
82 pinMode( LED1_GREEN, OUTPUT );
83 pinMode( LED1_BLUE, OUTPUT );
84
85 digitalWrite( LED2_RED, 1 );
86 digitalWrite( LED2_GREEN, 1 );
87 digitalWrite( LED2_BLUE, 1 );
88
89 pinMode( LED2_RED, OUTPUT );
90 pinMode( LED2_GREEN, OUTPUT );
91 pinMode( LED2_BLUE, OUTPUT );
92
93 digitalWrite( LED3_RED, 1 );
94 digitalWrite( LED3_GREEN, 1 );
95 digitalWrite( LED3_BLUE, 1 );
96
97 pinMode( LED3_RED, OUTPUT );
98 pinMode( LED3_GREEN, OUTPUT );
99 pinMode( LED3_BLUE, OUTPUT );
100}
101
102void init_joystick( int threshold );
103
Erik Gilling9c16e962011-03-16 17:27:09 -0700104byte b1, b2, b3, c;
Erik Gilling3edead52011-03-08 15:59:23 -0800105void setup()
106{
107 Serial.begin( 115200 );
108 Serial.print("\r\nStart");
109
110 init_leds();
111 init_relays();
112 init_buttons();
113 init_joystick( 5 ); // initialize with thresholding enabled, dead zone of 5 units
114
Erik Gillingccfe9392011-04-04 10:21:14 -0700115 touch_robot.set_CS_AutocaL_Millis(0xFFFFFFFF); // autocalibrate OFF
Erik Gilling3edead52011-03-08 15:59:23 -0800116
117 servos[0].attach(SERVO1);
118 servos[0].write(90);
119 servos[1].attach(SERVO2);
120 servos[1].write(90);
121 servos[2].attach(SERVO3);
122 servos[2].write(90);
123
Erik Gilling9c16e962011-03-16 17:27:09 -0700124
125 b1 = digitalRead(BUTTON1);
126 b2 = digitalRead(BUTTON2);
127 b3 = digitalRead(BUTTON3);
Erik Gillingccfe9392011-04-04 10:21:14 -0700128 c = 0;
Erik Gilling9c16e962011-03-16 17:27:09 -0700129
130 acc.powerOn();
Erik Gilling3edead52011-03-08 15:59:23 -0800131}
132
Erik Gilling3edead52011-03-08 15:59:23 -0800133void loop()
134{
Erik Gilling3edead52011-03-08 15:59:23 -0800135 byte err;
Erik Gilling9c16e962011-03-16 17:27:09 -0700136 byte idle;
137 static byte count = 0;
138 byte msg[3];
Erik Gillingccfe9392011-04-04 10:21:14 -0700139 long touchcount;
Erik Gilling3edead52011-03-08 15:59:23 -0800140
Erik Gilling9c16e962011-03-16 17:27:09 -0700141 if (acc.isConnected()) {
142 int len = acc.read(msg, sizeof(msg), 1);
143 int i;
144 byte b;
145 uint16_t val;
146 int x, y;
147 char c0;
Erik Gilling3edead52011-03-08 15:59:23 -0800148
Erik Gilling9c16e962011-03-16 17:27:09 -0700149 if (len > 0) {
150 // XXX: assumes only one command per packet
151 Serial.print(msg[0], HEX);
152 Serial.print(":");
153 Serial.print(msg[1], HEX);
154 Serial.print(":");
155 Serial.println(msg[2], HEX);
156 if (msg[0] == 0x2) {
157 if (msg[1] == 0x0)
158 analogWrite( LED1_RED, 255 - msg[2]);
159 else if (msg[1] == 0x1)
160 analogWrite( LED1_GREEN, 255 - msg[2]);
161 else if (msg[1] == 0x2)
162 analogWrite( LED1_BLUE, 255 - msg[2]);
163 else if (msg[1] == 0x3)
164 analogWrite( LED2_RED, 255 - msg[2]);
165 else if (msg[1] == 0x4)
166 analogWrite( LED2_GREEN, 255 - msg[2]);
167 else if (msg[1] == 0x5)
168 analogWrite( LED2_BLUE, 255 - msg[2]);
169 else if (msg[1] == 0x6)
170 analogWrite( LED3_RED, 255 - msg[2]);
171 else if (msg[1] == 0x7)
172 analogWrite( LED3_GREEN, 255 - msg[2]);
173 else if (msg[1] == 0x8)
174 analogWrite( LED3_BLUE, 255 - msg[2]);
175 else if (msg[1] == 0x10)
176 servos[0].write(map(msg[2], 0, 255, 0, 180));
177 else if (msg[1] == 0x11)
178 servos[1].write(map(msg[2], 0, 255, 0, 180));
179 else if (msg[1] == 0x12)
180 servos[2].write(map(msg[2], 0, 255, 0, 180));
181 } else if (msg[0] == 0x3) {
182 if (msg[1] == 0x0)
183 digitalWrite( RELAY1, msg[2] ? HIGH : LOW );
184 else if (msg[1] == 0x1)
185 digitalWrite( RELAY2, msg[2] ? HIGH : LOW );
Erik Gilling3edead52011-03-08 15:59:23 -0800186
Erik Gilling3edead52011-03-08 15:59:23 -0800187 }
Erik Gilling3edead52011-03-08 15:59:23 -0800188
189 }
190
Erik Gilling9c16e962011-03-16 17:27:09 -0700191 msg[0] = 0x1;
Erik Gilling3edead52011-03-08 15:59:23 -0800192
Erik Gilling9c16e962011-03-16 17:27:09 -0700193 b = digitalRead(BUTTON1);
194 if (b != b1) {
195 msg[1] = 0;
196 msg[2] = b ? 0 : 1;
197 acc.write(msg, 3);
198 b1 = b;
199 }
200
201 b = digitalRead(BUTTON2);
202 if (b != b2) {
203 msg[1] = 1;
204 msg[2] = b ? 0 : 1;
205 acc.write(msg, 3);
206 b2 = b;
207 }
208
209 b = digitalRead(BUTTON3);
210 if (b != b3) {
211 msg[1] = 2;
212 msg[2] = b ? 0 : 1;
213 acc.write(msg, 3);
214 b3 = b;
215 }
216
217 switch (count++ % 0x10) {
218
219 case 0:
220 val = analogRead(TEMP_SENSOR);
221 msg[0] = 0x4;
222 msg[1] = val >> 8;
223 msg[2] = val & 0xff;
224 acc.write(msg, 3);
225 break;
226
227 case 0x4:
228 val = analogRead(LIGHT_SENSOR);
229 msg[0] = 0x5;
230 msg[1] = val >> 8;
231 msg[2] = val & 0xff;
232 acc.write(msg, 3);
233 break;
234
235 case 0x8:
236 read_joystick(&x, &y);
237 msg[0] = 0x6;
238 msg[1] = constrain(x, -128, 127);
239 msg[2] = constrain(y, -128, 127);
240 acc.write(msg, 3);
241 break;
242
Erik Gilling9c16e962011-03-16 17:27:09 -0700243 /* captoutched needs to be asynchonous */
244 case 0xc:
Erik Gillingccfe9392011-04-04 10:21:14 -0700245 touchcount = touch_robot.capSense(5);
246
247 c0 = touchcount > 750;
248
Erik Gilling9c16e962011-03-16 17:27:09 -0700249 if (c0 != c) {
250 msg[0] = 0x1;
251 msg[1] = 3;
Erik Gillingccfe9392011-04-04 10:21:14 -0700252 msg[2] = c0;
Erik Gilling9c16e962011-03-16 17:27:09 -0700253 acc.write(msg, 3);
254 c = c0;
255 }
Erik Gillingccfe9392011-04-04 10:21:14 -0700256
Erik Gilling9c16e962011-03-16 17:27:09 -0700257 break;
Erik Gilling9c16e962011-03-16 17:27:09 -0700258 }
Erik Gilling3edead52011-03-08 15:59:23 -0800259 }
260
Erik Gilling9c16e962011-03-16 17:27:09 -0700261 delay(10);
Erik Gilling3edead52011-03-08 15:59:23 -0800262}
263
264// ==============================================================================
265// Austria Microsystems i2c Joystick
266
267/*
268 If a threshold is provided, the dead zone will be programmed such that interrupts will not
269 be generated unless the threshold is exceeded.
270
271 Note that if you use that mode, you will have to use passage of time with no new interrupts
272 to detect that the stick has been released and has returned to center.
273
274 If you need to explicitly track return to center, pass 0 as the threshold. "Center" will
275 still bounce around a little
276*/
277
278
279void init_joystick( int threshold )
280{
281 byte status = 0;
282
283 pinMode( JOY_SWITCH, INPUT );
284 digitalWrite( JOY_SWITCH, HIGH ); // enable the internal pullup
285
286 pinMode( JOY_nINT, INPUT );
287 digitalWrite( JOY_nINT, HIGH ); // enable the internal pullup
288
289 pinMode( JOY_nRESET, OUTPUT );
290
291 digitalWrite( JOY_nRESET, 1 );
292 delay(1);
293 digitalWrite( JOY_nRESET, 0 );
294 delay(1);
295 digitalWrite( JOY_nRESET, 1 );
296
297 Wire.begin();
298
299 do {
300 status = read_joy_reg( 0x0f ); // XXX need timeout
301 } while ((status & 0xf0) != 0xf0);
302
303 write_joy_reg( 0x2e, 0x86 ); // invert magnet polarity setting, per datasheet
304
305 calibrate_joystick( threshold ); // calibrate & set up dead zone area
306}
307
308
309int offset_X, offset_Y;
310
311void calibrate_joystick( int dz )
312{
313 char iii;
314 int x_cal = 0;
315 int y_cal = 0;
316
317 write_joy_reg( 0x0f, 0x00 ); // Low Power Mode, 20ms auto wakeup
318 // INTn output enabled
319 // INTn active after each measurement
320 // Normal (non-Reset) mode
321 delay(1);
322
323 read_joy_reg( 0x11 ); // dummy read of Y_reg to reset interrupt
324
325 for( iii = 0; iii != 16; iii++ ) { // read coords 16 times & average
326 while( !joystick_interrupt() ) // poll for interrupt
327 ;
328 x_cal += read_joy_reg( 0x10 ); // X pos
329 y_cal += read_joy_reg( 0x11 ); // Y pos
330 }
331
332 offset_X = -(x_cal>>4); // divide by 16 to get average
333 offset_Y = -(y_cal>>4);
334
335 //sprintf(msgbuf, "offsets = %d, %d\n", offset_X, offset_Y);
336 //Serial.print(msgbuf);
337
338 write_joy_reg( 0x12, dz - offset_X ); // Xp, LEFT threshold for INTn
339 write_joy_reg( 0x13, -dz - offset_X ); // Xn, RIGHT threshold for INTn
340 write_joy_reg( 0x14, dz - offset_Y ); // Yp, UP threshold for INTn
341 write_joy_reg( 0x15, -dz - offset_Y ); // Yn, DOWN threshold for INTn
342
343 if ( dz ) // dead zone threshold detect requested?
344 write_joy_reg( 0x0f, 0x04 ); // Low Power Mode, 20ms auto wakeup
345 // INTn output enabled
346 // INTn active when movement exceeds dead zone
347 // Normal (non-Reset) mode
348}
349
350
351void read_joystick( int *x, int *y )
352{
353 *x = read_joy_reg( 0x10 ) + offset_X;
354 *y = read_joy_reg( 0x11 ) + offset_Y; // reading Y clears the interrupt
355}
356
357char joystick_interrupt()
358{
359 return ( digitalRead( JOY_nINT ) == 0 );
360}
361
362
363#define JOY_I2C_ADDR 0x40
364
365char read_joy_reg( char reg_addr )
366{
367 char c;
368
369 Wire.beginTransmission( JOY_I2C_ADDR );
370 Wire.send( reg_addr );
371 Wire.endTransmission();
372
373 Wire.requestFrom( JOY_I2C_ADDR, 1 );
374
375 while(Wire.available())
376 c = Wire.receive();
377
378 return c;
379}
380
381void write_joy_reg( char reg_addr, char val )
382{
383 Wire.beginTransmission( JOY_I2C_ADDR );
384 Wire.send( reg_addr );
385 Wire.send( val );
386 Wire.endTransmission();
387}