daiqx 发表于 2014-4-4 20:26:27

求教Arduino中的avr usb (UsbStream库)与上位机用什么形式通.....

Arduino中的avr usb (UsbStream库)与上位机用什么形式通讯? 可以枚举到些设备,并且返回设备属性,用过hiddll 读取
"ReadFile"   , "WriteFile","HidD_SetFeature " , "HidD_GetFeature "都读不出正确数据 ,有人知道用什么形式读写吗?
看 usbstream 源码,只实现了usbFunctionSetup,是不是只能用控制端的形式收发数据?
是HidD_SetOutputReport和hidd_getinputreport这两个函数吗?具体怎样用。


/* Name: main.c
* Based on project: hid-data, example how to use HID for data transfer
* (Uses modified descriptor and usbFunctionSetup from it.)
* Original author: Christian Starkjohann
* Arduino modifications by: Philip J. Lindsay
* Creation Date: 2008-04-11
* Tabsize: 4
* Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH
* License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt)
* This Revision: $Id: main.c 692 2008-11-07 15:07:40Z cs $
*/

/*
This example should run on most AVRs with only little changes. No special
hardware resources except INT0 are used. You may have to change usbconfig.h for
different I/O pins for USB. Please note that USB D+ must be the INT0 pin, or
at least be connected to INT0 as well.
*/

#include <avr/io.h>
#include <avr/wdt.h>
#include <avr/interrupt.h>/* for sei() */
#include <util/delay.h>   /* for _delay_ms() */
#include <avr/eeprom.h>

#include <avr/pgmspace.h>   /* required by usbdrv.h */
#include "usbdrv.h"
#include "oddebug.h"      /* This is also an example for using debug macros */

#include "UsbStream.h"

// Ring buffer implementation nicked from HardwareSerial.cpp
// TODO: Don't nick it. :)
ring_buffer rx_buffer = { { 0 }, 0, 0 };
ring_buffer tx_buffer = { { 0 }, 0, 0 };


inline void store_char(unsigned char c, ring_buffer *the_buffer)
{
int i = (the_buffer->head + 1) % RING_BUFFER_SIZE;

// if we should be storing the received character into the location
// just before the tail (meaning that the head would advance to the
// current location of the tail), we're about to overflow the buffer
// and so we don't write the character or advance the head.
if (i != the_buffer->tail) {
    the_buffer->buffer = c;
    the_buffer->head = i;
}
}

UsbStreamDevice::UsbStreamDevice(ring_buffer *rx_buffer,
                               ring_buffer *tx_buffer) {
_rx_buffer = rx_buffer;
_tx_buffer = tx_buffer;
}

void UsbStreamDevice::begin() {
    // disable timer 0 overflow interrupt (used for millis)
    TIMSK0&=!(1<<TOIE0);

    cli();

    usbInit();
      
    usbDeviceDisconnect();
    uchar   i;
    i = 0;
    while(--i){             /* fake USB disconnect for > 250 ms */
      _delay_ms(1);
    }
    usbDeviceConnect();

    sei();
}
   
// TODO: Deprecate update
void UsbStreamDevice::update() {
refresh();
}

void UsbStreamDevice::refresh() {
usbPoll();
}

int UsbStreamDevice::available() {
/*
   */
return (RING_BUFFER_SIZE + _rx_buffer->head - _rx_buffer->tail) % RING_BUFFER_SIZE;
}

int UsbStreamDevice::read() {
/*
   */
// if the head isn't ahead of the tail, we don't have any characters
if (_rx_buffer->head == _rx_buffer->tail) {
    return -1;
} else {
    unsigned char c = _rx_buffer->buffer;
    _rx_buffer->tail = (_rx_buffer->tail + 1) % RING_BUFFER_SIZE;
    return c;
}
}

void UsbStreamDevice::write(byte c) {
/*
   */
store_char(c, _tx_buffer);
}

// TODO: Handle this better?
int tx_available() {
/*
   */
return (RING_BUFFER_SIZE + tx_buffer.head - tx_buffer.tail) % RING_BUFFER_SIZE;
}

int tx_read() {
/*
   */
// if the head isn't ahead of the tail, we don't have any characters
if (tx_buffer.head == tx_buffer.tail) {
    return -1;
} else {
    unsigned char c = tx_buffer.buffer;
    tx_buffer.tail = (tx_buffer.tail + 1) % RING_BUFFER_SIZE;
    return c;
}
}




/* ------------------------------------------------------------------------- */
/* ----------------------------- USB interface ----------------------------- */
/* ------------------------------------------------------------------------- */

#ifdef __cplusplus
extern "C"{
#endif
PROGMEM char usbHidReportDescriptor = {    /* USB report descriptor */
    0x06, 0x00, 0xff,            // USAGE_PAGE (Generic Desktop)
    0x09, 0x01,                  // USAGE (Vendor Usage 1)
    0xa1, 0x01,                  // COLLECTION (Application)
    0x15, 0x00,                  //   LOGICAL_MINIMUM (0)
    0x26, 0xff, 0x00,            //   LOGICAL_MAXIMUM (255)
    0x75, 0x08,                  //   REPORT_SIZE (8)
    0x95, 0x01,                  //   REPORT_COUNT (1)
    0x09, 0x00,                  //   USAGE (Undefined)
    0xb2, 0x02, 0x01,            //   FEATURE (Data,Var,Abs,Buf)
    0xc0                           // END_COLLECTION
};
/* Since we define only one feature report, we don't use report-IDs (which
* would be the first byte of the report). The entire report consists of 1
* opaque data bytes.
*/

/* ------------------------------------------------------------------------- */

usbMsgLen_t usbFunctionSetup(uchar data)
{
usbRequest_t    *rq = (usbRequest_t*)((void *)data);

    if((rq->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_CLASS){    /* HID class request */
      if(rq->bRequest == USBRQ_HID_GET_REPORT){/* wValue: ReportType (highbyte), ReportID (lowbyte) */
            /* since we have only one report type, we can ignore the report-ID */
          static uchar dataBuffer;/* buffer must stay valid when usbFunctionSetup returns */
          if (tx_available()) {
              dataBuffer = tx_read();
              usbMsgPtr = dataBuffer; /* tell the driver which data to return */
              return 1; /* tell the driver to send 1 byte */
          } else {
              // Drop through to return 0 (which will stall the request?)
          }
      }else if(rq->bRequest == USBRQ_HID_SET_REPORT){
            /* since we have only one report type, we can ignore the report-ID */

          // TODO: Check race issues?
          store_char(rq->wIndex.bytes, &rx_buffer);

      }
    }else{
      /* ignore vendor type requests, we don't use any */
    }
    return 0;
}
#ifdef __cplusplus
} // extern "C"
#endif

UsbStreamDevice UsbStream = UsbStreamDevice(&rx_buffer, &tx_buffer);

daiqx 发表于 2014-4-5 00:09:14

消灭零回复,高手在哪里?

takashiki 发表于 2014-4-5 08:32:17

是的,只能支持端点0的Feature报告。

ReadFile、WriteFile、HidD_SetFeature、HidD_GetFeature、HidD_SetOutputReport 、HidD_GetInputReport都可以的,只是我习惯用HidD_SetFeature、HidD_GetFeature,或者干脆自己实现这两个函数,省得连接hid.dll。

估计是你的HidD_GetFeature的第二个参数不对造成的,没有具体信息无法进一步分析。

daiqx 发表于 2014-4-5 16:26:54

takashiki 发表于 2014-4-5 08:32
是的,只能支持端点0的Feature报告。

ReadFile、WriteFile、HidD_SetFeature、HidD_GetFeature、HidD_SetO ...

谢谢回复! 我是这样调用的:HidD_GetFeature(handl,a(0),2),有时可以返回真,但 a(0),a(1)都不是正确结果。因为在之前API中得出Feature缓冲长度为2 所以用了个长度为2的数组。问题是看类库的源码知道下位机其实是返回一个字节的。
调用HidD_GetFeature有什么要求?
还有,再次谢谢你的回复,确定了我解决问题的方向.

daiqx 发表于 2014-4-5 16:46:09

takashiki 发表于 2014-4-5 08:32
是的,只能支持端点0的Feature报告。

ReadFile、WriteFile、HidD_SetFeature、HidD_GetFeature、HidD_SetO ...


我找到一个你在2010发在论坛的工具源码,其中有hid的操作,
看到这一段
"
        if not Assigned(hid) then Exit;
Data := Hex2Int('0'+edtReportID.Text);
        hid.GetFeature(Data, Hid.Caps.FeatureReportByteLength);

"

ReportId是什么东西?这个数值是那里得到的

麻烦你有空回复一下,呵

takashiki 发表于 2014-4-5 16:54:41

daiqx 发表于 2014-4-5 16:26
谢谢回复! 我是这样调用的:HidD_GetFeature(handl,a(0),2),有时可以返回真,但 a(0),a(1)都不是正确 ...

感觉你的语法非常怪异,用的不是C/C++吧,难道是VB?

是这么调用的,但是你得首先保证你的a(0)=0,即ID号,否则该函数可能会匹配到一个不存在的ID,从而读取失败。读取完成后,返回值存在a(0)中,a(1)纯粹就一摆设。
C/C++是这样的,你的编程语言我不知道该怎么写:a=0;
HidD_GetFeature(handl, &a, 2);

daiqx 发表于 2014-4-5 16:56:56

takashiki 发表于 2014-4-5 16:54
感觉你的语法非常怪异,用的不是C/C++吧,难道是VB?

是这么调用的,但是你得首先保证你的a(0)=0,即ID ...

就是VB这怪异的货,我再试一下,谢谢你

takashiki 发表于 2014-4-5 16:57:50

daiqx 发表于 2014-4-5 16:46
我找到一个你在2010发在论坛的工具源码,其中有hid的操作,
看到这一段
"


HID的每一个报告的Id啊,没有这项时就是0。为0时和为其他值时发送、接收的内容是不一样的(占用的字节数不一样),可以通过BusHound检测到,但是上位机写法是一样的。

daiqx 发表于 2014-4-5 17:02:46

takashiki 发表于 2014-4-5 16:57
HID的每一个报告的Id啊,没有这项时就是0。为0时和为其他值时发送、接收的内容是不一样的(占用的字节数 ...

如果我轮询调用这个函数可以吗?没有数据也会返回true吗?如果是的话,有什么方法确定是否得到数据?

takashiki 发表于 2014-4-5 17:47:50

daiqx 发表于 2014-4-5 17:02
如果我轮询调用这个函数可以吗?没有数据也会返回true吗?如果是的话,有什么方法确定是否得到数据? ...

当然可以轮询,对于特征端点我一向都这么干。没有数据时返回FALSE,有数据时返回TRUE。
如果直接使用DeviceIoControl的话,可以得到实际读入到的数据长度。估计HidD_GetFeature也是数据长度。
这样的:#defineIOCTL_HID_GETFEATURE    ((0x0B << 16)| (0x64 << 2)| 2)
a = 0;
DeviceIoControl(handl, IOCTL_HID_GETFEATURE, NULL, 0, &a, 2, &nRet, NULL);

比如你这个例子nRet应该返回1,虽然你期望得到2。

daiqx 发表于 2014-4-5 18:37:53

takashiki 发表于 2014-4-5 17:47
当然可以轮询,对于特征端点我一向都这么干。没有数据时返回FALSE,有数据时返回TRUE。
如果直接使用Devi ...

谢谢热心而又高手的takashiki 网友,我又可以继续折腾这个东西了。

daiqx 发表于 2014-4-9 17:28:56

终于可以读成功,不过写始终都不能成功,HidD_SetFeature可以调用成功,下位机也触发这个setreport的事件,但上位机的数组不能传递到下位机的data数组

如果以后有人查到这个帖子,读成功的VB代码如下,结果能写成功的网友希望可以说一下哈
Private Sub ReadReport()


Dim ReadBuffer(1) As Byte

Dim Resultb As Boolean
ReadBuffer(0) = 0
Resultb = HidD_GetFeature(ReadHandleK, ReadBuffer(0), 2)

If Resultb = False Then

Else

If ReadBuffer(1) > 0 Then
Debug.Print "HidD_GetFeature2返回成功 :" & Resultb

Debug.Print "HidD_GetFeature2 :" & Chr(ReadBuffer(1))

End If
End If

End Sub

daiqx 发表于 2014-4-12 15:58:15

终于实现 hid write 了 他娘的 Arduino hid
设置 #define USB_CFG_IMPLEMENT_FN_WRITE      1

添加
uchar   usbFunctionWrite(uchar *data, uchar len)
{
uchar i;
   for(i=0;i<len;i++)
           store_char(data, &rx_buffer);
   return 1;

}   //其实只能一个字节一个字节地写

修改

usbMsgLen_t usbFunctionSetup(uchar data)
{
usbRequest_t    *rq = (usbRequest_t*)((void *)data);

    if((rq->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_CLASS){    /* HID class request */
      if(rq->bRequest == USBRQ_HID_GET_REPORT){/* wValue: ReportType (highbyte), ReportID (lowbyte) */
            /* since we have only one report type, we can ignore the report-ID */
          static uchar dataBuffer;/* buffer must stay valid when usbFunctionSetup returns */
          if (tx_available()) {
              dataBuffer = tx_read();
         

              usbMsgPtr = dataBuffer; /* tell the driver which data to return */
              return 1; /* tell the driver to send 1 byte */
          } else {
              // Drop through to return 0 (which will stall the request?)
          }
      }else if(rq->bRequest == USBRQ_HID_SET_REPORT){
            /* since we have only one report type, we can ignore the report-ID */

          // TODO: Check race issues?
                return 0xff;
         

      }
    }else{
      /* ignore vendor type requests, we don't use any */
    }
    return 0;
}

VB 这样写
Dim Result As Long
SendBuffer(0)=0
SendBuffer(1)=ASC("a")
Result = HidD_SetFeature(ReadHandleK, SendBuffer(0), 2)

肯定是木有问题的,试了好久

daiqx 发表于 2014-4-12 16:02:31

对usb没有什么认识,对单片机也不太懂,有太多百撕不得骑姐的东西。这个东西只能做到这样了。 单字节读写呀,
hid啊,比串口都不如啊。
页: [1]
查看完整版本: 求教Arduino中的avr usb (UsbStream库)与上位机用什么形式通.....