#include <Mega32.h>
#include <delay.h>   
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#define CUTOFF 1  //define radius of cutoff region around 0
int extint;  //keeps track of
number of external interrupts
char send_message[12];  //message to send
over serial
unsigned char
message_pos;  //message cursor
int connected, enabled;  //keeps track of the connected/disconnected
                         //and enabled/disabled states of the device
unsigned int ms_timebase;  //milliseconds
unsigned int keypress_timebase;  //time for keypresses and buttons
unsigned char
accel, x1, y1, scroll;  //data read and
processed from ADC
unsigned char 
  admuxnum;  //specifies which pin to read the ADC from
unsigned char
pushed[4], prevpush[4], button[4];  //button debouncing variables
unsigned char
i;  //used for button reading loops
interrupt [EXT_INT0] void RTS(void){
  extint++;
  if(extint>1){  //wait until after first external interrupt
    message_pos= 0;
    send_message[0]= 'M';  //tell Windows we're a serial scroll mouse
    send_message[1]= 'Z';
    send_message[2]= 0;
    UCSRB.5= 1;
    PORTD.7= 1;
    connected= 1;  //we're connected
enabled= 1; //device is enabled
if(extint>5) {
    GICR= 0;  //after we've been recognized, stop telling Windows what we
are
  }
}
interrupt [USART_DRE] void send(void){
  if(send_message[message_pos]==0){ //if no more message, stop sending
    UCSRB.5= 0;
  }
  else{
    UDR= send_message[message_pos];
//otherwise keep sending message
    message_pos++;
  }
}
interrupt [ADC_INT] void readADC(void){
  accel=
ADCH;  //read
acceleration from ADC and store into accel
}
void initialize(){  //initialize all
the variables
  UCSRB= 0x18; //enable
TX
  UBRRH= 0b00000011; //1200
baud
  UBRRL= 0b01000000; //setting
up serial
  DDRD= 0xFA; //set
up port D
  PORTD.7= 0;  //turn on LED
  DDRB= 0x00;  //set up port B
  PORTB= 0xFF;
  extint=
0;  //start at
first external interrupt
  MCUCR= 0b10010010;  //set mcu to interrupt on any
change in serial line
  GICR= 0x40;  //enable external interrupts
  admuxnum=
0;  //read
x-axis first
  x1= 0;  //0 x-coords
  y1= 0;  //0 y-coords
  accel=
0;  //0
acceleration
  ADMUX= 0b01100000;  //read x-axis first
  ADCSR= 0b11101111;  //adc status
  connected= 0;  //device is not
connected
  enabled= 0;  //device is
disabled
  for(i=0; i<4; i++){  //reset all button
pushes
    prevpush[i]= 1;
    pushed[i]= 1;
    button[i]= 0;
  }
  memset(send_message, 0, 12);  //allocate memory
for serial comm
  message_pos= 0;  //set message cursor at beginning
  #asm("sei");  //enable interrupts
}
void main(void){
  initialize();  //initialize
variables used
  while(1){  //never stop
running
    if(connected==1){  //if device is
connected
        for(i=0; i<4;i++){  //detect any buttons pressed
          pushed[i]= (PINB>>i) & 0x01;
          if(prevpush[i]==
pushed[i]){
            button[i]= (~pushed[i]) & 0x01;  //make sure they're
pressed
          }
        }
        if(prevpush[0]==1
&& pushed[0]==0){  //if it was the enable button
          enabled=
enabled ^ 0x01;  //then
toggle enable/disable status of device
        }
        for(i=0; i<4;i++){  //otherwise store the button push
          prevpush[i]= pushed[i];
        }
            if(admuxnum==0){ //if set to read
x-axis acceleration
              ADMUX= 0b01100001;  //setup the ADC pin
              #asm("sleep");  //sleep processor to help sync up ADC reads
              x1= accel;  //read ADC
              admuxnum++;  //switch to read
y-axis
            }
            else{
              ADMUX=0b01100000;  //reading y-axis
              #asm("sleep");  //sleep processor to help sync up ADC reads
              y1= accel;  //read ADC
              admuxnum=
0;  //switch
back to read x-axis again
              if(x1==0) x1= 127;  //re-scale x-axis to be inverted
              else{
                       if(x1>128){  //this if-else
reverses the two halves of the x-scale
                        x1-=128;
                        /*x1= ~x1;  //this code flips
the x-axis
                        x1+=1;*/
                      }
                      else{
                        x1+=128;
                        /*x1= ~x1;  //this code flips
the x-axis
                        x1+=1;*/
                      }
                 }
              
              if(y1>128){  //this if-else inverts the y-scale
                y1-=128;
              /*  y1= ~y1;  //this code flips the y-axis
                y1+=1;*/
              }
              else{
                y1= (y1 ^ 0x80);
              /*  y1= ~y1;  //this code flips the y-axis
                y1+=1;*/
              }
              memcpy(&scroll, &y1, 1); 
//copy the value of y1 into scroll
              scroll= (scroll
& 0x07) | ((y1>>4) & 0x08); 
//scale down scroll speed
              y1 = (signed
char)((signed char)y1>>2);  //scale down mouse
speed in y-axis
              x1 = (signed char)((signed char)x1>>2);  //scale down mouse
speed in x-axis
              
                //if x value is
in the cutoff range, make it zero
          if(((signed char)x1) < CUTOFF && ((signed char)x1) >
-CUTOFF) x1=0;
          //normalize
any other values to respect cutoff range
          if(((signed char)x1) >= CUTOFF) x1= ((signed
char)((signed char)x1) - CUTOFF); 
          
          if(((signed char)x1) <= -CUTOFF) x1= ((signed char)((signed char)x1) +
CUTOFF);
          //if y
value is in cutoff range, make it zero
          if(((signed char)y1) < CUTOFF && ((signed char)y1) >
-CUTOFF) y1=0;  
          //normalize
any other values to respect cutoff range
          if(((signed char)y1) >= CUTOFF) y1= ((signed
char)((signed char)y1) - CUTOFF); 
          
          if(((signed char)y1) <= -CUTOFF) y1= ((signed char)((signed char)y1) +
CUTOFF);
        
              PORTD.7= button[3]
& 0x01;  //set
LED to button 3
              if(enabled==1){  //if the mouse status is enabled
                  if(button[3]==0){  //if not scrolling
                    //assemble
motion packets
                          send_message[0]= 0xC0 | ((button[1]<<5) & 0x20) |
((button[2]<<4) & 0x10) 
                                     |((y1>>4)&
0x0C) | ((x1>>6)& 0x03);  
                    send_message[1]= 0x80 | (x1 &
0x3F);
                    send_message[2]= 0x80 | (y1 &
0x3F);
                    send_message[3]= 0x80;
                  }
                  if(button[3]==1){  //if scrolling
                    send_message[0]= 0xC0;  //assemble
scrolling packets
                    send_message[1]= 0x80;
                    send_message[2]= 0x80;
                    send_message[3]= 0x80 | ((scroll)
& 0x0F);
                  }
                  send_message[4]= 0;  //end transmission
                  message_pos= 0;  //reset message cursor
                  UCSRB.5= 1;  //send the message through the serial interface
                  while(UCSRB.5==1){}  //until the message is done sending
                 }
            }
          }
        }
  }
