最近用Freescale 的cortex-M4 K60 MCU 做accessory 连接android 手机, K60这款M4 非常强大,丰富的外围设备,特别是免费的开源实时操作系统MQX ,

加上一个完全开源的usb host  stack ,使开发难度大大的降低了.

开发过程中,分析了下android 端的连接过程,具体如下:

1. host 端发送ctrl request 0x35, 请求 start accessory. kernel android composite driver 开始响应

----------------kernel----------------

2. kernel android usb gadget driver android.c 中:

点击(此处)折叠或打开

static int

android_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *c)

{

struct android_dev        *dev = _android_dev;

struct usb_composite_dev    *cdev = get_gadget_data(gadget);

struct usb_request        *req = cdev->req;

struct android_usb_function    *f;

int value = -EOPNOTSUPP;

unsigned long flags;

req->zero = 0;

req->complete = composite_setup_complete;

req->length = 0;

gadget->ep0->driver_data = cdev;

list_for_each_entry(f, &dev->enabled_functions, enabled_list) {

if (f->ctrlrequest) {

value = f->ctrlrequest(f, cdev, c);

if (value >= 0)

break;

}

}

/* Special case the accessory function.

* It needs to handle control requests before it is enabled.

*/

if (value < 0)

value=acc_ctrlrequest(cdev,c); /*处理 接收到的accessory 的ctrl request*/

3. acc_ctrlrequest 函数在f_accessory.c :

点击(此处)折叠或打开

static int acc_ctrlrequest(struct usb_composite_dev *cdev,

const struct usb_ctrlrequest *ctrl)

......

if (b_requestType == (USB_DIR_OUT | USB_TYPE_VENDOR)) {

if (b_request==ACCESSORY_START) { /*这个就是处理 0x35 request,并调度执行acc_work*/

dev->start_requested = 1;

schedule_delayed_work(

&dev->work, msecs_to_jiffies(10));

value = 0;

} else if (b_request == ACCESSORY_SEND_STRING) {/* 处理5个 string */

dev->string_index = w_index;

cdev->gadget->ep0->driver_data = dev;

cdev->req->complete = acc_complete_set_string;

value = w_length;

}

} else if (b_requestType == (USB_DIR_IN | USB_TYPE_VENDOR)) {

if (b_request == ACCESSORY_GET_PROTOCOL) {

*((u16 *)cdev->req->buf) = PROTOCOL_VERSION;

value = sizeof(u16);

/* clear any strings left over from a previous session */

memset(dev->manufacturer, 0, sizeof(dev->manufacturer));

memset(dev->model, 0, sizeof(dev->model));

memset(dev->description, 0, sizeof(dev->description));

memset(dev->version, 0, sizeof(dev->version));

memset(dev->uri, 0, sizeof(dev->uri));

memset(dev->serial, 0, sizeof(dev->serial));

dev->start_requested = 0;

}

}

......

}

4. acc_work 很简单, 发1个uevent ,接下来就进入android framework 部分处理了:

点击(此处)折叠或打开

static void acc_work(struct work_struct *data)

{

char *envp[2] = { "ACCESSORY=START", NULL };

kobject_uevent_env(&acc_device.this_device->kobj, KOBJ_CHANGE, envp);

}

进入android 处理

----------------android----------------

5. frameworks\base\services\java\com\android\server\usb\UsbDeviceManager.java

中的uevent 监控函数处理ACCESSORY=START 的uevent

点击(此处)折叠或打开

private final UEventObserver mUEventObserver = new UEventObserver() {

@Override

public void onUEvent(UEventObserver.UEvent event) {

if (DEBUG) Slog.v(TAG, "USB UEVENT: " + event.toString());

String state = event.get("USB_STATE");

String accessory = event.get("ACCESSORY");

if (state != null) {

mHandler.updateState(state);

} else if ("START".equals(accessory)) { /* 如果是accessory start uevent 交给setCurrentFunction 处理 */

if (DEBUG) Slog.d(TAG, "got accessory start");

setCurrentFunction(UsbManager.USB_FUNCTION_ACCESSORY, false);

6.   setCurrentFunction 函数如其名,设置 名为UsbManager.USB_FUNCTION_ACCESSORY 为当前function

UsbManager.USB_FUNCTION_ACCESSORY 就是string "accessory"

它给   handleMessage(Message msg) 函数发1个MSG_SET_CURRENT_FUNCTION消息

点击(此处)折叠或打开

public void setCurrentFunction(String function, boolean makeDefault) {

if (DEBUG) Slog.d(TAG, "setCurrentFunction(" + function + ") default: " + makeDefault);

mHandler.sendMessage(MSG_SET_CURRENT_FUNCTION, function, makeDefault);

}

7. 接下来到 public void handleMessage(Message msg) 的 MSG_SET_CURRENT_FUNCTION 分支部分

点击(此处)折叠或打开

case MSG_SET_CURRENT_FUNCTION:

String function = (String)msg.obj;

boolean makeDefault = (msg.arg1 == 1);

setEnabledFunctions(function, makeDefault); /* setEnabledFunctions("accessory",default);*/

8. private void setEnabledFunctions(String functions, boolean makeDefault)

点击(此处)折叠或打开

if (!mDefaultFunctions.equals(functions)) {

if (!setUsbConfig("none")) { /* 先断开,然后再设置*/

Slog.e(TAG, "Failed to disable USB");

// revert to previous configuration if we fail

setUsbConfig(mCurrentFunctions); /* 设置 accessory prop*/

9. setUsbConfig函数:

点击(此处)折叠或打开

private boolean setUsbConfig(String config) {

if (DEBUG) Slog.d(TAG, "setUsbConfig(" + config + ")");

// set the new configuration

SystemProperties.set("sys.usb.config", config);

return waitForState(config);

}

10. SystemProperties.set("sys.usb.config", "accessory"); 后init.rc 中如下

on property 动作被执行

点击(此处)折叠或打开

# USB accessory configuration

on property:sys.usb.config=accessory

write /sys/class/android_usb/android0/enable 0

write /sys/class/android_usb/android0/idVendor 18d1

write /sys/class/android_usb/android0/idProduct 2d00

write /sys/class/android_usb/android0/functions $sys.usb.config

write /sys/class/android_usb/android0/enable 1

setprop sys.usb.state $sys.usb.config

注意

setprop sys.usb.config = "none" 所做的操作如下:

# Used to disable USB when switching states

on property:sys.usb.config=none

stop adbd

write /sys/class/android_usb/android0/enable 0

write /sys/class/android_usb/android0/bDeviceClass 0

setprop sys.usb.state $sys.usb.config

11. 下面两个sysfs 的写入会进入到kernel 中 做相应function bind 等动作,

write /sys/class/android_usb/android0/functions $sys.usb.config

进行function bing 动作

write /sys/class/android_usb/android0/enable 1

这个enanble 注意是设置gadget 底层driver 进行一组disconnect ,connnect 动作

就是disable D+,D-, 告诉host 断开,然后 pullup D+ ,

请求host重新开始枚举自己

具体可跟下 kernel 的usb android.c中的

functions_store, enable_store 函数,这里不展开了

完成后 setprop sys.usb.state "accessory" 让setUsbConfig中的 return waitForState(config);

可以继续执行下去

到kernel 去处理了

----------------kernel----------------

12. 接下来 host 会开始进行新的枚举,

gadget driver 中的 收到setup 的irq 处理函数还是会调到

android_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *c){

只是走的分支不同, 前面enanble 时 已经 更新了ivendor=18d1,iprodunct=2d00,

还执行了acc_bind ,去创建endpoint,当然ep descript 也准备好了,

android_setup 中下面部分会被执行到:

if (value < 0)

value = composite_setup(gadget, c);

执行标准的请求,其中GET despritct 请求时把accessory相关的描述符传给accessory主机,

13. 主机收到descprit 后,很满意,发来set config ,批准连接,

还是android_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *c)

处理:

else if (c->bRequest == USB_REQ_SET_CONFIGURATION && cdev->config) {

schedule_work(&dev->work);     /* 去执行android_work */

}

14. static void android_work(struct work_struct *data)

执行

kobject_uevent_env(&dev->dev->kobj, KOBJ_CHANGE, uevent_envp => USB_STATE=CONFIGURED);

当然前面还有两个uevnent,USB_STATE=DISCONNECTED,USB_STATE=CONNECTED

----------------android----------------

15. 回到android 的

frameworks\base\services\java\com\android\server\usb\UsbDeviceManager.java

uevent 监视函数

点击(此处)折叠或打开

private final UEventObserver mUEventObserver = new UEventObserver() {

@Override

public void onUEvent(UEventObserver.UEvent event) {

if (DEBUG) Slog.v(TAG, "USB UEVENT: " + event.toString());

String state = event.get("USB_STATE");

String accessory = event.get("ACCESSORY");

if (state != null) {

mHandler.updateState(state);/*执行mHandler.updateState(“CONFIGURED”); */

16. mHandler.updateState(“CONFIGURED”); 的函数内容如下:

点击(此处)折叠或打开

public void updateState(String state) {

int connected, configured;

if ("DISCONNECTED".equals(state)) {

connected = 0;

configured = 0;

} else if ("CONNECTED".equals(state)) {

connected = 1;

configured = 0;

} else if ("CONFIGURED".equals(state)) {

connected = 1;

configured = 1; /* 这是connected =1,configured 也 =1 */

} else {

Slog.e(TAG, "unknown state " + state);

return;

}

removeMessages(MSG_UPDATE_STATE);

Message msg = Message.obtain(this, MSG_UPDATE_STATE);

msg.arg1 = connected;

msg.arg2 = configured;

// debounce disconnects to avoid problems bringing up USB tethering

sendMessageDelayed(msg, (connected == 0) ? UPDATE_DELAY : 0);

}

通过sendMessageDelayed 发conected =1,configured =1 消息到handleMessage

17. handle configured Message :

点击(此处)折叠或打开

public void handleMessage(Message msg) {

switch (msg.what) {

case MSG_UPDATE_STATE:

mConnected = (msg.arg1 == 1);

mConfigured = (msg.arg2 == 1);

updateUsbNotification();

updateAdbNotification();

if (containsFunction(mCurrentFunctions,

UsbManager.USB_FUNCTION_ACCESSORY)) {

updateCurrentAccessory(); /* 执行这里 */

}

18.  private void updateCurrentAccessory() {

点击(此处)折叠或打开

if (!mHasUsbAccessory) return;

if (mConfigured) {

String[] strings = nativeGetAccessoryStrings(); /* open acc 去读 host 发来的并且已经保存到accssory function driver 中的 5个string */

if (strings != null) {

mCurrentAccessory = new UsbAccessory(strings); /* 执行这里去创建 UsbAccessory */

Slog.d(TAG, "entering USB accessory mode: " + mCurrentAccessory);

// defer accessoryAttached if system is not ready

if (mBootCompleted) { /* ACTION_BOOT_COMPLETED = "android.intent.action.BOOT_COMPLETED";

判断android 启动完毕否 */

mSettingsManager.accessoryAttached(mCurrentAccessory); /* 去执行attatch 动作,*/

19. accessoryAttached 函数在 :frameworks\base\services\java\com\android\server\usb\UsbSettingsManager.java :

点击(此处)折叠或打开

public void accessoryAttached(UsbAccessory accessory) {

Intent intent = new Intent(UsbManager.ACTION_USB_ACCESSORY_ATTACHED);

intent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory);

intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

发ACTION_USB_ACCESSORY_ATTACHED intent ,

注意 apk 中的usb_accessory_filter.xml 中的内容要与host 发的string 匹配

这样apk 中等待ACTION_USB_ACCESSORY_ATTACHED intend 的apk 启动了

apk 开始是连接界面,连接成功后会提示打开apk否,点确定进入home activiy:

确定后,

接下来 可以进入某项进行操作了

android adk -(sdk),arm cortex-M4 连接android adk2012相关推荐

  1. ARM Cortex M4使用浮点运算单元(FPU)

    1.ARM Cortex M4   ARM Cortex-M4处理器是由ARM专门开发的最新嵌入式处理器,在M3的基础上强化了运算能力,新加了浮点.DSP.并行计算等.Cortex-M4处理器的最大亮 ...

  2. android的sdk和adt,ADT和Android SDK的安装

    本文主要涉及Android开发环境搭建时的Eclipse.ADT及Android SDK的安装方法,还有遇到的两个问题及其解决办法.其中,ADT的安装介绍了在线和离线安装两种方式. 注意:安装3.6版 ...

  3. php和android和mysql_如何使用JSON连接Android和PHP Mysql数据库

    我们先来看一个简单的Android app例子(这里是一个商品存货清单项目),在Android程序中,我们可以访问(call)PHP脚本来执行简单的CRUD操作(创建,读取,更新,删除).为了使你对它 ...

  4. android蓝牙在有效范围内自动连接,android – 如何在范围内找到可用的蓝牙设备?...

    这就是我在Activity中搜索蓝牙设备并在ListView中显示其名称和mac地址的方法.除了在ListView中显示设备外,您几乎可以使用发现的BluetoothDevice对象执行任何操作. F ...

  5. android广告sdk破例,ADT bundle和Android SDK是什么?(能否说的通俗一些,谢谢)

    满意答案 AJlee梨 2019.04.26 采纳率:44%    等级:6 已帮助:409人 这三个版本的出现有一定的历史的原因: 1 .最开始只有eclipse+独立的adt一种开发环境,但是由于 ...

  6. 找不到android的sdk,CircleCI – 找不到Android Studio项目的SDK位置

    尝试在CircleCI上构建项目时,在gradle构建期间发生以下错误.这个问题的原因是什么?我正在运行CircleCI 2.0. FAILURE: Build failed with an exce ...

  7. android的sdk离线安装详细教程,Android编程之SDK安装组件的离线安装方法分享

    本文实例讲述了Android编程之SDK安装组件的离线安装方法.分享给大家供大家参考,具体如下: 这次安装在Android开发环境搭建及配置phoneGap中,搜到了一下资料,留个备份. 一.迅雷下载 ...

  8. 华为怎么连接android studio,华为荣耀5x怎么连接Android studio

    匿名用户 1级 2019-03-09 回答 华为荣耀9开发者选项开启教程.开发者选项是安卓系统里的一个隐藏选项,在默认情况下是找不到的,在开发者选项里面,我们可以对手机进行更高权限的操作,如果你也想使 ...

  9. 基于Arm Cortex内核的32位MCU和MPU(M0、M0+、M3、M4、M33、M7、A7)

    基于Arm Cortex内核的32位MCU和MPU ST意法半导体产品矩阵 M3典型--STM32 F1系列Cortex-M3基础型MCU M4典型--带有DSP和FPU指令的STM32F4系列高性能 ...

最新文章

  1. 开放一些3D视觉相关职位!
  2. 使用 PHPMAILER 发送邮件实例
  3. 拥抱模块化Java平台:Java 10上的Apache CXF
  4. etherpeek nx在网络维护中的应用
  5. html计算天数,Javascript实现简易天数计算器
  6. qt建立c++工程导入项目_工程项目经理A、B、C、D四个等级的区别,你知道吗?
  7. 「代码随想录」121. 买卖股票的最佳时机【贪心】【动态规划】力扣/leetcode详解
  8. Map转json遇到一些问题
  9. 中国计算机学会(CCF)推荐中文科技期刊目录
  10. SSM框架面试题整理
  11. 鸿蒙系统和安装包,鸿蒙系统安装包
  12. TFTLCD显示实验_STM32F1开发指南_第十八章
  13. Web前端 学习知识点总结(十二)jQuery进阶 表单验证和简单正则表达式
  14. zuk z2 android 8,【2018-12-13】ZUK Z2/Z2Pro ZUI 10 尝鲜 Android 8.1 By YouLinw
  15. 如何设置PPT,演示者能看到备注而观众看不到
  16. PhotoShop: PSD精准切图
  17. 微信小程序如何存储数据?
  18. 苹果新Apple TV出现Bug如何解决?
  19. Spark word2vec使用
  20. linux 通过lvm合并磁盘

热门文章

  1. 智能家居DIY的又一神器ESPEasy For ioBroker
  2. SQL Server 练习题3
  3. 新房装修的顺序是什么呢?
  4. 太强了,这款开源日历工具库堪称神器!
  5. V神在BeyondBlock上的演讲:《Ethereum 2.0》
  6. 高等数学下册学习笔记(一)
  7. AWS EC2 云部署(使用方法及过程)
  8. spring面试题(二)
  9. kubernetes自动伸缩
  10. Python,设计一个游戏,游戏会随机数字,让你猜。