zoologist 发表于 2015-9-11 22:33:30

Arduino 控制USB设备(7)解析USB鼠标的例子(下)

前面实现了HP 鼠标数据的读取,下面继续研究 DELL 的鼠标。还是首先运行取得描述符的程序,结果如下:

Start
Device addressed... Requesting device descriptor.
Device descriptor:

Descriptor Length:        12
USB version:        1.10
Class:        00 Use class information in the Interface Descriptor
Subclass:        00
Protocol:        00
Max.packet size:        08
Vendor ID:        2188
Product ID:        0AE1
Revision ID:        0100
Mfg.string index:        00
Prod.string index:        01 Length: 38 Contents: USB OPTICAL MOUSE
Serial number index:        00
Number of conf.:        01

Configuration number 0
Total configuration length: 34 bytes

Configuration descriptor:
Total length:        0022
Number of interfaces:        01
Configuration value:        01
Configuration string:        00
Attributes:        A0 Remote Wakeup
Max.power:        32 100ma

Interface descriptor:
Interface number:        00
Alternate setting:        00
Endpoints:        01
Class:        03 HID (Human Interface Device)
Subclass:        01
Protocol:        02
Interface string:        00

HID descriptor:
Descriptor length:        09 9 bytes
HID version:        1.11
Country Code:        0 Not Supported
Class Descriptors:        1
Class Descriptor Type:        22 Report
Class Descriptor Length:66 bytes

HID report descriptor:

Length: 1 Type: Global        Tag: Usage Page        Generic Desktop Controls Data: 01
Length: 1 Type: Local        Tag: Usage        Data: 02
Length: 1 Type: Main        Tag: Collection        Application (mouse, keyboard) Data: 01
Length: 1 Type: Global        Tag: Report ID        Data: 01
Length: 1 Type: Local        Tag: Usage        Data: 01
Length: 1 Type: Main        Tag: Collection        Physical (group of axes) Data: 00
Length: 1 Type: Global        Tag: Usage Page        Button Data: 09
Length: 1 Type: Local        Tag: Usage Minimum        Data: 01
Length: 1 Type: Local        Tag: Usage Maximum        Data: 03
Length: 1 Type: Global        Tag: Logical Minimum        Data: 00
Length: 1 Type: Global        Tag: Logical Maximum        Data: 01
Length: 1 Type: Global        Tag: Report Count        Data: 03
Length: 1 Type: Global        Tag: Report Size        Data: 01
Length: 1 Type: Main        Tag: Input        Data,Variable,Absolute,No Wrap,Linear,Preferred State,No Null Position,Non-volatile(Ignore for Input), Data: 02
Length: 1 Type: Global        Tag: Report Count        Data: 01
Length: 1 Type: Global        Tag: Report Size        Data: 05
Length: 1 Type: Main        Tag: Input        Constant,Array,Absolute,No Wrap,Linear,Preferred State,No Null Position,Non-volatile(Ignore for Input), Data: 01
Length: 1 Type: Global        Tag: Usage Page        Generic Desktop Controls Data: 01
Length: 1 Type: Local        Tag: Usage        Data: 30
Length: 1 Type: Local        Tag: Usage        Data: 31
Length: 2 Type: Global        Tag: Logical Minimum        Data: 00 Data: F8
Length: 2 Type: Global        Tag: Logical Maximum        Data: FF Data: 07
Length: 1 Type: Global        Tag: Report Size        Data: 0C
Length: 1 Type: Global        Tag: Report Count        Data: 02
Length: 1 Type: Main        Tag: Input        Data,Variable,Relative,No Wrap,Linear,Preferred State,No Null Position,Non-volatile(Ignore for Input), Data: 06
Length: 1 Type: Local        Tag: Usage        Data: 38
Length: 1 Type: Global        Tag: Logical Minimum        Data: 81
Length: 1 Type: Global        Tag: Logical Maximum        Data: 7F
Length: 1 Type: Global        Tag: Report Size        Data: 08
Length: 1 Type: Global        Tag: Report Count        Data: 01
Length: 1 Type: Main        Tag: Input        Data,Variable,Relative,No Wrap,Linear,Preferred State,No Null Position,Non-volatile(Ignore for Input), Data: 06
Length: 0 Type: Main        Tag: End Collection
Length: 0 Type: Main        Tag: End Collection

Endpoint descriptor:
Endpoint address:        01 Direction: IN
Attributes:        03 Transfer type: Interrupt
Max.packet size:        0006
Polling interval:        0A 10 ms

同样,尝试之前的 Get_Report 方式的程序,得到的却是不停的输出的错误信息:

Setup packet error: 7
Mouse Poll Error: 7

没有办法直接了解这个错误编号的含义,最后只能用逻辑分析仪分析产生问题的原因:



可以看到当发送Get_Report之后,Device 会返回STALL 。

对比之前能够正常工作的 HP 鼠标,收到 Get_Report 后,会返回 ACK 还会继续通讯。



查看资料上说,返回STALL有可能是因为设备不支持该指令…… Windows的设备经常会出现这样的情况:可以正常工作,但是未必完整的 follow 工业标准。

上面的方法行不通,只能用中断方式来获取数据。我去掉了切换 Boot Protocol 的代码

/* Mouse communication via interrupt endpoint*/
/* Assumes EP1 as interrupt IN ep            */
#include "max3421e.h"
#include "usb.h"

#define DEVADDR 1
#define CONFVALUE 1
#define EP_MAXPKTSIZE 5
EP_RECORD ep_record[ 2 ];//endpoint record structure for the mouse


void setup();
void loop();

MAX3421E Max;
USB Usb;

void setup()
{
    Serial.begin( 115200 );
    Serial.println("Start");
    Max.powerOn();
    delay( 200 );
}

void loop()
{
byte rcode;
    Max.Task();
    Usb.Task();
    if( Usb.getUsbTaskState() == USB_STATE_CONFIGURING ) {
      mouse1_init();
    }//if( Usb.getUsbTaskState() == USB_STATE_CONFIGURING...
    if( Usb.getUsbTaskState() == USB_STATE_RUNNING ) {//poll the keyboard
      rcode = mouse1_poll();
      if( rcode ) {
          Serial.print("Mouse Poll Error: ");
          Serial.println( rcode, HEX );
      }//if( rcode...
    }//if( Usb.getUsbTaskState() == USB_STATE_RUNNING...
}
/* Initialize mouse */
void mouse1_init( void )
{
byte rcode = 0;//return code
byte tmpdata;
byte* byte_ptr = &tmpdata;
/**/
ep_record[ 0 ] = *( Usb.getDevTableEntry( 0,0 ));//copy endpoint 0 parameters
ep_record[ 1 ].MaxPktSize = EP_MAXPKTSIZE;
ep_record[ 1 ].sndToggle = bmSNDTOG0;
ep_record[ 1 ].rcvToggle = bmRCVTOG0;
Usb.setDevTableEntry( 1, ep_record );            //plug kbd.endpoint parameters to devtable
/* Configure device */
rcode = Usb.setConf( DEVADDR, 0, CONFVALUE );
if( rcode ) {
    Serial.print("Error configuring mouse. Return code : ");
    Serial.println( rcode, HEX );
    while(1);//stop
}//if( rcode...

rcode = Usb.setIdle( DEVADDR, 0, 0, 0, tmpdata );
if( rcode ) {
    Serial.print("Set Idle error. Return code : ");
    Serial.println( rcode, HEX );
    while(1);//stop
}

rcode = Usb.getIdle( DEVADDR, 0, 0, 0, (char *)byte_ptr );
if( rcode ) {
    Serial.print("Get Idle error. Return code : ");
    Serial.println( rcode, HEX );
    while(1);//stop
}
Serial.print("Idle Rate: ");
Serial.print(( tmpdata * 4 ), DEC );      //rate is returned in multiples of 4ms
Serial.println(" ms");
tmpdata = 0;
rcode = Usb.setIdle( DEVADDR, 0, 0, 0, tmpdata );
if( rcode ) {
    Serial.print("Set Idle error. Return code : ");
    Serial.println( rcode, HEX );
    while(1);//stop
}
Usb.setUsbTaskState( USB_STATE_RUNNING );
return;
}
/* Poll mouse via interrupt endpoint and print result */
/* assumes EP1 as interrupt endpoint                  */
byte mouse1_poll( void )
{
byte rcode,i;
char buf[ 6 ] = { 0 };                        //mouse report buffer

unsigned long int libuf[ sizeof(buf) ];
unsigned long int x;
unsigned long int y;


/* poll mouse */
rcode = Usb.inTransfer( DEVADDR, 1, sizeof(buf), buf, 1 );//

    if( rcode ) {//error
      if( rcode == 0x04 ) {//NAK
      rcode = 0;
      }
      return( rcode );
    }
    /* print buffer */
    if( buf[ 1 ] & 0x01 ) {
      Serial.println("Button1 pressed ");
    }
    if( buf[ 1 ] & 0x02 ) {
      Serial.println("Button2 pressed ");
    }
    if( buf[ 1 ] & 0x04 ) {
      Serial.println("Button3 pressed ");
    }
   
    for (int i=0;i<sizeof(buf);i++) {
       libuf=(buf) & 0xff;
    }
   
    /*
    Serial.print(libuf,HEX); Serial.print("");
    Serial.print(libuf,HEX); Serial.print("");
    Serial.print(libuf,HEX); Serial.print("");
    Serial.print(libuf,HEX); Serial.print("");   
    Serial.print(libuf,HEX); Serial.print("");         
    Serial.print(libuf,HEX); Serial.print("");            
    Serial.println("");
    */
   
    Serial.print("X-axis: ");
    x=((libuf & 0xF)<<8)+(libuf & 0xFF );
    if (x & 0x800) {
      Serial.print("-");
      x = ((~x) & 0x7FF) +1;
    }
   
    Serial.print(x, HEX);Serial.print("   ");
   
    Serial.print("Y-axis: ");   
    y=(((libuf>>4) & 0xF) +((libuf & 0xFF )<<4));
    if (y & 0x800) {
      Serial.print("-");
      y = ((~y) & 0x7FF) +1;
    }   
    Serial.print(y, HEX); Serial.print("   ");

    Serial.print("Wheel: ");   
    Serial.println(buf & 0xFF, HEX);   

    return( rcode );
}

和前面那个程序相比,这个特别之处在于返回值多了 Report_ID ,对于我们处理数据来说,只是有效数据从 Buf 开始,其他地方并无特别。

运行结果



完整代码下载

http://www.lab-z.com/ausb7/

基本上,鼠标的玩法就是这些。可以用鼠标做很多好玩的东西。

wing 发表于 2015-9-12 09:13:17

那个数据图非常专业呢,是用什么软件实现的?

HWL0541 发表于 2015-9-12 10:33:11

楼主厉害,真是高大上啊,我看不明白啊:'(

maxims 发表于 2015-9-12 22:15:47

能否提供一下你那个分析仪的详细信息?我也想采购一个

zoologist 发表于 2015-9-13 07:57:52

maxims 发表于 2015-9-12 22:15 static/image/common/back.gif
能否提供一下你那个分析仪的详细信息?我也想采购一个

Advisor T3   Ultra-portable SuperSpeed USB analyzer delivers market leading accuracy at an extraordinary price

http://teledynelecroy.com/protocolanalyzer/protocoloverview.aspx?seriesid=280&capid=103&mid=511

maxims 发表于 2015-9-13 18:54:21

zoologist 发表于 2015-9-13 07:57 static/image/common/back.gif
Advisor T3   Ultra-portable SuperSpeed USB analyzer delivers market leading accuracy at an extraor ...

看起来好高端的样子。。。。搞不懂~估计价格也不便宜吧?

maxims 发表于 2015-9-14 07:46:47

不是你个人买的啊?

蒸馏水--野妄 发表于 2016-10-17 16:44:45

楼主 我有个想法 用鼠标来探测一些机器的直线晃动的距离和频率 给出一些正确和不正确报警的反馈?

zoologist 发表于 2016-10-21 15:34:44

蒸馏水--野妄 发表于 2016-10-17 16:44
楼主 我有个想法 用鼠标来探测一些机器的直线晃动的距离和频率 给出一些正确和不正确报警的反馈?

可以的 没问题
页: [1]
查看完整版本: Arduino 控制USB设备(7)解析USB鼠标的例子(下)