android adk -(sdk),arm cortex-M4 连接android adk2012
最近用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相关推荐
- ARM Cortex M4使用浮点运算单元(FPU)
1.ARM Cortex M4 ARM Cortex-M4处理器是由ARM专门开发的最新嵌入式处理器,在M3的基础上强化了运算能力,新加了浮点.DSP.并行计算等.Cortex-M4处理器的最大亮 ...
- android的sdk和adt,ADT和Android SDK的安装
本文主要涉及Android开发环境搭建时的Eclipse.ADT及Android SDK的安装方法,还有遇到的两个问题及其解决办法.其中,ADT的安装介绍了在线和离线安装两种方式. 注意:安装3.6版 ...
- php和android和mysql_如何使用JSON连接Android和PHP Mysql数据库
我们先来看一个简单的Android app例子(这里是一个商品存货清单项目),在Android程序中,我们可以访问(call)PHP脚本来执行简单的CRUD操作(创建,读取,更新,删除).为了使你对它 ...
- android蓝牙在有效范围内自动连接,android – 如何在范围内找到可用的蓝牙设备?...
这就是我在Activity中搜索蓝牙设备并在ListView中显示其名称和mac地址的方法.除了在ListView中显示设备外,您几乎可以使用发现的BluetoothDevice对象执行任何操作. F ...
- android广告sdk破例,ADT bundle和Android SDK是什么?(能否说的通俗一些,谢谢)
满意答案 AJlee梨 2019.04.26 采纳率:44% 等级:6 已帮助:409人 这三个版本的出现有一定的历史的原因: 1 .最开始只有eclipse+独立的adt一种开发环境,但是由于 ...
- 找不到android的sdk,CircleCI – 找不到Android Studio项目的SDK位置
尝试在CircleCI上构建项目时,在gradle构建期间发生以下错误.这个问题的原因是什么?我正在运行CircleCI 2.0. FAILURE: Build failed with an exce ...
- android的sdk离线安装详细教程,Android编程之SDK安装组件的离线安装方法分享
本文实例讲述了Android编程之SDK安装组件的离线安装方法.分享给大家供大家参考,具体如下: 这次安装在Android开发环境搭建及配置phoneGap中,搜到了一下资料,留个备份. 一.迅雷下载 ...
- 华为怎么连接android studio,华为荣耀5x怎么连接Android studio
匿名用户 1级 2019-03-09 回答 华为荣耀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系列高性能 ...
最新文章
- 开放一些3D视觉相关职位!
- 使用 PHPMAILER 发送邮件实例
- 拥抱模块化Java平台:Java 10上的Apache CXF
- etherpeek nx在网络维护中的应用
- html计算天数,Javascript实现简易天数计算器
- qt建立c++工程导入项目_工程项目经理A、B、C、D四个等级的区别,你知道吗?
- 「代码随想录」121. 买卖股票的最佳时机【贪心】【动态规划】力扣/leetcode详解
- Map转json遇到一些问题
- 中国计算机学会(CCF)推荐中文科技期刊目录
- SSM框架面试题整理
- 鸿蒙系统和安装包,鸿蒙系统安装包
- TFTLCD显示实验_STM32F1开发指南_第十八章
- Web前端 学习知识点总结(十二)jQuery进阶 表单验证和简单正则表达式
- zuk z2 android 8,【2018-12-13】ZUK Z2/Z2Pro ZUI 10 尝鲜 Android 8.1 By YouLinw
- 如何设置PPT,演示者能看到备注而观众看不到
- PhotoShop: PSD精准切图
- 微信小程序如何存储数据?
- 苹果新Apple TV出现Bug如何解决?
- Spark word2vec使用
- linux 通过lvm合并磁盘