Leonardo HID устройста

NeiroN
NeiroN аватар
Offline
Зарегистрирован: 15.06.2013

Так как я купил пачку ProMicro совместимых с Leonardo

Хочется поизучать HID устройства. Кто встречал мануалы по страницам HID устройств и их обьявлению на русском?

Пока что - добавил Индикаторы к устройству клавиатуры. Нашол таблицы там много чего перечислено, но не очень понятно.

NeiroN
NeiroN аватар
Offline
Зарегистрирован: 15.06.2013

Вот HID.cpp

/* Copyright (c) 2011, Peter Barrett
**
** Permission to use, copy, modify, and/or distribute this software for
** any purpose with or without fee is hereby granted, provided that the
** above copyright notice and this permission notice appear in all copies.
**
** THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
** WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
** WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR
** BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES
** OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
** WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
** ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
** SOFTWARE.
*/

#include "Platform.h"
#include "USBAPI.h"
#include "USBDesc.h"

#if defined(USBCON)
#ifdef HID_ENABLED

// *** This used to be RAWHID_ENABLED
//#define RAWHID_ENABLED
#define KBAM_ENABLED
#define JOYHID_ENABLED

//	Singletons for mouse and keyboard

Mouse_ Mouse;
Keyboard_ Keyboard;

// *** Add a joystick too

#ifdef JOYHID_ENABLED
Joystick_ Joystick;
#endif

//================================================================================
//================================================================================

// HID report descriptor

#define LSB(_x) ((_x) & 0xFF)
#define MSB(_x) ((_x) >> 8)

#define RAWHID_USAGE_PAGE	0xFFC0
#define RAWHID_USAGE		0x0C00
#define RAWHID_TX_SIZE		64
#define RAWHID_RX_SIZE		64

extern const u8 _hidReportDescriptor[] PROGMEM;
const u8 _hidReportDescriptor[] = {

#define USAGE				0x09
#define USAGE_MIN			0x19
#define USAGE_MAX			0x29
#define LOGICAL_MIN			0x15
#define LOGICAL_MAX			0x25
#define LOGICAL_MAX_16B		0x26

#define PHYSICAL_MIN		0x35
#define PHYSICAL_MAX		0x45
#define PHYSICAL_MAX_16B	0x46

#define UNIT				0x65
#define UNIT_EXPONENT		0x55

#define REPORT_COUNT		0x95
#define REPORT_SIZE			0x75

#define COLLECTION			0xA1
#define END_COLLECTION		0xC0
#define APPLICATION			0x01
#define PHYSICAL			0x00

#define INPUT				0x81
#define OUTPUT				0x91

#define REPORT_ID			0x85

#define USAGE_PAGE			0x05

#define GENERIC_DESKTOP		0x01
#define MOUSE				0x02
#define JOYSTICK			0x04
#define KEYBOARD			0x06
#define BUTTON				0x09

// Axes
#define X_AXIS				0x30
#define Y_AXIS				0x31
#define Z_AXIS				0x32
#define rX_AXIS				0x33
#define rY_AXIS				0x34
#define rZ_AXIS				0x35
#define WHEEL_AXIS			0x38
#define THROTTLE			0xBB
#define RUDDER				0xBA
#define BRAKE				0xC5
#define CLUTCH				0xC6
#define SHIFTER				0xC7
#define STEERING			0xC8

// Data bit field flags
#define CONST_VAL			0x01// If not set, data type is data, rather then a constant
#define DATA				0x00// conterpoint of CONST_VAL

#define VARIABLE			0x02// If not set, data type is an array
#define ARRAY				0x00// counterpoint of VARIABLE

#define RELATIVE			0x04// if not set, data is returned in absolute coordinates
#define ABSOLUTE			0x00// counterpoint of RELATIVE


#ifdef KBAM_ENABLED
	//	Mouse
	USAGE_PAGE, GENERIC_DESKTOP,		// USAGE_PAGE (Generic Desktop)	// 54
	USAGE, MOUSE,				// USAGE (Mouse)
	COLLECTION, APPLICATION,		// COLLECTION (Application)
		USAGE, 0x01,				// USAGE (Pointer)
		COLLECTION, PHYSICAL,			// COLLECTION (Physical)
			REPORT_ID, 0x01,			// REPORT_ID (1)
			USAGE_PAGE, BUTTON,			// USAGE_PAGE (Button)
			USAGE_MIN, 0x01,			// USAGE_MINIMUM (Button 1)
			USAGE_MAX, 0x03,			// USAGE_MAXIMUM (Button 3)
			LOGICAL_MIN, 0x00,			// LOGICAL_MINIMUM (0)
			LOGICAL_MAX, 0x01,			// LOGICAL_MAXIMUM (1)
			REPORT_COUNT, 0x03,			// REPORT_COUNT (3)
			REPORT_SIZE, 0x01,			// REPORT_SIZE (1)
			INPUT, 0x02,				// INPUT (Data,Var,Abs)
			REPORT_COUNT, 0x01,			// REPORT_COUNT (1)
			REPORT_SIZE, 0x05,			// REPORT_SIZE (5)
			INPUT, CONST_VAL|VARIABLE|ABSOLUTE,	// INPUT (Cnst,Var,Abs)
			USAGE_PAGE, GENERIC_DESKTOP,		// USAGE_PAGE (Generic Desktop)
			USAGE, X_AXIS,				// USAGE (X)
			USAGE, Y_AXIS,				// USAGE (Y)
			USAGE, WHEEL_AXIS,			// USAGE (Wheel)
			LOGICAL_MIN, 0x81,			// LOGICAL_MINIMUM (-127)
			LOGICAL_MAX, 0x7f,			// LOGICAL_MAXIMUM (127)
			REPORT_SIZE, 0x08,			// REPORT_SIZE (8)
			REPORT_COUNT, 0x03,			// REPORT_COUNT (3)
			INPUT, DATA|VARIABLE|RELATIVE,		// INPUT (Data,Var,Rel)
		END_COLLECTION,			// END_COLLECTION
	END_COLLECTION,			// END_COLLECTION

	//	Keyboard
	USAGE_PAGE, GENERIC_DESKTOP,		// USAGE_PAGE (Generic Desktop)	// 47
	USAGE, KEYBOARD,			// USAGE (Keyboard)
	COLLECTION, APPLICATION,		// COLLECTION (Application)
		REPORT_ID, 0x02,			// REPORT_ID (2)
		USAGE_PAGE, 0x07,			// USAGE_PAGE (Keyboard)

		USAGE_MIN, 0xe0,			// USAGE_MINIMUM (Keyboard LeftControl)
		USAGE_MAX, 0xe7,			// USAGE_MAXIMUM (Keyboard Right GUI)
		LOGICAL_MIN, 0x00,			// LOGICAL_MINIMUM (0)
		LOGICAL_MAX, 0x01,			// LOGICAL_MAXIMUM (1)
		REPORT_SIZE, 0x01,			// REPORT_SIZE (1)

		REPORT_COUNT, 0x08,			// REPORT_COUNT (8)
		INPUT, DATA|VARIABLE|ABSOLUTE,		// INPUT (Data,Var,Abs)
		REPORT_COUNT, 0x01,			// REPORT_COUNT (1)
		REPORT_SIZE, 0x08,			// REPORT_SIZE (8)
		INPUT, CONST_VAL|VARIABLE|ABSOLUTE,	// INPUT (Cnst,Var,Abs)

		REPORT_COUNT, 0x05,			// REPORT_COUNT (5)
		REPORT_SIZE, 0x01,			// REPORT_SIZE (1)
		USAGE_PAGE, 0x08,			// USAGE_PAGE (LEDs)
		USAGE_MIN, 0x01,			// USAGE_MINIMUM (1)
		USAGE_MAX, 0x05,			// USAGE_MAXIMUM (5)
		OUTPUT, 0x02,				// OUTPUT (Data,Var,Abs) // LED report
		REPORT_COUNT, 0x01,			// REPORT_COUNT (1)
		REPORT_SIZE, 0x03,			// REPORT_SIZE (3)
		OUTPUT, CONST_VAL,			// OUTPUT (Constant) // padding

		REPORT_COUNT, 0x06,			// REPORT_COUNT (6)
		REPORT_SIZE, 0x08,			// REPORT_SIZE (8)
		LOGICAL_MIN, 0x00,			// LOGICAL_MINIMUM (0)
		LOGICAL_MAX, 0x65,			// LOGICAL_MAXIMUM (101)
		USAGE_PAGE, 0x07,			// USAGE_PAGE (Keyboard)

		USAGE_MIN, 0x00,			// USAGE_MINIMUM (Reserved (no event indicated))
		USAGE_MAX, 0x65,			// USAGE_MAXIMUM (Keyboard Application)
		INPUT, DATA|ARRAY|ABSOLUTE,	// INPUT (Data,Ary,Abs)
	END_COLLECTION,					// END_COLLECTION
#endif
#ifdef RAWHID_ENABLED
	//	RAW HID
	0x06, LSB(RAWHID_USAGE_PAGE), MSB(RAWHID_USAGE_PAGE),	// 30
	0x0A, LSB(RAWHID_USAGE), MSB(RAWHID_USAGE),

	COLLECTION, APPLICATION,			// Collection 0x01  (0x01 is the application collection, don't know why that wasn't noted)
		REPORT_ID, 0x03,				// REPORT_ID (3)
		REPORT_SIZE, 0x08,				// report size = 8 bits
		LOGICAL_MIN, 0x00,				// logical minimum = 0
		LOGICAL_MAX_16B, 0xFF, 0x00,		// logical maximum = 255
		REPORT_COUNT, 64,				// report count TX
		USAGE, 0x01,					// usage
		INPUT, DATA|VARIABLE|ABSOLUTE,			// Input (Data,Ary,Abs)
		REPORT_COUNT, 64,				// report count RX
		USAGE, 0x02,					// usage
		OUTPUT, DATA|VARIABLE|ABSOLUTE,			// Output (Data,Ary,Abs) 	// what? This comment contradicts the actual flag
	END_COLLECTION,					// end collection
#endif
// *** Here is where the RAW_HID has been converted to a Joystick device
// *** Inspired by helmpcb.com/electronics/usb-joystick
// *** Check out www.usb.org/developers/hidpage/ for more than you'll ever need to know about USB HID
// *** HID descriptor created using the HID descriptor tool from www.usb.org/developers/hidpage/dt2_4.zip (win32)

#ifdef JOYHID_ENABLED

	USAGE_PAGE, GENERIC_DESKTOP,		// USAGE_PAGE (Generic Desktop)
	USAGE, JOYSTICK,			// USAGE (Joystick)
	COLLECTION, 0x01,			// COLLECTION (Application)
		REPORT_ID, 0x03,				// REPORT_ID (3)  (This is important when HID_SendReport() is called)

		//Buttons:
		USAGE_PAGE, BUTTON,				// USAGE_PAGE (Button)
		USAGE_MIN, 0x01,				// USAGE_MINIMUM (Button 1)
		USAGE_MAX, 0x20,				// USAGE_MAXIMUM (Button 32)
		LOGICAL_MIN, 0x00,				// LOGICAL_MINIMUM (0)
		LOGICAL_MAX, 0x01,				// LOGICAL_MAXIMUM (1)
		REPORT_SIZE, 0x01,				// REPORT_SIZE (1)
		REPORT_COUNT, 0x20,				// REPORT_COUNT (32)
		UNIT_EXPONENT, 0x00,					// UNIT_EXPONENT (0)
		UNIT, 0x00,					// UNIT (None)
		INPUT, DATA|VARIABLE|ABSOLUTE,			// INPUT (Data,Var,Abs)

		// 8 bit Throttle and Steering
		USAGE_PAGE, 0x02,				// USAGE_PAGE (Simulation Controls)

		LOGICAL_MIN, 0x00,					// LOGICAL_MINIMUM (0)
		LOGICAL_MAX_16B, 0xff, 0x00,				// LOGICAL_MAXIMUM (255)
		COLLECTION, 0x00,					// COLLECTION (Physical)
			USAGE, RUDDER,					// USAGE (Steering)
			USAGE, THROTTLE,				// USAGE (Throttle)
			USAGE, BRAKE,					// USAGE (Brake)
			USAGE, CLUTCH,					// USAGE (Clutch)
			USAGE, SHIFTER,					// USAGE (Shifter)
			USAGE, STEERING,				// USAGE (Steering)
			REPORT_SIZE, 0x08,				// REPORT_SIZE (8)
			REPORT_COUNT, 0x06,				// REPORT_COUNT (6)
			INPUT, DATA|VARIABLE|ABSOLUTE,	// INPUT (Data,Var,Abs)
		END_COLLECTION,					// END_COLLECTION
		// Two Hat switches

		USAGE_PAGE, GENERIC_DESKTOP,				// USAGE_PAGE (Generic Desktop)

		USAGE, 0x39,					// USAGE (Hat switch)
		LOGICAL_MIN, 0x00,				// LOGICAL_MINIMUM (0)
		LOGICAL_MAX, 0x07,				// LOGICAL_MAXIMUM (7)
		PHYSICAL_MIN, 0x00,				// PHYSICAL_MINIMUM (0)
		PHYSICAL_MAX_16B, 0x3B, 0x01,			// PHYSICAL_MAXIMUM (315)
		UNIT, 0x14,					// UNIT (Eng Rot:Angular Pos)
		REPORT_SIZE, 0x04,				// REPORT_SIZE (4)
		REPORT_COUNT, 0x01,				// REPORT_COUNT (1)
		INPUT, DATA|VARIABLE|ABSOLUTE,			// INPUT (Data,Var,Abs)

		USAGE, 0x39,					// USAGE (Hat switch)
		LOGICAL_MIN, 0x00,				// LOGICAL_MINIMUM (0)
		LOGICAL_MAX, 0x07,				// LOGICAL_MAXIMUM (7)
		PHYSICAL_MIN, 0x00,				// PHYSICAL_MINIMUM (0)
		PHYSICAL_MAX_16B, 0x3B, 0x01,			// PHYSICAL_MAXIMUM (315)
		UNIT, 0x14,					// UNIT (Eng Rot:Angular Pos)
		REPORT_SIZE, 0x04,				// REPORT_SIZE (4)
		REPORT_COUNT, 0x01,				// REPORT_COUNT (1)
		INPUT, DATA|VARIABLE|ABSOLUTE,			// INPUT (Data,Var,Abs)

		LOGICAL_MIN, 0x00,				// LOGICAL_MINIMUM (0)
		LOGICAL_MAX_16B, 0xFF, 0x00,			// LOGICAL_MAXIMUM (255)
		REPORT_SIZE, 0x08,				// REPORT_SIZE (8)

		USAGE, 0x01,					// USAGE (Pointer)
		COLLECTION, 0x00,				// COLLECTION (Physical)
			USAGE, X_AXIS,					// USAGE (x)
			USAGE, Y_AXIS,					// USAGE (y)
			USAGE, Z_AXIS,					// USAGE (z)
			USAGE, rX_AXIS,					// USAGE (rx)
			USAGE, rY_AXIS,					// USAGE (ry)
			USAGE, rZ_AXIS,					// USAGE (rz)
			REPORT_COUNT, 0x06,				// REPORT_COUNT (2)
			INPUT, DATA|VARIABLE|ABSOLUTE,			// INPUT (Data,Var,Abs)
		END_COLLECTION,					// END_COLLECTION

	END_COLLECTION					// END_COLLECTION




#endif
};


extern const HIDDescriptor _hidInterface PROGMEM;
const HIDDescriptor _hidInterface =
{
	D_INTERFACE(HID_INTERFACE,1,3,0,0),
	D_HIDREPORT(sizeof(_hidReportDescriptor)),
	D_ENDPOINT(USB_ENDPOINT_IN (HID_ENDPOINT_INT),USB_ENDPOINT_TYPE_INTERRUPT,0x40,0x01)
};

//================================================================================
//================================================================================
//	Driver

u8 _hid_protocol = 1;
u8 _hid_idle = 1;

#define WEAK __attribute__ ((weak))


int WEAK HID_GetInterface(u8* interfaceNum)
{
	interfaceNum[0] += 1;	// uses 1
	return USB_SendControl(TRANSFER_PGM,&_hidInterface,sizeof(_hidInterface));
}

int WEAK HID_GetDescriptor(int i)
{
	return USB_SendControl(TRANSFER_PGM,_hidReportDescriptor,sizeof(_hidReportDescriptor));
}

void WEAK HID_SendReport(u8 id, const void* data, int len)
{
	USB_Send(HID_TX, &id, 1);
	USB_Send(HID_TX | TRANSFER_RELEASE,data,len);
}

bool WEAK HID_Setup(Setup& setup)
{
	u8 r = setup.bRequest;
	u8 requestType = setup.bmRequestType;
	if (REQUEST_DEVICETOHOST_CLASS_INTERFACE == requestType)
	{
		if (HID_GET_REPORT == r)
		{
			//HID_GetReport();
			return true;
		}
		if (HID_GET_PROTOCOL == r)
		{
			//Send8(_hid_protocol);	// TODO
			return true;
		}
	}

	if (REQUEST_HOSTTODEVICE_CLASS_INTERFACE == requestType)
	{
		if (HID_SET_PROTOCOL == r)
		{
			_hid_protocol = setup.wValueL;
			return true;
		}

		if (HID_SET_IDLE == r)
		{
			_hid_idle = setup.wValueL;
			return true;
		}
		
		if (HID_SET_REPORT == r)
		{
			if (setup.wLength == 2) 
			{
				uint8_t data[2];
				if (2 == USB_RecvControl(data, 2)) 
				{
					Keyboard.setLedStatus(data[1]);
				}
			}
		}
	}
	return false;
}

//================================================================================
//================================================================================
//	Joystick
//  Usage: Joystick.move(inputs go here)
//
//  The report data format must match the one defined in the descriptor exactly
//  or it either won't work, or the pc will make a mess of unpacking the data
//

#ifdef JOYHID_ENABLED

Joystick_::Joystick_()
{
}


#define joyBytes 17 		// should be equivalent to sizeof(JoyState_t)

void Joystick_::setState(JoyState_t *joySt)
{
	uint8_t data[joyBytes];
	uint32_t buttonTmp;
	buttonTmp = joySt->buttons;

	data[0] = buttonTmp & 0xFF;		// Break 32 bit button-state out into 4 bytes, to send over USB
	buttonTmp >>= 8;
	data[1] = buttonTmp & 0xFF;
	buttonTmp >>= 8;
	data[2] = buttonTmp & 0xFF;
	buttonTmp >>= 8;
	data[3] = buttonTmp & 0xFF;

	data[4] = joySt->rudder;		// Steering
	data[5] = joySt->throttle;		// Throttle
	data[6] = joySt->brake;			// Brake
	data[7] = joySt->clutch;		// Clutch
	data[8] = joySt->shifter;		// Shifter
	data[9] = joySt->steering;		// Steering

	data[10] = (joySt->hatSw2 << 4) | joySt->hatSw1;		// Pack hat-switch states into a single byte

	data[11] = joySt->xAxis;		// X axis
	data[12] = joySt->yAxis;		// Y axis
	data[13] = joySt->zAxis;		// Z axis
	data[14] = joySt->xRotAxis;		// rX axis
	data[15] = joySt->yRotAxis;		// rY axis
	data[16] = joySt->zRotAxis;		// rZ axis

	//HID_SendReport(Report number, array of values in same order as HID descriptor, length)
	HID_SendReport(3, data, joyBytes);
	// The joystick is specified as using report 3 in the descriptor. That's where the "3" comes from
}


#endif

//================================================================================
//================================================================================
//	Mouse

Mouse_::Mouse_(void) : _buttons(0)
{

}

void Mouse_::begin(void)
{
}

void Mouse_::end(void)
{
}

void Mouse_::click(uint8_t b)
{
	_buttons = b;
	move(0,0,0);
	_buttons = 0;
	move(0,0,0);
}

void Mouse_::move(signed char x, signed char y, signed char wheel)
{
	u8 m[4];
	m[0] = _buttons;
	m[1] = x;
	m[2] = y;
	m[3] = wheel;
	HID_SendReport(1,m,4);
}

void Mouse_::buttons(uint8_t b)
{
	if (b != _buttons)
	{
		_buttons = b;
		move(0,0,0);
	}
}

void Mouse_::press(uint8_t b)
{
	buttons(_buttons | b);
}

void Mouse_::release(uint8_t b)
{
	buttons(_buttons & ~b);
}

bool Mouse_::isPressed(uint8_t b)
{
	if ((b & _buttons) > 0)
		return true;
	return false;
}

//================================================================================
//================================================================================
//	Keyboard

Keyboard_::Keyboard_(void)
{
}

void Keyboard_::begin(void)
{
}

void Keyboard_::end(void)
{
}

void Keyboard_::sendReport(KeyReport* keys)
{
	HID_SendReport(2,keys,sizeof(KeyReport));
}

extern
const uint8_t _asciimap[128] PROGMEM;

#define SHIFT 0x80
const uint8_t _asciimap[128] =
{
	0x00,             // NUL
	0x00,             // SOH
	0x00,             // STX
	0x00,             // ETX
	0x00,             // EOT
	0x00,             // ENQ
	0x00,             // ACK
	0x00,             // BEL
	0x2a,			// BS	Backspace
	0x2b,			// TAB	Tab
	0x28,			// LF	Enter
	0x00,             // VT
	0x00,             // FF
	0x00,             // CR
	0x00,             // SO
	0x00,             // SI
	0x00,             // DEL
	0x00,             // DC1
	0x00,             // DC2
	0x00,             // DC3
	0x00,             // DC4
	0x00,             // NAK
	0x00,             // SYN
	0x00,             // ETB
	0x00,             // CAN
	0x00,             // EM
	0x00,             // SUB
	0x00,             // ESC
	0x00,             // FS
	0x00,             // GS
	0x00,             // RS
	0x00,             // US

	0x2c,		   //  ' '
	0x1e|SHIFT,	   // !
	0x34|SHIFT,	   // "
	0x20|SHIFT,    // #
	0x21|SHIFT,    // $
	0x22|SHIFT,    // %
	0x24|SHIFT,    // &
	0x34,          // '
	0x26|SHIFT,    // (
	0x27|SHIFT,    // )
	0x25|SHIFT,    // *
	0x2e|SHIFT,    // +
	0x36,          // ,
	0x2d,          // -
	0x37,          // .
	0x38,          // /
	0x27,          // 0
	0x1e,          // 1
	0x1f,          // 2
	0x20,          // 3
	0x21,          // 4
	0x22,          // 5
	0x23,          // 6
	0x24,          // 7
	0x25,          // 8
	0x26,          // 9
	0x33|SHIFT,      // :
	0x33,          // ;
	0x36|SHIFT,      // <
	0x2e,          // =
	0x37|SHIFT,      // >
	0x38|SHIFT,      // ?
	0x1f|SHIFT,      // @
	0x04|SHIFT,      // A
	0x05|SHIFT,      // B
	0x06|SHIFT,      // C
	0x07|SHIFT,      // D
	0x08|SHIFT,      // E
	0x09|SHIFT,      // F
	0x0a|SHIFT,      // G
	0x0b|SHIFT,      // H
	0x0c|SHIFT,      // I
	0x0d|SHIFT,      // J
	0x0e|SHIFT,      // K
	0x0f|SHIFT,      // L
	0x10|SHIFT,      // M
	0x11|SHIFT,      // N
	0x12|SHIFT,      // O
	0x13|SHIFT,      // P
	0x14|SHIFT,      // Q
	0x15|SHIFT,      // R
	0x16|SHIFT,      // S
	0x17|SHIFT,      // T
	0x18|SHIFT,      // U
	0x19|SHIFT,      // V
	0x1a|SHIFT,      // W
	0x1b|SHIFT,      // X
	0x1c|SHIFT,      // Y
	0x1d|SHIFT,      // Z
	0x2f,          // [
	0x31,          // bslash
	0x30,          // ]
	0x23|SHIFT,    // ^
	0x2d|SHIFT,    // _
	0x35,          // `
	0x04,          // a
	0x05,          // b
	0x06,          // c
	0x07,          // d
	0x08,          // e
	0x09,          // f
	0x0a,          // g
	0x0b,          // h
	0x0c,          // i
	0x0d,          // j
	0x0e,          // k
	0x0f,          // l
	0x10,          // m
	0x11,          // n
	0x12,          // o
	0x13,          // p
	0x14,          // q
	0x15,          // r
	0x16,          // s
	0x17,          // t
	0x18,          // u
	0x19,          // v
	0x1a,          // w
	0x1b,          // x
	0x1c,          // y
	0x1d,          // z
	0x2f|SHIFT,    //
	0x31|SHIFT,    // |
	0x30|SHIFT,    // }
	0x35|SHIFT,    // ~
	0				// DEL
};

uint8_t USBPutChar(uint8_t c);

// press() adds the specified key (printing, non-printing, or modifier)
// to the persistent key report and sends the report.  Because of the way
// USB HID works, the host acts like the key remains pressed until we
// call release(), releaseAll(), or otherwise clear the report and resend.
size_t Keyboard_::press(uint8_t k)
{
	uint8_t i;
	if (k >= 136) {			// it's a non-printing key (not a modifier)
		k = k - 136;
	} else if (k >= 128) {	// it's a modifier key
		_keyReport.modifiers |= (1<<(k-128));
		k = 0;
	} else {				// it's a printing key
		k = pgm_read_byte(_asciimap + k);
		if (!k) {
				setWriteError();
				return 0;
			}
		if (k & 0x80) {						// it's a capital letter or other character reached with shift
			_keyReport.modifiers |= 0x02;	// the left shift modifier
			k &= 0x7F;
		}
	}

	// Add k to the key report only if it's not already present
	// and if there is an empty slot.
	if (_keyReport.keys[0] != k && _keyReport.keys[1] != k &&
		_keyReport.keys[2] != k && _keyReport.keys[3] != k &&
		_keyReport.keys[4] != k && _keyReport.keys[5] != k) {

		for (i=0; i<6; i++) {
			if (_keyReport.keys[i] == 0x00) {
				_keyReport.keys[i] = k;
				break;
			}
		}
		if (i == 6) {
				setWriteError();
				return 0;
			}
	}
	sendReport(&_keyReport);
	return 1;
}

// release() takes the specified key out of the persistent key report and
// sends the report.  This tells the OS the key is no longer pressed and that
// it shouldn't be repeated any more.
size_t Keyboard_::release(uint8_t k)
			{
	uint8_t i;
	if (k >= 136) {			// it's a non-printing key (not a modifier)
		k = k - 136;
	} else if (k >= 128) {	// it's a modifier key
		_keyReport.modifiers &= ~(1<<(k-128));
		k = 0;
	} else {				// it's a printing key
		k = pgm_read_byte(_asciimap + k);
		if (!k) {
			return 0;
			}
		if (k & 0x80) {							// it's a capital letter or other character reached with shift
			_keyReport.modifiers &= ~(0x02);	// the left shift modifier
			k &= 0x7F;
		}
	}

	// Test the key report to see if k is present.  Clear it if it exists.
	// Check all positions in case the key is present more than once (which it shouldn't be)
	for (i=0; i<6; i++) {
		if (0 != k && _keyReport.keys[i] == k) {
			_keyReport.keys[i] = 0x00;
	}
	}

	sendReport(&_keyReport);
	return 1;
}

void Keyboard_::releaseAll(void)
{
	_keyReport.keys[0] = 0;
	_keyReport.keys[1] = 0;
	_keyReport.keys[2] = 0;
	_keyReport.keys[3] = 0;
	_keyReport.keys[4] = 0;
	_keyReport.keys[5] = 0;
	_keyReport.modifiers = 0;
	sendReport(&_keyReport);
}

size_t Keyboard_::write(uint8_t c)
{
	uint8_t p = press(c);		// Keydown
	uint8_t r = release(c);		// Keyup
	return (p);					// just return the result of press() since release() almost always returns 1
}
void Keyboard_::setLedStatus(uint8_t s)
{
	_ledStatus = s;
}

uint8_t Keyboard_::getLedStatus(void)
{
	return _ledStatus;
}
#endif

#endif /* if defined(USBCON) */

И  USBAPI.h

#ifndef __USBAPI__
#define __USBAPI__

#if defined(USBCON)

//================================================================================
//================================================================================
//	USB

class USBDevice_
{
public:
	USBDevice_();
	bool configured();

	void attach();
	void detach();	// Serial port goes down too...
	void poll();
};
extern USBDevice_ USBDevice;

//================================================================================
//================================================================================
//	Serial over CDC (Serial1 is the physical port)

class Serial_ : public Stream
{
private:
	ring_buffer *_cdc_rx_buffer;
public:
	void begin(uint16_t baud_count);
	void end(void);

	virtual int available(void);
	virtual void accept(void);
	virtual int peek(void);
	virtual int read(void);
	virtual void flush(void);
	virtual size_t write(uint8_t);
	operator bool();
};
extern Serial_ Serial;

//================================================================================
//================================================================================
//	Joystick
//  Implemented in HID.cpp
//  The list of parameters here needs to match the implementation in HID.cpp


typedef struct JoyState 		// Pretty self explanitory. Simple state to store all the joystick parameters
{
	uint8_t		xAxis;
	uint8_t		yAxis;
	uint8_t		zAxis;

	uint8_t		xRotAxis;
	uint8_t		yRotAxis;
	uint8_t		zRotAxis;

	uint8_t		rudder;
	uint8_t		throttle;
	uint8_t 	brake;
	uint8_t		clutch;
	uint8_t		shifter;
	uint8_t		steering;


	uint8_t		hatSw1;			// 0-7 correspond to 0-315° in 45° steps. 8 means the hat-switch is centered
	uint8_t		hatSw2;			// All other values are invalid

	uint32_t	buttons;		// 32 general buttons (Each bit corresponds to a separate button)

} JoyState_t;

class Joystick_
{
public:
	Joystick_();

	void setState(JoyState_t *joySt);

};
extern Joystick_ Joystick;

//================================================================================
//================================================================================
//	Mouse

#define MOUSE_LEFT		0x01
#define MOUSE_RIGHT		0x02
#define MOUSE_MIDDLE	0x04
#define MOUSE_ALL (MOUSE_LEFT | MOUSE_RIGHT | MOUSE_MIDDLE)

class Mouse_
{
private:
	uint8_t _buttons;
	void buttons(uint8_t b);
public:
	Mouse_(void);
	void begin(void);
	void end(void);
	void click(uint8_t b = MOUSE_LEFT);
	void move(signed char x, signed char y, signed char wheel = 0);
	void press(uint8_t b = MOUSE_LEFT);		// press LEFT by default
	void release(uint8_t b = MOUSE_LEFT);	// release LEFT by default
	bool isPressed(uint8_t b = MOUSE_LEFT);	// check LEFT by default
};
extern Mouse_ Mouse;

//================================================================================
//================================================================================
//	Keyboard

#define KEY_LEFT_CTRL		0x80
#define KEY_LEFT_SHIFT		0x81
#define KEY_LEFT_ALT		0x82
#define KEY_LEFT_GUI		0x83
#define KEY_RIGHT_CTRL		0x84
#define KEY_RIGHT_SHIFT		0x85
#define KEY_RIGHT_ALT		0x86
#define KEY_RIGHT_GUI		0x87

#define KEY_UP_ARROW		0xDA
#define KEY_DOWN_ARROW		0xD9
#define KEY_LEFT_ARROW		0xD8
#define KEY_RIGHT_ARROW		0xD7
#define KEY_BACKSPACE		0xB2
#define KEY_TAB				0xB3
#define KEY_RETURN			0xB0
#define KEY_ESC				0xB1
#define KEY_INSERT			0xD1
#define KEY_DELETE			0xD4
#define KEY_PAGE_UP			0xD3
#define KEY_PAGE_DOWN		0xD6
#define KEY_HOME			0xD2
#define KEY_END				0xD5
#define KEY_CAPS_LOCK		0xC1
#define KEY_F1				0xC2
#define KEY_F2				0xC3
#define KEY_F3				0xC4
#define KEY_F4				0xC5
#define KEY_F5				0xC6
#define KEY_F6				0xC7
#define KEY_F7				0xC8
#define KEY_F8				0xC9
#define KEY_F9				0xCA
#define KEY_F10				0xCB
#define KEY_F11				0xCC
#define KEY_F12				0xCD

#define KEY_NUM_LOCK		0xDB
#define KEY_SCROLL_LOCK		0xCF

#define LED_NUM_LOCK		0x01
#define LED_CAPS_LOCK		0x02
#define LED_SCROLL_LOCK		0x04

//	Low level key report: up to 6 keys and shift, ctrl etc at once
typedef struct
{
	uint8_t modifiers;
	uint8_t reserved;
	uint8_t keys[6];
} KeyReport;

class Keyboard_ : public Print
{
private:
	KeyReport _keyReport;
	uint8_t   _ledStatus;
	void sendReport(KeyReport* keys);
public:
	Keyboard_(void);
	void begin(void);
	void end(void);
	virtual size_t write(uint8_t k);
	virtual size_t press(uint8_t k);
	virtual size_t release(uint8_t k);
	virtual void releaseAll(void);
	virtual void setLedStatus(uint8_t);
	virtual uint8_t getLedStatus(void);
};
extern Keyboard_ Keyboard;

//================================================================================
//================================================================================
//	Low level API

typedef struct
{
	uint8_t bmRequestType;
	uint8_t bRequest;
	uint8_t wValueL;
	uint8_t wValueH;
	uint16_t wIndex;
	uint16_t wLength;
} Setup;

//================================================================================
//================================================================================
//	HID 'Driver'

int		HID_GetInterface(uint8_t* interfaceNum);
int		HID_GetDescriptor(int i);
bool	HID_Setup(Setup& setup);
void	HID_SendReport(uint8_t id, const void* data, int len);

//================================================================================
//================================================================================
//	MSC 'Driver'

int		MSC_GetInterface(uint8_t* interfaceNum);
int		MSC_GetDescriptor(int i);
bool	MSC_Setup(Setup& setup);
bool	MSC_Data(uint8_t rx,uint8_t tx);

//================================================================================
//================================================================================
//	CSC 'Driver'

int		CDC_GetInterface(uint8_t* interfaceNum);
int		CDC_GetDescriptor(int i);
bool	CDC_Setup(Setup& setup);

//================================================================================
//================================================================================

#define TRANSFER_PGM		0x80
#define TRANSFER_RELEASE	0x40
#define TRANSFER_ZERO		0x20

int USB_SendControl(uint8_t flags, const void* d, int len);
int USB_RecvControl(void* d, int len);

uint8_t	USB_Available(uint8_t ep);
int USB_Send(uint8_t ep, const void* data, int len);	// blocking
int USB_Recv(uint8_t ep, void* data, int len);		// non-blocking
int USB_Recv(uint8_t ep);							// non-blocking
void USB_Flush(uint8_t ep);

#endif

#endif /* if defined(USBCON) */

Вобщем хочется добавить еще класс устройства:

USAGE_PAGE (Alphnumeric Display)	05 14
USAGE (Alphanumeric Display)	09 01
LOGICAL_MINIMUM (0)	15 00 
COLLECTION (Logical)	A1 02 
  USAGE (Display Attributes Report)	09 20
  COLLECTION (Logical)	A1 02 
    USAGE (Rows)	09 35
    USAGE (Columns)	09 36
    USAGE (Character Width)	09 3D
    USAGE (Character Height)	09 3E
    REPORT_ID (1)	85 01 
    LOGICAL_MAXIMUM (31)	25 1F 
    REPORT_SIZE (5)	75 05 
    REPORT_COUNT (4)	95 04 
    FEATURE (Cnst,Var,Abs)	B1 03 
    REPORT_SIZE (1)	75 01 
    REPORT_COUNT (3)	95 03 
    LOGICAL_MAXIMUM (1)	25 01 
    USAGE (ASCII Character Set)	09 21
    USAGE (Data Read Back)	09 22
    USAGE (Vertical Scroll)	09 29
    FEATURE (Cnst,Var,Abs)	B1 03 
    REPORT_COUNT (3)	95 03 
    FEATURE (Cnst,Var,Abs)	B1 03 
  END_COLLECTION	C0
  REPORT_SIZE (8)	75 08 
  REPORT_COUNT (1)	95 01 
  LOGICAL_MAXIMUM (2)	25 02 
  USAGE (Display Status)	09 2D
  COLLECTION (Logical)	A1 02 
    USAGE (Stat Not Ready)	09 2E
    USAGE (Stat Ready)	09 2F
    USAGE (Err Not a loadable character)	09 30
    INPUT (Data,Ary,Abs,Null)	81 40 
  END_COLLECTION	C0
  USAGE (Cursor Position Report)	09 32
  COLLECTION (Logical)	A1 02 
    REPORT_ID (2)	85 02 
    REPORT_SIZE (4)	75 04 
    REPORT_COUNT (1)	95 01 
    LOGICAL_MAXIMUM (15)	25 0F 
    USAGE (Column)	09 34
    FEATURE (Data,Var,Abs,NPrf)	B1 22 
    LOGICAL_MAXIMUM (1)	25 01 
    USAGE (Row)	09 33
    FEATURE (Data,Var,Abs,NPrf)	B1 22 
  END_COLLECTION	C0
  USAGE (Character Report)	09 2B
  COLLECTION (Logical)	A1 02 
    REPORT_ID (3)	85 03 
    REPORT_SIZE (8)	75 08 
    REPORT_COUNT (4)	95 04 
    LOGICAL_MAXIMUM (126)	25 7E 
    USAGE (Display Data)	09 2C
    FEATURE (Data,Var,Abs,Buf)	B2 02 01 
  END_COLLECTION	C0
  REPORT_ID (4)	85 04 
  USAGE (Font Report)	09 3B
  COLLECTION (Logical)	A1 02 
    LOGICAL_MINIMUM (0)	15 00 
    LOGICAL_MAXIMUM (126)	25 7E 
    REPORT_SIZE (8)	75 08 
    REPORT_COUNT (1)	95 01 
    USAGE (Display Data)	09 2C
    OUTPUT (Data,Var,Abs)	91 02 
    REPORT_COUNT (5)	95 05 
    USAGE (Font Data)	09 3C
    OUTPUT (Data,Var,Abs,Buf)	92 02 01 
  END_COLLECTION	C0
END_COLLECTION	C0

Выдрал из программки HID Descriptor Tool

Допустим я смогу добавить это к другим дискрипторам, но как с этим работать и что я получу - вообще без понятия

Вобщем как слать что- то на комп более менее понятно(думаю добавить еще Тормоз и сцепление к джойстику), но как получить с компа - вообще не ясно. Для клавиатуры(светодиоды) там получают 2 байта - почему 2 и почему значение во втором - я не понял.

NeiroN
NeiroN аватар
Offline
Зарегистрирован: 15.06.2013

Джойстик допилил - сделал на радиопульт 4 кнопки

JoyState joySt;
#define NUM_PINS 4
uint8_t pins[NUM_PINS] = {6,7,4,5};
char syms[NUM_PINS] = {'a','b','c','d'};

void setup(){
  for(int i=0;i<NUM_PINS;i++) pinMode(pins[i], INPUT);
	joySt.xAxis = 127;
	joySt.yAxis = 127;
	joySt.zAxis = 127;

	joySt.xRotAxis = 255;
	joySt.yRotAxis = 255;
	joySt.zRotAxis = 255;

	joySt.rudder = 127;
	joySt.throttle = 127;
	joySt.brake = 127;
	joySt.clutch = 127;
	joySt.shifter = 127;
	joySt.steering = 127;

	joySt.hatSw1 = 0;			// 0-7 correspond to 0-315° in 45° steps. 8 means the hat-switch is centered
	joySt.hatSw2 = 0;			// All other values are invalid
	joySt.buttons = 0;

}
void loop(){
  //Keyboard.print("Test");
  for(int i=0;i<NUM_PINS;i++){
    if(digitalRead(pins[i])){
      bitSet(joySt.buttons,i);
      //Keyboard.print(syms[i]);
    }else{
      bitClear(joySt.buttons,i);
    }
  }
  Joystick.setState(&joySt);
  delay(10);
}

думаю прикрутить MPU-6050 гироскоп акселнрометр гироскоп->углыповорота, акселерометр->x,y,z

Многие называют это хедтрекер.