blob: 454c051e09fd16ccd5cd4078bef66880def9cd38 [file] [log] [blame]
Erik Gilling3edead52011-03-08 15:59:23 -08001#include <Max3421e.h>
2#include <Usb.h>
3#include <Wire.h>
4#include <Servo.h>
5
6#define USB_ACCESSORY_VENDOR_ID 0x18D1
7#define USB_ACCESSORY_PRODUCT_ID 0x2D00
8
9#define USB_ACCESSORY_ADB_PRODUCT_ID 0x2D01
10#define ACCESSORY_STRING_MANUFACTURER 0
11#define ACCESSORY_STRING_MODEL 1
12#define ACCESSORY_STRING_TYPE 2
13#define ACCESSORY_STRING_VERSION 3
14
15#define ACCESSORY_SEND_STRING 52
16#define ACCESSORY_START 53
17
18
19#define LED3_RED 2
20#define LED3_GREEN 3
21#define LED3_BLUE 4
22
23#define LED2_RED 5
24#define LED2_GREEN 6
25#define LED2_BLUE 7
26
27#define LED1_RED 8
28#define LED1_GREEN 9
29#define LED1_BLUE 10
30
31#define SERVO1 11
32#define SERVO2 12
33#define SERVO3 13
34
35#define TOUCH 14
36
37#define RELAY1 A0
38#define RELAY2 A1
39
40#define LIGHT_SENSOR A2
41#define TEMP_SENSOR A3
42
43#define BUTTON1 A6
44#define BUTTON2 A7
45#define BUTTON3 A8
46
47#define JOY_SWITCH A9 // pulls line down when pressed
48#define JOY_nINT A10 // active low interrupt input
49#define JOY_nRESET A11 // active low reset output
50
51
52MAX3421E Max;
53USB Usb;
54Servo servos[3];
55
56
57void setup();
58void loop();
59
60uint8_t usbBuff[256];
61
62
63void init_buttons()
64{
65 pinMode( BUTTON1, INPUT );
66 pinMode( BUTTON2, INPUT );
67 pinMode( BUTTON3, INPUT );
68
69 digitalWrite( BUTTON1, HIGH ); // enable the internal pullups
70 digitalWrite( BUTTON2, HIGH );
71 digitalWrite( BUTTON3, HIGH );
72}
73
74
75void init_relays()
76{
77 pinMode( RELAY1, OUTPUT );
78 pinMode( RELAY2, OUTPUT );
79}
80
81
82void init_leds()
83{
84 digitalWrite( LED1_RED, 1 );
85 digitalWrite( LED1_GREEN, 1 );
86 digitalWrite( LED1_BLUE, 1 );
87
88 pinMode( LED1_RED, OUTPUT );
89 pinMode( LED1_GREEN, OUTPUT );
90 pinMode( LED1_BLUE, OUTPUT );
91
92 digitalWrite( LED2_RED, 1 );
93 digitalWrite( LED2_GREEN, 1 );
94 digitalWrite( LED2_BLUE, 1 );
95
96 pinMode( LED2_RED, OUTPUT );
97 pinMode( LED2_GREEN, OUTPUT );
98 pinMode( LED2_BLUE, OUTPUT );
99
100 digitalWrite( LED3_RED, 1 );
101 digitalWrite( LED3_GREEN, 1 );
102 digitalWrite( LED3_BLUE, 1 );
103
104 pinMode( LED3_RED, OUTPUT );
105 pinMode( LED3_GREEN, OUTPUT );
106 pinMode( LED3_BLUE, OUTPUT );
107}
108
109void init_joystick( int threshold );
110
111void setup()
112{
113 Serial.begin( 115200 );
114 Serial.print("\r\nStart");
115
116 init_leds();
117 init_relays();
118 init_buttons();
119 init_joystick( 5 ); // initialize with thresholding enabled, dead zone of 5 units
120
121
122 servos[0].attach(SERVO1);
123 servos[0].write(90);
124 servos[1].attach(SERVO2);
125 servos[1].write(90);
126 servos[2].attach(SERVO3);
127 servos[2].write(90);
128
129 Max.powerOn();
130 delay( 200 );
131}
132
133bool isAndroidVendor(USB_DEVICE_DESCRIPTOR *desc)
134{
135 return desc->idVendor == 0x18d1 || desc->idVendor == 0x22B8;
136}
137
138bool isAccessoryDevice(USB_DEVICE_DESCRIPTOR *desc)
139{
140 return desc->idProduct == 0x2D00 || desc->idProduct == 0x2D01;
141}
142
143void sendString(byte addr, int index, char *str)
144{
145 Usb.ctrlReq(addr, 0, USB_SETUP_HOST_TO_DEVICE | USB_SETUP_TYPE_VENDOR | USB_SETUP_RECIPIENT_DEVICE,
146 ACCESSORY_SEND_STRING, 0, 0, index, strlen(str) + 1, str);
147
148}
149
150void switchDevice(byte addr)
151{
152 sendString(addr, ACCESSORY_STRING_MANUFACTURER, "Google, Inc.");
153 sendString(addr, ACCESSORY_STRING_MODEL, "DemoKit");
154 sendString(addr, ACCESSORY_STRING_TYPE, "Sample Program");
155 sendString(addr, ACCESSORY_STRING_VERSION, "1.0");
156
157 Usb.ctrlReq(addr, 0, USB_SETUP_HOST_TO_DEVICE | USB_SETUP_TYPE_VENDOR | USB_SETUP_RECIPIENT_DEVICE,
158 ACCESSORY_START, 0, 0, 0, 0, NULL);
159}
160
161bool findEndpoints(byte addr, EP_RECORD *inEp, EP_RECORD *outEp)
162{
163 int len;
164 byte err;
165 uint8_t *p;
166
167 err = Usb.getConfDescr(addr, 0, 4, 0, (char *)usbBuff);
168 if (err) {
169 Serial.print("Can't get config descriptor length\n");
170 return false;
171 }
172
173 len = usbBuff[2] | ((int)usbBuff[3] << 8);
174 Serial.print("Config Desc Length: ");
175 Serial.println(len, DEC);
176 if (len > sizeof(usbBuff)) {
177 Serial.print("config descriptor too large\n");
178 /* might want to truncate here */
179 return false;
180 }
181
182 err = Usb.getConfDescr(addr, 0, len, 0, (char *)usbBuff);
183 if (err) {
184 Serial.print("Can't get config descriptor\n");
185 return false;
186 }
187
188 p = usbBuff;
189 inEp->epAddr = 0;
190 outEp->epAddr = 0;
191 while (p < (usbBuff + len)){
192 uint8_t descLen = p[0];
193 uint8_t descType = p[1];
194 USB_ENDPOINT_DESCRIPTOR *epDesc;
195 EP_RECORD *ep;
196
197 switch (descType) {
198 case USB_DESCRIPTOR_CONFIGURATION:
199 Serial.print("config desc\n");
200 break;
201
202 case USB_DESCRIPTOR_INTERFACE:
203 Serial.print("interface desc\n");
204 break;
205
206 case USB_DESCRIPTOR_ENDPOINT:
207 epDesc = (USB_ENDPOINT_DESCRIPTOR *)p;
208 if (!inEp->epAddr && (epDesc->bEndpointAddress & 0x80))
209 ep = inEp;
210 else if (!outEp->epAddr)
211 ep = outEp;
212 else
213 ep = NULL;
214
215 if (ep) {
216 ep->epAddr = epDesc->bEndpointAddress & 0x7f;
217 ep->Attr = epDesc->bmAttributes;
218 ep->MaxPktSize = epDesc->wMaxPacketSize;
219 ep->sndToggle = bmSNDTOG0;
220 ep->rcvToggle = bmRCVTOG0;
221 }
222 break;
223
224 default:
225 Serial.print("unkown desc type ");
226 Serial.println( descType, HEX);
227 break;
228 }
229
230 p += descLen;
231 }
232
233 return inEp->epAddr && outEp->epAddr;
234}
235
236EP_RECORD ep_record[ 8 ]; //endpoint record structure for the mouse
237
238
239void doAndroid(void)
240{
241 byte err;
242 byte idle;
243 byte b1, b2, b3, c;
244 EP_RECORD inEp, outEp;
245 byte count = 0;
246
247 if (findEndpoints(1, &inEp, &outEp)) {
248
249 ep_record[inEp.epAddr] = inEp;
250 if (outEp.epAddr != inEp.epAddr)
251 ep_record[outEp.epAddr] = outEp;
252
253 Serial.print("inEp: ");
254 Serial.println(inEp.epAddr, HEX);
255 Serial.print("outEp: ");
256 Serial.println(outEp.epAddr, HEX);
257
258 ep_record[0] = *(Usb.getDevTableEntry(0,0));
259 Usb.setDevTableEntry(1, ep_record);
260
261 err = Usb.setConf( 1, 0, 1 );
262 if (err)
263 Serial.print("Can't set config to 1\n");
264
265 Usb.setUsbTaskState( USB_STATE_RUNNING );
266
267 b1 = digitalRead(BUTTON1);
268 b2 = digitalRead(BUTTON2);
269 b3 = digitalRead(BUTTON3);
270 c = captouched();
271
272 while(1) {
273 int len = Usb.newInTransfer(1, inEp.epAddr, sizeof(usbBuff),
274 (char *)usbBuff, 1);
275 int i;
276 byte b;
277 byte msg[3];
278 msg[0] = 0x1;
279
280 if (len > 0) {
281 // XXX: assumes only one command per packet
282 Serial.print(usbBuff[0], HEX);
283 Serial.print(":");
284 Serial.print(usbBuff[1], HEX);
285 Serial.print(":");
286 Serial.println(usbBuff[2], HEX);
287 if (usbBuff[0] == 0x2) {
288 if (usbBuff[1] == 0x0)
289 analogWrite( LED1_RED, 255 - usbBuff[2]);
290 else if (usbBuff[1] == 0x1)
291 analogWrite( LED1_GREEN, 255 - usbBuff[2]);
292 else if (usbBuff[1] == 0x2)
293 analogWrite( LED1_BLUE, 255 - usbBuff[2]);
294 else if (usbBuff[1] == 0x3)
295 analogWrite( LED2_RED, 255 - usbBuff[2]);
296 else if (usbBuff[1] == 0x4)
297 analogWrite( LED2_GREEN, 255 - usbBuff[2]);
298 else if (usbBuff[1] == 0x5)
299 analogWrite( LED2_BLUE, 255 - usbBuff[2]);
300 else if (usbBuff[1] == 0x6)
301 analogWrite( LED3_RED, 255 - usbBuff[2]);
302 else if (usbBuff[1] == 0x7)
303 analogWrite( LED3_GREEN, 255 - usbBuff[2]);
304 else if (usbBuff[1] == 0x8)
305 analogWrite( LED3_BLUE, 255 - usbBuff[2]);
306 else if (usbBuff[1] == 0x10)
307 servos[0].write(map(usbBuff[2], 0, 255, 0, 180));
308 else if (usbBuff[1] == 0x11)
309 servos[1].write(map(usbBuff[2], 0, 255, 0, 180));
310 else if (usbBuff[1] == 0x12)
311 servos[2].write(map(usbBuff[2], 0, 255, 0, 180));
312 } else if (usbBuff[0] == 0x3) {
313 if (usbBuff[1] == 0x0)
314 digitalWrite( RELAY1, usbBuff[2] ? HIGH : LOW );
315 else if (usbBuff[1] == 0x1)
316 digitalWrite( RELAY2, usbBuff[2] ? HIGH : LOW );
317
318 }
319
320// for (i = 0; i < len; i++)
321// Serial.print('\n');
322 }
323
324 b = digitalRead(BUTTON1);
325 if (b != b1) {
326 msg[1] = 0;
327 msg[2] = b ? 0 : 1;
328 Usb.outTransfer(1, outEp.epAddr, 3, (char *)msg);
329 b1 = b;
330 }
331
332 b = digitalRead(BUTTON2);
333 if (b != b2) {
334 msg[1] = 1;
335 msg[2] = b ? 0 : 1;
336 Usb.outTransfer(1, outEp.epAddr, 3, (char *)msg);
337 b2 = b;
338 }
339
340 b = digitalRead(BUTTON3);
341 if (b != b3) {
342 msg[1] = 2;
343 msg[2] = b ? 0 : 1;
344 Usb.outTransfer(1, outEp.epAddr, 3, (char *)msg);
345 b3 = b;
346 }
347
348 if ((count++ % 16) == 0) {
349 uint16_t val;
350 int x, y;
351
352 val = analogRead(TEMP_SENSOR);
353 msg[0] = 0x4;
354 msg[1] = val >> 8;
355 msg[2] = val & 0xff;
356 Usb.outTransfer(1, outEp.epAddr, 3, (char *)msg);
357
358 val = analogRead(LIGHT_SENSOR);
359 msg[0] = 0x5;
360 msg[1] = val >> 8;
361 msg[2] = val & 0xff;
362 Usb.outTransfer(1, outEp.epAddr, 3, (char *)msg);
363
364 read_joystick(&x, &y);
365 msg[0] = 0x6;
366 msg[1] = constrain(x, -128, 127);
367 msg[2] = constrain(y, -128, 127);
368 Usb.outTransfer(1, outEp.epAddr, 3, (char *)msg);
369
370 char c0 = captouched();
371 if (c0 != c) {
372 msg[0] = 0x1;
373 msg[1] = 3;
374 msg[2] = c0 ? 0 : 1;
375 Usb.outTransfer(1, outEp.epAddr, 3, (char *)msg);
376 c = c0;
377 }
378 }
379
380 delay(10);
381
382 }
383
384 }
385
386}
387
388
389void loop()
390{
391 USB_DEVICE_DESCRIPTOR *devDesc = (USB_DEVICE_DESCRIPTOR *) usbBuff;
392 byte err;
393
394 Max.Task();
395 Usb.Task();
396 if( Usb.getUsbTaskState() >= USB_STATE_CONFIGURING ) {
397 Serial.print("\nDevice addressed... ");
398 Serial.print("Requesting device descriptor.");
399
400 err = Usb.getDevDescr(1, 0, 0x12, (char *) devDesc);
401 if (err) {
402 Serial.print("\nDevice descriptor cannot be retrieved. Program Halted\n");
403 while(1);
404 }
405
406 if (isAndroidVendor(devDesc)) {
407 Serial.print("found android device\n");
408
409 if (isAccessoryDevice(devDesc)) {
410 Serial.print("found android acessory device\n");
411 doAndroid();
412 } else {
413 Serial.print("found possible device. swithcing to serial mode\n");
414 switchDevice(1);
415 }
416 }
417
418 while (Usb.getUsbTaskState() != USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE) {
419 Max.Task();
420 Usb.Task();
421
422
423 }
424
425 Serial.print("detached\n");
426
427 }
428
429}
430
431// ==============================================================================
432// Austria Microsystems i2c Joystick
433
434/*
435 If a threshold is provided, the dead zone will be programmed such that interrupts will not
436 be generated unless the threshold is exceeded.
437
438 Note that if you use that mode, you will have to use passage of time with no new interrupts
439 to detect that the stick has been released and has returned to center.
440
441 If you need to explicitly track return to center, pass 0 as the threshold. "Center" will
442 still bounce around a little
443*/
444
445
446void init_joystick( int threshold )
447{
448 byte status = 0;
449
450 pinMode( JOY_SWITCH, INPUT );
451 digitalWrite( JOY_SWITCH, HIGH ); // enable the internal pullup
452
453 pinMode( JOY_nINT, INPUT );
454 digitalWrite( JOY_nINT, HIGH ); // enable the internal pullup
455
456 pinMode( JOY_nRESET, OUTPUT );
457
458 digitalWrite( JOY_nRESET, 1 );
459 delay(1);
460 digitalWrite( JOY_nRESET, 0 );
461 delay(1);
462 digitalWrite( JOY_nRESET, 1 );
463
464 Wire.begin();
465
466 do {
467 status = read_joy_reg( 0x0f ); // XXX need timeout
468 } while ((status & 0xf0) != 0xf0);
469
470 write_joy_reg( 0x2e, 0x86 ); // invert magnet polarity setting, per datasheet
471
472 calibrate_joystick( threshold ); // calibrate & set up dead zone area
473}
474
475
476int offset_X, offset_Y;
477
478void calibrate_joystick( int dz )
479{
480 char iii;
481 int x_cal = 0;
482 int y_cal = 0;
483
484 write_joy_reg( 0x0f, 0x00 ); // Low Power Mode, 20ms auto wakeup
485 // INTn output enabled
486 // INTn active after each measurement
487 // Normal (non-Reset) mode
488 delay(1);
489
490 read_joy_reg( 0x11 ); // dummy read of Y_reg to reset interrupt
491
492 for( iii = 0; iii != 16; iii++ ) { // read coords 16 times & average
493 while( !joystick_interrupt() ) // poll for interrupt
494 ;
495 x_cal += read_joy_reg( 0x10 ); // X pos
496 y_cal += read_joy_reg( 0x11 ); // Y pos
497 }
498
499 offset_X = -(x_cal>>4); // divide by 16 to get average
500 offset_Y = -(y_cal>>4);
501
502 //sprintf(msgbuf, "offsets = %d, %d\n", offset_X, offset_Y);
503 //Serial.print(msgbuf);
504
505 write_joy_reg( 0x12, dz - offset_X ); // Xp, LEFT threshold for INTn
506 write_joy_reg( 0x13, -dz - offset_X ); // Xn, RIGHT threshold for INTn
507 write_joy_reg( 0x14, dz - offset_Y ); // Yp, UP threshold for INTn
508 write_joy_reg( 0x15, -dz - offset_Y ); // Yn, DOWN threshold for INTn
509
510 if ( dz ) // dead zone threshold detect requested?
511 write_joy_reg( 0x0f, 0x04 ); // Low Power Mode, 20ms auto wakeup
512 // INTn output enabled
513 // INTn active when movement exceeds dead zone
514 // Normal (non-Reset) mode
515}
516
517
518void read_joystick( int *x, int *y )
519{
520 *x = read_joy_reg( 0x10 ) + offset_X;
521 *y = read_joy_reg( 0x11 ) + offset_Y; // reading Y clears the interrupt
522}
523
524char joystick_interrupt()
525{
526 return ( digitalRead( JOY_nINT ) == 0 );
527}
528
529
530#define JOY_I2C_ADDR 0x40
531
532char read_joy_reg( char reg_addr )
533{
534 char c;
535
536 Wire.beginTransmission( JOY_I2C_ADDR );
537 Wire.send( reg_addr );
538 Wire.endTransmission();
539
540 Wire.requestFrom( JOY_I2C_ADDR, 1 );
541
542 while(Wire.available())
543 c = Wire.receive();
544
545 return c;
546}
547
548void write_joy_reg( char reg_addr, char val )
549{
550 Wire.beginTransmission( JOY_I2C_ADDR );
551 Wire.send( reg_addr );
552 Wire.send( val );
553 Wire.endTransmission();
554}
555
556/* Capacitive touch technique from Mario Becker, Fraunhofer IGD, 2007 http://www.igd.fhg.de/igd-a4 */
557
558char captouched()
559{
560 char iii, jjj, retval;
561
562 retval = 0;
563
564 for( jjj = 0; jjj != 10; jjj++ ) {
565 delay( 10 );
566
567 pinMode( TOUCH, INPUT );
568 digitalWrite( TOUCH, HIGH );
569
570 for ( iii = 0; iii < 16; iii++ )
571 if( digitalRead( TOUCH ) )
572 break;
573
574 digitalWrite( TOUCH, LOW );
575 pinMode( TOUCH, OUTPUT );
576
577 retval += iii;
578 }
579
580 return retval;
581}