//
ECE 476 MISSILE COMMAND PROJECT: MOUSE CODE
// 
//
CEM OZKAYNAK, BRIAN SMITH
//
//****************************************************************************
// Note: we used PS/2 mouse interaction code
originally developed 
// for a Minesweeper Program by Chee
Ming, Chaw and Elaine Siu for 476 in 2003 
// 
// They developed the
following functions in this source file:
//         mouse_send
//         mouse_read
//         poll_mouse
//         reset_mouse
// The remaining functions
we developed. 
//****************************************************************************
#include <Mega32.h>
#include <stdio.h>
// sprintf
#include <delay.h>
// delay_ms      
             
#include <stdlib.h>
//timeout values for each task
#define t1 100   
// heart beat timer
#define t2 2000  
// debug
#define t3 200   
// for sampling mouse
//I like these 
#define begin {
#define end  
}                                  
                   
#define DATA_IN  PINA.0 //data line from mouse                                            
#define CLK_IN  
PINA.1 //clock line from mouse
#define DATA_OUT PORTA.0 //data line from mouse
#define LOW     
0
#define HIGH    
1            
#define MOUSE_SPEED 2
#define CURSOR_X_MAX 122
#define CURSOR_X_MIN 4
#define CURSOR_Y_MAX 77
#define CURSOR_Y_MIN 15                          
#define CMD_UPDATE_CURSOR                0xf1
register
unsigned char data @4; 
                                                                          
#asm    
        .equ PORTA=0x1b
        .equ DDRA=0x1a        
       
.MACRO DATALOW
        sbi DDRA,0    ;DDRA.0=1
        cbi PORTA,0   ;PORTA.0=0
        .ENDM
        
       
.MACRO RELDATA
        cbi DDRA,0    ;DDRA.0=0
        sbi PORTA,0   ;PORTA.0=1
        .ENDM
        
       
.MACRO CLKLOW
        sbi DDRA,1    ;DDRA.1=1
        cbi PORTA,1   ;PORTA.1=0
        .ENDM
        
       
.MACRO RELCLK
        cbi DDRA,1    ;DDRA.1=0
        sbi PORTA,1   ;PORTA.1=1
        .ENDM
#endasm
                
#define MAXROW 10
#define MAXCOL 15
//the three task subroutines
   
void mouse_send(char data);         // Send 1 byte of data to mouse.   
unsigned
char mouse_read(void);     // Read 1 byte of data from mouse  
void
initialize(void); //all the usual mcu stuff                     
          
unsigned int time1;       
//timeout counters        
unsigned int time2;         
unsigned int time3;                      
char str[80];
unsigned
char mouse_x,mouse_y,mouse_status;             
int cursor_x, cursor_y;                           //current cursor
position
         
//**********************************************************
//timer 0 overflow ISR
interrupt
[TIM0_COMP] void timer0_overflow(void)
begin       
  //Decrement
the 2 times if they are not already zero
  if (time1>0) 
--time1;                               
  if (time2>0) 
--time2;
end       
interrupt
[TIM1_COMPA] void t1_cmpA(void)  
begin    
        //Decrement
the time if not already zero
   if (time3>0)       
--time3;
end
//**********************************************************     
// Send a byte of data to mouse. It consist of 1
start bit, 8 data bits, 1 parity
// bit, 1 stop bit. 
// After the mouse recieved the data correctly, the mouse will send back an
ACK bit.
// "data" is the data to be sent. parity bit is odd parity of the 8 bits data.   
// Data is read by mouse at rising edge of CLK.
void mouse_send(char data)
begin 
  unsigned char Bit,parity,i;
  #asm("RELDATA");        
  #asm("RELCLK");
  delay_us(300);
  #asm("CLKLOW");               //Pull CLK Low
  delay_us(300);                // need to wait for at least
100us
  #asm("DATALOW");              // Pull DATA Low when holding CLK
Low
  delay_us(100);
  #asm("RELCLK");                //Release CLK and continue to
hold Data Low. This
                                  //
is also the Start bit.
  delay_us(40);
  while(CLK_IN!=LOW) { }       
// wait for CLK to go low 
  i=0; Bit=0b00000001;                                                     
  parity=1;                    
// odd parity = 1 ^ bit0 ^ bit1 ^ ... ^ bit7
     
  while(i<=8)
    begin
        
      if(i==8)                  // If i=8
send parity bit otherwise, send the next
                           //
bit of data.
      { if(parity)             
// DATA_OUT=(i==8? parity : (data & Bit)
);
          { #asm("RELDATA");
}          
        else 
          { #asm("DATALOW"); }
       }
      else
      { if(data & Bit)
          { #asm("RELDATA"); }
        else
          { #asm("DATALOW"); }
      }
      while(CLK_IN!=HIGH) {}                    // wait for CLK to go high.
mouse
                                         //
read data at rising edge.
      while(CLK_IN!=LOW) 
{}                    // wait for
CLK to go low. 
      parity=parity ^ DATA_OUT;                 // update parity bit.
     
Bit=Bit<<1;                               // Prepare mask
      i++;
    end
  #asm("RELDATA");                              // Release Data
line. This is the stop bit. 
  delay_us(50);                                 // give time
for transient to settle.
  while(DATA_IN!=LOW) {}                        // wait for Data line
to go low     
         
  while(CLK_IN!=LOW) 
{}                        // wait
for CLK to go low. Start of ACK from mouse.
  while(DATA_IN==LOW || CLK_IN==LOW) {}         // End of ACK from mouse.           
   
  #asm("CLKLOW");                               // Inhibit the
mouse from transmitting data.
end                                                          
//**********************************************************
// This function read a
byte of data from the mouse and return the byte
unsigned
char mouse_read(void)
begin
  unsigned char i,t[10];  
  #asm("RELCLK");         //release the CLK 
  #asm("RELDATA");        //release DATA line.
  delay_us(200);          // wait for at least 100us
  while(CLK_IN==HIGH) 
{} // wait for falling edge. we read data at
falling edge of CLK
  i=0;  
  delay_us(5);
  
  while(CLK_IN==LOW)  
{} // wait for CLK to go high.
  while(i<=8)
    begin
      while(CLK_IN==HIGH) {} // wait for falling edge of CLK   
        t[i]=DATA_IN;        // store each bit
        i++;       
      while(CLK_IN==LOW) {}
    end   
  while(CLK_IN==LOW) {} 
 
data=128*t[7]+64*t[6]+32*t[5]+16*t[4]+8*t[3]+4*t[2]+2*t[1]+t[0];
//combine the collected bits into a byte       
  #asm("CLKLOW");          //pull CLK low to prevent mouse from
sending data until being asked
  return data;
  
end                   
                
//******************************************                  
//Update the cursor's variables with new location
void update_cursor(void)
begin
        if (mouse_y!=0)           //calculate vertical position
according to its sign and value                    
               
if ((mouse_status
& 0b00100000)!=0) { cursor_y=cursor_y+(256-mouse_y);
} 
               
else { cursor_y=cursor_y-mouse_y; }    
        if (mouse_x!=0)           //calculate horizontal position
according to its sign and value                    
               
if ((mouse_status
& 0b00010000)!=0) { cursor_x=cursor_x-(256-mouse_x);
} 
               
else { cursor_x=cursor_x+mouse_x; }
               
        if (cursor_x>CURSOR_X_MAX) cursor_x=CURSOR_X_MAX;   
// limit cursor to within the screen
           if (cursor_x<CURSOR_X_MIN) cursor_x=CURSOR_X_MIN;   
// 100 x 128 pixels screen
           if (cursor_y>CURSOR_Y_MAX) cursor_y=CURSOR_Y_MAX;
           if (cursor_y<CURSOR_Y_MIN) cursor_y=CURSOR_Y_MIN;
end                                                              
 
//*******************************************                                 
// This routine poll the
mouse's status and movement data.
void poll_mouse(void)
begin  
    mouse_send(0xeb);                     //Request data from mouse
    mouse_read();                         //Read the acknowledge
byte
    mouse_status=mouse_read();            //Read
mouse status
    mouse_x=mouse_read();                
//Read mouse horizontal movement
    mouse_y=mouse_read();                
//Read mouse vertical movement
end
//**********************************************
// This function is called
to reset the mouse and put it into remote mode.
// In remote mode, mouse
only send data upon request from the microcontroller.
// This function is called
when manual reset of the mouse is required. This is for
// overcoming interference problem from some
unknown EM field.
void reset_mouse(void)
begin
  mouse_send(0xff);     // reset mouse
  mouse_read();         // read mouse acknowledge (0xFA)
  mouse_read();         // read some blank bytes.  
  mouse_read();     
  mouse_send(0xf0);     // Set mouse to remote mode.
  mouse_read();         // read mouse acknowledge (0xFA)           
  delay_ms(100);
end             
//**********************************************
//*********************************************
// Send mouse information to tv screen:
// cursor locations, button status
void update_TV(void)
begin         
              PORTB
= cursor_x;
              PORTC = cursor_y;
end
//Main 
void
main(void)
begin  
  initialize();
       
  //main task
scheduler loop 
  while(1) 
  begin
              //update mouse click bits
              if (mouse_status & 0x01)
                     PORTD.2 = 1;   
              else
                     PORTD.2 = 0;
              if (mouse_status & 0x02)
                     PORTD.1 = 1;   
              else
                     PORTD.1 = 0;      
            //Regularly poll mouse and send info
to tv
            if(time3 == 0)
            begin 
                   
time3=t3;
                      poll_mouse();              // Poll mouse
                      update_cursor();           //updates cursor location
                      update_TV();            //send info to other micro        
                      delay_ms(15);  
        end  
        if(time1==0)                      // heart beat LED
        begin
         
time1=t1;                                   // reset timer
         
PORTD.7=~PORTD.7;                          // toggle heart beat
LED
        end
        if (PIND.6==0)
               
reset_mouse();                 
// Manually reset mouse
      
    end   // end while
end      //end main  
#define lineTime
1018   
//**********************************************************
//Initialize
void
initialize(void)
begin      
  #asm("cli");
  //init
timer 1 to send mouse info at regular interval
  OCR1A = lineTime;         //One
NTSC line
  TCCR1B =
9;                 //full speed;
clear-on-match
  TCCR1A =
0x00;        //turn off pwm and oc lines
  TIMSK =
0x12;                //enable interrupt
T1 cmp 
  
  OCR0 =
250;          //set the compare re to 250
time ticks
  //prescalar to 64 and turn on clear-on-match
 
TCCR0=0b00001011;        
  
  //init the
task timers
 
time1=t1;    // Heart beat timer
  time2=t2;
 
time3=t3;    // debounce timer
  //init
ports                                                              
  DDRA =
0b11111100;    // PA0 DATA IN, PA1 CLOCK
IN     
 
DDRD.6=0;             // Use for
mouse reset
 
PORTD.6=1;            // enable pullup resistor
 
DDRD.7=1;             // used for
heart beat indicator  
 
DDRD.3=1;             
  DDRD.2=1;                       // left click bit
  DDRD.1=1;                       // right click bit
  
  
  //init
UART:
  //UCSRB =
0x10 + 0x08 ;
  //UBRRL =
16; //57600 bps      
  //UBRRH =
0;                         
   
  DDRA.0=1; 
  PORTA.0=1;
  delay_ms(500);
  DDRA.0=0;
    
   DDRA.1=1; 
  PORTA.1=1;
  delay_ms(500);
  DDRA.1=0;
  
  //ports to
output cursor position
  DDRB =
0xff; //portB outputs x-pos
  DDRC =
0xff; //portC outputs y-pos
  
  // init
mouse variables
  cursor_x=64;
  cursor_y=50; 
  PORTB = cursor_x;
  PORTC = cursor_y;
  PORTD.2 =
0;                
  #asm("RELCLK");
  #asm("RELDATA");  
  
  //init
mouse state  
  reset_mouse();    
  
  #asm("sei")
end