2011年2月10日星期四

Facebook開發工具比較(for .Net)

 
Facebook開發工具比較(for .Net)
 
臉書整合服務寫於 2010年12月28日 6:53
 
Facebook官方提供的Api SDK,如果依程式語言來區分的話一共有以下幾種:
 
  • JavaScript SDK
  • PHP SDK
  • Python SDK
  • iOS SDK for iPhone, iPod touch, and iPad
  • Android SDK 
 
明 顯地,Facebook官方並沒有提供 for .Net的SDK,所以如果要使用.Net來開發Facebook的應用服務的話,就必須再借助第三方廠商所開發的SDK工具。我沒有實際去找出目前網路 上所有 for .Net的SDK,但就我爬文的結果,被使用最廣泛的主要有三套,如下:
 
 
 
(1) Facebook Developer Toolkit
 
(2) csharp-sdk
 
(3) Facebook C# SDK
 
 
 
來跟大家分享一下我比較的一些結果。
 
 
 
Facebook Developer Toolkit 
 
‧下載的網址:http://facebooktoolkit.codeplex.com/  (for .Net 2.0版本)
 
是 微軟官方所出版的Facebook for .Net SDK,沒錯!就是微軟官方所出的。一開始我看到好像找到寶一樣的開心,文件和範例都蠻齊全的。但是,我再詳細看這個SDK的支援還有最新更新的日期,才 發現它不支援Facebook新版的Graph API,也就是不支援OAuth 2.0 規格的登入授權方式。
 
舊版的 Facebook API登入是使用session_key以及動態的secret,新版的 Facebook API登入則是使用access_token(請參考:i am Jason: Facebook Open Graph的登入授權方式)。雖然現在Facebook API新舊並存,如果是用舊版的Api寫的程是目前都還可以跑,但不曉得哪Facebook要給它停掉,所以還是決定不採用。而且, 後來微軟官方自己也都沒有再更新這個套件了,我再去看這個工具的討論版,蠻多抱怨的文章 ,所以...
 
 
 
csharp-sdk
 
 
for .Net 4.0版本,而且要用Visual Studio 2010才能開啟專案檔,記得!還要自己將套件編譯過才能使用(給的很沒誠意!) 
 
本套件是Facebook官方開發人員所釋出的 for .Net SDK,但是從2010年7月17日公開到現在,一直都在Alpha版,沒錯!好像都沒再更新了。所以, Facebook也沒有將這個工具放在官方正式SDK清單裡面。
 
我看了[after dusk, before dawn]部落格針對該套件寫了幾篇文章,寫的很不錯,有興趣研究的可以連到[after dusk, before dawn: [Facebook] 臉書的C Sharp SDK]研究。
 
我 自己使用的感覺, csharp-sdk將比較繁瑣的Facebook訊息傳遞包裝成簡單的方法,並且提供便利的Jason物件解析方式(Facebook很多都是利用 Jason傳遞資料),基本上是一個麻雀雖小五臟俱全的工具。如果你要比較複雜的功能,或是後來Facebook又釋出的新功能,這個工具可能就達不到, 而要自己再開發。
 
Facebook使用者登入授權的方式主要有兩種,官方說明,一種是利用網頁傳地參數的方式,另一種是利用JS SDK取得Cookie來認證 ,csharp-sdk基本上是使用第一種方式,
 
利用網頁傳地參數的方式會有一些不便之處,後續再分享我的解決方式。
 
 
 
Facebook C# SDK
 
 ‧下載的網址:http://facebooksdk.codeplex.com/
 
for .Net 3.5 & 4.0版本,而且要用Visual Studio 2010才能開啟專案檔。一開始我以為是微軟官方的Facebook for .Net SDK,結果錯!不是微軟官方所出的,是另外的團隊所開發的,我看到的更新版本日期是
 
 
 
Current 4.1.0
 
Date    Fri Dec 17 2010 at 4:00 PM
 
 
 
真是好開心!有再更新耶~(標準越來越低了,有更新就好~),連微軟官方都公開直接支持這個 SDK(這是微軟的風格嗎?) ,範例也都有了,而且相當的齊全,連 Api文件都有了耶~佛心來著~
 
 
 
範例
 
 
 
馬上來測試看看,我是測試CSASPNETFacebookApp專案,但照上面的步驟來編譯,一直會出現Facebook授權失敗的錯誤訊息,我到專案的討論區上,也看到不少人有跟我同樣的問題,現在只能期待這個問題在下一個版本可以被修正。
 
 
 
【後續建議】
 
如果你的專案不大,我直接推薦csharp-sdk,快速上手又輕巧。
 
基本上我是蠻期待Facebook C# SDK這一套的工具的,但是Facebook常常在變動規則,要一直跟著 Facebook的隨興,又不會給搞死的第三方SDK套件,真的必須俱備有兩把刷子!
 
連微軟都索性不再更新官方的Facebook for .Net SDK了。Facebook C# SDK,加油! 
 
 
 
Best Regards
Miao
 
 

2011年1月24日星期一

USB设备描述符

 
USB中,USB HOST是通过各种描述符来识别设备的,有设备描述符,
配置描述符,接口描述符,端点描述符,字符串描述符,报告描述符等等。
USB报告描述符(Report Descriptor)HID设备中的一个描述符,它是比较
复杂的一个描述符。
USB HID设备是通过报告来给传送数据的,报告有输入报告和输出报告。
输入报告是
USB设备发送给主机的,例如USB鼠标将鼠标移动和鼠标点击等
信息返回给电脑,键盘将按键数据数据返回给电脑等;输出报告是主机发送
USB设备的,例如键盘上的数字键盘锁定灯和大写字母锁定灯等。报告是
一个数据包,里面包含的是所要传送的数据。输入报告是通过中断输入端点
输入的,而输出报告有点区别,当没有中断输出端点时,可以通过控制输出
端点
0发送,当有中断输出端点时,通过中断输出端点发出。
而报告描述符,是描述一个报告以及报告里面的数据是用来干什么用的。
通过它,USB HOST可以分析出报告里面的数据所表示的意思。它通过控制输入
端点0返回,主机使用获取报告描述符命令来获取报告描述符,注意这个请求
是发送到接口的,而不是到设备。一个报告描述符可以描述多个报告,不同的
报告通过报告ID来识别,报告ID在报告最前面,即第一个字节。当报告描述符中
没有规定报告ID时,报告中就没有ID字段,开始就是数据。更详细的说明请参看
USB HID协议,该协议可从Http://www.usb.org下载。
 
一个USB设备有一个设备描述符,设备描述符里面决定了该设备有多
少种配置,每种配置描述符对应着配置描述符;而在配置描述符中又定义
了该配置里面有多少个接口,每个接口有对应的接口描述符;在接口描
述符里面又定义了该接口有多少个端点,每个端点对应一个端点描述符;
端点描述符定义了端点的大小,类型等等。由此我们可以看出,USB
描述符之间的关系是一层一层的,最上一层是设备描述符,下面是配置
描述符,再下面是接口描述符,再下面是端点描述符。在获取描述符时,
先获取设备描述符,然后再获取配置描述符,根据配置描述符中的配置
集合长度,一次将配置描述符、接口描述符、端点描述符一起一次读回。
其中可能还会有获取设备序列号,厂商字符串,产品字符串等。
USB主机在检测到USB设备插入后,就要对设备进行枚举了。为什么要枚举呢?枚举就是从设备读取一些信息,知道设备是什么样的设备,如何进行通信,这样主机就可以根据这些信息来加载合适的驱动程序。调试USB设备,很重要的一点就是USB的枚举过程,只要枚举成功了,那么就已经成功大半了。
在说枚举之前,先大概说说
USB的一种传输模式――控制传输。这种传输在USB中是非常重要的,它要保证数据的正确性,在设备的枚举过程中都是使用控制传输的。控制传输分为三个阶段:①建立阶段。②数据阶段。③确认阶段。建立(setup)阶段都是由USB主机发起,它是一个setup数据包,里面包含一些数据请求的命令以及一些数据。如果建立阶段是输入请求,那么数据阶段就要输入数据;如果建立阶段是输出请求,那么数据阶段就要输出数据。如果在数据阶段,即便不需要传送数据,也要发一个0长度的数据包。数据阶段过后就是确认阶段。确认阶段刚好跟数据阶段相反,如果是输入请求,则它是一个输出数据包;如果是输出请求,则它是一个输入数据包。确认阶段用来确认数据的正确传输。
好了,下面我们来看看枚举的详细过程。
首先,
USB主机检测到USB设备插入后,就会先对设备复位。设备复位后,USB主机就会对地址为0的设备发送获取设备描述符的标准请求。所有的USB设备在总线复位后其地址都为0,这样主机就可以跟那些刚刚插入的设备通过地址0通信。主机在建立阶段发出获取设备描述符的输入请求,设备收到该请求后,在数据阶段将设备描述符返回给主机。主机在成功获取到一个数据包的设备描述符后并且确认没有什么错误后(注意:有些USB设备的端点0大小不足18字节(但至少具有8字节),而标准的设备描述有18字节,在这种情况下,USB设备只能暂时按最大包将部分设备描述符返回,而主机在成功获取到前面一部分描述符后,就不会再请求剩下的设备描述符部分,而是进入设置地址阶段),就会返回一个0长度的确认数据包给设备。
然后主机再对设备复位一下,接下来就会进入到设置地址阶段。这时
USB主机发出一个设置地址的请求,并在后面跟着一个0长度的数据输出包。地址包含在建立包中,具体的地址USB主机会负责管理,它会分配一个唯一的地址给新的设备。USB设备在收到地址后,返回0长度的应答包,设备在收到这个0长度应答包的ACK之后,就可以起用新的地址了。这样设备就分配到了一个唯一的设备地址,以后主机就通过它来进行访问该设备。
然后主机再次获取设备描述符,这次跟第一次可能有点不一样,这次需要获取完全部的
18个字节的设备描述符。当然,如果你的端点0缓冲大于18字节的话,那就跟第一次的情形一样了。
接下来,主机就会获取配置描述符。配置描述符总共为
9字节。主机在获取到配置描述符后,根据里面的配置集合总长度,再获取配置集合。配置集合包括配置描述符,接口描述符,端点描符等等。
如果有字符串描述符的话,还要获取字符串描述符。另外
HID设备还有HID描述符等。使用BUS HOUND以及通过串口返回信息,很容易看到具体的过程。总之是主机请求什么,你的程序就响应什么。
下面这些数据是使用BUS HOUND抓的,这个是在WIN2000下抓到的,如果在WINXP下,就看不到设置地址之前的数据。
写了注释下面的部分就是主机和设备之间的数据通信,而其它的则是主机跟根集线器之间的通信数据。
USB是个通用的总线,端口都是统一的。但是USB设备却各种各样,
例如
USB鼠标,USB键盘,U盘等等,那么USB主机是如何识别出不同的
设备的呢?这就要依赖于描述符了。
USB的描述符主要有设备描述符,配置描述符,接口描述符,
端点描述符,字符串描述符,
HID描述符,报告描述符等等。
关于报告描述符,请看我以前写的:《
USB HID报告及报告描述符简介
http://group.ednchina.com/93/198.aspx
一个USB设备有一个设备描述符,设备描述符里面决定了该设备有多
少种配置,每种配置描述符对应着配置描述符;而在配置描述符中又定义
了该配置里面有多少个接口,每个接口有对应的接口描述符;在接口描
述符里面又定义了该接口有多少个端点,每个端点对应一个端点描述符;
端点描述符定义了端点的大小,类型等等。由此我们可以看出,
USB
描述符之间的关系是一层一层的,最上一层是设备描述符,下面是配置
描述符,再下面是接口描述符,再下面是端点描述符。在获取描述符时,
先获取设备描述符,然后再获取配置描述符,根据配置描述符中的配置
集合长度,一次将配置描述符、接口描述符、端点描述符一起一次读回。
其中可能还会有获取设备序列号,厂商字符串,产品字符串等。

每种描述符都有自己独立的编号,如下:
#define DEVICE_DESCRIPTOR 0x01 //设备描述符
#define CONFIGURATION_DESCRIPTOR 0x02 //配置描述符
#define STRING_DESCRIPTOR 0x03 //字符串描述符
#define INTERFACE_DESCRIPTOR 0x04 //接口描述符
#define ENDPOINT_DESCRIPTOR 0x05 //端点描述符

下面分别详细介绍一下各描述符。
1.设备描述符
//定义标准的设备描述符结构
typedef struct _DEVICE_DCESCRIPTOR_STRUCT
{
BYTE blength; //设备描述符的字节数大小
BYTE bDescriptorType; //设备描述符类型编号
WORD bcdUSB; //USB版本号
BYTE bDeviceClass; //USB分配的设备类代码
BYTE bDeviceSubClass; //USB分配的子类代码
BYTE bDeviceProtocol; //USB分配的设备协议代码
BYTE bMaxPacketSize0; //端点0的最大包大小
WORD idVendor; //厂商编号
WORD idProduct; //产品编号
WORD bcdDevice; //设备出厂编号
BYTE iManufacturer; //设备厂商字符串的索引
BYTE iProduct; //描述产品字符串的索引
BYTE iSerialNumber; //描述设备序列号字符串的索引
BYTE bNumConfigurations; //可能的配置数量
}
DEVICE_DESCRIPTOR_STRUCT, * pDEVICE_DESCRIPTOR_STRUCT;
//实际的设备描述符示例
code DEVICE_DESCRIPTOR_STRUCT device_descriptor= //设备描述符
{
sizeof(DEVICE_DESCRIPTOR_STRUCT), //设备描述符的字节数大小,这里是18字节
DEVICE_DESCRIPTOR, //设备描述符类型编号,设备描述符是01
0x1001, //USB版本号,这里是USB01.10,即USB1.1。由于51是大端模式,所以高低字节交换
0x00, //USB分配的设备类代码,0表示类型在接口描述符中定义
0x00, //USB分配的子类代码,上面一项为0时,本项也要设置为0
0x00, //USB分配的设备协议代码,上面一项为0时,本项也要设置为0
0x10, //端点0的最大包大小,这里为16字节
0x7104, //厂商编号,这个是需要跟USB组织申请的ID号,表示厂商代号。
0xf0ff, //该产品的编号,跟厂商编号一起配合使用,让主机注册该设备并加载相应的驱动程序
0x0100, //设备出厂编号
0x01, //设备厂商字符串的索引,在获取字符串描述符时,使用该索引号来识别不同的字符串
0x02, //描述产品字符串的索引,同上
0x03, //描述设备序列号字符串的索引,同上
0x01 //可能的配置数为1,即该设备只有一个配置
};
2.配置描述符
//定义标准的配置描述符结构
typedef struct _CONFIGURATION_DESCRIPTOR_STRUCT
{
BYTE bLength; //配置描述符的字节数大小
BYTE bDescriptorType; //配置描述符类型编号
WORD wTotalLength; //此配置返回的所有数据大小
BYTE bNumInterfaces; //此配置所支持的接口数量
BYTE bConfigurationValue; //Set_Configuration命令所需要的参数值
BYTE iConfiguration; //描述该配置的字符串的索引值
BYTE bmAttributes; //供电模式的选择
BYTE MaxPower; //设备从总线提取的最大电流
}
CONFIGURATION_DESCRIPTOR_STRUCT, * pCONFIGURATION_DESCRIPTOR_STRUCT;
2.接口描述符
//定义标准的接口描述符结构
typedef struct _INTERFACE_DESCRIPTOR_STRUCT
{
BYTE bLength; //接口描述符的字节数大小
BYTE bDescriptorType; //接口描述符的类型编号
BYTE bInterfaceNumber; //该接口的编号
BYTE bAlternateSetting; //备用的接口描述符编号
BYTE bNumEndpoints; //该接口使用的端点数,不包括端点0
BYTE bInterfaceClass; //接口类型
BYTE bInterfaceSubClass; //接口子类型
BYTE bInterfaceProtocol; //接口遵循的协议
BYTE iInterface; //描述该接口的字符串索引值
}
INTERFACE_DESCRIPTOR_STRUCT, * pINTERFACE_DESCRIPTOR_STRUCT;
4.端点描述符
//定义标准的端点描述符结构
typedef struct _ENDPOINT_DESCRIPTOR_STRUCT
{
BYTE bLegth; //端点描述符字节数大小
BYTE bDescriptorType; //端点描述符类型编号
BYTE bEndpointAddress; //端点地址及输入输出属性
BYTE bmAttributes; //端点的传输类型属性
WORD wMaxPacketSize; //端点收、发的最大包大小
BYTE bInterval; //主机查询端点的时间间隔
}
ENDPOINT_DESCRIPTOR_STRUCT, * pENDPOINT_DESCRIPTOR_STRUCT;
下面是一个配置描述符集合的定义
typedef struct _CON_INT_ENDP_DESCRIPTOR_STRUCT
{
CONFIGURATION_DESCRIPTOR_STRUCT configuration_descriptor;
INTERFACE_DESCRIPTOR_STRUCT interface_descritor;
ENDPOINT_DESCRIPTOR_STRUCT endpoint_descriptor[ENDPOINT_NUMBER];
}CON_INT_ENDP_DESCRIPTOR_STRUCT;
配置描述符集合的示例

code CON_INT_ENDP_DESCRIPTOR_STRUCT con_int_endp_descriptor= //配置描述符集合
{
//configuration_descriptor //
配置描述符
{
sizeof(CONFIGURATION_DESCRIPTOR_STRUCT), //
配置描述符的字节数大小,这里为9
CONFIGURATION_DESCRIPTOR, //
配置描述符类型编号,配置描述符为2
(sizeof(CONFIGURATION_DESCRIPTOR_STRUCT)+
sizeof(INTERFACE_DESCRIPTOR_STRUCT)+
sizeof(ENDPOINT_DESCRIPTOR_STRUCT)*ENDPOINT_NUMBER)*256+
(sizeof(CONFIGURATION_DESCRIPTOR_STRUCT)+
sizeof(INTERFACE_DESCRIPTOR_STRUCT)+
sizeof(ENDPOINT_DESCRIPTOR_STRUCT)*ENDPOINT_NUMBER)/256, //
配置描述符集合的总大小
0x01, //只包含一个接口
0x01, //该配置的编号
0x00, //iConfiguration字段
0x80, //采用总线供电,不支持远程唤醒
0xC8 //从总线获取最大电流400mA
},
//interface_descritor //
接口描述符
{
sizeof(INTERFACE_DESCRIPTOR_STRUCT), //
接口描述符的字节数大小,这里为9
INTERFACE_DESCRIPTOR, //
接口描述符类型编号,接口描述符为3
0x00, //
接口编号为4
0x00, //
该接口描述符的编号为0
ENDPOINT_NUMBER, //
0端点数量为2,只使用端点主端点输入和输出
0x08, //定义为USB大容量存储设备
0x06, //使用的子类,为简化块命令
0x50, //使用的协议,这里使用单批量传输协议
0x00 //接口描述符字符串索引,为0,表示没有字符串
},
//endpoint_descriptor[]
{
{ //主端点输入描述
sizeof(ENDPOINT_DESCRIPTOR_STRUCT), //端点描述符的字节数大小,这里为7
ENDPOINT_DESCRIPTOR, //端点描述符类型编号,端点描述符为5
MAIN_POINT_IN, //端点号,主输入端点
ENDPOINT_TYPE_BULK, //使用的传输类型,批量传输
0x4000, //该端点支持的最大包尺寸,64字节
0x00 //中断扫描时间,对批量传输无效
},
{ //主端点输出描述
sizeof(ENDPOINT_DESCRIPTOR_STRUCT), //端点描述符的字节数大小,这里为7
ENDPOINT_DESCRIPTOR, //端点描述符类型编号,端点描述符为5
MAIN_POINT_OUT, //端点号,主输出端点
ENDPOINT_TYPE_BULK, //使用的传输类型,批量传输
0x4000, //该端点支持的最大包尺寸,64字节
0x00 //中断扫描时间,对批量传输无效
}
}
};
其中关于端点的类型定义如下
//定义的端点类型
#define ENDPOINT_TYPE_CONTROL 0x00 //控制传输
#define ENDPOINT_TYPE_ISOCHRONOUS 0x01 //同步传输
#define ENDPOINT_TYPE_BULK 0x02 //批量传输
#define ENDPOINT_TYPE_INTERRUPT 0x03 //中断传输
端点号的定义如下
#define MAIN_POINT_OUT 0x02 //2号输出端点
#define MAIN_POINT_IN 0x82 //2号输入端点
 
 
 
 

2011年1月21日星期五

FW: [嘻嘻哈哈] USB接口的红外电脑遥控

USB接口的红外电脑遥控

USB接口的红外电脑遥控

摘要:本设计采用2262,2272一对无线控制芯片来实现红外的发射和硬件解码。而在USB控制模块则采用51+PDIUSBD12来实现USB设备的枚举和数据传送。

本次设计的要点在于USB键盘的实现,因为本次设计最终与主机进行通信是将USB设备枚举成USB键盘,从而获得操作系统的支持,实现免驱动安装的目的。

(一)方案的选择

1:红外的软件解码

此方案是通过软件的复杂化来简化硬件结构,此方案不仅要求对红外协议的熟悉,而且软件解码耗时较大,不适合进行实时性数据的传送。

2:红外的硬件解码

此方案通过一对无线发射和接受芯片2262,2272来实现红外的解码。其特点是红外传送的实时性好,简化软件编写量,且外围硬件电路并不复杂,故在本次设计中采用此方案。

3:采用LPC2148来实现USB的控制

此方案中,LPC2148是一款内置USB模块的微控制器。用其来实现USB的控制和传送可以最大化的简化外围电路和程序的稳定性,但其缺点是芯片价格高,需要另外学习ARM7系列的编程特点。



4:采用51+PDIUSBD12来实现USB的控制

PDIUSBD12是一款性价比很高的USB 器件它通常用作微控制器系统中实现与微控制器进行通信的高速通用并行接口它还支持本地的DMA 传输,支持USB1.1协议。虽然采用51+PDIUSBD12形式使硬件复杂,但由此换来的软件编写环境的熟悉和价格上的优势,故采用此方案。

(二)USB协议和HID键盘的实现

本设计是通过将此USB设备枚举成USB键盘来实现电脑的控制,所以必定设计到USB设备的枚举,故在此先对USB的枚举进行简单的论述。

枚举就是从设备读取一些信息,知道设备是什么样的设备,如何进行通信,这样主机就可以根据这些信息来加载合适的驱动程序。 在说枚举之前,先大概说说USB的一种传输模式――控制传输。这种传输在USB中是非常重要的,它要保证数据的正确性,在设备的枚举过程中都是使用控制传输的。控制传输分为三个阶段:①建立阶段。②数据阶段。③确认阶段。建立(setup)阶段都是由USB主机发起,它是一个setup数据包,里面包含一些数据请求的命令以及一些数据。如果建立阶段是输入请求,那么数据阶段就要输入数据;如果建立阶段是输出请求,那么数据阶段就要输出数据。如果在数据阶段,即便不需要传送数据,也要发一个0长度的数据包。数据阶段过后就是确认阶段。确认阶段刚好跟数据阶段相反,如果是输入请求,则它是一个输出数据包;如果是输出请求,则它是一个输入数据包。确认阶段用来确认数据的正确传输。



1:枚举过程
首先,USB主机检测到USB设备插入后,就会先对设备复位。设备复位后,USB主机就会对地址为0的设备发送获取设备描述符的标准请求。所有的USB设备在总线复位后其地址都为0,这样主机就可以跟那些刚刚插入的设备通过地址0通信。主机在建立阶段发出获取设备描述符的输入请求,设备收到该请求后,在数据阶段将设备描述符返回给主机。主机在成功获取到一个数据包的设备描述符后并且确认没有什么错误后(注意:有些USB设备的端点0大小不足18字节(但至少具有8字节),而标准的设备描述有18字节,在这种情况下,USB设备只能暂时按最大包将部分设备描述符返回,而主机在成功获取到前面一部分描述符后,就不会再请求剩下的设备描述符部分,而是进入设置地址阶段),就会返回一个0长度的确认数据包给设备。
然后主机再对设备复位一下,接下来就会进入到设置地址阶段。这时USB主机发出一个设置地址的请求,并在后面跟着一个0长度的数据输出包。地址包含在建立包中,具体的地址USB主机会负责管理,它会分配一个唯一的地址给新的设备。USB设备在收到地址后,返回0长度的应答包,设备在收到这个0长度应答包的ACK之后,就可以起用新的地址了。这样设备就分配到了一个唯一的设备地址,以后主机就通过它来进行访问该设备。
然后主机再次获取设备描述符,这次跟第一次可能有点不一样,这次需要获取完全部的18个字节的设备描述符。当然,如果你的端点0缓冲大于18字节的话,那就跟第一次的情形一样了。
接下来,主机就会获取配置描述符。配置描述符总共为9字节。主机在获取到配置描述符后,根据里面的配置集合总长度,再获取配置集合。配置集合包括配置描述符,接口描述符,端点描符等等。

如果在设备描述符中定义了字符串描述符,而主机还需要获取字符串描述符。字符串描述符的长度不固定,可由程序员自行确定。
而在此设计中,由于键盘是一种HID设备,故主机还需要获取HID设备类描述符。HID设备类描述符包括HID描述符、报告描述符、物理描述符三种,其中报告描述符是必须的,而另外两种则为可选描述符。

主机得到各种正确的描述符,则为枚举成功,主机加载合适的驱动,即可进行通讯。

2:各种描述符

一个USB设备有一个设备描述符,设备描述符里面决定了该设备有多
少种配置,每种配置描述符对应着配置描述符;而在配置描述符中又定义
了该配置里面有多少个接口,每个接口有对应的接口描述符;在接口描
述符里面又定义了该接口有多少个端点,每个端点对应一个端点描述符;
端点描述符定义了端点的大小,类型等等。由此我们可以看出,USB的
描述符之间的关系是一层一层的,最上一层是设备描述符,下面是配置
描述符,再下面是接口描述符,再下面是端点描述符。在获取描述符时,
先获取设备描述符,然后再获取配置描述符,根据配置描述符中的配置
集合长度,一次将配置描述符、接口描述符、端点描述符一起一次读回。
其中可能还会有获取设备序列号,厂商字符串,产品字符串等。


每种描述符都有自己独立的编号,如下:
DEVICE_DESCRIPTOR 0x01 //设备描述符
CONFIGURATION_DESCRIPTOR 0x02 //配置描述符
STRING_DESCRIPTOR 0x03 //字符串描述符
INTERFACE_DESCRIPTOR 0x04 //接口描述符
ENDPOINT_DESCRIPTOR 0x05 //端点描述符

设备描述符



BYTE blength; //设备描述符的字节数大小
BYTE bDescriptorType; //设备描述符类型编号
WORD bcdUSB; //USB版本号
BYTE bDeviceClass; //USB分配的设备类代码
BYTE bDeviceSubClass; //USB分配的子类代码
BYTE bDeviceProtocol; //USB分配的设备协议代码
BYTE bMaxPacketSize0; //端点0的最大包大小
WORD idVendor; //厂商编号
WORD idProduct; //产品编号
WORD bcdDevice; //设备出厂编号
BYTE iManufacturer; //设备厂商字符串的索引
BYTE iProduct; //描述产品字符串的索引
BYTE iSerialNumber; //描述设备序列号字符串的索引
BYTE bNumConfigurations; //可能的配置数量

配置描述符

BYTE bLength; //配置描述符的字节数大小
BYTE bDescriptorType; //配置描述符类型编号
WORD wTotalLength; //此配置返回的所有数据大小
BYTE bNumInterfaces; //此配置所支持的接口数量
BYTE bConfigurationValue; //配置值
BYTE iConfiguration; //描述该配置的字符串索引值
BYTE bmAttributes; //供电模式的选择
BYTE MaxPower; //设备从总线提取的最大电流



接口描述符
BYTE bLength; //接口描述符的字节数大小
BYTE bDescriptorType; //接口描述符的类型编号
BYTE bInterfaceNumber; //该接口的编号
BYTE bAlternateSetting; //备用的接口描述符编号
BYTE bNumEndpoints; //接口使用的端点数不包括端点0
BYTE bInterfaceClass; //接口类型
BYTE bInterfaceSubClass; //接口子类型
BYTE bInterfaceProtocol; //接口遵循的协议
BYTE iInterface; //描述该接口的字符串索引值



端点描述符
BYTE bLegth; //端点描述符字节数大小
BYTE bDescriptorType; //端点描述符类型编号
BYTE bEndpointAddress; //端点地址及输入输出属性
BYTE bmAttributes; //端点的传输类型属性
WORD wMaxPacketSize; //端点收、发的最大包大小
BYTE bInterval; //主机查询端点的时间间隔



字符串描述符



字符串描述符包括设备厂家描述符、产品描述符、设备序列号描述符。其作用主要是打上自己的商标,防止与其它厂家或其它产品一样,或者被其它厂家倒版,这一块有自己定义,长度也是由自己设定。

基本格式为:

BYTE bLegth; //字符串描述符字节数大小(N+2)
BYTE USB_STRING_DESCRIPTOR_TYPE //字符串类型编码

下面的数据有自己定义 //自己定义,长度为N


HID设备类描述符



通过上面的描述,主机可得到USB设备的大概信息,但如果仅只有以上那些的话,USB设备是不能和主机进行通信的。因为在上面的描述符中根本就没有定义USB设备的具体功能和传递信息的数据格式,而这就需要类描述符。

而因为本设计中的USB键盘所属的为人机接口类(HID),所以我们主要就叙述HID设备类描述符。



HID设备类描述符中自行定义了3种类描述符,分别为HID描述符、报告描述符和物理描述符,其中HID描述符和物理描述符不是必须的。

而报告描述符,是描述一个报告以及报告里面的数据是用来干什么用的。
通过它,USB HOST可以分析出报告里面的数据所表示的意思。它通过控制输入端点0返回,主机使用获取报告描述符命令来获取报告描述符,注意这个请求是发送到接口的,而不是到设备。一个报告描述符可以描述多个报告,不同的报告通过报告ID来识别,报告ID在报告最前面,即第一个字节。当报告描述符中没有规定报告ID时,报告中就没有ID字段,开始就是数据。

以下为普通USB键盘的报告描述符(不支持多媒体功能)
0x05, 0x01, //USAGE_PAGE (Generic Desktop)用途页为通用桌面设备 0x09, 0x06, //USAGE (Keyboard) 用途为键盘
0xa1, 0x01, //COLLECTION (Application)集合开始 0x05, 0x07, //USAGE_PAGE (Keyboard) 用途页为按键
0x19, 0xe0, //USAGE_MINIMUM (Keyboard LeftControl)用途最小值
0x29, 0xe7, //USAGE_MAXIMUM (Keyboard Right GUI)用途最大值
0x15, 0x00, //LOGICAL_MINIMUM (0) 逻辑最小值为0
0x25, 0x01, //LOGICAL_MAXIMUM (1) 逻辑最大值为1
0x75, 0x01, //REPORT_SIZE (1) 报告大小(即这个字段的宽度)为1bit
0x95, 0x08, //REPORT_COUNT (8) 报告的个数为8,即总共有8个bits
//输入用,变量,值,绝对值。像键盘这类一般报告绝对值
0x81, 0x02, // INPUT (Data,Var,Abs)
/*上面这这几项描述了一个输入用的字段,总共为8个bits,每个bit表示一个按键,分别从左ctrl键到右GUI键。这8个bits刚好构成一个字节,它位于报告的第一个字节。它的最低位,即bit-0对应着左ctrl键,如果返回的数据该位为1,则表示左ctrl键被按下,否则,左ctrl键没有按下。最高位,即bit-7表示右GUI键的按下情况。中间的几个位,需要根据HID协议中规定的用途页表(HID Usage Tables)来确定。这里通常用来表示特殊键,例如ctrl,shift,del键等 */
0x95, 0x01, // REPORT_COUNT (1)
0x75, 0x08, // REPORT_SIZE (8)
0x81, 0x03, // INPUT (Cnst,Var,Abs)

0x95, 0x05, // REPORT_COUNT (5)
0x75, 0x01, // REPORT_SIZE (1)
0x05, 0x08, // USAGE_PAGE (LEDs) 控制键盘上的LED用的
0x19, 0x01, // USAGE_MINIMUM (Num Lock) 数字键锁定灯
0x29, 0x05, // USAGE_MAXIMUM (Kana)
//输出,用来控制LED。变量,值,绝对值。1表示灯亮,0表示灯灭
0x91, 0x02, // OUTPUT (Data,Var,Abs)
0x95, 0x01, // REPORT_COUNT (1)
0x75, 0x03, // REPORT_SIZE (3)
0x91, 0x03, // OUTPUT (Cnst,Var,Abs)
//由于要按字节对齐,而前面控制LED的只用了5个bit,
//所以后面需要附加3个不用bit,设置为常量
0x95, 0x06, // REPORT_COUNT (6)
0x75, 0x08, // REPORT_SIZE (8)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0xFF, // LOGICAL_MAXIMUM (255)
0x05, 0x07, // USAGE_PAGE (Keyboard)
0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated))
0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application)
0x81, 0x00, // INPUT (Data,Ary,Abs)
/*以上定义了6个8bit宽的数组,每个8bit(即一个字节)用来表示一个 按键,所以可以同时有6个按键按下。没有按键按下时,全部返回0。如果按下的键太多,导致键盘扫描系统无法区分按键时,则全部返回0x01,即6个0x01。如果有一个键按下,则这6个字节中的第一个字节为相应的键值(具体的值参看HID Usage Tables),如果两个键按下,则第1、2两个字节分别为相应的键值,以次类推。*/

USB HID设备传送数据有两种方式:

一是通过报告来给传送数据,报告有输入报告和输出报告。输入报告是USB设备发送给主机的,例如USB鼠标将鼠标移动和鼠标点击等信息返回给电脑,键盘将按键数据数据返回给电脑等;输出报告是主机发送给USB设备的,例如键盘上的数字键盘锁定灯和大写字母锁定灯等。报告是一个数据包,里面包含的是所要传送的数据。输入报告是通过中断输入端点输入的,而输出报告有点区别,当没有中断输出端点时,可以通过控制输出端点0发送,当有中断输出端点时,通过中断输出端点发出。在USB2.0协议中提出不提倡通过这种方式来进行传送数据。

二是通过端点的中断传送进行传递数据,在本设计中就是通过端点2的中断来进行与主机的数据交换。

(三)无线电脑遥控实现

本设计是通过2262配合红外发射头来进行发送数据,用与之相匹配的2267(地址,频率匹配)和红外接收头来接收数据。在单片机每次的定时器0中断的时候进行读取数据,通过每次的端点2的中断将数据传递至主机,从而实现对主机的相应控制。

具体实现为:在每一次2262的有按键按下的同时使2262工作,将数据传送至2272,而2272将从2262解码出数据,等待单片机的读取。若2262没有按键按下,则2272的数据为0。在定时器0中断的中断服务程序中,读出2272解码出来的其中的按键信息,将其变换成控制相应按键的USB键盘数据流,通过PDIUSBD12的端点2将数据传递至主机,从而实现一次相应的控制。因为端点2的中断和定时器0的中断是循环不断的进行,所以也就能实时地读取到键盘的信息,完成无线电脑遥控的目的。



05 01 // USAGE_PAGE (Generic Desktop)
09 03 //USAGE
a1 01 //collection

09 01 //USAGE
15 00 //最小值
26 ff 00

75 08 ,//REPORT_SIZE (8)
95 08 //报告的个数为8
81 00 //输入
15 00 //最小值
25 01 //最大值


95 40 //报告长度64
75 01 ,//每个段大小为3bits
05 08 //USAGE_PAGE (Generic Desktop)
19 01 //用途最小值
29 40 //用途最大值
91 02 //报告相对值
c0

HID报告描述符_百度文库
http://blog.sina.com.cn/s/blog_4cd5d2bb0100f72p.html

--
Best Regards



--
Kimi 于 1/21/2011 05:01:00 上午 发布在 嘻嘻哈哈 <http://joke-xixihaha.blogspot.com/2011/01/usb.html> 上