311 lines
9.4 KiB
C
Executable File
311 lines
9.4 KiB
C
Executable File
/* Name: main.c
|
|
* Project: hid-mouse, a very simple HID example
|
|
* Author: Christian Starkjohann
|
|
* Creation Date: 2008-04-07
|
|
* Tabsize: 4
|
|
* Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH
|
|
* License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt)
|
|
* This Revision: $Id: main.c 692 2008-11-07 15:07:40Z cs $
|
|
*/
|
|
|
|
/*
|
|
This example should run on most AVRs with only little changes. No special
|
|
hardware resources except INT0 are used. You may have to change usbconfig.h for
|
|
different I/O pins for USB. Please note that USB D+ must be the INT0 pin, or
|
|
at least be connected to INT0 as well.
|
|
|
|
We use VID/PID 0x046D/0xC00E which is taken from a Logitech mouse. Don't
|
|
publish any hardware using these IDs! This is for demonstration only!
|
|
*/
|
|
|
|
#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" /* This is also an example for using debug macros */
|
|
|
|
/* Keyboard usage values, see usb.org's HID-usage-tables document, chapter
|
|
* 10 Keyboard/Keypad Page for more codes.
|
|
*/
|
|
#define MOD_CONTROL_LEFT (1<<0)
|
|
#define MOD_SHIFT_LEFT (1<<1)
|
|
#define MOD_ALT_LEFT (1<<2)
|
|
#define MOD_GUI_LEFT (1<<3)
|
|
#define MOD_CONTROL_RIGHT (1<<4)
|
|
#define MOD_SHIFT_RIGHT (1<<5)
|
|
#define MOD_ALT_RIGHT (1<<6)
|
|
#define MOD_GUI_RIGHT (1<<7)
|
|
|
|
#define KEY_A 4
|
|
#define KEY_B 5
|
|
#define KEY_C 6
|
|
#define KEY_D 7
|
|
#define KEY_E 8
|
|
#define KEY_F 9
|
|
#define KEY_G 10
|
|
#define KEY_H 11
|
|
#define KEY_I 12
|
|
#define KEY_J 13
|
|
#define KEY_K 14
|
|
#define KEY_L 15
|
|
#define KEY_M 16
|
|
#define KEY_N 17
|
|
#define KEY_O 18
|
|
#define KEY_P 19
|
|
#define KEY_Q 20
|
|
#define KEY_R 21
|
|
#define KEY_S 22
|
|
#define KEY_T 23
|
|
#define KEY_U 24
|
|
#define KEY_V 25
|
|
#define KEY_W 26
|
|
#define KEY_X 27
|
|
#define KEY_Y 28
|
|
#define KEY_Z 29
|
|
#define KEY_1 30
|
|
#define KEY_2 31
|
|
#define KEY_3 32
|
|
#define KEY_4 33
|
|
#define KEY_5 34
|
|
#define KEY_6 35
|
|
#define KEY_7 36
|
|
#define KEY_8 37
|
|
#define KEY_9 38
|
|
#define KEY_0 39
|
|
|
|
#define KEY_F1 58
|
|
#define KEY_F2 59
|
|
#define KEY_F3 60
|
|
#define KEY_F4 61
|
|
#define KEY_F5 62
|
|
#define KEY_F6 63
|
|
#define KEY_F7 64
|
|
#define KEY_F8 65
|
|
#define KEY_F9 66
|
|
#define KEY_F10 67
|
|
#define KEY_F11 68
|
|
#define KEY_F12 69
|
|
|
|
#define KEY_RETURN 40
|
|
#define KEY_UP 82
|
|
#define KEY_DOWN 81
|
|
#define KEY_LEFT 80
|
|
#define KEY_RIGHT 79
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
/* ----------------------------- USB interface ----------------------------- */
|
|
/* ------------------------------------------------------------------------- */
|
|
|
|
PROGMEM char usbHidReportDescriptor[63] = {
|
|
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
|
|
0x09, 0x06, // USAGE (Keyboard)
|
|
0xa1, 0x01, // COLLECTION (Application)
|
|
0x05, 0x07, // USAGE_PAGE (Keyboard)
|
|
0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl)
|
|
0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI)
|
|
0x15, 0x00, // LOGICAL_MINIMUM (0)
|
|
0x25, 0x01, // LOGICAL_MAXIMUM (1)
|
|
0x75, 0x01, // REPORT_SIZE (1)
|
|
0x95, 0x08, // REPORT_COUNT (8)
|
|
0x81, 0x02, // INPUT (Data,Var,Abs)
|
|
0x95, 0x01, // REPORT_COUNT (1)
|
|
0x75, 0x08, // REPORT_SIZE (8)
|
|
0x81, 0x03, // INPUT (Cnst,Var,Abs)
|
|
0x95, 0x05, // REPORT_COUNT (5)
|
|
0x75, 0x01, // REPORT_SIZE (1)
|
|
0x05, 0x08, // USAGE_PAGE (LEDs)
|
|
0x19, 0x01, // USAGE_MINIMUM (Num Lock)
|
|
0x29, 0x05, // USAGE_MAXIMUM (Kana)
|
|
0x91, 0x02, // OUTPUT (Data,Var,Abs)
|
|
0x95, 0x01, // REPORT_COUNT (1)
|
|
0x75, 0x03, // REPORT_SIZE (3)
|
|
0x91, 0x03, // OUTPUT (Cnst,Var,Abs)
|
|
0x95, 0x06, // REPORT_COUNT (6)
|
|
0x75, 0x08, // REPORT_SIZE (8)
|
|
0x15, 0x00, // LOGICAL_MINIMUM (0)
|
|
0x25, 0x65, // LOGICAL_MAXIMUM (101)
|
|
0x05, 0x07, // USAGE_PAGE (Keyboard)
|
|
0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated))
|
|
0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application)
|
|
0x81, 0x00, // INPUT (Data,Ary,Abs)
|
|
0xc0 // END_COLLECTION
|
|
};
|
|
|
|
#define SENDBUFFER_SIZE 128
|
|
char g_SendBuffer[SENDBUFFER_SIZE];
|
|
char *g_SendBufferWritePointer = g_SendBuffer;
|
|
char *g_SendBufferReadPointer = g_SendBuffer;
|
|
|
|
void SendBufferWrite(char Character)
|
|
{
|
|
*g_SendBufferWritePointer = Character;
|
|
g_SendBufferWritePointer++;
|
|
|
|
if (g_SendBufferWritePointer - g_SendBuffer >= SENDBUFFER_SIZE)
|
|
g_SendBufferWritePointer = g_SendBuffer;
|
|
}
|
|
|
|
char SendBufferRead(void)
|
|
{
|
|
if (g_SendBufferWritePointer == g_SendBufferReadPointer)
|
|
return 0;
|
|
|
|
char Character = *g_SendBufferReadPointer;
|
|
g_SendBufferReadPointer++;
|
|
|
|
if (g_SendBufferReadPointer - g_SendBuffer >= SENDBUFFER_SIZE)
|
|
g_SendBufferReadPointer = g_SendBuffer;
|
|
|
|
return Character;
|
|
}
|
|
|
|
void SendString(char *String)
|
|
{
|
|
while (*String != 0)
|
|
{
|
|
char Character = *String;
|
|
String++;
|
|
|
|
SendBufferWrite(Character);
|
|
}
|
|
}
|
|
|
|
typedef struct{
|
|
uchar buttonMask;
|
|
uchar reserved;
|
|
uchar buttons[6];
|
|
}report_t;
|
|
|
|
static report_t reportBuffer;
|
|
static uchar idleRate; /* repeat rate for keyboards, never used for mice */
|
|
|
|
char g_ShouldKeyUp = 0;
|
|
static void SendKeys(void)
|
|
{
|
|
reportBuffer.buttonMask=0;
|
|
reportBuffer.reserved=0;
|
|
|
|
reportBuffer.buttons[0]=0;
|
|
reportBuffer.buttons[1]=0;
|
|
reportBuffer.buttons[2]=0;
|
|
reportBuffer.buttons[3]=0;
|
|
reportBuffer.buttons[4]=0;
|
|
reportBuffer.buttons[5]=0;
|
|
|
|
if (g_ShouldKeyUp)
|
|
{
|
|
usbSetInterrupt((void *)&reportBuffer, sizeof(reportBuffer));
|
|
g_ShouldKeyUp = 0;
|
|
return;
|
|
}
|
|
g_ShouldKeyUp = 1;
|
|
|
|
char Character = SendBufferRead();
|
|
if (!Character)
|
|
{
|
|
g_ShouldKeyUp = 0;
|
|
return;
|
|
}
|
|
|
|
|
|
if ('a' <= Character && Character <= 'z')
|
|
{
|
|
reportBuffer.buttons[0] = Character - 'a' + KEY_A;
|
|
}
|
|
else if ('A' <= Character && Character <= 'Z')
|
|
{
|
|
reportBuffer.buttons[0] = Character - 'A' + KEY_A;
|
|
// reportBuffer.buttonMask = MOD_SHIFT_LEFT;
|
|
}
|
|
else if ('1' <= Character && Character <= '9')
|
|
{
|
|
reportBuffer.buttons[0] = Character - '1' + KEY_1;
|
|
}
|
|
else if (Character == '0')
|
|
{
|
|
reportBuffer.buttons[0] = KEY_0;
|
|
}
|
|
else if (Character == ' ')
|
|
{
|
|
reportBuffer.buttons[0] = 44;
|
|
}
|
|
else if (Character == '.')
|
|
{
|
|
reportBuffer.buttons[0] = 55;
|
|
}
|
|
else
|
|
{
|
|
g_ShouldKeyUp = 0;
|
|
return;
|
|
}
|
|
|
|
usbSetInterrupt((void *)&reportBuffer, sizeof(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) */
|
|
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)
|
|
{
|
|
uint16_t i;
|
|
SendString("this is some pretty awesome stuff");
|
|
|
|
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.
|
|
*/
|
|
|
|
odDebugInit();
|
|
usbInit();
|
|
usbDeviceDisconnect(); /* enforce re-enumeration, do this while interrupts are disabled! */
|
|
i = 0b11111111111;
|
|
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 output: main loop iterates */
|
|
wdt_reset();
|
|
usbPoll();
|
|
if(usbInterruptIsReady()){
|
|
/* called after every poll of the interrupt endpoint */
|
|
SendKeys();
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------- */
|