// ECE 476 MISSILE COMMAND PROJECT: MOUSE CODE

// CORNELL UNIVERSITY, 2005

// 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