1
0
mirror of https://github.com/arduino/Arduino.git synced 2025-01-29 18:52:13 +01:00

[sam] added AndroidAccesory class from ADK

This commit is contained in:
Cristian Maglie 2012-04-18 14:34:51 +02:00
parent 761d472f23
commit 008df0430c
9 changed files with 743 additions and 0 deletions

View File

@ -0,0 +1,336 @@
/*
* 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(F("device supports protcol 1\n"));
} else {
Serial.print(F("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);
while (usb.getUsbTaskState() != USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE) {
max.Task();
usb.Task();
}
return true;
}
// Finds the first bulk IN and bulk OUT endpoints
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(F("Can't get config descriptor length\n"));
return false;
}
len = descBuff[2] | ((int)descBuff[3] << 8);
if (len > sizeof(descBuff)) {
Serial.print(F("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(F("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(F("config desc\n"));
break;
case USB_DESCRIPTOR_INTERFACE:
Serial.print(F("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(F("unkown desc type "));
Serial.println( descType, HEX);
break;
}
p += descLen;
}
if (!(inEp->epAddr && outEp->epAddr))
Serial.println(F("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.println(inEp.epAddr, HEX);
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(F("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(F("\nDevice addressed... "));
Serial.print(F("Requesting device descriptor.\n"));
err = usb.getDevDescr(1, 0, 0x12, (char *) devDesc);
if (err) {
Serial.print(F("\nDevice descriptor cannot be retrieved. Trying again\n"));
return false;
}
if (isAccessoryDevice(devDesc)) {
Serial.print(F("found android acessory device\n"));
connected = configureAndroid();
} else {
Serial.print(F("found possible device. swithcing to serial mode\n"));
switchDevice(1);
}
} else if (usb.getUsbTaskState() == USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE) {
if (connected)
Serial.println(F("disconnect\n"));
connected = false;
}
return connected;
}
bool AndroidAccessory::dataBufferIsEmpty() {
return (numBytesInDataBuff == nextByteInDataBuffOffset);
}
void AndroidAccessory::refillDataBuffer() {
int bytesRead = 0;
numBytesInDataBuff = nextByteInDataBuffOffset = 0;
// TODO: Add is connected check?
bytesRead = read(dataBuff, sizeof(dataBuff));
if (bytesRead >= 1) {
numBytesInDataBuff = bytesRead;
}
}
int AndroidAccessory::read() {
if (dataBufferIsEmpty()) {
refillDataBuffer();
}
return dataBufferIsEmpty() ? -1 : dataBuff[nextByteInDataBuffOffset++];
}
int AndroidAccessory::peek() {
if (dataBufferIsEmpty()) {
refillDataBuffer();
}
return dataBufferIsEmpty() ? -1 : dataBuff[nextByteInDataBuffOffset];
}
int AndroidAccessory::available() {
// Strictly speaking this doesn't meet the "This is only for bytes
// that have already arrived" definition from
// <http://arduino.cc/en/Reference/StreamAvailable> but since the
// data isn't handled by an ISR it's the only way to avoid hanging
// waiting for `available()` to return true.
if (dataBufferIsEmpty()) {
refillDataBuffer();
}
return numBytesInDataBuff - nextByteInDataBuffOffset;
}
int AndroidAccessory::read(void *buff, int len, unsigned int nakLimit)
{
return usb.newInTransfer(1, in, len, (char *)buff, nakLimit);
}
size_t AndroidAccessory::write(uint8_t *buff, size_t len)
{
usb.outTransfer(1, out, len, (char *)buff);
return len;
}
size_t AndroidAccessory::write(uint8_t c) {
return write(&c, 1);
}
void AndroidAccessory::flush() {
/*
"Waits for the transmission of outgoing [...] data to complete."
from <http://arduino.cc/en/Serial/Flush>
We're treating this as a no-op at the moment.
*/
}

View File

@ -0,0 +1,90 @@
/*
* 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 "Arduino.h"
#include "Stream.h"
#define DATA_BUFFER_SIZE 64
class AndroidAccessory : public Stream {
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];
// TODO: Reuse `descBuff` after connection and/or stream descriptor?
uint8_t descBuff[256];
byte dataBuff[DATA_BUFFER_SIZE];
unsigned int numBytesInDataBuff;
unsigned int nextByteInDataBuffOffset;
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);
bool dataBufferIsEmpty();
void refillDataBuffer();
// Private because it bypasses the data buffer.
int read(void *buff, int len, unsigned int nakLimit = USB_NAK_LIMIT);
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);
virtual size_t write(uint8_t *buff, size_t len);
virtual int available(void);
virtual int peek(void);
virtual int read(void);
virtual void flush();
virtual size_t write(uint8_t);
using Print::write; // pull in write(str) and write(buf, size) from Print
};
#endif /* __AndroidAccessory_h__ */

View File

@ -0,0 +1,17 @@
---------------------------------------------------------------------------------------------------
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.
---------------------------------------------------------------------------------------------------

View File

@ -0,0 +1,11 @@
Copyright Google, Inc. 2011
This directory contains files & directories originally found in the
ADK_release_0512.zip archive:
README.txt This file
AndroidAccessory.* Open Accessory Protocol and USB Host Libraries
The original README.txt suggested you go to
http://a.android.com/demokit for more information about how to use the
ADK.

View File

@ -0,0 +1,66 @@
/*
* ADK usb digitalRead
*
* TADA!
*
* (c) 2012 D. Cuartielles & A. Goransson
* http://arduino.cc, http://1scale1.com
*
*/
#include <Max3421e.h>
#include <Usb.h>
#include <AndroidAccessory.h>
// accessory descriptor. It's how Arduino identifies itself to Android
char applicationName[] = "Mega_ADK"; // the app on your phone
char accessoryName[] = "Mega_ADK"; // your Arduino board
char companyName[] = "Arduino SA";
// make up anything you want for these
char versionNumber[] = "1.0";
char serialNumber[] = "1";
char url[] = "http://labs.arduino.cc/adk/ADK_count"; // the URL of your app online
// button variables
int buttonPin = A1;
int buttonState = 0;
char letter = 'a';
// counters
long timer = millis();
// initialize the accessory:
AndroidAccessory usb(companyName, applicationName,
accessoryName,versionNumber,url,serialNumber);
void setup() {
// start the connection to the device over the USB host:
usb.powerOn();
pinMode(buttonPin, INPUT);
}
void loop() {
/* Read button state */
buttonState = digitalRead(buttonPin);
/* Print to usb */
if(millis()-timer>100) { // sending 10 times per second
if (usb.isConnected()) { // isConnected makes sure the USB connection is ope
if (buttonState == HIGH) {
usb.write( 'a' );
}
else{
usb.write( ' ' );
}
}
timer = millis();
}
}

View File

@ -0,0 +1,65 @@
/*
* ADK usb digitalRead
*
* TADA!
*
* (c) 2012 D. Cuartielles & A. Goransson
* http://arduino.cc, http://1scale1.com
*
*/
#include <Max3421e.h>
#include <Usb.h>
#include <AndroidAccessory.h>
// accessory descriptor. It's how Arduino identifies itself to Android
char applicationName[] = "Mega_ADK"; // the app on your phone
char accessoryName[] = "Mega_ADK"; // your Arduino board
char companyName[] = "Arduino SA";
// make up anything you want for these
char versionNumber[] = "1.0";
char serialNumber[] = "1";
char url[] = "http://labs.arduino.cc/adk/ADK_count"; // the URL of your app online
// led variables
int ledPin = 10;
// counters
long timer = millis();
// initialize the accessory:
AndroidAccessory usb(companyName, applicationName,
accessoryName,versionNumber,url,serialNumber);
void setup() {
Serial.begin( 9600 );
// start the connection to the device over the USB host:
usb.powerOn();
pinMode(ledPin, OUTPUT);
}
void loop() {
/* Print to usb */
if(millis()-timer>100) { // sending 10 times per second
if (usb.isConnected()) { // isConnected makes sure the USB connection is ope
char val = usb.read();
Serial.print( val );
if( val == 'a' )
digitalWrite( ledPin, HIGH );
else if( val == 'b' )
digitalWrite( ledPin, LOW );
}
timer = millis();
}
}

View File

@ -0,0 +1,63 @@
/*
* ADK usb digitalRead
*
* TADA!
*
* (c) 2012 D. Cuartielles & A. Goransson
* http://arduino.cc, http://1scale1.com
*
*/
#include <Max3421e.h>
#include <Usb.h>
#include <AndroidAccessory.h>
// accessory descriptor. It's how Arduino identifies itself to Android
char applicationName[] = "Mega_ADK"; // the app on your phone
char accessoryName[] = "Mega_ADK"; // your Arduino board
char companyName[] = "Arduino SA";
// make up anything you want for these
char versionNumber[] = "1.0";
char serialNumber[] = "1";
char url[] = "http://labs.arduino.cc/adk/ADK_count"; // the URL of your app online
// button variables
int sliderPin = A1;
int val;
// counters
long timer = millis();
// initialize the accessory:
AndroidAccessory usb(companyName, applicationName,
accessoryName,versionNumber,url,serialNumber);
void setup() {
// start the connection to the device over the USB host:
usb.powerOn();
pinMode(sliderPin, INPUT);
}
void loop() {
/* Read button state */
val = analogRead(sliderPin);
val /= 4;
/* Print to usb */
if(millis()-timer>100) { // sending 10 times per second
if (usb.isConnected()) { // isConnected makes sure the USB connection is ope
usb.write(val);
}
timer = millis();
}
}

View File

@ -0,0 +1,61 @@
/*
* ADK usb analogWrite
*
* TADA!
*
* (c) 2012 D. Cuartielles & A. Goransson
* http://arduino.cc, http://1scale1.com
*
*/
#include <Max3421e.h>
#include <Usb.h>
#include <AndroidAccessory.h>
// accessory descriptor. It's how Arduino identifies itself to Android
char applicationName[] = "Mega_ADK"; // the app on your phone
char accessoryName[] = "Mega_ADK"; // your Arduino board
char companyName[] = "Arduino SA";
// make up anything you want for these
char versionNumber[] = "1.0";
char serialNumber[] = "1";
char url[] = "http://labs.arduino.cc/adk/ADK_count"; // the URL of your app online
// led variables
int ledPin = 10;
// counters
long timer = millis();
// initialize the accessory:
AndroidAccessory usb(companyName, applicationName,
accessoryName,versionNumber,url,serialNumber);
void setup() {
Serial.begin( 9600 );
// start the connection to the device over the USB host:
usb.powerOn();
pinMode(ledPin, OUTPUT);
}
void loop() {
/* Print to usb */
if(millis()-timer>100) { // sending 10 times per second
if (usb.isConnected()) { // isConnected makes sure the USB connection is ope
int val = usb.read();
Serial.println( val );
analogWrite( ledPin, val );
}
timer = millis();
}
}

View File

@ -0,0 +1,34 @@
#include <Max3421e.h>
#include <Usb.h>
#include <AndroidAccessory.h>
AndroidAccessory acc("Google, Inc.",
"DemoKit",
"DemoKit Arduino Board",
"1.0",
"http://www.android.com",
"0000000012345678");
void setup();
void loop();
void setup()
{
Serial.begin(115200);
Serial.print("\r\nStart");
acc.powerOn();
}
void loop()
{
byte msg[3];
if (acc.isConnected()) {
Serial.print("Accessory connected. ");
int len = acc.read(msg, sizeof(msg), 1);
Serial.print("Message length: ");
Serial.println(len, DEC);
}
delay(100);
}