申明:本文部分内容为网络相关资料整理,并结合本人实际工作总结而成。请引用或者转载注明出处,对于文章内容有疑问请留言。
Android Open Accessory Protocol1.0
Android USB配件必须遵守Android开放式配件(AOA)协议,该协议定义了配件(accessory)如何检测和设置与Android设备通信。附件应执行以下步骤:等待并检测连接的设备。
确定设备的附件模式支持。
尝试以附件模式启动设备(如果需要)。
如果设备支持AOA,请与设备建立通信。
以下部分说明如何实施这些步骤。
注意:开发通过USB连接到Android设备的新附件时,请使用AOAv2。
等待和检测连接的设备
附件应持续检查连接的Android设备。当设备连接时,附件应确定设备是否支持附件模式。
确定附件模式支持
当Android设备连接时,它可以处于以下三种状态之一:
支持Android附件模式,并已处于附件模式。
支持Android附件模式,但不在附件模式。
不支持Android附件模式。
在初始连接期间,附件应检查所连接设备的USB设备描述符的供应商ID (vendor ID)和产品ID( product ID)。供应商ID( vendor ID)应与Google的ID(0x18D1)匹配。如果设备已处于附件模式,则产品ID应为0x2D00或0x2D01,并且附件可以使用其自己的通信协议通过批量传输端点与设备建立通信(设备无需在附件模式下启动)。
注意:0x2D00保留给支持附件模式的Android设备。 0x2D01保留用于支持附件模式的设备以及Android调试桥(ADB)协议,该协议暴露了具有两个用于ADB的批量端点的第二个接口。如果在计算机上模拟附件,则可以使用这些端点来调试附件应用程序。通常,不要使用此接口,除非附件在设备上实施到ADB的直通。
如果在USB设备描述符中找到的供应商ID或产品ID与期望值不匹配,则附件无法确定设备是否支持Android附件模式。附件应尝试以附件模式(下面详述)启动设备以确定设备支持。
尝试在附件模式下启动
如果供应商和产品ID在附件模式下不对应于Android供电的设备,则附件不能辨别设备是否支持(但不在附件模式)或者设备不支持附件模式。这可能是因为支持附件模式(但不处于附件模式)的设备最初报告设备制造商供应商和产品ID,而不是AOA供应商和产品ID。
附件应尝试以附件模式启动设备,以确定设备是否支持该模式:
1.发送51控制请求(“获取协议”),以确定设备是否支持Android附件协议。如果设备支持协议,则返回表示支持的协议版本的非零数字。控制请求在端点0上,具有以下特性:
requestType:USB_DIR_IN | USB_TYPE_VENDOR
请求:51
值:0
索引:0
data:协议版本号(16位小端字节从设备到附件)
2.如果设备返回支持的协议版本,请向设备发送带有标识字符串信息的控制请求。该信息允许设备确定附件的适当应用(或者如果不存在适当的应用,则向用户呈现URL)。控制请求在端点0(对于每个字符串ID)上具有以下特征:
requestType:USB_DIR_OUT | USB_TYPE_VENDOR
请求:52
值:0
index:string ID
数据 零终止的UTF8字符串从附件发送到设备
支持以下字符串ID,每个字符串的最大大小为256字节(必须以\ 0结尾)。
制造商名称:0
型号名称:1
描述:2
版本:3
URI:4
序列号:5
3.发送控制请求,要求设备以附件模式启动。控制请求在端点0上,具有以下特性:
requestType:USB_DIR_OUT | USB_TYPE_VENDOR
请求:53
值:0
索引:0
data:none
完成这些步骤后,附件应等待连接的USB设备以附件模式在总线上重新引入自身,然后重新枚举连接的设备。该算法通过检查供应商和产品ID来确定附件模式支持,如果设备成功切换到附件模式,则该ID应该是正确的(例如,对应于Google的供应商和产品ID而不是设备制造商的ID)。如果ID是正确的,则附件移动以与设备建立通信。
注意:AOA当前不支持同时的AOA和MTP连接。要从AOA切换到MTP,附件必须首先断开USB设备(物理或电气等效的方式),然后使用MTP重新连接。
如果任何步骤失败,附件确定设备不支持Android附件模式并等待下一个设备连接。
建立与设备的通信
如果附件在附件模式下检测到Android设备,则附件可以查询设备接口和端点描述符,以获得用于与设备通信的批量端点。
接口数量和批量端点取决于产品ID。产品ID为:
0x2D00的Android设备具有一个接口,两个批量端点用于输入和输出通信。
0x2D01有两个接口,每个接口有两个批量端点,用于输入和输出通信。第一个接口处理标准通信,第二个接口处理ADB通信。要使用接口,请找到第一个批量输入和输出端点,使用SET_CONFIGURATION(0x09)设备请求将设备配置设置为1,然后使用端点进行通信。
Android Open Accessory Protocol 2.0
本文档介绍了Android Open Accessory(AOA)协议自其初始版本以来的更改,并且是AOA第一版的文档的补充。Android Open Accessory Protocol 2.0增加了两个新功能:音频输出(从Android设备到附件)和支持作为一个或多个人机接口设备(HID)到Android设备的附件。 Android应用程序开发人员可以使用的Android SDK API保持不变。
检测的 Android 开放配件 2.0 支持
为了使附件确定所连接的Android设备是否支持附件以及协议级别,附件必须发送getProtocol()命令并检查结果。 Android设备支持初始版本的Android Open Accessory协议返回1,表示协议版本号。 支持本文档中描述的新功能的设备必须为协议版本返回2。 协议版本2.0向上兼容,因此为原始附件协议设计的附件仍然适用于较新的Android设备。 下面的代码从Android开发工具包2011年的AndroidAccessory库演示了这个协议检查:
bool AndroidAccessory::switchDevice(byte addr)
{
int protocol = getProtocol(addr);
if (protocol >= 1) {
Serial.print("device supports protocol 1 or higher\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;
}
AOA 2.0包括新的USB产品ID,每个组合的USB接口在附件模式下可用。 可能的USB接口有:
accessory - 提供2个批量端点用于与Android应用程序通信的接口。
audio - 新的标准USB音频类接口,用于将音频从Android设备流式传输到附件。
adb - 在开发附件时仅用于调试目的的接口。仅在用户已在Android设备的“设置”中启用USB调试时启用。
在 AOA 1.0 中,有只有两个 USB 产品 Id:
0x2D00 - accessory
0x2D01 - accessory + adb
AOA 2.0 添加一个可选的 USB 音频接口,因此,包括 USB 接口的新组合的产品Id:
0x2D02 - audio
0x2D03 - audio + adb
0x2D04 - accessory + audio
0x2D05 - accessory + audio + adb
音频支持
AOA 2.0包括从Android设备到附件的音频输出的可选支持。 此版本的协议支持标准的USB音频类接口,能够2比特16位PCM音频,比特率为44100Khz。 AOA 2.0目前仅限于此输出模式,但将来可能会添加其他音频模式。
要启用音频支持,附件必须发送新的USB控制请求:
SET_AUDIO_MODE
requestType: USB_DIR_OUT | USB_TYPE_VENDOR
request: 58
value: 0 for no audio (default),
1 for 2 channel, 16-bit PCM at 44100 KHz
index: 0
data none
此命令必须在发送ACCESSORY_START命令以进入附件模式之前发送。
HID 的支持
AOA 2.0允许附件使用Android设备注册一个或多个HID设备。这种方法颠倒了典型的USB HID设备(如USB鼠标和键盘)的通信方向。通常,HID设备是连接到诸如个人计算机的USB主机的外围设备。但是在AOA协议的情况下,USB主机充当USB外围设备的一个或多个输入设备。
AOA 2.0中的HID支持只是标准HID事件的代理。该实现不对事件的内容或类型做出假设,并且仅将其传递到输入系统,因此AOA 2.0附件可以充当任何HID设备(鼠标,键盘,游戏控制器等)。它可以用于像媒体播放器上的播放/暂停按钮那样简单的东西,或者像使用鼠标和全QWERTY键盘的扩展坞那样复杂的东西。
AOA 2.0协议添加了四个新的USB控制请求,以允许附件作为一个或多个HID输入设备到Android设备。由于HID支持完全通过端点零上的控制请求完成,因此不需要新的USB接口来提供这种支持。控制请求如下:
ACCESSORY_REGISTER_HID向Android设备注册新的HID设备。附件提供用于标识其他三个呼叫的HID设备的ID号。该ID有效,直到USB断开连接或者直到附件发送ACCESSORY_UNREGISTER_HID以注销HID设备。
ACCESSORY_UNREGISTER_HID注销先前使用ACCESSORY_REGISTER_HID注册的HID设备。
ACCESSORY_SET_HID_REPORT_DESC向Android设备发送HID设备的报告描述符。此请求用于描述HID设备的功能,并且必须在向Android设备报告任何HID事件之前发送。如果报告描述符大于端点零的最大包大小,则发送多个ACCESSORY_SET_HID_REPORT_DESC命令以传送整个描述符。
ACCESSORY_SEND_HID_EVENT将输入事件从附件发送到Android设备。
这些新的控制请求的代码定义如下:
/* Control request for registering a HID device.
* Upon registering, a unique ID is sent by the accessory in the
* value parameter. This ID will be used for future commands for
* the device
*
* requestType: USB_DIR_OUT | USB_TYPE_VENDOR
* request: ACCESSORY_REGISTER_HID_DEVICE
* value: Accessory assigned ID for the HID device
* index: total length of the HID report descriptor
* data none
*/
#define ACCESSORY_REGISTER_HID 54
/* Control request for unregistering a HID device.
*
* requestType: USB_DIR_OUT | USB_TYPE_VENDOR
* request: ACCESSORY_REGISTER_HID
* value: Accessory assigned ID for the HID device
* index: 0
* data none
*/
#define ACCESSORY_UNREGISTER_HID 55
/* Control request for sending the HID report descriptor.
* If the HID descriptor is longer than the endpoint zero max packet size,
* the descriptor will be sent in multiple ACCESSORY_SET_HID_REPORT_DESC
* commands. The data for the descriptor must be sent sequentially
* if multiple packets are needed.
*
* requestType: USB_DIR_OUT | USB_TYPE_VENDOR
* request: ACCESSORY_SET_HID_REPORT_DESC
* value: Accessory assigned ID for the HID device
* index: offset of data in descriptor
* (needed when HID descriptor is too big for one packet)
* data the HID report descriptor
*/
#define ACCESSORY_SET_HID_REPORT_DESC 56
/* Control request for sending HID events.
*
* requestType: USB_DIR_OUT | USB_TYPE_VENDOR
* request: ACCESSORY_SEND_HID_EVENT
* value: Accessory assigned ID for the HID device
* index: 0
* data the HID report for the event
*/
#define ACCESSORY_SEND_HID_EVENT 57
AOA 1.0 与互操作性功能
原始的AOA协议支持Android应用程序通过USB直接与USB主机(附件)通信。 AOA 2.0保持这种支持,但添加了新功能,以允许附件与Android操作系统本身(特别是音频和输入系统)通信。 AOA 2.0的设计使得有可能构建附件,除了原始功能集之外,还使用新的音频和/或HID支持。 只需使用本文档中描述的新功能以及原始的AOA协议功能。
在没有 Android 的应用程序情况下连接 AOA 2.0
可以设计使用新的音频和HID支持,但不需要与Android设备上的应用程序通信的附件(例如,音频基座)。 在这种情况下,用户不想看到与找到并将新附加的附件与能够与其通信的Android应用相关联的对话提示。 为了防止在连接设备和附件后出现这些对话框,附件可以简单地不向Android设备发送制造商和型号名称。 如果这些字符串未被提供给Android设备,则附件能够利用AOA 2.0中的新音频和HID支持,而系统不试图找到与附件通信的应用。 此外,如果未提供这些字符串,则在设备进入附件模式后,Android设备USB配置中不会显示附件USB接口。
Accessory Development Kit 2011 Guide
协议网址:https://developer.android.com/adk/index.htmlhttps://developer.android.com/adk/adk.html
附件开发套件(ADK)是硬件制造商和业余爱好者用作Android的配件开发的参考实施。每个ADK版本都提供了源代码和硬件规格,使开发您自己的附件的过程更容易。鼓励根据ADK创建新的和替代的硬件!
Android配件可以是音频对接站,健身机,个人医疗测试设备,气象站或任何其他外部硬件设备,增加了Android的功能。
附件使用Android开放附件(AOA)协议与Android设备通信,通过USB电缆或通过蓝牙连接。如果您正在构建使用USB的附件,请确保您了解如何实施AOA协议以在您的附件硬件和Android之间建立通信。有关详细信息,请参阅Android Open Acessory协议。
以下部分提供了有关Android配件开发套件,如何使用它们以及如何开始为Android构建自己的配件的更多信息。
ADK 2012指南
在Google I / O 2012上发布的ADK入门指南。
ADK 2011指南
2011年Google I / O发布的原始ADK入门指南。
Android开放附件开发套件(ADK)是基于Arduino开源电子原型平台的Android开放附件的参考实现。附件的硬件设计文件,实现附件固件的代码以及与附件交互的Android应用程序作为套件的一部分提供,以帮助硬件构建者和软件开发人员开始构建自己的附件。硬件设计文件和固件代码包含在ADK软件包下载中。
在Google I / O 2011开发者大会上制作并分发了数量有限的套件。然而,许多硬件制造商已经复制和增强了原始设计,并且这些板可以购买。以下列出的经销商目前正在生产Android Open Accessory兼容开发板:
Arduino商店提供基于ATmega2560并支持ADK固件的Arduino Mega ADK(用于欧盟国家或非欧盟国家)。
DIY Drones提供了一个面向RC(无线电控制)和UAV(无人驾驶飞行器)爱好者的Arduino兼容板。
mbed提供了一个微控制器和一个库来开发支持Android附件协议的附件。有关详细信息,请参阅mbed with Android ADK。
Microchip提供基于PIC的USB微控制器板。
现代设备提供支持ADK固件的Arduino兼容板。
RT Corp提供基于Android ADK板设计的Arduino兼容板。
Seeed Studio提供了一个支持ADK固件的Arduino兼容板。
SparkFun的IOIO板现在已经测试支持ADK固件。
Troido生产了一个Arduino兼容版本的ADK硬件。
我们期望更多的硬件分销商创建各种套件,所以请继续关注进一步的发展
ADK组件
ADK的主要硬件和软件组件包括:
一个基于Arduino Mega2560和Circuits @ Home USB主机屏蔽设计(现在称为ADK板)的USB微控制器板,稍后将作为Android USB附件实现。 ADK板提供输入和输出引脚,您可以通过使用称为“屏蔽”(shields)的附件来实现。用C ++编写的定制固件安装在电路板上,以定义电路板的功能以及与所连接的屏蔽和Android设备的交互。板的硬件设计文件位于硬件/目录中。
固定在ADK板顶部的Android演示屏蔽(ADK屏蔽)实现板上的输入和输出点。这些实现包括操纵杆,LED输出,以及温度和光传感器。您可以创建或购买自己的盾牌或将您自己的功能连接到ADK板以实现自定义功能。屏蔽的硬件设计文件位于硬件/。
基于Arduino USB主机屏蔽库的库为USB微控制器板提供了作为USB主机的逻辑。这允许电路板启动与USB设备的交易。描述如何使用整个库超出了本文档的范围。如果需要,本文档指出与图书馆的重要交互。有关更多信息,请参阅arduino_USB主机屏蔽库的源代码,位于arduino_libs / USB_Host_Shield目录中。
Arduino sketch,arduino_libs / AndroidAccessory / examples / demokit / demokit.pde定义了在ADK板上运行的固件,用C ++编写。草图调用Android附件协议库以与Android设备进行交互。它还将数据从ADK板和屏蔽发送到Android应用程序,并从Android应用程序接收数据,并将其输出到ADK板和屏蔽。
Android附件协议库,位于arduino_libs / AndroidAccessory目录中。此库定义如何枚举总线,找到支持附件模式的连接的Android设备,以及如何设置与设备的通信。
其他第三方库支持ADK板的功能:
CapSense library CapSense库
I2C / TWI (Two-Wire Interface) library I2C / TWI(双线接口)库
Servo library 伺服库
Spi library Spi库
Wire library 线库
Android应用程序DemoKit,与ADK板和屏蔽进行通信。此项目的源在app /目录中
ADK入门
以下部分介绍如何在计算机上安装Arduino软件,使用Arduino IDE安装ADK板的固件,以及安装和运行随附的ADK板的Android应用程序。 开始之前,请下载以下项目以设置开发环境:
Arduino 1.0或更高版本:包含库和一个IDE,用于编码和安装固件到ADK板。
CapSense库v.04:包含感测人体电容的库。 ADK屏蔽上的电容按钮需要此库。
ADK软件包:包含ADK板的固件和ADK板和屏蔽的硬件设计文件
安装Arduino软件和必要的库
安装Arduino软件:
按照Arduino网站上的描述,下载并安装Arduino 1.0或更高版本。
注意:如果您使用Mac,请安装Arduino软件包中包含的FTDI USB串行驱动程序,即使安装说明另有说明。
下载并将ADK包解压缩到您选择的目录。你应该有一个应用程序,arduino_libs和硬件目录。
下载并提取CapSense包到您选择的目录。
安装必要的库:
在Windows上:
将arduino_libs / AndroidAccessory和arduino_libs / USB_Host_Shield目录(完整目录,而不仅仅是其中的文件)复制到<arduino_installation_root> / libraries /目录。
将提取的CapSense / library目录及其内容复制到<arduino_installation_root> / libraries /目录。
在Mac上:
如果它不存在,则在用户帐户的Documents目录中创建一个Arduino目录,在其中包含一个libraries目录。
将arduino_libs / AndroidAccessory和arduino_libs / USB_Host_Shield目录(完整目录,而不仅仅是其中的文件)复制到Documents / Arduino / libraries /目录。
将提取的CapSense / library目录及其内容复制到Documents / Arduino / libraries /目录。
在Linux(Ubuntu)上:
将firmware / arduino_libs / AndroidAccessory和firmware / arduino_libs / USB_Host_Shield目录(完整目录,而不仅仅是其中的文件)复制到<arduino_installation_root> / libraries /目录。
将提取的CapSense / library目录及其内容复制到<arduino_installation_root> / libraries /目录。
通过在shell提示符下输入sudo apt-get install avr-libc来安装avr-libc库。
您现在应该在Arduino库/目录中有三个新目录:AndroidAccessory,USB_Host_Shield和CapSense。
将固件安装到ADK板
要将固件安装到ADK板上:
使用micro-USB端口将ADK板连接到计算机,允许双向通信,并为ADK板供电。
启动Arduino IDE。
单击工具>板> Arduino Mega 2560以指定ADK板的类型。
选择适当的USB端口:
在Windows上:单击工具>串行端口> COM#以指定通信端口。 COM端口号因计算机而异。 COM1通常保留用于串行端口连接。你最有可能想要COM2或COM3。
在Mac上:单击工具>串行端口> dev / tty.usbserial - ###以指定通信端口。
在Linux(Ubuntu)上:单击工具>串行端口> dev / ttyUSB#以指定通信端口。
要打开Demokit草图(固件代码),请单击文件>示例> AndroidAccessory> demokit。
单击草图>验证/编译以确保草图没有错误。
选择文件>上传。当Arduino输出完成上传时,板已准备好与您的Android设备通信。
运行DemoKit Android应用程序
DemoKit Android应用程序在Android设备上运行,并与ADK板通信。 ADK板接收命令,例如点亮板的LED或从板发送数据,例如操纵杆移动和温度读数。
安装应用程序后,您可以通过移动彩色LED或伺服滑块(确保伺服器已连接)或按下应用程序中的继电器按钮与ADK板进行交互。 在ADK盾牌上,您可以按按钮并移动操纵杆以查看其在应用程序中显示的输出。
监视ADK板
ADK固件由几个文件组成,如果您想要构建自己的附件,您应该看看。 arduino_libs / AndroidAccessory目录中的文件是最重要的文件,具有检测和连接到支持附件模式的Android设备的逻辑。 随意添加调试语句(Arduino Serial.println()语句)到位于<arduino_installation_root> / libraries / AndroidAccessory目录中的代码和demokit.pde草图,并将草图重新上传到ADK板,以了解如何 固件工作。
您可以通过单击工具>串行监视器并将波特率设置为115200来查看Arduino串行监视器中的调试语句。以下有关附件如何与Android设备通信的章节描述了您在自己的附件中应该做的许多事情。
ADK板如何实现Android附件协议
如果您可以访问ADK板和屏蔽,以下部分描述了安装在ADK板上的固件代码。固件演示了如何实现Android附件协议的实际示例。即使您没有ADK板和屏蔽,阅读通过硬件检测和与附件模式下的设备交互仍然有用,如果你想移植代码为自己的配件。
固件的重要部分是arduino_libs / AndroidAccessory / examples / demokit / demokit / demokit.pde sketch,它是接收和发送数据到Android设备上运行的DemoKit应用程序的代码。用于检测和设置与Android设备通信的代码包含在arduino_libs / AndroidAccessory / AndroidAccessory.h和arduino_libs / AndroidAccessory / AndroidAccessory.cpp文件中。此代码包括大部分逻辑,将帮助您实现自己的附件的固件。在阅读下面的部分时,在文本编辑器中打开这三个文件可能很有用。
以下部分描述在实现Android附件协议中描述的算法的上下文中的固件代码。
等待和检测连接的设备
在固件代码(demokit.pde)中,loop()函数重复运行并调用AndroidAccessory :: isConnected()来检查任何连接的设备。 如果存在连接的设备,则其不断地更新去往和来自板和应用的输入和输出流。 如果没有连接,它会不断检查要连接的设备:
...
AndroidAccessory acc("Google, Inc.",
"DemoKit",
"DemoKit Arduino Board",
"1.0",
"http://www.android.com",
"0000000012345678");
...
void loop()
{
...
if (acc.isConnected()) {
//communicate with Android application
}
else{
//set the accessory to its default state
}
...
}
确定连接的设备的附件模式支持
当设备连接到ADK板时,它可以已经处于附件模式,支持附件模式,不处于该模式,或不支持附件模式。 AndroidAccessory :: isConnected()方法检查这些情况,并在loop()函数调用它时做出相应的响应。 此功能首先检查连接的设备是否尚未处理。 如果没有,它获取连接设备的设备描述符,通过调用AndroidAccessory :: isAccessoryDevice()来确定设备是否已处于附件模式。 此方法检查设备描述符的供应商和产品ID。 处于附件模式的设备具有供应商ID 0x18D1和产品ID 0x2D00或0x2D01。 如果设备处于附件模式,则ADK板可以与设备建立通信。 如果不是,板将尝试以附件模式启动设备。
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 accessory device\n");
connected = configureAndroid();
} else {
Serial.print("found possible device. switching to serial mode\n");
switchDevice(1);
}
} else if (usb.getUsbTaskState() == USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE) {
connected = false;
}
return connected;
}
尝试在附件模式下启动设备
如果设备尚未处于附件模式,则ADK板必须通过发送控制请求51来确定其是否支持它,以检查设备支持的USB附件协议的版本(参见AndroidAccessory :: getProtocol())。 Android 2.3.4(API级别10)及更高版本支持协议版本1。 Android 4.1(API级别16)及更高版本支持协议版本2。 将来可能支持大于2的版本。 如果返回了适当的协议版本,则板发送控制请求52(对于每个具有AndroidAcessory:sendString()的字符串,发送控制请求52)以发送其标识信息,并且尝试利用控制请求53以附件模式启动设备.AndroidAccessory :: switchDevice()方法负责:
bool AndroidAccessory::switchDevice(byte addr)
{
int protocol = getProtocol(addr);
if (protocol >= 1) {
Serial.print("device supports protocol 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;
}
如果此方法返回false,板将等待,直到连接新设备。 如果成功,则当ADK板重新枚举总线时,器件在USB总线上显示为处于附件模式。 当设备处于附件模式时,附件然后建立与设备的通信
与设备建立通信
如果检测到设备处于附件模式,则附件必须找到正确的批量端点并设置与设备的通信。当ADK板在附件模式下检测到Android设备时,它调用AndroidAccessory :: configureAndroid()函数:
...
if (isAccessoryDevice(devDesc)) {
Serial.print("found android acessory device\n");
connected = configureAndroid();
}
...
这反过来调用findEndpoints()函数:
...
bool AndroidAccessory::configureAndroid(void)
{
byte err;
EP_RECORD inEp, outEp;
if (!findEndpoints(1, &inEp, &outEp))
return false;
...
AndroidAccessory :: findEndpoints()函数查询Android设备的配置描述符,并找到要与USB设备通信的批量数据端点。 为此,它首先获取设备的配置描述符的前四个字节(仅需要descBuff [2]和descBuff [3]),其中包含有关通过获取描述符返回的数据总长度的信息。 该数据用于确定描述符是否可以适合描述符缓冲区。 此描述符还包含有关所有接口和端点描述符的信息。 如果描述符具有适当的大小,则该方法读取整个配置描述符,并用该设备的配置描述符填充整个描述符缓冲区。 如果由于某种原因不再能获得描述符,则返回错误。
...
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;
}
...
一旦描述符在存储器中,指针被分配到缓冲器的第一位置并且用于索引用于读取的缓冲器。有两个端点指针(输入和输出)被传递到AndroidAccessory :: findEndpoints()并且它们的地址被设置为0,因为代码还没有找到任何合适的批量端点。循环读取缓冲区,解析每个配置,接口或端点描述符。对于每个描述符,位置0始终包含描述符的大小(以字节为单位),位置1始终包含描述符类型。使用这两个值,循环跳过任何配置和接口描述符,并使用descLen变量增加缓冲区以获得下一个描述符。
注意:处于附件模式的Android设备可能有两个接口,一个用于与设备的默认通信,另一个用于ADB通信。默认通信接口总是首先索引,因此查找第一个输入和输出批量端点将返回默认通信端点,这是demokit.pde草图。如果您正在编写自己的固件,则为您的配件找到适当端点的逻辑可能不同。
当它找到第一个输入和输出端点描述符时,它将端点指针设置为这些地址。如果findEndpoints()函数查找输入和输出端点,则返回true。它忽略它找到的任何其他端点(ADB接口的端点,如果存在)。
...
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;
}
...
回到configureAndroid()函数,如果找到了端点,它们被适当地设置为通信。 设备的配置设置为1,并且设备的状态设置为“正在运行”,这表示设备已正确设置为与USB附件通信。 设置此状态可防止在AndroidAccessory :: isConnected()函数中重新检测和重新配置设备。
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;
}
最后,需要读取和写入适当端点的方法。 demokit.pde草图根据从Android设备读取或由ADK板发送的数据调用这些方法。 例如,移动ADK屏蔽上的操纵杆会写入由Android设备上运行的DemoKit应用程序读取的数据。 DemoKit应用程序上的移动滑块由demokit.pde草图读取,并更改附件的状态,例如点亮或更改LED灯的颜色。
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; }
有关ADK板如何读取和写入数据的信息,请参阅demokit.pde草图。
Accessory Development Kit 2012 Guide
2012年的Android配件开发套件(ADK)是Android开放附件设备的最新参考实施,旨在帮助Android硬件配件制造商和软件开发人员为Android创建配件。 ADK 2012基于Arduino开源电子原型平台,具有一些硬件和软件扩展,可以与Android设备进行通信。在Google I / O 2012开发人员会议上制作和分发了一些有限的这些工具包。如果你没有收到这些工具包,不要害怕!硬件的规格和设计文件也被发布供制造商和爱好者使用。你应该期望看到具有类似功能的套件可供购买,或者你可以自己建立一个!
该ADK展示的一个重要的新功能之一是通过USB连接播放音频的能力。如果您有兴趣为Android制作音频相关的USB配件,请务必查看此ADK中USB音频基座的参考实现。
组件:
ADK 2012基于Arduino开源电子原型平台,是一种开放式硬件设计。硬件设计文件和固件源代码包含在ADK软件下载中。 ADK包含两个主要的物理硬件组件:
主处理板包含微处理器,USB连接,电源连接器和输入/输出引脚。该板可以从硬件的其余部分中单独卸下和使用。
包含传感器,LED,输入控制,音频放大器和扬声器输出的屏蔽,包含在定制的多边形箱体外壳中。
ADK的主要硬件特性如下:
ARM 32位Cortex M3微处理器
为Android设备单独的USB连接和计算机连接进行编程和调试
光,颜色,接近度,温度,湿度,大气压力和加速度的传感器
Micro SD卡插槽
蓝牙支持
ADK预装了一个可以立即使用的闹钟固件程序。 Android Play应用程式(ADK 2012)可在Google Play上架。 Android应用程序和ADK固件(Arduino sketch)的源代码可以从此页面下载。
ADK 2012还附带了一些附件,可帮助您开发附件,包括:
交流电源适配器
USB A至Micro USB B连接器电缆
Micro USB B至Micro USB AB连接器(小型,矩形插头)
Micro SD卡,预装在ADK SD卡插槽中
使用闹钟:
ADK上预装了闹钟程序。此固件程序允许您使用ADK作为闹钟。
要使用ADK作为闹钟:
轻轻挤压外壳的两个最宽的面,打开ADK。
将提供的交流电源适配器(圆形连接器)连接到主ADK板,或将USB电缆连接到计算机上的端口和计算机上的USB端口。
将你的指尖放在控制面上的时钟符号上。
注意:您可能需要握住手指1-2秒。
使用时钟数字内的加号(+)和减号( - )来设置正确的时间。
将指尖放在闹钟符号上以激活闹钟设置。
使用时钟数字内的加号(+)和减号( - )设置闹钟时间。
使用最后两位数字内的加号(+)和减号( - )打开(开启)或关闭(oF)闹钟。
要设置闹铃音,请将指尖放在闹钟符号上,然后点击机箱顶部的滑块控件。
要将ADK 2012伴随应用程序用于闹钟:
在运行Android 3.1(API Level 12)或更高版本的Android设备上加载随播应用程序:
使用支持NFC的Android设备,将设备解锁并保持在ADK机箱的左侧。按照提示安装应用程序。
- 要么 -
在您的设备上启动Google Play,搜索ADK 2012应用程序并进行安装。如果您找不到应用程式,表示您的装置不相容。尝试在其他设备上安装。
使用以下方法之一将Android设备连接到ADK:
使用蓝牙进行连接:
将交流电源适配器插入ADK。
在Android设备上,打开蓝牙(设置>蓝牙)。
在“设置”页面中,按蓝牙选项查看配对的设备。
选择搜索设备以找到ADK 2012附件,然后按照屏幕上的说明进行连接。
配对完成后,在Android设备上启动ADK 2012应用程序。
在开始屏幕上,选择使用蓝牙按钮。
在配对设备列表中,选择ADK 2012设备。
ADK 2012应用程序应切换到菜单屏幕,您可以开始与ADK附件交互。
使用USB连接:
将交流电源适配器插入ADK。
将Micro USB AB连接器(小的矩形插头)连接到ADK板上标有Phone的端口。
解锁您的Android设备,然后将Micro USB B连接器连接到您的设备。
注意:您的设备必须支持Android USB配件模式。支持此模式的设备包括Google Nexus设备。
在Android设备上,您应该看到一个提示连接到ADK DemoKit 2012,选择确定。
ADK 2012应用程序应该会自动启动,您可以开始与ADK交互。
注意:通过USB连接到Android设备使用ADK时,请确保已插入交流电源适配器。与计算机的USB连接不能提供足够的电压为ADK和设备的USB连接供电。
播放音频
ADK 2012带有音频输出功能,包括放大器和扬声器。您可以使用蓝牙或USB连接从Android设备播放音频。
通过蓝牙播放音频:
按照上一节中的说明将Android设备通过蓝牙连接到ADK。
在Android设备上,导航到设置>蓝牙页面以查看已配对设备的列表,并确保ADK已连接。
选择ADK 2012项目旁边的设置图标。
确保已启用媒体音频选项。
导航到播放音乐或其他音频的应用程序。
播放歌曲或声音,并在ADK扬声器上听它!
要通过USB播放音频,您必须使用运行Android 4.1(API级别16)或更高版本的设备:
将交流电源适配器插入ADK。
将Micro USB AB连接器(小的矩形插头)连接到ADK板上的电话端口。
解锁您的Android设备,然后将Micro USB B连接器连接到您的设备。
注意:您的设备必须支持Android USB配件模式。支持此模式的设备包括Google Nexus设备。
在Android设备上,您应该看到提示连接到ADK DemoKit 2012,选择取消并允许ADK作为媒体设备连接。
导航到播放音乐或其他音频的应用程序。
播放歌曲或声音,并在ADK扬声器上听它!
注意:通过USB连接到Android设备使用ADK时,请确保已插入交流电源适配器。与计算机的USB连接不能提供足够的电压为ADK和设备的USB连接供电。
使用ADK 2012开发配件
ADK 2012是一个硬件平台和一套用于原型设计Android配件的软件库。 本节讨论如何设置开发环境以对ADK进行编程,从而使其能够执行您想要的操作,并测试用于构建您自己的Android配件的软件。
下载ADK源
ADK 2012的支持软件和硬件规格可从Android源存储库获取。 按照以下说明获取ADK的源材料。
下载ADK 2012软件,源代码和硬件设计规范。
下载并安装Git为您的开发系统。
下载并设置repo工具,如Android开源项目网站上所述。
注意:使用Windows的开发人员必须使用Linux兼容性软件包(如cygwin)来安装和运行repo。 在兼容性环境中,您必须安装curl,git和python才能下载并使用repo工具。
在终端窗口中,为下载的源文件创建一个新目录,初始化和同步本地存储库:
$> mkdir android-accessories
$> cd android-accessories
$> repo init -u https://android.googlesource.com/accessories/manifest
$> repo sync
成功完成此过程后,您应该具有使用ADK 2012的源代码和工具:
adk2012 / board - ADK 2012的源代码和硬件设计文件
adk2012 / app - ADK 2012 Android随播应用程序的源代码
external / ide - ADK 2012集成开发环境(IDE)的源代码
external / toolchain - ADK 2012 IDE使用的工具链
设置开发环境
ADK 2012附带了一个集成开发环境(IDE),可用于开发软件和编程ADK 2012附件。以下说明解释如何设置和运行ADK 2012 IDE。
要设置和运行ADK 2012 IDE:
从java.oracle.com下载并安装Java Development Kit 6或更高版本。
为您的开发平台下载ADK 2012 IDE:
视窗
苹果电脑
Linux 32bit,64bit
解压缩下载的存档。
通过导航到解包的ADK2012_IDE /文件夹并运行该应用程序并执行arduino文件。
成功安装并运行ADK 2012 IDE后,必须将其配置为使用ADK 2012库。
要配置ADK 2012 IDE以与ADK库一起使用:
启动ADK 2012 IDE,然后选择“文件”>“首选项”。
在首选项对话框中,记下Sketchbook位置目录。
将<adk-source-download> / adk2012 / board / library / ADK2目录及其内容复制到sketchbook / libraries /目录中,以便创建sketchbook / libraries / ADK2目录。
停止并重新启动ADK 2012 IDE。
在IDE中,选择“文件”>“示例”>“ADK2”,然后选择示例草图之一:
时钟 - 预先加载到ADK 2012上的草图。
BluetoothScan - 一个示例草图,演示将附件通过蓝牙连接到Android设备的代码。
usbaccessory - 一个示例草图,演示通过USB电缆将附件连接到Android设备的代码。
将Micro USB电缆从ADK板上的计算机端口连接到开发计算机。
在ADK 2012 IDE中,通过选择工具>串行端口并选择ADK的串行端口,与ADK建立串行端口连接。
在ADK 2012 IDE中,通过选择工具>板> Google ADK2选择ADK。
修改示例草图或创建自己的草图。
通过选择“文件”>“上传”将草图上传到ADK。当ADK 2012 IDE报告完成上传时,草图已上传,ADK已准备好与您的Android设备通信。
使用ADK替代构建系统
另一种基于文件的构建和上传系统也可用于ADK 2012.该系统基于命令行,适用于使用IDE环境将软件加载到附件硬件上的不便或不合需要的生产环境。
设置环境:
下载ADK 2012源代码文件。
在终端窗口中,导航到<adk-source-download> / adk2012 / board / MakefileBasedBuild。
执行以下命令并按照说明进行操作:
$> ./setup
为您的附件构建程序:
将您的附件代码放在MakefileBasedBuild / app目录中,包括所有必需的库文件。 有关程序格式的示例,请参见app / main.c文件。
执行以下命令并按照说明进行操作:
$> ./build
要在附件硬件上加载程序:
运行上面的构建过程,并确保您的程序已成功编译。
通过USB电缆将附件连接到开发计算机。
检查附件所连接的端口,并将Flash脚本中的UART变量修改为正确的端口地址。 在Linux机器上,端口地址通常为/ dev / ttyUSB0。
执行以下命令将程序加载到附件上:
$> ./flash
ADK如何与Android设备连接
任何Android配件的基本功能是它能够与Android设备连接和通信。 在为附件构建软件时,首先要在附件和Android设备之间创建快速可靠的连接。 本节介绍ADK 2012中使用的连接和通信要点,以便您可以将其应用于开发自己的Android配件。
ADK通过蓝牙连接
ADK 2012应用程序和硬件附件使用蓝牙串行端口配置文件(SPP)连接进行通信。 此连接允许ADK附件和Android设备之间的双向通信。
注意:ADK硬件的实现允许使用其他配置文件和多个连接。 但是,ADK 2012附件和Android应用程序之间的基本通信使用SPP。
附件蓝牙代码
为了启用蓝牙通信,ADK 2012附件的clock.ino草图在setup()方法期间调用btStart()方法以启用射频通信并开始侦听蓝牙连接:
ADK L;
void setup() {
L.adkInit();
L.btStart();
}
...
void btStart(){
uint8_t i, dlci;
int f;
L.btEnable(adkBtConnectionRequest, adkBtLinkKeyRequest, adkBtLinkKeyCreated,
adkBtPinRequest, NULL);
dlci = L.btRfcommReserveDlci(RFCOMM_DLCI_NEED_EVEN);
if(!dlci) dbgPrintf("BTADK: failed to allocate DLCI\n");
else{
//change descriptor to be valid...
for(i = 0, f = -1; i < sizeof(sdpDescrADK); i++){
if(sdpDescrADK[i] == MAGIX){
if(f == -1) f = i;
else break;
}
}
if(i != sizeof(sdpDescrADK) || f == -1){
dbgPrintf("BTADK: failed to find a single marker in descriptor\n");
L.btRfcommReleaseDlci(dlci);
return;
}
sdpDescrADK[f] = dlci >> 1;
dbgPrintf("BTADK has DLCI %u\n", dlci);
L.btRfcommRegisterPort(dlci, btAdkPortOpen, btAdkPortClose, btAdkPortRx);
L.btSdpServiceDescriptorAdd(sdpDescrADK, sizeof(sdpDescrADK));
}
}
请注意,sdpDescrADK对象在变量BT_ADK_UUID中包含通用唯一标识符(UUID)。 此标识符必须与Android应用程序代码中BluetoothSocket连接请求中提供的设备UUID相匹配。
一旦蓝牙启用了上面显示的代码,配件就会侦听连接请求。 ADK库处理侦听和连接详细信息,因此附件在每次循环执行期间调用ADK :: adkEventProcess()一次:
void loop(void)
{
...
L.adkEventProcess(); //let the adk framework do its thing
...
}
如果已建立蓝牙连接,则任何命令都将路由到btAdkPortRx()回调方法(作为btStart()方法的一部分在ADK库中注册)并进行相应处理。 ADK附件使用ADK :: btRfcommPortTx()方法通过蓝牙连接返回消息。 有关更多详细信息,请参阅clock.ino sketch中的这些方法的实现。
Android应用蓝牙代码
在ADK 2012 Android应用程序中,用于处理蓝牙连接的代码封装在BTConnection类中。 在此类中,应用程序请求访问蓝牙适配器,并与ADK 2012附件协商连接。 这里是相关代码的总结:
mAdapter = BluetoothAdapter.getDefaultAdapter();
BluetoothDevice device = mAdapter.getRemoteDevice(address);
mSocket = device.createInsecureRfcommSocketToServiceRecord(ADK_UUID);
mSocket.connect();
请注意第二行中的ADK_UUID参数。 此标识符必须与附件输出的标识符(前面提到的BT_ADK_UUID变量)匹配,否则协议协商失败,并且不会创建BluetoothSocket。 一旦建立连接,您就从套接字获取InputStream和OutputStream对象以与附件通信:
mInStream = mSocket.getInputStream();
mOutStream = mSocket.getOutputStream();
查看ADK 2012软件下载中提供的BTConnection.java文件,了解更多实现细节。
ADK通过USB连接
ADK 2012应用程序和硬件附件也可以使用USB连接进行通信,类似于原始ADK。
附件USB代码
ADK库负责USB连接的大多数实现细节,附件代码必须进行几次调用以初始化USB连接,包括设置附件标识字符串:
ADK L;
void setup() {
L.adkInit();
L.usbSetAccessoryStringVendor(...);
L.usbSetAccessoryStringName(...);
L.usbSetAccessoryStringLongname(...);
L.usbSetAccessoryStringVersion(...);
L.usbSetAccessoryStringUrl(...);
L.usbSetAccessoryStringSerial(...);
L.usbStart();
}
注意:标识字符串必须与在连接的Android应用程序中指定的USB附件过滤器设置匹配,否则应用程序无法与附件连接。
一旦使用上面显示的代码启用USB,配件就会侦听连接请求。 ADK库处理侦听和连接详细信息,因此附件在每次循环执行期间调用ADK :: adkEventProcess()一次:
void loop(void)
{
...
L.adkEventProcess(); //let the adk framework do its thing
...
}
然后,附件必须检查是否有USB连接,以处理命令和发送消息。 这里是相关代码的总结:
void loop() {
if (L.accessoryConnected()) {
int recvLen = L.accessoryReceive(msg, sizeof(msg));
if (recvLen > 0) {
... // process message
}
L.accessorySend(outmsg, outmsgLen);
}
L.adkEventProcess();
}
有关更多详细信息,请参阅clock.ino sketch中的这些方法的实现。
Android应用程序USB代码
在ADK 2012 Android应用程序中,用于处理USB连接的代码封装在UsbConnection类中。 此类设置BroadcastReceiver监听USB事件,然后在接收到匹配的连接事件时尝试连接。 这里是相关代码的总结:
import com.android.future.usb.UsbAccessory;
import com.android.future.usb.UsbManager;
mUSBManager = UsbManager.getInstance(this);
UsbAccessory acc = mUSBManager.getAccessoryList()[0];
if (!mUSBManager.hasPermission(acc)) return;
ADK 2012应用程序使用支持库实现USB附件连接,以支持运行Android 2.3.4(API级别10)的设备。 如果你只需要支持Android 3.1(API Level 12)和更高的设备,就可以替换前4行代码如下:
import android.hardware.usb.UsbAccessory
import android.hardware.usb.UsbManager
mUSBManager = (UsbManager) getSystemService(Context.USB_SERVICE);
UsbAccessory acc = (UsbAccessory)
intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
请注意,当USB附件标识信息与应用程序清单语句引用的res / xml / usb_accessory_filter.xml文件中的信息匹配时,应用程序只接收事件:
<meta-data
android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED"
android:resource="@xml/usb_accessory_filter" />
来自其他USB设备的连接不会被ADK 2012附件接收。
一旦建立连接,应用程序就可以通过文件输入和输出流与附件通信,如以下示例代码所示:
ParcelFileDescriptor mFD = mUSBManager.openAccessory(acc);
if (mFD != null) {
FileDescripter fd = mFD.getFileDescriptor();
mIS = new FileInputStream(fd); // use this to receive messages
mOS = new FileOutputStream(fd); // use this to send commands
}
查看ADK 2012源代码中提供的UsbConnection.java文件以获取更多实现详细信息。
USB音频基座实现
ADK 2012引入的一个重要的新功能是能够通过USB连接播放音频。 此创新是作为Android开放式配件(AOA)协议2.0的更新引入的,并且可在运行Android 4.1(API级别16)及更高版本的设备上使用。
ADK 2012为附件开发人员提供了此功能的参考实现。 无需在连接的Android设备上安装软件应用程序,附件开发人员只需要支持AOA v2。 该实现示出了由于附件上可用的音频硬件,16位,44.1kHz立体声PCM源数据的音频输出被压缩成单个通道。
使用ADK库提供的音频输出功能只需要一些函数调用。 前几个调用在附件setup()例程中,它们为USB连接和音频输出准备附件,如下面的代码示例中所概述的:
ADK L;
void setup() {
L.audioInit();
L.usbh_init()
L.usbStart();
}
有关ADK :: audioInit()函数的更多信息,请参见libraries / ADK / Audio.c库文件。 有关ADK :: usbh_init()函数的更多信息,请参阅libraries / ADK / Usbh.c库文件。
完成此设置后,loop()函数调用ADK :: adkEventProcess()来处理音频输出和其他ADK函数:
void loop(void)
{
...
L.adkEventProcess(); //let the adk framework do its thing
...
}
此调用为ADK执行任务排队,并且作为执行过程的一部分,任务队列在库/ ADK / Usbh.c中执行usbh_work(),它处理音频输出请求。 有关详细信息,请查看此函数的实现。 有关音频输出的其他实现细节,请参见libraries / ADK / accessory.c库文件。
USB方案总结 Android部分
Android开放配件协议Android Open Accessory (AOA) http://source.android.com/devices/accessories/protocol.htmlAndroid USB配件必须遵守Android开放式配件(AOA)协议,该协议定义了配件(accessory)如何检测和设置与Android设备通信。附件应执行以下步骤:
1.等待并检测连接的设备。
2.确定设备的附件模式支持。
3.尝试以附件模式启动设备(如果在USB设备描述符中找到的供应商ID或产品ID与期望值不匹配,则附件无法确定设备是否支持Android附件模式。附件应尝试以附件模式(下面详述)启动设备以确定设备支持。)。
4.如果设备支持AOA,请与设备建立通信。
注意:开发通过USB连接到Android设备的新附件时,请使用AOAv2。
Android Open Accessory Protocol 2.0增加了两个新功能:音频输出(从Android设备到附件)和支持作为一个或多个人机接口设备(HID)到Android设备的附件。 Android应用程序开发人员可以使用的Android SDK API保持不变。
在 AOA 1.0 中,有只有两个 USB 产品 Id:
0x2D00 - accessory
0x2D01 - accessory + adb
AOA 2.0包括新的USB产品ID,每个组合的USB接口在附件模式下可用。 可能的USB接口有:
accessory - 提供2个批量端点用于与Android应用程序通信的接口。
audio - 新的标准USB音频类接口,用于将音频从Android设备流式传输到附件。
adb - 在开发附件时仅用于调试目的的接口。仅在用户已在Android设备的“设置”中启用USB调试时启用。
AOA 2.0 添加一个可选的 USB 音频接口,因此,包括 USB 接口的新组合的产品Id:
0x2D02 - audio
0x2D03 - audio + adb
0x2D04 - accessory + audio
0x2D05 - accessory + audio + adb
音频支持
AOA 2.0包括从Android设备到附件的音频输出的可选支持。 此版本的协议支持标准的USB音频类接口,能够2比特16位PCM音频,比特率为44100Khz。 AOA 2.0目前仅限于此输出模式,但将来可能会添加其他音频模式。
要启用音频支持,附件必须发送新的USB控制请求:SET_AUDIO_MODE
HID 的支持
AOA 2.0允许附件使用Android设备注册一个或多个HID设备。这种方法颠倒了典型的USB HID设备(如USB鼠标和键盘)的通信方向。通常,HID设备是连接到诸如个人计算机的USB主机的外围设备。但是在AOA协议的情况下,USB主机充当USB外围设备的一个或多个输入设备。
AOA 2.0中的HID支持只是标准HID事件的代理。该实现不对事件的内容或类型做出假设,并且仅将其传递到输入系统,因此AOA 2.0附件可以充当任何HID设备(鼠标,键盘,游戏控制器等)。它可以用于像媒体播放器上的播放/暂停按钮那样简单的东西,或者像使用鼠标和全QWERTY键盘的扩展坞那样复杂的东西。
定制配件Custom Accessories https://source.android.com/devices/accessories/custom.html
通过USB电缆连接到Android设备的附件必须支持Android Open Accessory(AOA)协议,该协议指定附件如何通过USB与Android设备建立通信。由于Android设备的低功率输出,AOA需要附件作为USB主机,这意味着连接附件必须为总线供电。
AOA有两个版本支持不同类型的通信:
AOAv1。支持通用附件通信和adb调试。适用于Android 3.1(API Level 12)及更高版本,并通过Android 2.3.4(API级别10)及更高版本中的Add-On Library支持。
AOAv2。支持音频流和人机接口设备(HID)功能。适用于Android 4.1(API级别16)。
如果使用通用附件协议与附件(而不是adb或音频协议)进行通信,则必须提供可检测USB附件连接并建立通信的Android应用程序。
通过USB连接音频:
通过USB连接的配件可以使用AOAv2(Android 4.1(API级别16)及更高版本支持),Android设备连接到支持此协议的配件后,Android系统将其视为标准音频输出设备和路由所有音频到该附件。在Android设备上不需要辅助软件应用程序。
注意:由于Android设备的低功率输出,AOA需要附件作为USB主机,这意味着连接附件必须为总线供电。
AOAv2还通过USB连接支持人机接口设备(HID)协议,使诸如音频基座等附件提供硬件播放控制,如暂停,快进或音量按钮。
定制音频配件Building AudioAccessories https://source.android.com/devices/accessories/audio.html
音频通过USB,Android可以在几种模式下使用USB:
Development。不支持音频。
Accessory。由Android Open Accessory(AOA)2.0提供,并提供有限的音频功能,详情见:定制音频配件Building Audio Accessories
Host。使Android设备能够驱动USB总线,并与各种基于USB的外设(包括音频接口)进行操作。实现主机模式的设备将与遵循USB耳机规范的USB耳机兼容。主机模式音频在USB数字音频中描述。
USB Accessory https://developer.android.com/guide/topics/connectivity/usb/accessory.html
android ADK
ADK(Accessory Development Kit)协议:https://developer.android.com/adk/index.html
Google I/O 2011: Android Open Accessory API and Development Kit (ADK):https://www.youtube.com/watch?v=s7szcpXf2rE
支持AOA2.0手机型号:
http://www.kenwood.com/cs/ce/aoa2/chi.html
说明:当前列表仅对市面主流手机品牌部分型号的AOA2.0协议兼容性进行说明,对于兼容AOA2.0的手机在使用AOA2.0协议时所发生的一些其他如手机通话不从手机扬声器播出,音乐无法在硬件设备播放等无法预料的情况暂时无法说明。
制造商 型号 Android OS 版本 备注
Samsung Galaxy S5 5.0 不支持
Samsung Galaxy S5 4.4.2 支持
Samsung Galaxy S4 5.0.1 不支持
Samsung Galaxy S4 4.4.2 支持
Samsung Galaxy S4 4.3 支持
Samsung Galaxy S3 4.3 支持
Samsung Galaxy S2 4.1.2 不支持
Samsung Galaxy Note 8.0 4.2.2 支持
Samsung Galaxy Note 2 4.3 支持
Samsung Galaxy Note 3 4.4.2 支持
Samsung Galaxy Note 3 4.3 支持
Samsung Galaxy Tab 2 4.2.2 支持
Google Samsung Nexus 4.3 支持
Google Samsung Nexus 4.2.1 支持
Google Samsung Nexus S 4.1.2 支持
Google LG Nexus 5 5.1.1 支持
Google Asus Nexus 7 4.4.2 支持
Sony Xperia Z 4.4.2 支持
Sony Xperia Z1 5.0.2 支持
Sony Xperia Sp 4.3 支持
Sony Xperia C 4.2.2 支持
Sony Xperia A 4.2.2 支持
Sony Xperia Z2 (L50T) 4.4.2 支持
Sony Walkman NW-F886 4.1.1 支持
HuaWei Ascend Y511 4.2.2 支持
HuaWei Ascend P7 4.4.2 不支持
HuaWei Ascend P6 4.2.2 不支持
HuaWei Ascend G6 4.3 支持
Xiao Mi Redmi 4.2.2 支持
Xiao Mi Redmi Note 4.2.2 支持
Xiao Mi Mi 2 4.1.1 不支持
Xiao Mi Mi 1S 4.1.2 不支持
Xiao Mi Mi 1 4.1.2 不支持
Motorola Moto G 5.0.2 支持
HTC HTC One (M8) 5.0.1 不支持
HTC HTC One 5.0.2 支持
HTC HTC J One 4.2.2 不支持
LG G2 4.4.2 支持
LG LG isai 4.2.2 支持
Fujitsu Arrows X 4.4.2 不支持
OPPO N1 4.2.2 不支持
Lenovo Vibe X S960 4.2.2 支持
VIVO Vivo Y11 4.2.2 支持
Acer Liquid S2 4.2.2 支持
数据通道传输速度:
采用批量传输端口进行数据的传输, USB协议规定。控制传输应确保在低/全速时能够使用10%的带宽,高速时能够使用20%的带宽。而批量传输并没有保留任何带宽。即批量传输只有在控制传输和其它传输不需要使用其带宽的情况下,方能使用剩下的带宽。因此,尽管总线闲置时批量传输可以在一段时间里尽快地传输大量的数据,但总线忙时批量传输就可能工作很慢。
通常PC主机可能同时使用诸如鼠标、键盘、摄像头、打印机和扫描仪等多种USB设备,它们分别采用不同的传输方式。可以设想.如果开始只有一个设备以批量传输方式独占系统的全部带宽。显然速度会很快(接近53 MB/s)。但如果新插入的若干设备需要使用控制传输全部20%的保留带宽,那么先前设备批量传输的可用带宽就会下降到原先的80%,传输速度可能变为42 MB/s以下。作为一种更极端情况是批量传输设备插入前,已有设备以控制传输方式完全占有了20%的保留带宽.其它设备也以中断或者同步传输方式共同占据了剩下的80%带宽,那么批量传输设备就会因为没有保留带宽,只能处于等待的状态。
http://www.voidcn.com/blog/luckywang1103/article/p-2145641.html
录音时PCM码流如何分包传输 硬件端 android端处理:
预想方案(实际可实施方案需要STM32和Android端根据PCM码流格式 大小以及数据通道数据传输情况进行私有协议的商量之后再确定):STM32获取到麦克风PCM码流之后,将实时PCM码流分包放入缓冲区中通过AOA2.0 accessory指定的批量传输端口进行发送,Android端在批量传输端口通过16384字节缓冲区进行循环接收数据,接收完成后demo可以对PCM码流进行相应的后续操作,如整包合并,播放PCM码流,生成音频文件。
注:
根据AOA2.0定义,accessory数据通道使用的是批量传输端口,在USB协议中,批量传输端口批量传输:用于对延迟要求宽松,大量数据的可靠传输,如 U 盘等。低速 USB 设备不支持批量传输,高速批量端点的最大包长度为 512,全速批量端点的最大包长度可以为 8、 16、 32、 64。批量传输在访问 USB 总线时,相对其他传输类型具有最低的优先级, USB HOST 总是优先安排其他类型的传输,当总线带宽有富余时才安排批量传输。高速的批量端点必须支持 PING 操作,向主机报告端点的状态, NYET 表示否定应答,没有准备好接收下一个数据包, ACK 表示肯定应答,已经准备好接收下一个数据包。
根据上段所述,因为PCM码流的下发,是通过AOA2.0数据通道进行传输,批量端口传输速度会受到USB版本和USB其他端口数据占用传输带宽情况好坏的影响,所以PCM码流的传输速度和传输稳定性会受到一定程度的影响。
按照AOA2.0协议,accessory数据通道和audio音频通道使用的同时性没有特别确切的说明(如下图),所以对于数据通道和音频通道能否同时使用且相互没有影响还需要经过代码的实际验证,有可能在使用不同的通道时,需要断开之前的通道然后发送新的控制指令,进行新的通道连接,连接成功之后在传输数据。