From 2f634de59b551eda0c5702157156600f8914f160 Mon Sep 17 00:00:00 2001 From: Erik Gilling Date: Wed, 16 Mar 2011 17:26:36 -0700 Subject: Add AndroidAccessory library Change-Id: I1e47598ea3a47ea0545dc2ce4b375b0c461c02f2 --- AndroidAccessory/AndroidAccessory.cpp | 256 ++++++++++++++++++++++++++++++++++ AndroidAccessory/AndroidAccessory.h | 69 +++++++++ 2 files changed, 325 insertions(+) create mode 100644 AndroidAccessory/AndroidAccessory.cpp create mode 100644 AndroidAccessory/AndroidAccessory.h 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 +#include +#include + +#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__ */ -- cgit v1.2.3