2023-04-22 16:15:03 -06:00
//#include <HID.h>
# include <stdint.h>
# include <Arduino.h>
# include "PluggableUSB.h"
# define _USING_HID
// HID 'Driver'
// ------------
# define HID_GET_REPORT 0x01
# define HID_GET_IDLE 0x02
# define HID_GET_PROTOCOL 0x03
# define HID_SET_REPORT 0x09
# define HID_SET_IDLE 0x0A
# define HID_SET_PROTOCOL 0x0B
# define HID_HID_DESCRIPTOR_TYPE 0x21
# define HID_REPORT_DESCRIPTOR_TYPE 0x22
# define HID_PHYSICAL_DESCRIPTOR_TYPE 0x23
// HID subclass HID1.11 Page 8 4.2 Subclass
# define HID_SUBCLASS_NONE 0
# define HID_SUBCLASS_BOOT_INTERFACE 1
// HID Keyboard/Mouse bios compatible protocols HID1.11 Page 9 4.3 Protocols
# define HID_PROTOCOL_NONE 0
# define HID_PROTOCOL_KEYBOARD 1
# define HID_PROTOCOL_MOUSE 2
// Normal or bios protocol (Keyboard/Mouse) HID1.11 Page 54 7.2.5 Get_Protocol Request
// "protocol" variable is used for this purpose.
# define HID_BOOT_PROTOCOL 0
# define HID_REPORT_PROTOCOL 1
// HID Request Type HID1.11 Page 51 7.2.1 Get_Report Request
# define HID_REPORT_TYPE_INPUT 1
# define HID_REPORT_TYPE_OUTPUT 2
# define HID_REPORT_TYPE_FEATURE 3
typedef struct
{
uint8_t len ; // 9
uint8_t dtype ; // 0x21
uint8_t addr ;
uint8_t versionL ; // 0x101
uint8_t versionH ; // 0x101
uint8_t country ;
uint8_t desctype ; // 0x22 report
uint8_t descLenL ;
uint8_t descLenH ;
} HIDDescDescriptor ;
typedef struct
{
InterfaceDescriptor hid ;
HIDDescDescriptor desc ;
EndpointDescriptor in ;
} HIDDescriptor ;
class HIDSubDescriptor {
public :
HIDSubDescriptor * next = NULL ;
HIDSubDescriptor ( const void * d , const uint16_t l ) : data ( d ) , length ( l ) { }
const void * data ;
const uint16_t length ;
} ;
class HID_ : public PluggableUSBModule
{
public :
HID_ ( void ) ;
int begin ( void ) ;
int SendReport ( uint8_t id , const void * data , int len ) ;
void AppendDescriptor ( HIDSubDescriptor * node ) ;
protected :
// Implementation of the PluggableUSBModule
int getInterface ( uint8_t * interfaceCount ) ;
int getDescriptor ( USBSetup & setup ) ;
bool setup ( USBSetup & setup ) ;
uint8_t getShortName ( char * name ) ;
private :
uint8_t epType [ 1 ] ;
HIDSubDescriptor * rootNode ;
uint16_t descriptorSize ;
uint8_t protocol ;
uint8_t idle ;
} ;
// Replacement for global singleton.
// This function prevents static-initialization-order-fiasco
// https://isocpp.org/wiki/faq/ctors#static-init-order-on-first-use
HID_ & HID ( ) ;
# define D_HIDREPORT(length) { 9, 0x21, 0x01, 0x01, 0, 1, 0x22, lowByte(length), highByte(length) }
HID_ & HID ( )
{
static HID_ obj ;
return obj ;
}
int HID_ : : getInterface ( uint8_t * interfaceCount )
{
* interfaceCount + = 1 ; // uses 1
HIDDescriptor hidInterface = {
D_INTERFACE ( pluggedInterface , 1 , USB_DEVICE_CLASS_HUMAN_INTERFACE , HID_SUBCLASS_NONE , HID_PROTOCOL_NONE ) ,
D_HIDREPORT ( descriptorSize ) ,
D_ENDPOINT ( USB_ENDPOINT_IN ( pluggedEndpoint ) , USB_ENDPOINT_TYPE_INTERRUPT , USB_EP_SIZE , 0x01 )
} ;
return USB_SendControl ( 0 , & hidInterface , sizeof ( hidInterface ) ) ;
}
int HID_ : : getDescriptor ( USBSetup & setup )
{
// Check if this is a HID Class Descriptor request
if ( setup . bmRequestType ! = REQUEST_DEVICETOHOST_STANDARD_INTERFACE ) { return 0 ; }
if ( setup . wValueH ! = HID_REPORT_DESCRIPTOR_TYPE ) { return 0 ; }
// In a HID Class Descriptor wIndex contains the interface number
if ( setup . wIndex ! = pluggedInterface ) { return 0 ; }
int total = 0 ;
HIDSubDescriptor * node ;
for ( node = rootNode ; node ; node = node - > next ) {
int res = USB_SendControl ( TRANSFER_PGM , node - > data , node - > length ) ;
if ( res = = - 1 )
return - 1 ;
total + = res ;
}
// Reset the protocol on reenumeration. Normally the host should not assume the state of the protocol
// due to the USB specs, but Windows and Linux just assumes its in report mode.
protocol = HID_REPORT_PROTOCOL ;
return total ;
}
uint8_t HID_ : : getShortName ( char * name )
{
name [ 0 ] = ' H ' ;
name [ 1 ] = ' I ' ;
name [ 2 ] = ' D ' ;
name [ 3 ] = ' A ' + ( descriptorSize & 0x0F ) ;
name [ 4 ] = ' A ' + ( ( descriptorSize > > 4 ) & 0x0F ) ;
return 5 ;
}
void HID_ : : AppendDescriptor ( HIDSubDescriptor * node )
{
if ( ! rootNode ) {
rootNode = node ;
} else {
HIDSubDescriptor * current = rootNode ;
while ( current - > next ) {
current = current - > next ;
}
current - > next = node ;
}
descriptorSize + = node - > length ;
}
int HID_ : : SendReport ( uint8_t id , const void * data , int len )
{
// auto ret = USB_Send(pluggedEndpoint, &id, 1);
// if (ret < 0) return ret;
auto ret2 = USB_Send ( pluggedEndpoint | TRANSFER_RELEASE , data , len ) ;
if ( ret2 < 0 ) return ret2 ;
return ret2 ;
}
bool HID_ : : setup ( USBSetup & setup )
{
if ( pluggedInterface ! = setup . wIndex ) {
return false ;
}
uint8_t request = setup . bRequest ;
uint8_t requestType = setup . bmRequestType ;
if ( requestType = = REQUEST_DEVICETOHOST_CLASS_INTERFACE )
{
if ( request = = HID_GET_REPORT ) {
// TODO: HID_GetReport();
return true ;
}
if ( request = = HID_GET_PROTOCOL ) {
// TODO: Send8(protocol);
return true ;
}
if ( request = = HID_GET_IDLE ) {
// TODO: Send8(idle);
}
}
if ( requestType = = REQUEST_HOSTTODEVICE_CLASS_INTERFACE )
{
if ( request = = HID_SET_PROTOCOL ) {
// The USB Host tells us if we are in boot or report mode.
// This only works with a real boot compatible device.
protocol = setup . wValueL ;
return true ;
}
if ( request = = HID_SET_IDLE ) {
idle = setup . wValueL ;
return true ;
}
if ( request = = HID_SET_REPORT )
{
//uint8_t reportID = setup.wValueL;
//uint16_t length = setup.wLength;
//uint8_t data[length];
// Make sure to not read more data than USB_EP_SIZE.
// You can read multiple times through a loop.
// The first byte (may!) contain the reportID on a multreport.
//USB_RecvControl(data, length);
}
}
return false ;
}
HID_ : : HID_ ( void ) : PluggableUSBModule ( 1 , 1 , epType ) ,
rootNode ( NULL ) , descriptorSize ( 0 ) ,
protocol ( HID_REPORT_PROTOCOL ) , idle ( 1 )
{
epType [ 0 ] = EP_TYPE_INTERRUPT_IN ;
PluggableUSB ( ) . plug ( this ) ;
}
int HID_ : : begin ( void )
{
return 0 ;
}
static const uint8_t _hidReportDescriptor [ 137 ] PROGMEM =
{
0x05 , 0x01 , // Usage Page (Generic Desktop Ctrls)
0x09 , 0x05 , // Usage (Game Pad)
0xA1 , 0x01 , // Collection (Application)
0x15 , 0x00 , // Logical Minimum (0)
0x25 , 0x01 , // Logical Maximum (1)
0x35 , 0x00 , // Physical Minimum (0)
0x45 , 0x01 , // Physical Maximum (1)
0x75 , 0x01 , // Report Size (1)
0x95 , 0x0D , // Report Count (13)
0x05 , 0x09 , // Usage Page (Button)
0x19 , 0x01 , // Usage Minimum (0x01)
0x29 , 0x0D , // Usage Maximum (0x0D)
0x81 , 0x02 , // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x95 , 0x03 , // Report Count (3)
0x81 , 0x01 , // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x05 , 0x01 , // Usage Page (Generic Desktop Ctrls)
0x25 , 0x07 , // Logical Maximum (7)
0x46 , 0x3B , 0x01 , // Physical Maximum (315)
0x75 , 0x04 , // Report Size (4)
0x95 , 0x01 , // Report Count (1)
0x65 , 0x14 , // Unit (System: English Rotation, Length: Centimeter)
0x09 , 0x39 , // Usage (Hat switch)
0x81 , 0x42 , // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,Null State)
0x65 , 0x00 , // Unit (None)
0x95 , 0x01 , // Report Count (1)
0x81 , 0x01 , // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x26 , 0xFF , 0x00 , // Logical Maximum (255)
0x46 , 0xFF , 0x00 , // Physical Maximum (255)
0x09 , 0x30 , // Usage (X)
0x09 , 0x31 , // Usage (Y)
0x09 , 0x32 , // Usage (Z)
0x09 , 0x35 , // Usage (Rz)
0x75 , 0x08 , // Report Size (8)
0x95 , 0x04 , // Report Count (4)
0x81 , 0x02 , // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x06 , 0x00 , 0xFF , // Usage Page (Vendor Defined 0xFF00)
0x09 , 0x20 , // Usage (0x20)
0x09 , 0x21 , // Usage (0x21)
0x09 , 0x22 , // Usage (0x22)
0x09 , 0x23 , // Usage (0x23)
0x09 , 0x24 , // Usage (0x24)
0x09 , 0x25 , // Usage (0x25)
0x09 , 0x26 , // Usage (0x26)
0x09 , 0x27 , // Usage (0x27)
0x09 , 0x28 , // Usage (0x28)
0x09 , 0x29 , // Usage (0x29)
0x09 , 0x2A , // Usage (0x2A)
0x09 , 0x2B , // Usage (0x2B)
0x95 , 0x0C , // Report Count (12)
0x81 , 0x02 , // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x0A , 0x21 , 0x26 , // Usage (0x2621)
0x95 , 0x08 , // Report Count (8)
0xB1 , 0x02 , // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x0A , 0x21 , 0x26 , // Usage (0x2621)
0x91 , 0x02 , // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x26 , 0xFF , 0x03 , // Logical Maximum (1023)
0x46 , 0xFF , 0x03 , // Physical Maximum (1023)
0x09 , 0x2C , // Usage (0x2C)
0x09 , 0x2D , // Usage (0x2D)
0x09 , 0x2E , // Usage (0x2E)
0x09 , 0x2F , // Usage (0x2F)
0x75 , 0x10 , // Report Size (16)
0x95 , 0x04 , // Report Count (4)
0x81 , 0x02 , // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0xC0 , // End Collection
// 137 bytes
} ;
typedef struct
{
uint16_t buttons ; // 2
uint8_t hatAndConstant ; // 1
2023-05-15 18:49:22 -06:00
uint8_t axis [ 4 ] ; // 4
2023-04-22 16:15:03 -06:00
uint8_t reserved1 [ 12 ] ; // 12
uint64_t finalConstant ; // 8
} InstrumentButtonState ;
class Instrument
{
public :
Instrument ( void ) ;
void SendReport2 ( InstrumentButtonState * buttons ) ;
} ;
Instrument : : Instrument ( void )
{
static HIDSubDescriptor node ( _hidReportDescriptor , sizeof ( _hidReportDescriptor ) ) ;
HID ( ) . AppendDescriptor ( & node ) ;
//AppendDescriptor(&node);
}
void Instrument : : SendReport2 ( InstrumentButtonState * buttons )
{
HID ( ) . SendReport ( 0 , ( uint8_t * ) buttons , 27 ) ; //sizeof(InstrumentButtonState)); // Ummmmm... the struct size is 27, and wireshark shows the URB size as 27 when I put 26 here
//USB_Send(pluggedInterface | TRANSFER_RELEASE, buttons, 27);
//USB_Send(1 | TRANSFER_RELEASE, buttons, 2);
//controller.write((uint8_t*)buttons, 2);
}
int TESTBUTTON = 2 ;
2023-05-15 18:49:22 -06:00
int BIT0 = 2 ;
int BIT1 = 3 ;
int BIT2 = 4 ;
int BIT3 = 5 ;
int BIT4 = 6 ;
int BIT5 = 7 ;
int BIT6 = 8 ;
int BIT7 = 9 ;
int BIT8 = 10 ;
int BIT9 = 11 ;
//int wammyPin = 12;
int STRUM_DOWN = 0 ;
int STRUM_UP = 1 ;
int TILT_SWITCH = 2 ;
int BUTTON_GREEN = 3 ;
int BUTTON_RED = 4 ;
int BUTTON_YELLOW = 5 ;
int BUTTON_BLUE = 6 ;
int BUTTON_ORANGE = 7 ;
int SOLO_BUTTON_GREEN = 8 ;
int SOLO_BUTTON_RED = 9 ;
int SOLO_BUTTON_YELLOW = 10 ;
int SOLO_BUTTON_BLUE = 11 ;
int SOLO_BUTTON_ORANGE = 12 ;
int BUTTON_PLUS = 13 ;
int BUTTON_MINUS = 18 ;
int ANALOG_WAMMY = 19 ;
int BUTTON_UP = 20 ;
int BUTTON_RIGHT = 21 ;
int BUTTON_DOWN = 22 ;
int BUTTON_LEFT = 23 ;
uint16_t GREEN_BIT = 0x0002 ;
uint16_t RED_BIT = 0x0004 ;
uint16_t YELLOW_BIT = 0x0008 ;
uint16_t BLUE_BIT = 0x0001 ;
uint16_t ORANGE_BIT = 0x0010 ;
uint16_t SOLO_BIT = 0x0040 ;
uint16_t OVERDRIVE_BIT = 0x0020 ;
uint16_t PLUS_BIT = 0x0200 ;
uint16_t MINUS_BIT = 0x0100 ;
2023-04-22 16:15:03 -06:00
int OBLED = 13 ;
Instrument instrument ;
InstrumentButtonState buttonState ;
2023-05-15 18:49:22 -06:00
void setButtonBits ( uint16_t bits , bool state )
{
if ( state )
{
buttonState . buttons | = bits ;
}
else
{
buttonState . buttons & = ~ bits ;
}
}
void setOtherBits ( uint8_t bits , bool state )
{
if ( state )
{
buttonState . hatAndConstant | = bits ;
}
else
{
buttonState . hatAndConstant & = ~ bits ;
}
}
2023-04-22 16:15:03 -06:00
void setup ( ) {
// put your setup code here, to run once:
2023-05-15 18:49:22 -06:00
//pinMode(TESTBUTTON, INPUT_PULLUP);
pinMode ( STRUM_DOWN , INPUT_PULLUP ) ;
pinMode ( STRUM_UP , INPUT_PULLUP ) ;
pinMode ( TILT_SWITCH , INPUT_PULLUP ) ;
pinMode ( BUTTON_GREEN , INPUT_PULLUP ) ;
pinMode ( BUTTON_RED , INPUT_PULLUP ) ;
pinMode ( BUTTON_YELLOW , INPUT_PULLUP ) ;
pinMode ( BUTTON_BLUE , INPUT_PULLUP ) ;
pinMode ( BUTTON_ORANGE , INPUT_PULLUP ) ;
pinMode ( SOLO_BUTTON_GREEN , INPUT_PULLUP ) ;
pinMode ( SOLO_BUTTON_RED , INPUT_PULLUP ) ;
pinMode ( SOLO_BUTTON_YELLOW , INPUT_PULLUP ) ;
pinMode ( SOLO_BUTTON_BLUE , INPUT_PULLUP ) ;
pinMode ( SOLO_BUTTON_ORANGE , INPUT_PULLUP ) ;
pinMode ( BUTTON_PLUS , INPUT_PULLUP ) ;
pinMode ( BUTTON_MINUS , INPUT_PULLUP ) ;
pinMode ( ANALOG_WAMMY , INPUT ) ;
pinMode ( BUTTON_UP , INPUT_PULLUP ) ;
pinMode ( BUTTON_RIGHT , INPUT_PULLUP ) ;
pinMode ( BUTTON_DOWN , INPUT_PULLUP ) ;
pinMode ( BUTTON_LEFT , INPUT_PULLUP ) ;
//pinMode(OBLED, OUTPUT);
2023-04-22 16:15:03 -06:00
buttonState . buttons = 0x0000 ;
buttonState . hatAndConstant = 0x08 ;
2023-05-15 18:49:22 -06:00
//buttonState.instrumentIdentifier = 0x80808080;//0x7f807f80;// guitar identifier //0x80808080; // Drum identifier
buttonState . axis [ 0 ] = 0 ;
buttonState . axis [ 1 ] = 0 ;
buttonState . axis [ 2 ] = 0 ;
buttonState . axis [ 3 ] = 0 ;
2023-04-22 16:15:03 -06:00
for ( int i = 0 ; i < 12 ; i + + )
{
buttonState . reserved1 [ i ] = 0x0 ;
}
buttonState . finalConstant = 0x0200020002000200 ;
}
void loop ( ) {
// put your main code here, to run repeatedly:
buttonState . buttons = 0 ;
2023-05-15 18:49:22 -06:00
buttonState . hatAndConstant = 0 ;
//setButtonBits(0x0082, !digitalRead(TESTBUTTON));
// setButtonBits(0x0080, !digitalRead(BIT0));
// setButtonBits(0x0040, !digitalRead(BIT1));
// setButtonBits(0x0020, !digitalRead(BIT2));
// setButtonBits(0x0010, !digitalRead(BIT3));
// setButtonBits(0x0008, !digitalRead(BIT4));
// setButtonBits(0x0004, !digitalRead(BIT5));
// setButtonBits(0x0002, !digitalRead(BIT6));
// setButtonBits(0x0001, !digitalRead(BIT7));
// setButtonBits(0x8000, !digitalRead(BIT8));
// setButtonBits(0x4000, !digitalRead(BIT9));
setButtonBits ( GREEN_BIT , ! digitalRead ( BUTTON_GREEN ) | | ! digitalRead ( SOLO_BUTTON_GREEN ) ) ;
setButtonBits ( RED_BIT , ! digitalRead ( BUTTON_RED ) | | ! digitalRead ( SOLO_BUTTON_RED ) ) ;
setButtonBits ( YELLOW_BIT , ! digitalRead ( BUTTON_YELLOW ) | | ! digitalRead ( SOLO_BUTTON_YELLOW ) ) ;
setButtonBits ( BLUE_BIT , ! digitalRead ( BUTTON_BLUE ) | | ! digitalRead ( SOLO_BUTTON_BLUE ) ) ;
setButtonBits ( ORANGE_BIT , ! digitalRead ( BUTTON_ORANGE ) | | ! digitalRead ( SOLO_BUTTON_ORANGE ) ) ;
setButtonBits ( SOLO_BIT , ! digitalRead ( SOLO_BUTTON_GREEN ) | | ! digitalRead ( SOLO_BUTTON_RED ) | | ! digitalRead ( SOLO_BUTTON_YELLOW ) | | ! digitalRead ( SOLO_BUTTON_BLUE ) | | ! digitalRead ( SOLO_BUTTON_ORANGE ) ) ;
setButtonBits ( OVERDRIVE_BIT , ! digitalRead ( TILT_SWITCH ) ) ;
setButtonBits ( PLUS_BIT , ! digitalRead ( BUTTON_PLUS ) ) ;
setButtonBits ( MINUS_BIT , ! digitalRead ( BUTTON_MINUS ) ) ;
if ( ! digitalRead ( BUTTON_UP ) | | ! digitalRead ( STRUM_UP ) )
2023-04-22 16:15:03 -06:00
{
2023-05-15 18:49:22 -06:00
buttonState . hatAndConstant = 0x00 ;
} else if ( ! digitalRead ( BUTTON_RIGHT ) )
{
buttonState . hatAndConstant = 0x02 ;
} else if ( ! digitalRead ( BUTTON_DOWN ) | | ! digitalRead ( STRUM_DOWN ) )
{
buttonState . hatAndConstant = 0x04 ;
} else if ( ! digitalRead ( BUTTON_LEFT ) )
2023-04-22 16:15:03 -06:00
{
2023-05-15 18:49:22 -06:00
buttonState . hatAndConstant = 0x06 ;
} else
{
buttonState . hatAndConstant = 0x08 ;
2023-04-22 16:15:03 -06:00
}
2023-05-15 18:49:22 -06:00
//uint16_t wammy = (analogRead(A11) / 100) - 1;
//buttonState.hatAndConstant |= wammy << 4;
uint8_t wammy = analogRead ( ANALOG_WAMMY ) / 4 ;
buttonState . axis [ 2 ] = wammy ;
//setOtherBits(0x08, !digitalRead(A0));
//setOtherBits(0x04, !digitalRead(A1));
//setOtherBits(0x02, !digitalRead(A2));
//setOtherBits(0x01, !digitalRead(A3));
//setButtonBits(0x0200, !digitalRead(A4));
//setButtonBits(0x0100, !digitalRead(A5));
// if (!digitalRead(TESTBUTTON))
// {
// buttonState.buttons |= 0x0082;
// }
// else
// {
// buttonState.buttons &= ~0x0082;
// }
2023-04-22 16:15:03 -06:00
//digitalWrite(OBLED, LOW);
//delay(200);
//digitalWrite(OBLED, HIGH);
instrument . SendReport2 ( & buttonState ) ;
delay ( 10 ) ;
}