How to use a control-out interupt to write data from a PC?

General discussions about V-USB, our firmware-only implementation of a low speed USB device on Atmel's AVR microcontrollers
Post Reply
rb20e
Posts: 4
Joined: Sat May 08, 2010 5:33 am

How to use a control-out interupt to write data from a PC?

Post by rb20e » Sat May 08, 2010 6:05 am

Hello all,

I am new to AVR-usb and really appreciate all the work gone into making this project.

I am trying to make a device that is based on the hid-mouse example. Basically I have a device that uses an accelerometer and I use the x,y,z values of the sensor in an app i have written in java using the libusb library on Windows. I now want to be able to turn a few leds on/off on the device based on calculations happening in the java app. This is essentially 1 byte long. (I can't do this directly from the avr as the leds turn on/off based on states in the java app that take in more than the just the accelerometer)

Thus far I am able to read from the avr fine but I have no idea as to how to implement an interrupt write-out. I need to send one byte of data out for every 500 reads. I am looking for help here as I cant seem to get the write part working. I have looked at the hid-data example but I think that implements a bulk out instead of a interrupt out. (correct me if Im wrong).

I have set

Code: Select all

#define USB_CFG_IMPLEMENT_FN_WRITE      1
and
#define USB_CFG_IMPLEMENT_FN_WRITEOUT   1


and my descriptor is this:

Code: Select all


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

PROGMEM char usbHidReportDescriptor[21] = { /* USB report descriptor, size must match usbconfig.h */
    0x06, 0x00, 0xff,              // USAGE_PAGE (Vendor Defined Page 1)
    0x09, 0x01,                    // USAGE (Vendor Usage 1)
    0xa1, 0x01,                    // COLLECTION (Application)
    0x09, 0x02,                    //   USAGE (Vendor Usage 2)
    0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
    0x26, 0xff, 0x00,              //   LOGICAL_MAXIMUM (255)
    0x75, 0x08,                    //   REPORT_SIZE (8)
    0x95, 0x03,                    //   REPORT_COUNT (4)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0xc0                           // END_COLLECTION
};

typedef struct {
   unsigned char xValue;
   unsigned char yValue;
   unsigned char zValue;
   unsigned char pValue;
} report_t;

static report_t reportBuffer = {0, 0, 0, 0};
static uchar idleRate;   /* repeat rate for keyboards, never used for mice */

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

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

    /* The following requests are never used. But since they are required by
     * the specification, we implement them in this example.
     */
    if((rq->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_CLASS){    /* class request type */
        DBG1(0x50, &rq->bRequest, 1);   /* debug output: print our request */
        if(rq->bRequest == USBRQ_HID_GET_REPORT){  /* wValue: ReportType (highbyte), ReportID (lowbyte) */
            /* we only have one report type, so don't look at wValue */
            usbMsgPtr = (void *)&reportBuffer;
            return sizeof(reportBuffer);
        }else if(rq->bRequest == USBRQ_HID_GET_IDLE){
            usbMsgPtr = &idleRate;
            return 1;
        }else if(rq->bRequest == USBRQ_HID_SET_IDLE){
            idleRate = rq->wValue.bytes[1];
        }
    }else{
        /* no vendor specific requests implemented */
    }
    return 0;   /* default for not implemented requests: return no data back to host */
}

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



I read the sensor from my java app like so:

Code: Select all

Device dev = USB.getDevice((short)0x16c0, (short)0x5df);
try{
   byte[] data = new byte[] { 0, 1, 2, 3 };
   byte[] readData = new byte[data.length];
   dev.open(1, 0, -1);
   //read
   dev.readInterrupt(0x81, readData, readData.length, 2000, false);
   next_valueX = readData[0] & 0xff;
   next_valueY = readData[1] & 0xff;
   next_valueZ = readData[2] & 0xff;
   next_valueP = readData[3] & 0xff;
   //write
   dev.writeInterrupt(0x??, data, data.length, 2000, false);
   dev.close();
}catch (USBException e){
   e.printStackTrace();
}


This is the code for what Im using in the AVR:

Code: Select all


int main(void){
   uchar   i;
   wdt_enable(WDTO_1S);
   /* Even if you don't use the watchdog, turn it off here. On newer devices,
   * the status of the watchdog (on/off, period) is PRESERVED OVER RESET!
   */
   DBG1(0x00, 0, 0);       /* debug output: main starts */
   /* RESET status: all port bits are inputs without pull-up.
   * That's the way we need D+ and D-. Therefore we don't need any
   * additional hardware initialization.
   */
   init_UART(MYUBRR);

   odDebugInit();
   usbInit();
   usbDeviceDisconnect();  /* enforce re-enumeration, do this while interrupts are disabled! */
   i = 0;
   while(--i){             /* fake USB disconnect for > 250 ms */
      wdt_reset();
      _delay_ms(1);
   }
   usbDeviceConnect();
   sei();
   DBG1(0x01, 0, 0);       /* debug output: main loop starts */
   for(;;){                /* main event loop */
      DBG1(0x02, 0, 0);   /* debug outut: main loop iterates */
      wdt_reset();

      USART_rec_byte();

      usbPoll();
      if(usbInterruptIsReady()){
         DBG1(0x03, 0, 0);   /* debug output: interrupt report prepared */
         usbSetInterrupt((void *)&reportBuffer, sizeof(reportBuffer));
      }
   }
   return 0;
}


Where USART_rec_byte(); is a function that sorts data for the sensor that I read in.

I understand that 0x81 is the address of the IN endpoint, so how exactly do I set the address of the OUT endpoint or is this predefined somewhere?
Do I add in another line in the sescriptoe for an output?
0x??, 0x02, // INPUT (Data,Var,Abs)

Also how do I handle this in the AVR? Is there a usbGetInterrupt () something similar?

Any help or pointers on what I should be looking it would be extremely helpful...

Thanks in advance.
-James

ulao
Rank 4
Rank 4
Posts: 481
Joined: Mon Aug 25, 2008 8:45 pm

Re: How to use a control-out interupt to write data from a PC?

Post by ulao » Sun May 09, 2010 4:18 am

I think your after the same thing I am
viewtopic.php?f=8&t=4231

The function you want is usbFunctionWrite. Let me know if you have any luck, see the hid-data example provided with the driver it shows how its done.

rb20e
Posts: 4
Joined: Sat May 08, 2010 5:33 am

Re: How to use a control-out interupt to write data from a PC?

Post by rb20e » Tue May 11, 2010 6:31 am

Hi,
Yup similar to that .

Tried that but appears to be no way that I am able to communicate in Java.

Tried using the test app that comes with libusb and all i get is errors for read / write using the hid-data type example. I believe I am trying to implement usbFunctionWriteOut() but thus far without success.

I have the USB_CFG_IMPLEMENT_FN_WRITEOUT = 1 and the function with stuff to do but I have no idea why I cannot write. Should I be adding something in the descriptor? or the usbFunctionSetup()?

Christian might know how you would use this?

Ciao.

ulao
Rank 4
Rank 4
Posts: 481
Joined: Mon Aug 25, 2008 8:45 pm

Re: How to use a control-out interupt to write data from a PC?

Post by ulao » Tue May 11, 2010 2:43 pm

Well yes you do need the control added in the descriptor. I dont know what it should look like in your case, is depends on how you want to interface the device. For example if your device is going to receive data like the data example set it up like that.

Also yes, the usbFunctionSetup does need to change, you need to add the USBRQ_HID_SET_REPORT ( see my thread )

Christian most certainly does, and he does come around from time to time. I have not seen him is awhile, hope to see him here soon.

rb20e
Posts: 4
Joined: Sat May 08, 2010 5:33 am

Re: How to use a control-out interupt to write data from a PC?

Post by rb20e » Wed May 12, 2010 4:30 am

Yup, I looked at your post and have implemented pretty much the same thing.

Thing is Im stuck pretty much at the same place you are. Nothing seems to be written to the avr from the pc, although reading is fine.

Did you manage to get the led to flash for your project? if you did could you post your code for the avr here?

thanks

ulao
Rank 4
Rank 4
Posts: 481
Joined: Mon Aug 25, 2008 8:45 pm

Re: How to use a control-out interupt to write data from a PC?

Post by ulao » Wed May 12, 2010 3:40 pm

Nope, thing.. Its like I'm missing something? Hopping for someone to school me on this.

Guest

Re: How to use a control-out interupt to write data from a PC?

Post by Guest » Wed Jun 02, 2010 4:29 am

to use hid interrupt out functionality, you need to have ,
1. define your own device & configuration descriptor (see avr-cdc from recursion for an example)
2. hid report should have a output report.
3. implement function_write_out

Post Reply