usbtestCC.c

This program for BoostC compiler shows how to use onboard USB on PIC18F2455 (by Robert Lang).



//###########################################################################
// 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.
            }
        }
    }



http://www.sourceboost.com/home.html

Copyright © 2002-2006 SourceBoost Technologies