summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorErik Gilling <konkers@android.com>2011-03-16 17:26:36 -0700
committerErik Gilling <konkers@android.com>2011-03-22 14:10:21 -0700
commit2f634de59b551eda0c5702157156600f8914f160 (patch)
tree660a52eac70554f096ace979cc11e6fc5e0a7763
parentbb9ab4b7d243fd2bbf62462d972216eda03a7802 (diff)
downloadarduino-2f634de59b551eda0c5702157156600f8914f160.tar.gz
Add AndroidAccessory library
Change-Id: I1e47598ea3a47ea0545dc2ce4b375b0c461c02f2
-rw-r--r--AndroidAccessory/AndroidAccessory.cpp256
-rw-r--r--AndroidAccessory/AndroidAccessory.h69
2 files changed, 325 insertions, 0 deletions
diff --git a/AndroidAccessory/AndroidAccessory.cpp b/AndroidAccessory/AndroidAccessory.cpp
new file mode 100644
index 0000000..d063910
--- /dev/null
+++ b/AndroidAccessory/AndroidAccessory.cpp
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#include <Max3421e.h>
+#include <Usb.h>
+#include <AndroidAccessory.h>
+
+#define USB_ACCESSORY_VENDOR_ID 0x18D1
+#define USB_ACCESSORY_PRODUCT_ID 0x2D00
+
+#define USB_ACCESSORY_ADB_PRODUCT_ID 0x2D01
+#define ACCESSORY_STRING_MANUFACTURER 0
+#define ACCESSORY_STRING_MODEL 1
+#define ACCESSORY_STRING_DESCRIPTION 2
+#define ACCESSORY_STRING_VERSION 3
+#define ACCESSORY_STRING_URI 4
+#define ACCESSORY_STRING_SERIAL 5
+
+#define ACCESSORY_GET_PROTOCOL 51
+#define ACCESSORY_SEND_STRING 52
+#define ACCESSORY_START 53
+
+
+AndroidAccessory::AndroidAccessory(const char *manufacturer,
+ const char *model,
+ const char *description,
+ const char *version,
+ const char *uri,
+ const char *serial) : manufacturer(manufacturer),
+ model(model),
+ description(description),
+ version(version),
+ uri(uri),
+ serial(serial),
+ connected(false)
+{
+
+}
+
+void AndroidAccessory::powerOn(void)
+{
+ max.powerOn();
+ delay(200);
+}
+
+int AndroidAccessory::getProtocol(byte addr)
+{
+ uint16_t protocol = -1;
+ usb.ctrlReq(addr, 0, USB_SETUP_DEVICE_TO_HOST | USB_SETUP_TYPE_VENDOR | USB_SETUP_RECIPIENT_DEVICE,
+ ACCESSORY_GET_PROTOCOL, 0, 0, 0, 2, (char *)&protocol);
+ return protocol;
+}
+
+void AndroidAccessory::sendString(byte addr, int index, const char *str)
+{
+ usb.ctrlReq(addr, 0, USB_SETUP_HOST_TO_DEVICE | USB_SETUP_TYPE_VENDOR | USB_SETUP_RECIPIENT_DEVICE,
+ ACCESSORY_SEND_STRING, 0, 0, index, strlen(str) + 1, (char *)str);
+}
+
+
+bool AndroidAccessory::switchDevice(byte addr)
+{
+ int protocol = getProtocol(addr);
+
+ if (protocol == 1) {
+ Serial.print("device supports protcol 1\n");
+ } else {
+ Serial.print("could not read device protocol version\n");
+ return false;
+ }
+
+ sendString(addr, ACCESSORY_STRING_MANUFACTURER, manufacturer);
+ sendString(addr, ACCESSORY_STRING_MODEL, model);
+ sendString(addr, ACCESSORY_STRING_DESCRIPTION, description);
+ sendString(addr, ACCESSORY_STRING_VERSION, version);
+ sendString(addr, ACCESSORY_STRING_URI, uri);
+ sendString(addr, ACCESSORY_STRING_SERIAL, serial);
+
+ usb.ctrlReq(addr, 0, USB_SETUP_HOST_TO_DEVICE | USB_SETUP_TYPE_VENDOR | USB_SETUP_RECIPIENT_DEVICE,
+ ACCESSORY_START, 0, 0, 0, 0, NULL);
+ return true;
+}
+
+bool AndroidAccessory::findEndpoints(byte addr, EP_RECORD *inEp, EP_RECORD *outEp)
+{
+ int len;
+ byte err;
+ uint8_t *p;
+
+ err = usb.getConfDescr(addr, 0, 4, 0, (char *)descBuff);
+ if (err) {
+ Serial.print("Can't get config descriptor length\n");
+ return false;
+ }
+
+
+ len = descBuff[2] | ((int)descBuff[3] << 8);
+ if (len > sizeof(descBuff)) {
+ Serial.print("config descriptor too large\n");
+ /* might want to truncate here */
+ return false;
+ }
+
+ err = usb.getConfDescr(addr, 0, len, 0, (char *)descBuff);
+ if (err) {
+ Serial.print("Can't get config descriptor\n");
+ return false;
+ }
+
+ p = descBuff;
+ inEp->epAddr = 0;
+ outEp->epAddr = 0;
+ while (p < (descBuff + len)){
+ uint8_t descLen = p[0];
+ uint8_t descType = p[1];
+ USB_ENDPOINT_DESCRIPTOR *epDesc;
+ EP_RECORD *ep;
+
+ switch (descType) {
+ case USB_DESCRIPTOR_CONFIGURATION:
+ Serial.print("config desc\n");
+ break;
+
+ case USB_DESCRIPTOR_INTERFACE:
+ Serial.print("interface desc\n");
+ break;
+
+ case USB_DESCRIPTOR_ENDPOINT:
+ epDesc = (USB_ENDPOINT_DESCRIPTOR *)p;
+ if (!inEp->epAddr && (epDesc->bEndpointAddress & 0x80))
+ ep = inEp;
+ else if (!outEp->epAddr)
+ ep = outEp;
+ else
+ ep = NULL;
+
+ if (ep) {
+ ep->epAddr = epDesc->bEndpointAddress & 0x7f;
+ ep->Attr = epDesc->bmAttributes;
+ ep->MaxPktSize = epDesc->wMaxPacketSize;
+ ep->sndToggle = bmSNDTOG0;
+ ep->rcvToggle = bmRCVTOG0;
+ }
+ break;
+
+ default:
+ Serial.print("unkown desc type ");
+ Serial.println( descType, HEX);
+ break;
+ }
+
+ p += descLen;
+ }
+
+ if (!(inEp->epAddr && outEp->epAddr))
+ Serial.println("can't find accessory endpoints");
+
+ return inEp->epAddr && outEp->epAddr;
+}
+
+bool AndroidAccessory::configureAndroid(void)
+{
+ byte err;
+ EP_RECORD inEp, outEp;
+
+ if (!findEndpoints(1, &inEp, &outEp))
+ return false;
+
+ memset(&epRecord, 0x0, sizeof(epRecord));
+
+ epRecord[inEp.epAddr] = inEp;
+ if (outEp.epAddr != inEp.epAddr)
+ epRecord[outEp.epAddr] = outEp;
+
+ in = inEp.epAddr;
+ out = outEp.epAddr;
+
+ Serial.print("inEp: ");
+ Serial.println(inEp.epAddr, HEX);
+ Serial.print("outEp: ");
+ Serial.println(outEp.epAddr, HEX);
+
+ epRecord[0] = *(usb.getDevTableEntry(0,0));
+ usb.setDevTableEntry(1, epRecord);
+
+ err = usb.setConf( 1, 0, 1 );
+ if (err) {
+ Serial.print("Can't set config to 1\n");
+ return false;
+ }
+
+ usb.setUsbTaskState( USB_STATE_RUNNING );
+
+ return true;
+}
+
+bool AndroidAccessory::isConnected(void)
+{
+ USB_DEVICE_DESCRIPTOR *devDesc = (USB_DEVICE_DESCRIPTOR *) descBuff;
+ byte err;
+
+ max.Task();
+ usb.Task();
+
+ if (!connected &&
+ usb.getUsbTaskState() >= USB_STATE_CONFIGURING &&
+ usb.getUsbTaskState() != USB_STATE_RUNNING) {
+ Serial.print("\nDevice addressed... ");
+ Serial.print("Requesting device descriptor.");
+
+ err = usb.getDevDescr(1, 0, 0x12, (char *) devDesc);
+ if (err) {
+ Serial.print("\nDevice descriptor cannot be retrieved. Program Halted\n");
+ while(1);
+ }
+
+ if (isAccessoryDevice(devDesc)) {
+ Serial.print("found android acessory device\n");
+
+ connected = configureAndroid();
+ } else {
+ Serial.print("found possible device. swithcing to serial mode\n");
+ switchDevice(1);
+ }
+ } else if (usb.getUsbTaskState() == USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE) {
+ connected = false;
+ }
+
+ return connected;
+}
+
+int AndroidAccessory::read(void *buff, int len, unsigned int nakLimit)
+{
+ return usb.newInTransfer(1, in, len, (char *)buff, nakLimit);
+}
+
+int AndroidAccessory::write(void *buff, int len)
+{
+ usb.outTransfer(1, out, len, (char *)buff);
+ return len;
+}
+
diff --git a/AndroidAccessory/AndroidAccessory.h b/AndroidAccessory/AndroidAccessory.h
new file mode 100644
index 0000000..1d4542d
--- /dev/null
+++ b/AndroidAccessory/AndroidAccessory.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __AndroidAccessory_h__
+#define __AndroidAccessory_h__
+
+#include "WProgram.h"
+
+class AndroidAccessory {
+private:
+ const char *manufacturer;
+ const char *model;
+ const char *description;
+ const char *version;
+ const char *uri;
+ const char *serial;
+
+ MAX3421E max;
+ USB usb;
+ bool connected;
+ uint8_t in;
+ uint8_t out;
+
+ EP_RECORD epRecord[8];
+
+ uint8_t descBuff[256];
+
+ bool isAccessoryDevice(USB_DEVICE_DESCRIPTOR *desc)
+ {
+ return desc->idVendor == 0x18d1 &&
+ (desc->idProduct == 0x2D00 || desc->idProduct == 0x2D01);
+ }
+
+ int getProtocol(byte addr);
+ void sendString(byte addr, int index, const char *str);
+ bool switchDevice(byte addr);
+ bool findEndpoints(byte addr, EP_RECORD *inEp, EP_RECORD *outEp);
+ bool configureAndroid(void);
+
+public:
+ AndroidAccessory(const char *manufacturer,
+ const char *model,
+ const char *description,
+ const char *version,
+ const char *uri,
+ const char *serial);
+
+ void powerOn(void);
+
+ bool isConnected(void);
+ int read(void *buff, int len, unsigned int nakLimit = USB_NAK_LIMIT);
+ int write(void *buff, int len);
+};
+
+
+#endif /* __AndroidAccessory_h__ */