How to use a control-out interupt to write data from a PC?
Posted: 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
and my descriptor is this:
I read the sensor from my java app like so:
This is the code for what Im using in the AVR:
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
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