At this point I have built a circuit (atmega88), setup avrstudio and winavr, started a project based on the mouse example and modified the report to be a joystick with 1 analog axis and 8 buttons.
The project compiles and after uploading to the circuit it is recognized by the PC as such.
The problem I have now is that I am not an experienced programmer and I am not able to decipher the API to understand how to get the hardware to send the data to the PC.
Please see my main.c file and assume nothing about my programming knowledge. I am self taught and my understanding is very patchy and broken.
If I could get a lesson an reading the ADC and the IO of the micro and get that data to the PC it would be helpful.
Code: Select all
/* Name: main.c
*/
#include <avr/io.h>
#include <avr/wdt.h>
#include <avr/interrupt.h> /* for sei() */
#include <util/delay.h> /* for _delay_ms() */
#include <avr/pgmspace.h> /* required by usbdrv.h */
#include "usbdrv/usbdrv.h"
/* ------------------------------------------------------------------------- */
/* ----------------------------- USB interface ----------------------------- */
/* ------------------------------------------------------------------------- */
PROGMEM char usbHidReportDescriptor[37] = { /* USB report descriptor, size must match usbconfig.h */
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x04, // USAGE (Joystick)
0xa1, 0x01, // COLLECTION (Application)
0x05, 0x09, // USAGE_PAGE (Button)
0x19, 0x01, // USAGE_MINIMUM (Button 1)
0x29, 0x08, // USAGE_MAXIMUM (Button 8)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x01, // LOGICAL_MAXIMUM (1)
0x95, 0x08, // REPORT_COUNT (8)
0x75, 0x01, // REPORT_SIZE (1)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x30, // USAGE (X)
0x15, 0x81, // LOGICAL_MINIMUM (-127)
0x25, 0x7f, // LOGICAL_MAXIMUM (127)
0x95, 0x01, // REPORT_COUNT (1)
0x75, 0x08, // REPORT_SIZE (8)
0x81, 0x02, // INPUT (Data,Var,Abs)
0xc0 // END_COLLECTION
};
typedef struct
{
uint8_t buttons;
int8_t axis_x;
}
report_t;
static report_t reportBuffer;
static uint8_t idleRate;
/* ------------------------------------------------------------------------- */
usbMsgLen_t usbFunctionSetup(uint8_t 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 */
{
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 */
}
/* ------------------------------------------------------------------------- */
int main(void)
{
uint8_t 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!
*/
/* 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.
*/
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();
for(;;)
{ /* main event loop */
wdt_reset();
usbPoll();
if(usbInterruptIsReady())
{
/* called after every poll of the interrupt endpoint */
usbSetInterrupt((void *)&reportBuffer, sizeof(reportBuffer));
}
}
}
/* ------------------------------------------------------------------------- */