Code: Select all
//=========================================================================
//
// Project: PPM2USB, a AVR-based PPM to USB-Joystick Converter using V-USB.
// Author: Thomas Pfeifer
// Creation Date: 2010-09-10
//
// WWW: http://thomaspfeifer.net/ppm2usb_adapter.htm
//
// Copyright: (c) 2010, Thomas Pfeifer - http://www.thomaspfeifer.net
//
// This software is free for non-commercial use. It may be copied,
// modified, and redistributed provided that this copyright notice
// is preserved on all copies.
//
// You may NOT use this software, in whole or in part, in support
// of any commercial product without the express consent of the
// author.
//
// There is no warranty or other guarantee of fitness of this
// software for any purpose. It is provided solely "as is".
//
//=========================================================================
#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.h"
#include "oddebug.h"
#include "ppm.h"
/* ------------------------------------------------------------------------- */
/* ----------------------------- USB interface ----------------------------- */
/* ------------------------------------------------------------------------- */
PROGMEM char usbHidReportDescriptor[208] = { // USB report descriptor, size must match usbconfig.h
// device 1
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x04, // USAGE (Joystick)
0xa1, 0x01, // COLLECTION (Application)
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x75, 0x08, // REPORT_SIZE (8)
0x85, 0x05, // REPORT_ID (5)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255)
0x35, 0x00, // PHYSICAL_MINIMUM (0)
0x46, 0xff, 0x00, // PHYSICAL_MAXIMUM (255)
0x09, 0x01, // USAGE (Pointer)
0xa1, 0x00, // COLLECTION (Physical)
0x09, 0x34, // USAGE (Ry)
0x09, 0x41, // USAGE (Vy)
0x09, 0x32, // USAGE (Z)
0x09, 0x33, // USAGE (Rx)
0x09, 0x30, // USAGE (X)
0x09, 0x31, // USAGE (Y)
0x95, 0x06, // REPORT_COUNT (6)
0x81, 0x82, // INPUT (Data,Var,Abs,Vol)
0xc0, // END_COLLECTION
0x09, 0x04, // USAGE (Joystick)
0xa1, 0x00, // COLLECTION (Physical)
0x85, 0x05, // REPORT_ID (5)
0x05, 0x09, // USAGE_PAGE (Button)
0x19, 0x01, // USAGE_MINIMUM (Button 1)
0x29, 0x03, // USAGE_MAXIMUM (Button 3)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x01, // LOGICAL_MAXIMUM (1)
0x95, 0x03, // REPORT_COUNT (3)
0x75, 0x01, // REPORT_SIZE (1)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x95, 0x01, // REPORT_COUNT (1)
0x75, 0x05, // REPORT_SIZE (5)
0x81, 0x03, // INPUT (Cnst,Var,Abs)
0xc0, // END_COLLECTION
0xc0, // END_COLLECTION [b](73 bytes)[/b]
// device 2
0x06, 0x00, 0xff, // USAGE_PAGE (Vendor Defined Page 0)
0x09, 0x01, // USAGE (Vendor Usage 1)
0xa1, 0x01, // COLLECTION (Application)
0x09, 0x01, // USAGE (Vendor Usage 1)
0xa1, 0x00, // COLLECTION (Physical)
0x75, 0x08, // REPORT_SIZE (8)
0x95, 0x07, // REPORT_COUNT (7)
0x85, 0x01, // REPORT_ID (1)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255)
0x35, 0x00, // PHYSICAL_MINIMUM (0)
0x46, 0xff, 0x00, // PHYSICAL_MAXIMUM (255)
0x09, 0x30, // USAGE (0x30)
0x09, 0x31, // USAGE (0x31)
0x09, 0x32, // USAGE (0x32)
0x09, 0x33, // USAGE (0x33)
0x09, 0x34, // USAGE (0x34)
0x09, 0x35, // USAGE (0x35)
0x09, 0x36, // USAGE (0x36)
0x81, 0x02, // INPUT (Data,Var,Abs)
0xc0, // END_COLLECTION
0xc0, // END_COLLECTION (45 bytes)
// device 3
0x06, 0x00, 0xff, // USAGE_PAGE (Vendor Defined Page 0)
0x09, 0x01, // USAGE (Vendor Usage 1)
0xa1, 0x01, // COLLECTION (Application)
0x09, 0x01, // USAGE (Vendor Usage 1)
0xa1, 0x00, // COLLECTION (Physical)
0x75, 0x08, // REPORT_SIZE (8)
0x95, 0x07, // REPORT_COUNT (7)
0x85, 0x03, // REPORT_ID (3)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255)
0x35, 0x00, // PHYSICAL_MINIMUM (0)
0x46, 0xff, 0x00, // PHYSICAL_MAXIMUM (255)
0x09, 0x30, // USAGE (0x30)
0x09, 0x31, // USAGE (0x31)
0x09, 0x32, // USAGE (0x32)
0x09, 0x33, // USAGE (0x33)
0x09, 0x34, // USAGE (0x34)
0x09, 0x35, // USAGE (0x35)
0x09, 0x36, // USAGE (0x36)
0x81, 0x02, // INPUT (Data,Var,Abs)
0xc0, // END_COLLECTION
0xc0, // END_COLLECTION (45 bytes)
// device 4
0x06, 0x00, 0xff, // USAGE_PAGE (Vendor Defined Page 0)
0x09, 0x01, // USAGE (Vendor Usage 1)
0xa1, 0x01, // COLLECTION (Application)
0x09, 0x01, // USAGE (Vendor Usage 1)
0xa1, 0x00, // COLLECTION (Physical)
0x75, 0x08, // REPORT_SIZE (8)
0x95, 0x07, // REPORT_COUNT (7)
0x85, 0x03, // REPORT_ID (3)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255)
0x35, 0x00, // PHYSICAL_MINIMUM (0)
0x46, 0xff, 0x00, // PHYSICAL_MAXIMUM (255)
0x09, 0x30, // USAGE (0x30)
0x09, 0x31, // USAGE (0x31)
0x09, 0x32, // USAGE (0x32)
0x09, 0x33, // USAGE (0x33)
0x09, 0x34, // USAGE (0x34)
0x09, 0x35, // USAGE (0x35)
0x09, 0x36, // USAGE (0x36)
0x81, 0x02, // INPUT (Data,Var,Abs)
0xc0, // END_COLLECTION
0xc0, // END_COLLECTION (45 bytes)
[b]// device 5 need 45 bytes
// device 6 need 45 bytes[/b]
};
static uchar idleRate; /* repeat rate for keyboards, never used for mice */
static struct reportBuffer_t
{
uint8_t report_id;
uint8_t Vy;
uint8_t Ry;
uint8_t Rx;
uint8_t Z;
uint8_t Y;
uint8_t X;
uint16_t Button;
} reportBuffer;
/* ------------------------------------------------------------------------- */
usbMsgLen_t usbFunctionSetup(uchar data[8])
{
usbRequest_t *rq = (void *)data;
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) */
if (rq->wValue.bytes[0] == 5)
{reportBuffer.report_id = 0x05;} // set report ID so computer knows what data struct is sent
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) {
wdt_enable(WDTO_1S);
odDebugInit();
DBG1(0x00, 0, 0); /* debug output: main starts */
ppmInit();
usbInit();
usbDeviceDisconnect(); /* enforce re-enumeration, do this while interrupts are disabled! */
uchar 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 */
uchar changed=0;
ppmNewData=1;
for(;;){ /* main event loop */
DBG1(0x02, 0, 0); /* debug output: main loop iterates */
wdt_reset();
usbPoll();
if (ppmNewData) {
ppmNewData=0;
if (reportBuffer.Vy !=ppmGet(0)) {reportBuffer.Vy=ppmGet(0); changed=1;}
if (reportBuffer.Ry !=ppmGet(1)) {reportBuffer.Ry=ppmGet(1); changed=1;}
if (reportBuffer.Rx !=ppmGet(2)) {reportBuffer.Rx=ppmGet(2); changed=1;}
if (reportBuffer.Z !=ppmGet(3)) {reportBuffer.Z=ppmGet(3); changed=1;}
if (reportBuffer.Y !=ppmGet(4)) {reportBuffer.Y=ppmGet(4); changed=1;}
if (reportBuffer.X !=ppmGet(5)) {reportBuffer.X=ppmGet(5); changed=1;}
if (reportBuffer.Button !=ppmGet(6)) {reportBuffer.Button=ppmGet(6); changed=1;}
if (changed) {
if(usbInterruptIsReady()){
changed=0;
// called after every poll of the interrupt endpoint
DBG1(0x03, 0, 0); // debug output: interrupt report prepared
usbSetInterrupt((void *)&reportBuffer, sizeof(reportBuffer));
}
}
}
}
}
This code works fine with 4 devices detected as expected, but I need 2 more devices.
That mean need 255 more bytes.
Any suggestion welcome.