//###########################################################################
// filename: usbtestCC.c
//##########################################################################
// The Irritating Mouse - This program causes the mouse pointer to move in a
// figure 8 (infinity) shape
// CC indicates changes from original Circuit Cellar source
//
// Author: Copyright 2005 by Robert Lang
// Building on the work of: Reston Condit
// Dan Butler
// Andrew Smallridge
//
// Revision: 1.1
// Date: January 2005
// Compiled using: BOOSTC 1.93
//
// Revision History:
// 1.0 Initial development and conversion to BOOSTC and PIC18F2455 based on
// program "Mouse in a circle" example
// 1.1 Added serial port for debugging messages
//
// Comments:
// bXXX indicate specific bits in registers defined in usb_defs.h
// usb buffers are defined in usbdefs.h
//################################################################################
//
// include files:
#include "system.h" //pic definition files required by boostc
#include "usb_defs.h"
//
//###############################################################################
// using a 20 Mhz external crystal
#pragma DATA _CONFIG1L, 00110100b // USBPPL, CPU divide by 4 , PPL divide by 5
#pragma DATA _CONFIG1H, 00001111b // disable oscillator switchover,
// disable failsafe clock monitor, HSPPL
#pragma DATA _CONFIG2L, 00111111b // USB voltage regulator enabled,
// brownout set for 2.1 volts, hardware brownout only, PWRT disabled
#pragma DATA _CONFIG2H, 00011110b // watchdog timer disabled
#pragma DATA _CONFIG3H, 10000000b // MCLR enabled
#pragma DATA _CONFIG4L, 10000001b // DEBUG off, disable extended instructons,
// LVP disabled, enable stack full/underflow reset
#pragma DATA _CONFIG5L, 00001111b // Read Code protection off
#pragma DATA _CONFIG5H, 11000000b // Read EEPROM and boot block protection off
#pragma DATA _CONFIG6L, 00001111b // Write Code protection off
#pragma DATA _CONFIG6H, 11100000b // Write EEPROM, boot block and
// config register protection off
#pragma DATA _CONFIG7L, 00001111b // Table read protection off
#pragma DATA _CONFIG7H, 01000000b // Boot block table read protection off
// ################################################################################
unsigned char USB_IsIdle;
unsigned char USB_status_device;
unsigned char USB_Curr_Config;
unsigned char USB_address_pending;
unsigned char USB_dev_req;
unsigned char USB_Interface [3];
unsigned char USB_USTAT;
unsigned char ACTIVE_BUF;
unsigned char USB_protocol;
unsigned char USWSTAT;
unsigned int USB_PID_ERR = 0; //error counters
unsigned int USB_CRC5_ERR = 0;
unsigned int USB_CRC16_ERR = 0;
unsigned int USB_DFN8_ERR = 0;
unsigned int USB_BTO_ERR = 0;
unsigned int USB_WRT_ERR = 0;
unsigned int USB_OWN_ERR = 0;
unsigned int USB_BTS_ERR = 0;
unsigned char * EP0_start; //ep0 pointers modified from CC
unsigned char * EP0_end; // modified from CC
unsigned char EP0_maxLength;
struct BufferDescriptorEntry // buffer descriptor
{
unsigned char EPStat;
unsigned char bytes;
unsigned int address;
};
struct BufferStruct // buffer structure
{
unsigned char bmRequestType;
unsigned char bRequest;
unsigned int wValue;
unsigned int wIndex;
unsigned int wLength;
};
struct BufferDescriptorEntry * BDT= (struct BufferDescriptorEntry *)0x400;
struct BufferStruct * Buffer; //define Buffer as pointer to a BufferStruct
struct BufferStruct BufferCopy;
struct BufferDescriptorEntry BDTCopy;
//string descriptors in unicode format
const char String0 [] = {4,STRING,9,4};
const char String1 [] = {20, STRING,
'M',0,
'i',0,
'c',0,
'r',0,
'o',0,
'c',0,
'h',0,
'i',0,
'p',0};
const char String2[] = {56,STRING,
'P',0,
'i',0,
'c',0,
'1',0,
'8',0,
'F',0,
'2',0,
'4',0,
'5',0,
'5',0,
' ',0,
'I',0,
'r',0,
'r',0,
'i',0,
't',0,
'a',0,
't',0,
'i',0,
'n',0,
'g',0,
' ',0,
'M',0,
'o',0,
'u',0,
's',0,
'e',0};
// Report descriptor prepared by USB DESCRIPTOR TOOL
// http://www.usb.org/developers/hidpage/#Descriptor_Tool
const char ReportDescriptor1[] = {
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x02, // USAGE (Mouse)
0xa1, 0x01, // COLLECTION (Application)
0x09, 0x01, // USAGE (Pointer)
0xa1, 0x00, // COLLECTION (Physical)
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, 0x01, // INPUT (Cnst,Ary,Abs)
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x30, // USAGE (X)
0x09, 0x31, // USAGE (Y)
0x15, 0x81, // LOGICAL_MINIMUM (-127)
0x25, 0x7f, // LOGICAL_MAXIMUM (127)
0x75, 0x08, // REPORT_SIZE (8)
0x95, 0x02, // REPORT_COUNT (2)
0x81, 0x06, // INPUT (Data,Var,Rel)
0xc0, // END_COLLECTION
0xc0 // END_COLLECTION
};
const char DeviceDescriptor [] = {0x12, // 18 bytes long
DEVICE, // descriptor type
0x10, 0x01, // USB specification release (1.10)
0x00, // class code
0x00, // subclass code
0x00, // protocol code
0x08, // maximum packet size
0xD8,0x04, // vendor id (04d8) microchip
0x09,0x00, //product id (0009)
0x00,0x02, // device release number 2.00
0x01, // index to string that describes vendor
0x02, // index to string that describes product
0x00, // index to string that describes serial number (none)
0x01 // number of possible configurations
};
//CONFIG DESCRIPTOR ORDER CORRESPONDS TO HID 1.0 OR LATER
const char ConfigDescriptor [] = {0x09, // 9 bytes long
CONFIGURATION, // descriptor type
0x22, 0x00, // total length of config, interface, HID and endpoint descriptors
0x01, // number of interfaces
0x01, // configuration number
0x00, // index to string that describes configuration (none)
0xA0, // configuration attributes , remote wakeup
0x32, // current consumption in 2mA units (100 mA)
/* Interface Descriptor */ 0x09,// 9 bytes long
INTERFACE, // descriptor type
0x00, // number of this interface (zerp based)
0x00, // alternate setting (none)
0x01, // number of endpoints used by interface
0x03, // class code
0x01, // subclass code
0x02, // protocol
0x00, // index to string that describes endpoint (none)
/* HID descriptor described above */
0x09, 0x21, 0x10, 0x01, 0x00, 0x01, 0x22, sizeof(ReportDescriptor1), sizeof(ReportDescriptor1)>>8,
/* Endpoint 1 descriptor */ 0x07, // 7 bytes long
ENDPOINT, // descriptor type
0x81, // endpoint characteristics (IN endpoint)
0x03, // endpoint attributes (interrupt)
0x03, 0x00, // max packet size (HID 3 byte report)
0x0A //polling interval in 1 msec increments (10)
};
const unsigned int ReportDescrSize = sizeof(ReportDescriptor1);
const char HIDDescriptor [] = {0x09, // 9 bytes long
0x21, // descriptor type, HID=21
0x10, 0x01, // HUD class version 1.10
0x00, // country code (none)
0x01, // Number of HID class descriptors
0x22, // Type of class descriptor (report)
sizeof(ReportDescriptor1), sizeof(ReportDescriptor1)>>8 // Size of report descriptor
};
//********************************************
// serial port routines
////////////////////////////////////////////////////////////////////////////
// Output a character
// By Robert Lang
// Based on coding by Andrew Smallridge
////////////////////////////////////////////////////////////////////////////
void putc(char tx_char)
{
volatile bit btxif@PIR1.TXIF; //
while (!btxif); // wait until tx register is empty
txreg = tx_char;
}
////////////////////////////////////////////////////////////////////////////
// This routine outputs an unsigned char as
// two ascii characters representing its hex value
// By Robert Lang
////////////////////////////////////////////////////////////////////////////
void hex( unsigned char value)
{
unsigned char TEST[2];
char HV;
unsigned char i;
TEST[0]=value>>4; // get high order nibble
TEST[1]=value & 0x0F; //mask out high order nibble leaving low
for (i=0; i<2;i++) //output two hex characters per char
{
switch (TEST[i]) // assign the ascii
{
case 1:
HV='1';
break;
case 2:
HV='2';
break;
case 3:
HV='3';
break;
case 4:
HV='4';
break;
case 5:
HV='5';
break;
case 6:
HV='6';
break;
case 7:
HV='7';
break;
case 8:
HV='8';
break;
case 9:
HV='9';
break;
case 0xA:
HV='a';
break;
case 0xB:
HV='b';
break;
case 0xC:
HV='c';
break;
case 0xD:
HV='d';
break;
case 0xE:
HV='e';
break;
case 0xF:
HV='f';
break;
default:
HV='0';
}
putc(HV); // output ascii character
}
putc(' '); // output blank between words
}
////////////////////////////////////////////////////////////////////////////
// Initialise the UART
// By Robert Lang
// Based on coding by Andrew Smallridge
////////////////////////////////////////////////////////////////////////////
// BRG_mode - sets the hardware baud rate generator speed mode
// BRG_mode == 0 for low speed mode
// BRG_divisor - set hardware baud rate generator divisor
void UART_Init(unsigned char BRG_mode, unsigned char BRG_divisor)
{
unsigned char brgh;
set_bit(ddrc,RC7);
clear_bit(ddrc,RC6);
// setup the USART baud rate
// configure baud rate generator mode High vs Low speed
if (BRG_mode)
brgh = 4;
else
brgh = 0;
// configure the divisor
spbrg = BRG_divisor;
txsta= brgh;
txsta= 00100000b + txsta;
// 7 Async mode - don't care
// 6 8 bit selection
// 5 Enable TX
// 4 SYNC - Async mode
// 3 not implemented
// 2 BRGH - high speed
// 1-0 don't care
rcsta = 10010000b; // enable the USART receive logic
// 7 SPEN - Serial Port Enable
// 6 8 bit selection
// 5 Don't care
// 4 CREN - Enable continuous receive
// 3 disable address detection
// 2-0 don't care
clear_bit(rcsta,CREN); // clear continous receive bit
set_bit(rcsta,CREN); // set continous receive bit
}
////////////////////////////////////////////////////////////////////////////
// Output a string
// Robert Lang
// Based on coding by Andrew Smallridge
////////////////////////////////////////////////////////////////////////////
void puts(char *source)
{
while (*source != 0) // wait until tx register is empty
putc(*source++);
putc(0x0d);
putc(0x0a);
}
////////////////////////////////////////////////////////////////////////////
// Output a carriage return and linefeed
// Robert Lang
////////////////////////////////////////////////////////////////////////////
void new_line()
{
putc(0x0d);
putc(0x0a);
}
/* PutEP1 **************************************************************** */
/* Tests the EP1 IN OWNS bit. If there is a buffer available to us, your */
/* buffer is copied and turned over to the SIE for transmission on the */
/* next IN transfer and returns TRUE (1). If the buffer is not available, */
/* FALSE is returned (0). */
/* *********************************************************************** */
unsigned char PutEP1 (unsigned char bytes, signed char *buffer)
{
signed char * tobuffer;
unsigned char i;
ddrb=0; //setup b for output
if ((bd1statie & 0x80) == 0) /* do we own the buffer? UOWN=0*/
{
bd1cntie = bytes;
tobuffer = (signed char *) ((unsigned int)bd1adrlie + (unsigned int)(bd1adrhie <<8));
for (i = 0; i < bytes; i++) {
tobuffer [i] = buffer[i];
}
#ifdef DEBUG_SERIAL
hex(tobuffer[0]); // output hex representation of bytes transmitted
hex(tobuffer[1]);
hex(tobuffer[2]);
new_line();
//putc('.'); //just output a decimal point instead
#endif
bd1statie &= 0x40; /* save only the Data 1/0 bit */
bd1statie ^= 0x40; /* toggle Data 0/1 bit */
bd1statie ^= 0x88; /* release buffer */
return TRUE;
}
return FALSE; /* Buffer not available, return false */
}
/* ********************************************************************* */
/* Enable Wakeup on interupt and Activity interrupt then put the */
/* device to sleep to save power. Activity on the D+/D- lines will */
/* set the ACTIVITY interrupt, waking up the part. */
/* ********************************************************************* */
void USBSleep ()
{
bACTIVITY_E = 1; // enable activity interrupt
bUIDLE = 0; //disable idle interrupt
bSUSPND = 1; // put in suspend mode
USB_IsIdle = 1; // mark device as idle
}
/* ********************************************************************* */
/* Service the Activity Interrupt. This is only enabled when the */
/* device is put to sleep as a result of inactivity on the bus. This */
/* code wakes up the part, disables the activity interrupt and reenables */
/* the idle interrupt. */
/* ********************************************************************* */
void USBActivity ()
{
bACTIVITY = 0;
bACTIVITY_E = 0;
bSUSPND = 0; //normal operation
USB_IsIdle = 0;
}
/* ****************************************************************** */
/* USB Reset interrupt triggered (SE0) */
/* initialize the Buffer Descriptor Table, */
/* Transition to the DEFAULT state, */
/* Set address to 0 */
/* enable the USB */
/* ****************************************************************** */
void USBReset ()
{
portb = 1; // Lite led 0 to indicate Reset status
USB_Curr_Config = 0;
USB_IsIdle = 0;
bTOK_DONE=0; // clear TOK_DNE bit in uir 4 times to
bTOK_DONE=0; // clear out the USTAT FIFO. See Microchip
bTOK_DONE=0; // 18F2455 data sheet.
bTOK_DONE=0;
bd0cntoe=8; //set up for 8 byte buffer
bd0statoe = 0x88; // EP0 Out buffer (USB OWNS)
bd0statie = 0x08; // EP0 In buffer (MCU OWNS)
uaddr = 0; // clear address
uir = 0; // clear USB interrupt flag
uie = 00000101b; // enable reset and activity interrupt
uep0 = ENDPT_CONTROL;
USWSTAT=DEFAULT_STATE;
USB_status_device = 1;
}
/* ******************* */
/* CopyDescriptorToEP0 ************************************************** */
/* copies the next chunk of buffer descriptor over to the EP0 In buffer. */
/* Inputs: */
/* EP0_start - points to first byte of configuration table to transfer */
/* EP0_end - total number of bytes to transfer */
/* EP0_maxLength - maximum number of bytes that can be sent during */
/* a single transfer */
/* */
/* toggles the data0/1 bit before setting the UOWN bit over to SIE. */
/* ********************************************************************** */
void CopyDescriptorToEP0 ()
{
unsigned char * USBbuffer; /* pointer to the USB Buffers */
unsigned char bufindex;
USBbuffer = (unsigned char *) ((unsigned int)bd0adrlie + (unsigned int)(bd0adrhie <<8));
bufindex = 0;
while ((bufindex < EP0_maxLength) && ((unsigned short)EP0_start <(unsigned short) EP0_end))
{
USBbuffer [bufindex] = *EP0_start;
++ EP0_start;
++ bufindex;
}
if (bufindex < EP0_maxLength) /* are we sending a short packet? */
USB_dev_req = 0; /* Yes, clear the device reqest */
#ifdef DEBUG_SERIAL
hex(USBbuffer[0]); // output hex representation of first two bytes transmitted
hex(USBbuffer[1]);
hex(bufindex); //reports bytes transmitted
new_line();
#endif
bd0cntie = bufindex;
bd0statie &= 0x40; /* save only the DTS bit */
bd0statie ^= 0x40; /* toggle data DTS bit */
bd0statie |= 0x88; /* set OWN and DTSEN bits */
}
/* ******** */
/* Init USB ********************************************************* */
/* Initializes the USB peripheral, sets up the interrupts */
/* ****************************************************************** */
void InitUSB ()
{
ucfg= 00010000b; //use onchip receiver, internal pullup resistors, low
// speed and no pingpong buffers
uie = 00000001b; // enable the Reset interrupt ONLY!!
uir = 0; // clear all USB interrupt flags
pie2= 00100000b ; //enable usb interrupts
ucon = 01000000b; // reset pingpong buffers
ucon = 00001000b; // unlock pingpong buffers and enable usb
USB_Curr_Config = 0;
USB_status_device = 1;
char USB_Interface [] = {0,0,0};
USB_dev_req = NULL;
// clear all error counters
USB_PID_ERR = 0;
USB_CRC5_ERR = 0;
USB_CRC16_ERR = 0;
USB_DFN8_ERR = 0;
USB_BTO_ERR = 0;
USB_BTS_ERR = 0;
intcon = intcon | 11000000b; // Enable GIE & PEIE
#ifdef DEBUG_SERIAL
puts("I");
#endif
}
/* ********************************************************************* */
/* This is activated by the STALL bit in the UIR register. It really */
/* just tells us that the SIE sent a STALL handshake. So far, Don't */
/* see that any action is required. Clear the bit and move on. */
/* ********************************************************************* */
void USBStall ()
{
bSTALL = 0;
}
/* ****************************************************************** */
/* The SIE detected an error. This code increments the appropriate */
/* error counter and clears the flag. */
/* ****************************************************************** */
void Count_Error ()
{
if (bPID_ERR && bPID_ERR_E){
++ USB_PID_ERR;
}
if (bCRC5 && bCRC5_E){
++ USB_CRC5_ERR;
}
if (bCRC16 && bCRC16_E){
++ USB_CRC16_ERR;
}
if (bDFN8 && bDFN8_E){
++ USB_DFN8_ERR;
}
if (bBTO_ERR && bBTO_ERR_E){
++ USB_BTO_ERR;
}
if (bBTS_ERR && bBTS_ERR_E){
++ USB_BTS_ERR;
}
ueir = 0; //Clear all USB error flag bits
bUERR = 0; //Clear master USB error flag bit
}
/* ******************************************************************* */
/* Process token done interrupt... Most of the work gets done through */
/* this interrupt. Token Done is signaled in response to an In, Out, */
/* or Setup transaction. */
/* ******************************************************************* */
void Process_Req ()
{
unsigned char *OutBuffer;
unsigned char *UEPArray;
unsigned char DescriptorType;
unsigned char Endpoint;
unsigned char Interface;
unsigned char DescriptorID;
unsigned char StringID;
USB_USTAT = ustat;
ACTIVE_BUF =(USB_USTAT >>3)*2; //EP*2 (IF OUTPUT)
ACTIVE_BUF =(ACTIVE_BUF + (USB_USTAT&0x4)>>2); //=EP*2 + 1 (IF INPUT)
//save data in buffer descriptor table
BDTCopy.EPStat = BDT[ACTIVE_BUF].EPStat;
BDTCopy.bytes = BDT[ACTIVE_BUF].bytes;
BDTCopy.address = BDT[ACTIVE_BUF].address;
bTOK_DONE = 0;
if ((BDTCopy.EPStat & 0x3C) == TOKEN_IN) // TOKEN IN
{
if (USB_USTAT == 0x04)
{ /* Process EP0 In's */
if (USB_dev_req == GET_DESCRIPTOR)
{
CopyDescriptorToEP0 ();
}
}
else if (USB_USTAT == 0x0C)
{ /* process EP1 In's */
}
else
{ /* process EP2 In's */
}
}
else if ((BDTCopy.EPStat & 0x3C) == TOKEN_OUT) //TOKEN OUT
{
if (USB_USTAT == 0x00)
{ /* process EP1 Out's */
}
else if (USB_USTAT == 0x08)
{ /* process EP1 Out's */
}
else
{ /* process EP2 Out's */
}
}
else if ((BDTCopy.EPStat & 0x3C) == TOKEN_SETUP) // TOKEN SETUP
{
Buffer = (struct BufferStruct *) ((unsigned int)bd0adrloe + (unsigned int)(bd0adrhoe <<8));
BufferCopy.bmRequestType = Buffer->bmRequestType;
BufferCopy.bRequest = Buffer->bRequest;
BufferCopy.wValue = Buffer->wValue;
BufferCopy.wIndex = Buffer->wIndex;
BufferCopy.wLength = Buffer->wLength;
bPID_ERR=0; // Clear REQUEST ERROR
bd0cntoe = 0x08;
if (BufferCopy.bmRequestType == 0x21)
bd0statoe = 0xC8;
else
bd0statoe = 0x88;/* Turn the buffer around, make it available for the SIE */
bd0statie = 0x08;
bPKT_DIS = 0;
USB_dev_req = 0;
switch (BufferCopy.bmRequestType)
{
// First bmRequestType ************************************
case HOSTTODEVICE: // 00
#ifdef DEBUG_SERIAL
puts("H>D");
#endif
switch (BufferCopy.bRequest)
{
//================
case CLEAR_FEATURE: //01
/* Remote wakeup is only valid device feature */
if (BufferCopy.wValue == 1)
{
USB_status_device &= 0xFD;
Send_0Len_pkt;
}
else
{
#ifdef DEBUG_SERIAL
puts("stall");
#endif
STALL_EP0;}
break;
//================
case SET_FEATURE: //03
/* Set Device Feature. Only valid device */
if ((BufferCopy.wValue & 0xff) == 1)
{
USB_status_device |= 0x02; /* feature is remote wakeup */
Send_0Len_pkt;
}
else
{
#ifdef DEBUG_SERIAL
puts("stall");
#endif
STALL_EP0;}
break;
//================
case SET_ADDRESS: //05
USB_address_pending = BufferCopy.wValue;
#ifdef DEBUG_SERIAL
puts("SA");
hex(USB_address_pending); // output the address as ascii (one char)
new_line();
#endif
if (USB_address_pending < 0x80)
{
Send_0Len_pkt;
USB_dev_req = SET_ADDRESS;
uie = 00001001b; //enable transaction complete and reset interrupts
}
else
{
#ifdef DEBUG_SERIAL
puts("stall");
#endif
STALL_EP0;}
break;
//================
case SET_CONFIGURATION: //09
if (BufferCopy.wValue <= NUM_CONFIGURATIONS)
USB_Curr_Config = BufferCopy.wValue;
#ifdef DEBUG_SERIAL
puts("SC");
hex(USB_Curr_Config); //output the config
#endif
if (BufferCopy.wValue == 0)
{
USWSTAT= ADDRESS_STATE;
#ifdef DEBUG_SERIAL
puts("A");
#endif
}
else
{
USWSTAT= CONFIG_STATE;
#ifdef DEBUG_SERIAL
puts("C");
#endif
}
Send_0Len_pkt;
bd1statie = 0x48; //SET MCU AS OWNER OF THIS BUFFER, ENABLE DATA TOGGLE SYNC
uep1 = ENDPT_NON_CONTROL;
break;
//================
default:
{
#ifdef DEBUG_SERIAL
puts("stall");
#endif
STALL_EP0;}
break;
}
break;
// Second bmRequestType ************************************
case HOSTTOINTERFACE: //01
#ifdef DEBUG_SERIAL
puts("H>I");
#endif
switch (BufferCopy.bRequest)
{
//================
case SET_INTERFACE: //0B
#ifdef DEBUG_SERIAL
puts("SInter");
#endif
if (USWSTAT == CONFIG_STATE)
{
Interface = BufferCopy.wIndex;
USB_Interface [Interface] = BufferCopy.wValue;
Send_0Len_pkt;
}
else
{
#ifdef DEBUG_SERIAL
puts("stall");
#endif
STALL_EP0;}
break;
//================
case CLEAR_FEATURE: //01
//================
case SET_FEATURE: //03
/* Set Interface feature - Not Valid */
//================
default:
{
#ifdef DEBUG_SERIAL
puts("stall");
#endif
STALL_EP0;}
break;
//================
}
break;
// Third bmRequestType ************************************
case HOSTTOENDPOINT:
#ifdef DEBUG_SERIAL
puts("H>E");
#endif
switch (BufferCopy.bRequest)
{
//================
case CLEAR_FEATURE: //01
UEPArray = (unsigned char *) &uep0;
Endpoint = BufferCopy.wIndex & 0x0F;
if (BufferCopy.wValue == 0)
/* Only valid feature is 0 (Remote Wakeup) */
{
if (((USWSTAT & 0x03) == ADDRESS_STATE) && (Endpoint == 0))
{
UEPArray [Endpoint] &= 0xFE;
Send_0Len_pkt;
}
else if (((USWSTAT& 0x03) == CONFIG_STATE) && (Endpoint < 3))
{
UEPArray [Endpoint] &= 0xFE;
Send_0Len_pkt;
}
else
{
#ifdef DEBUG_SERIAL
puts("stall");
#endif
STALL_EP0;}
}
else
{
#ifdef DEBUG_SERIAL
puts("stall");
#endif
STALL_EP0;}
break;
//================
case SET_FEATURE: //03
UEPArray = (unsigned char *) &uep0;
Endpoint = BufferCopy.wIndex & 0x0F;
if (BufferCopy.wValue == 0) /* Only valid feature is 0 (Remote Wakeup) */
{
if (((USWSTAT& 0x03) == ADDRESS_STATE) && (Endpoint == 0))
{
UEPArray [Endpoint] |= 1;
Send_0Len_pkt;
}
else if (((USWSTAT& 0x03) == CONFIG_STATE) && (Endpoint < 3))
{
UEPArray [Endpoint] |= 1;
Send_0Len_pkt;
}
else
{
#ifdef DEBUG_SERIAL
puts("stall");
#endif
STALL_EP0;}
}
else
{
#ifdef DEBUG_SERIAL
puts("stall");
#endif
STALL_EP0;}
break;
//================
default:
{
#ifdef DEBUG_SERIAL
puts("stall");
#endif
STALL_EP0;}
}
break;
// Fourth bmRequestType ************************************
case DEVICETOHOST: //80
#ifdef DEBUG_SERIAL
puts("D>H");
#endif
switch (BufferCopy.bRequest)
{
//================
case GET_CONFIGURATION:
#ifdef DEBUG_SERIAL
puts("GC");
#endif
OutBuffer = (unsigned char *) ((unsigned int)bd0adrlie + (unsigned int)(bd0adrhie <<8));
OutBuffer [0] = USB_Curr_Config;
bd0cntie = 1;
bd0statie = 0xc8;
break;
//================
case GET_DESCRIPTOR:
#ifdef DEBUG_SERIAL
puts("GD");
#endif
DescriptorID = (unsigned char) (BufferCopy.wValue >> 8);
if (DescriptorID == DEVICE)
{
#ifdef DEBUG_SERIAL
puts("device");
#endif
USB_dev_req = GET_DESCRIPTOR;
EP0_start = DeviceDescriptor;
EP0_end = DeviceDescriptor + sizeof(DeviceDescriptor);
if (BufferCopy.wLength < ((unsigned short)EP0_end - (unsigned short)EP0_start))
EP0_end = EP0_start + BufferCopy.wLength;
EP0_maxLength = 8;
CopyDescriptorToEP0 ();
}
else if (DescriptorID == CONFIGURATION)
{
#ifdef DEBUG_SERIAL
puts("config");
#endif
USB_dev_req = GET_DESCRIPTOR;
EP0_start = ConfigDescriptor;
EP0_end = ConfigDescriptor + sizeof(ConfigDescriptor);
if (BufferCopy.wLength < ((unsigned short)EP0_end - (unsigned short)EP0_start))
EP0_end = EP0_start + BufferCopy.wLength;
EP0_maxLength = 8;
CopyDescriptorToEP0 ();
}
else if (DescriptorID == STRING)
{
#ifdef DEBUG_SERIAL
puts("string");
#endif
StringID = (unsigned char) BufferCopy.wValue;
USB_dev_req = GET_DESCRIPTOR;
EP0_maxLength = 8;
switch (StringID)
{
case 0:
EP0_start = String0; // String0 is start of string0
EP0_end = String0 + String0[0]; // String[0] is length of String0
if (BufferCopy.wLength < ((unsigned short)EP0_end - (unsigned short)EP0_start))
EP0_end = EP0_start + BufferCopy.wLength;
CopyDescriptorToEP0 (); // this copies the whole string in 8 byte pieces
break;
case 1:
EP0_start = String1;
EP0_end = String1 + String1[0];
if (BufferCopy.wLength < ((unsigned short)EP0_end - (unsigned short)EP0_start))
EP0_end = EP0_start + BufferCopy.wLength;
CopyDescriptorToEP0 ();
break;
case 2:
EP0_start = String2;
EP0_end = String2 + String2[0];
if (BufferCopy.wLength < ((unsigned short)EP0_end - (unsigned short)EP0_start))
EP0_end = EP0_start + BufferCopy.wLength;
CopyDescriptorToEP0 ();
break;
// Additional string processing can be added here
default:
{
#ifdef DEBUG_SERIAL
puts("stall IN");
#endif
STALL_PID_EP0IN;} /* REQUEST ERROR */
}
}
else
{
#ifdef DEBUG_SERIAL
puts("stall IN");
#endif
STALL_PID_EP0IN;} /* REQUEST ERROR */
break;
//================
case GET_STATUS:
#ifdef DEBUG_SERIAL
puts("GS");
#endif
OutBuffer = (unsigned char *)BDT [EP0IN].address;
OutBuffer[0] = USB_status_device;
OutBuffer[1] = 0;
bd0cntie = 2;
bd0statie = 0xc8;
break;
//================
default:
break;
}
//================
break;
// Fifth bmRequestType ************************************
case INTERFACETOHOST:
#ifdef DEBUG_SERIAL
puts("I>H");
#endif
switch (BufferCopy.bRequest)
{
//================
case GET_INTERFACE:
#ifdef DEBUG_SERIAL
puts("GI");
#endif
Interface = BufferCopy.wIndex;
if ((USWSTAT== CONFIG_STATE) && (Interface < NUM_INTERFACES))
{
OutBuffer = (unsigned char *) BDT [EP0IN].address;
OutBuffer[0] = USB_Interface [Interface];
bd0cntie = 1;
bd0statie = 0xc8;
}
else
{
#ifdef DEBUG_SERIAL
puts("stall");
#endif
STALL_EP0;}
break;
//================
case GET_STATUS:
#ifdef DEBUG_SERIAL
puts("GS");
#endif
OutBuffer = (unsigned char *) BDT [EP0IN].address;
OutBuffer[1] = 0;
bd0cntie = 2;
Interface = BufferCopy.wIndex;
if ((USWSTAT == ADDRESS_STATE) && (Interface == 0))
{
OutBuffer[0] = USB_Interface [Interface];
bd0statie = 0xc8;
}
else if ((USWSTAT == CONFIG_STATE) && (Interface < NUM_INTERFACES))
{
OutBuffer[0] = USB_Interface [Interface];
bd0statie = 0xc8;
}
else
{
#ifdef DEBUG_SERIAL
puts("stall");
#endif
STALL_EP0;}
break;
//================
case GET_DESCRIPTOR:
DescriptorType = BufferCopy.wValue >> 8;
if (DescriptorType == HID_REPORT_DESCRIPTOR)
/* 22 special HID request to return report descriptor */
{
#ifdef DEBUG_SERIAL
puts("HID RD");
#endif
USB_dev_req = GET_DESCRIPTOR;
if (BufferCopy.wIndex == 0);
{
EP0_start = ReportDescriptor1;
EP0_end = EP0_start + sizeof (ReportDescriptor1);
EP0_maxLength = 8;
if (BufferCopy.wLength < sizeof (ReportDescriptor1))
EP0_end = EP0_start + BufferCopy.wLength;
CopyDescriptorToEP0 ();
}
if (BufferCopy.wIndex == 1);
{
/* Repeat above code for another Report Descriptor. */
}
}
else if (DescriptorType == HID_DESCRIPTOR)
/* 21 HID descriptor */
{
#ifdef DEBUG_SERIAL
puts("HID D");
#endif
USB_dev_req = GET_DESCRIPTOR;
if (BufferCopy.wIndex == 0)
{
EP0_start = HIDDescriptor;
EP0_end = EP0_start + sizeof (HIDDescriptor);
EP0_maxLength = 8;
if (BufferCopy.wLength < sizeof (HIDDescriptor))
EP0_end = EP0_start + BufferCopy.wLength;
CopyDescriptorToEP0 ();
}
if (BufferCopy.wIndex == 1)
{
/* Repeat above code for another HID Descriptor. */
}
}
else
{
#ifdef DEBUG_SERIAL
puts("stall");
#endif
STALL_EP0;} /* unrecognised request */
break;
//================
default:
break;
}
//================
break;
// Sixth bmRequestType ************************************
case ENDPOINTTOHOST:
#ifdef DEBUG_SERIAL
puts("E>H");
#endif
if (BufferCopy.bRequest == GET_STATUS)
{
#ifdef DEBUG_SERIAL
puts("GS");
#endif UEPArray = (unsigned char *) &uep0;
Endpoint = BufferCopy.wIndex & 0x0F;
OutBuffer = (unsigned char *) ((unsigned int)bd0adrlie + (unsigned int)(bd0adrhie <<8));
// OutBuffer = (unsigned char * ) bd0adrlie;
OutBuffer[1] = 0;
bd0cntie = 2;
if (Endpoint < 3)
{
OutBuffer[0] = UEPArray [Endpoint] & 0x01;
bd0statie = 0xc8;
}
else
{
#ifdef DEBUG_SERIAL
puts("stall");
#endif
STALL_EP0;}
}
break;
// Seventh bmRequestType (others) ************************************
default:
if (BufferCopy.bmRequestType & 0x20) {
#ifdef DEBUG_SERIAL
puts("HID");
#endif
OutBuffer = (unsigned char *) ((unsigned int)bd0adrlie + (unsigned int)(bd0adrhie <<8));
switch (BufferCopy.bmRequestType)
{
case 0x21: /* Host to Device HID request */
#ifdef DEBUG_SERIAL
puts("H>HID");
#endif
switch (BufferCopy.bRequest)
{
case HID_SET_PROTOCOL: /* Set Protocol */
#ifdef DEBUG_SERIAL
puts("SP");
#endif
USB_protocol = BufferCopy.wValue;
Send_0Len_pkt;
break;
case HID_SET_REPORT: /* Set HID Report */
#ifdef DEBUG_SERIAL
puts("SR");
#endif
// Add Set_Report Function above for OUT TOKEN and uncomment
// following two lines
// USB_dev_req = HID_SET_REPORT;
break;
case HID_SET_IDLE: /* Set Idle */
#ifdef DEBUG_SERIAL
puts("SIdle");
// stall EP0 to let host know that device
// will send reports whether or not data has changed.
puts("stall");
#endif
STALL_EP0;
break;
default:
#ifdef DEBUG_SERIAL
puts("Ub");// unrecognized bRequest
hex(BufferCopy.bRequest);
puts("stall");
#endif
STALL_EP0;
}
break;
case 0xA1: /* Dev2HostHIDRequest */
#ifdef DEBUG_SERIAL
puts("HID>H");
#endif
switch (BufferCopy.bRequest)
{
case HID_GET_PROTOCOL: /* Get Protocol */
#ifdef DEBUG_SERIAL
puts("GP");
#endif
OutBuffer[0] = USB_protocol;
bd0cntie = 1;
bd0statie = 0xC8;
break;
case HID_GET_REPORT: /* Get HID Report */
// Add Get_Report Function here and uncomment following two lines
// BD0IST = 0xc8; // Turn over BDT to SIE
#ifdef DEBUG_SERIAL
puts("GR");
#endif
break;
case HID_GET_IDLE: /* Get Idle */
#ifdef DEBUG_SERIAL
puts("GI"); // device does not support get idle, just stall
puts("stall");
#endif
STALL_EP0;
break;
default:
// device does not support get idle, just stall
#ifdef DEBUG_SERIAL
puts("Ub"); // unrecognized brequest
hex(BufferCopy.bRequest);
#endif
STALL_EP0;
}
break;
case 0x22: /* Host2DevReportRequest */
#ifdef DEBUG_SERIAL
puts("22");
puts("stall");
#endif
STALL_EP0;
break;
case 0x23: /* Host2DevPhysicalRequest */
#ifdef DEBUG_SERIAL
puts("23");
puts("stall");
#endif
STALL_EP0;
break;
case 0xA2: /* Dev2HostReportRequest */
#ifdef DEBUG_SERIAL
puts("a2");
puts("stall");
#endif
STALL_EP0;
break;
case 0xA3: /* Dev2HostPhysicalRequest */
#ifdef DEBUG_SERIAL
puts("a3");
puts("stall");
#endif
STALL_EP0;
break;
default:
#ifdef DEBUG_SERIAL
puts("Ubm"); // unrecognized bmRequest
hex(BufferCopy.bmRequestType);
puts("stall");
#endif
STALL_EP0;
}
}
}
}
}
/* ********************************************************************* */
/* Branch off and service the USB interrupt flags */
/* ********************************************************************* */
void ServiceUSB ()
{
if (bTOK_DONE)
Process_Req();
if (bSTALL)
{
#ifdef DEBUG_SERIAL
puts("Unstall");
#endif
USBStall ();}
if (bUERR)
{
#ifdef DEBUG_SERIAL
puts("Error");
#endif
Count_Error ();}
if (bUIDLE)
{
#ifdef DEBUG_SERIAL
puts("Sleep");
#endif
USBSleep ();}
}
////////////////////////////////////////////////////////////////
// Interrupt service routine. Branch off to different interrupts
////////////////////////////////////////////////////////////////
void interrupt (void)
{
portb=0; //clear indicator leds
if (bUSBIE && bUSBIF) {
if (bACTIVITY && bACTIVITY_E) // WAS IT AN ACTIVITY WAKEUP?
USBActivity ();
if (bUSBRST && bUSBRST_E)// USB reset must be serviced immediately
USBReset();
if (bTOK_DONE && bTOK_DONE_E) // WAS IT A TOKEN DONE
{
if (USB_dev_req == SET_ADDRESS) // Finish Set Address
{
USB_dev_req = NULL;
USB_Curr_Config = 0;
uaddr = USB_address_pending;
uie = 00000001b; // enable just the reset interrupt
if (USB_address_pending > 0)
{
USWSTAT= ADDRESS_STATE;
}
else
{
USWSTAT= DEFAULT_STATE;
}
}
bTOK_DONE=0; // clear Token Done flag
}
bUSBIF=0; // Clear USB interrupt flag
}
}
//*****************************************************
// AT LAST THE MAIN PROGRAM
//*****************************************************
void main() {
unsigned char i;
unsigned short j;
signed char buffer [3];
//const signed char tablex [] = {0, -1, -2, -3, -2, -1, 0, 1, 2, 3, 2, 1};
//const signed char tabley [] = {0, -1, -1, 0, 1, 1, 0, -1, -1, 0, 1, 1};
const signed char tablex [] = {-1, -1, -1, 1, 1, 1, 1, 1, 1, -1, -1, -1};
const signed char tabley [] = {-1, 0, 1, 1, 0, -1, -1, 0, 1, 1, 0, -1 };
const unsigned char led[]={1,2,4,8,16};
// The table array contains the directional data for simulated mouse
// movement to form the infinity symbol (i.e. figure 8). Movements are relative
// to the previous position.
ddrb = 0;
for (i=0; i<5;i++)
{
portb=led[i]; // flash leds to make sure chip is running
for (j=0; j<64000; j++); // Small delay (greater than 16us) in order to
};
#ifdef DEBUG_SERIAL
// Setting the serial port baud rate is a bit tricky
// This project uses a 20Mhz crystal, however the system clock
// is actually 24Mhz based on the CPUDIV config bits and desire for
// compatibility with USB.
// UART_Init(0,155); // 2400 BAUD @ 24Mhz clock
// UART_Init(1,155); // 9600 BAUD @ 24Mhz clock
// UART_Init(1,77); // 19200 BAUD @ 24Mhz clock
UART_Init(1,38); // 38400 BAUD @ 24Mhz clock
// UART_Init(1,47); // MIDI 31250 BAUD
puts("USB Irritating Mouse V1.1"); //CC
#endif
InitUSB (); // allow SIE to come online before beginning USB
// initialization
buffer [0] = 0; //we won't be simulating mouse buttons
i = 10;
j=0;
t0con=11000111b; //set up timer0 as 8 bit timer with prescaler of 256 and enable
// 4/24* 10^6 * 256 * 256 = 10.9 msec timer overflow
#ifdef DEBUG_SERIAL
while (!bTMR0IF) {} // wait until timer expires first time
puts("TMR0 up"); // message means timer is working
bTMR0IF =0;
#endif
while (1)
{
if (bTMR0IF) { // Poll all functions every 10.9ms
bTMR0IF=0; // clear the timer flag
ServiceUSB(); // Service USB functions
// send same data 10 times (100 msec)
if (i > 9) {
i = 0;
j++;
if (j==12)
{j=0;} // (limit to length of table array)
} // Increment infinity vectors
buffer[1] = tablex[j]; // X vector
buffer[2] = tabley[j]; // Y vector
}
if (ConfiguredUSB()) { // Wait until device is configured before using
// EP1. If Endpoints 1 or 2 are used before
// the device is configured, errors will occur.
if (PutEP1(3, buffer)) // Increment i if EP1 IN buffer is accessible
{i++;
// to the PIC. If not accessible, try again
} // next time.
}
}
}
Copyright © 2002-2006 SourceBoost Technologies