Air Mouse Code
Air Mouse Code
h>
#include <stdio.h> // sprintf
#include <delay.h>
/*D - Input/Output to Computer
*
D.1 - Output Clock
*
D.3 - Input Clock
*
D.6 - Output Data
*
D.4 - Input Data
*/
//define some useful maps to bits
#define CLK_OUT PORTC.1 //
#define DATA_OUT PORTC.6
#define CLK_IN PINC.3
#define DATA_IN PINC.4
//#define VCC_IN PINA.4
//define PS/2 data line states
#define IDLE 0
#define INHIBIT 1
#define BUSY 2
#define WAIT_FOR_REQUEST 3
#define REQUEST 4
#define POWEROFF 5
// boolean defines
#define TRUE 1
#define FALSE 0
unsigned char Ytilt, Xtilt, Button0, Button1, ScrollState;
//ScrollState 1 => scrolling.
//ScrollState 0 => button pushing.
signed char Xmove, Ymove, timetemp, OldXmove, OldYmove;
unsigned int time, Button0pushed, Button1pushed, ButtonTimeDiff;
// byte declarations
unsigned char byte_index;
unsigned char transmit_byte;
unsigned char transmit_parity;
unsigned char receive_byte;
unsigned char receive_bit;
unsigned char previous_byte;
unsigned char resend_byte;
// clock
unsigned
unsigned
unsigned
unsigned
unsigned
unsigned
#define HIGH 1
#define FALL 2
#define LOW 3
// queue declarations
#define QUEUELEN 200
unsigned char queue[QUEUELEN]; //queue of data sent by keyboard. (first in, firs
t out)
unsigned char queueFull;
//indicates if queue is full
unsigned char queueEmpty;//indicates if queue is empty
unsigned char queueIn;
//indicates where to put data into queue
unsigned char queueOut;
//indicates where to take data out of queue
// PS/2
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
ACK
SELF_TEST_PASS 0xAA
INIT
SCALING21
// mouse
unsigned
unsigned
unsigned
unsigned
unsigned
unsigned
unsigned
0xFC
0xFF
0xFE
OxEB
0xE9
0xE8
0xFA
0x00
0x02
declarations
char deviceID;
char data_reporting;
char sample_rate;
char scaling; // 0 = 1:1, 1 = 2:1
char resolution;
char waiting_for_sample_rate;
char waiting_for_resolution;
//}
//printf("%x\n\r", trans
mit_byte);
delay_us(150);
// used to wait until host is ready
}
break;
case 11:
// finished transmission
transmit = 0; // transmit fini
shed
byte_index = 0; // reset byte in
dex
break;
default:
break;
}
// set the new clock state
CLK_OUT = 1;
next_clock_state = HIGH;
break; // end of RISE
case HIGH:
// pull
the clock to 0
next_clock_state = LOW; // set the next clock st
ate to low
break; // end of FALL
case LOW: // clock is low - nothing happens here
next_clock_state = RISE;
// next clock st
ate is rising
break; // end of RISE
}
}
if(receive) {
// get the next clock state
clock_state = next_clock_state;
switch (clock_state) {
case RISE:
// all receiving done on the rising edge
of the clock
CLK_OUT = 1;
// get the bit off the data line
// and place into the receive_byte
if (byte_index >=0 && byte_index < 8) {
receive_bit = DATA_IN;
receive_byte = ((receive_bit & 0x01) <<
byte_index) | receive_byte;
}
// update variables for the next state
if (byte_index < 11) {
next_clock_state = HIGH;
byte_index++;
}
break;
case HIGH:
switch (byte_index) {
case 10:
DATA_OUT = 0;
break;
case 11:
DATA_OUT = 1;
// send ACK
receive_byte = 0;
receive_bit = 0;
break;
default:
//if (byte_index == 1)
//
PORTB.4 = 0x0;
break;
}
next_clock_state = FALL;
break;
case FALL:
// hosts transmits on the falling edge
CLK_OUT = 0;
next_clock_state = LOW;
break;
case LOW:
next_clock_state = RISE;
//printf("BYTE: %c\n\r", byte_index);
break;
}
}
switch (mouse_state) {
case IDLE:
IN == 0)
te
next_clock_state = LOW;
transmit = 0;
// mouse can no
receive = 0;
// mouse can no
clock
longer transmit
longer receive
}
else { // check if mouse needs to be in BUSY state -- a
nything on queue?
if(queueEmpty == FALSE)
{
mouse_state = BUSY;
// transition to busy state
transmit = 1;
// allow mouse to transmit
receive = 0;
// make sure we don't receive!
next_clock_state = RISE;
// turn
on the clock
byte_index = 0;
// reset the byte index for transmit
}
else // otherwise we should just stay in IDLE
{
mouse_state = IDLE;
}
}
break;
case BUSY:
//PORTB.0 = 0x0;
// again check if host is trying to inhibt
// by pulling the clock low when it should be high
if ((clock_state == HIGH || clock_state == RISE) && CLK_
IN == 0)
{
mouse_state = INHIBIT; // go to the INHIBIT sta
te
next_clock_state = LOW;
transmit = 0;
// mouse can no
receive = 0;
// mouse can no
clock
longer transmit
longer receive
}
else { // go back to IDLE if mouse has nothing to send
or receive
if ( !(transmit|| receive) )
mouse_state = IDLE;
else
mouse_state = BUSY;
// other
// go to BUSY state to p
rocess data
mouse_state = BUSY;
else
mouse_state = REQUEST;
wise stay in REQUEST until data comes
break;
// other
}//end switch
}
//insert data into queue. Return 1 if queue full, or 0 if inserted data sucessf
ully
unsigned char queuePut(unsigned char d)
{
if (queueFull==TRUE) {
//check if queue is full
return(TRUE);
}
queue[queueIn]=d;
queueIn++;
ck in the next d value
queueEmpty=FALSE;
more
if (queueIn==QUEUELEN)
queueIn=0;
if (queueIn==queueOut)
queueFull=TRUE;
inning
return(0);
}
//get data out of queue. Return 0 if queue empty or the actual data if not empt
y
unsigned char queueGet(void)
{
char d;
if(resend_byte == TRUE) // in case we need to resend data due to an INHI
BIT
{
resend_byte = FALSE;
return previous_byte;
}
if (queueEmpty==TRUE)
return(0);
d=queue[queueOut];
queueOut++;
t next d value
queueFull=FALSE;
delay_ms(375);
previous_byte = d;
send it.
return(d);
}
//calculate the parity of a character
unsigned char getParity(unsigned char x)
{
unsigned char temp, i;
temp=1;
for(i=0;i<8;i++)
{
temp=temp^(x&1);
x>>=1;
}
return temp;
}
void process_command(unsigned char host_command) {
//PORTB.3 = 0x0;
delay_us(50); // do this stuff at rising edge of CLK
//PORTB = 0xFF;
//delay_ms(1000);
//PORTB = host_command;
//delay_ms(1000);
if (host_command == RESET)
{
queueIn = 0;
queueOut=0;
queueEmpty = TRUE;
queueFull = FALSE;
delay_us(500);
}
// Acknowledge the incoming request
queuePut(ACK);
// we received a byte w/ the new resolution
if(waiting_for_resolution) {
// check for valid resolution
if(host_command >= 0 && host_command <= 3)
resolution = host_command;
else {
queuePut(ERROR);
}
waiting_for_resolution = 0;
return;
}
// we received a byte w/ the new sample rate
if(waiting_for_sample_rate) {
// check for valid sample rate
if(host_command >= 10 && host_command <= 200) {
sample_rate = host_command;
}
else { // bad sample rate
queuePut(ERROR);
}
waiting_for_sample_rate = 0;
return;
}
switch (host_command) {
case RESET:
// RESET
PORTB.2 = 0x0;
deviceID = 0x03;
// create a devi
ce ID
queuePut(SELF_TEST_PASS);
// respond w/ self-test
passed (0xAA)
queuePut(deviceID);
ice ID
// <FIX > queuePut(INIT_SUCC_1);
data_reporting = 0;
// disable data
sample_rate = 100;
scaling = 0;
resolution = 0x02;
reporting
ing rate to 100
n to 4
break;
case RESEND:
// Host requests for resending of data
resend_byte = TRUE;
//PORTB.7 = 0x0;
break;
case EN_DATA_REPORT:
// Enabling of data reporting
PORTB.7 = 0x0; // indicates mouse was detected
data_reporting = TRUE;
break;
case SET_SCALING11:
scaling = 0;
break;
case SET_SCALING21:
scaling = 1;
break;
case GET_DEVICE_ID:
// host requests device ID
PORTB.5 = 0x00;
queuePut(deviceID);
break;
case SET_RES: // host requests to set resolution
// host sends next byte with valid resolution
// set a flag to get this byte
waiting_for_resolution = 1;
break;
case STATUS_REQ: //status request respond 0xFA, 0x00, 0x02, 0x64
queuePut(0x00);
// <FIX> have to create the righ
t byte here ...
queuePut(resolution);
queuePut(sample_rate);
break;
case SET_SAMPLE_RATE: // host requests setting of sample rate
// host sends next byte with valid sample rate
// set a flag to get this byte
waiting_for_sample_rate = 1;
break;
case DIS_DATA_REPORT: // disable data reporting
data_reporting = 0;
break;
case SET_DEFAULT:
data_reporting = 0;
sample_rate = 100;
resolution = 4;
break;
default:
break;
}
}
void init_serial(void) {
//serial setup for debugging using printf, etc.
UCSRB = 0x18;
UBRRL = 103;
putsf("\r\nStarting...\r\n");
//set up timer 0
//OCR2=249; //1 mSec
//TIMSK=0b10000010; //turn on timer 0 cmp-match ISR
//TCCR2=0b00001011; //prescalar to 64 and Clr-on-match
r_ready=0;
t_ready=1;
puts_string();
}
void initialize(void)
{
Button0pushed = 1050;
Button1pushed = 1050;
ADMUX = 0b01000000; //ADLAR is not set
ADCSRA = 0b11000111; //Enable & Start ADC w/ division factor of 128
OCR0=5;
//20 uSec
TIMSK=2;
//turn on timer 0 cmp-match ISR
TCCR0=0b00001011;
//prescalar to 64 and Clr-on-match
// Set up the A/D
//ADMUX = 0b00100001; //ADLAR is set
//ADCSR = 0b11000111; //Enable & Start ADC w/ division factor of 128
// setup Port D for PS/2 communication
DDRC = 0b01000010;
PORTC = 0b01000010;
// setup LEDs for debugging
DDRB = 0xFF;
PORTB = 0xFF;
//DDRD = 0xFF;
//PORTD = 0xFF;
// use Port C for buttons
//DDRC=0x00;
// set as input
// counter to be used in ISR
count = 0;
// initialize our outputs
CLK_OUT = 1;
DATA_OUT = 1;
//printf("<Button0, Xmove: %d, %d> <Button1, Ymove: %d, %d> \r\n", Butto
n0, Xmove, Button1, Ymove);
// begin real work
while (1) {
// can we generate a new packet?
if(gen_mouse_packet == TRUE && data_reporting == TRUE) {
//if(1){
gen_mouse_packet = FALSE;
// if (1){
// check buttons
mouse_byte1 = 0x08;
mouse_posX = 0x00;
mouse_posY = 0x00;
Xmove = 0;
Ymove = 0;
scroll_byte = 0;
/*if (PINC.2 == 0x0){
//PORTB.0 == 0x0;
left_button_click = 1;
}
else {
left_button_click = 0;
//PORTB.0 == 0x1;
}
if (PINC.1 == 0x0){
//PORTB.1 = 0x0;
middle_button_click = 1;
}
else {
middle_button_click = 0;
//PORTB.0 == 0x1;
}
if (PINC.0 == 0x0){
//PORTB.2 = 0x0;
right_button_click = 1;
}
else {
right_button_click = 0;
//PORTB.0 == 0x1;
}
if (PINC.3 == 0x0) {
mouse_posX = 10;
}
if (PINC.4 == 0x0) {
mouse_posX = -10;
}
if (PINC.5 == 0x0) {
mouse_posY = 10;
}
if (PINC.6 == 0x0) {
mouse_posY = -10;
}*/
Button0 = 0;
Button1 = 0;
OldXmove = Xmove;
OldYmove = Ymove;
ADMUX = 0b01100000; //tilt around Y axis (accel on the
side is being read) => X axis motion on computer
ADCSRA.6 = 1;
while(ADCSRA.6 == 1){
//wait for an ADC conversion to finish
}
Ytilt = (ADCH);
Xmove = (signed char)(Ytilt);
ADMUX = 0b01100001; //tilt around X axis (accel on top
is being read) => Y axis motion on computer
ADCSRA.6 = 1;
while(ADCSRA.6 == 1){
//wait for an ADC conversion to finish
}
Xtilt = (ADCH);
Ymove = (signed char)(Xtilt);
if (Xmove < -121 || Xmove > 121) {//tolerance condition
Xmove = 0;
}
if (Xmove > 0){ //Need to correct descending system to a
scending system
//Xmove = (-127)-Xmove;
Xmove = (-132)-Xmove; //Smoother with 133 rath
er than 127
}
else if (Xmove < 0){
//Xmove = 127-Xmove;
Xmove = 132-Xmove;
}
if (Ymove < -123 || Ymove > 123) {//tolerance condition
Ymove = 0;
}
if (Ymove < 0){ //Need to correct descending system to a
scending system
Ymove = (-127)-Ymove;
//if (Button0 >= 140 && (Xmove>-25)){ //Can't press button while
tilted
if (((Xmove>-10)&&(Button0 >140))||((Xmove<-10)&&(Button0 >= (1
40-Xmove)))) {//This will allow buttons to be pushed even while mouse is tilted.
Button0pushed = time+150;
if (Button0pushed >= 1000) Button0pushed = (Button0pushe
d-999); //Overflow check
Button0 = 1;
}
else {
Button0 = 0;
Button0pushed = 1050;
}
}
if (Button1pushed = 1050 || Button1pushed <= time){
ADMUX = 0b01100011; //tilt around X axis (accel on top is being
read) => Y axis motion on computer
ADCSRA.6 = 1;
while(ADCSRA.6 == 1){
//wait for an ADC conversion to finish
}
Button1 = (ADCH);
//if (Button1 >= 140 && (Xmove>-25)){
if (((Xmove>-10)&&(Button1 >140))||((Xmove<-10)&&(Button1 >= (1
40-Xmove)))) {//This will allow buttons to be pushed even while mouse is tilted.
Button1 = 1;
Button1pushed = time+150;
if (Button1pushed >= 1000) Button1pushed = (Button1pushe
d-999); //Overflow check
}
else{
Button1 = 0;
Button1pushed = 1050;
}
}
//Check for both buttons pushed together (within 20ms) to toggle
scroll mode off & on
//first check the time difference between the button pushes.
if (Button1pushed > Button0pushed) ButtonTimeDiff = Button1pushed - Butt
on0pushed;
//else ButtonTimeDiff = Button0pushed - Button1pushed;
if (ButtonTimeDiff <= 80 && (Button0pushed!= 1050) && Button1pushed!=105
0){//Less than 20ms
ScrollState = ~ScrollState; //Toggle the scroll state
//Note that a 255 => scr
olling and a 0 => normal button functionality
}
//Safety conditions:
portb_cycle = 0;
}
queuePut(mouse_byte1);
queuePut(Xmove);
queuePut(Ymove);
/* new code */
if (ScrollState != 0 && Button0 == 1) {
scroll_byte = 4;
}
if (ScrollState != 0 && Button1 == 1) {
scroll_byte = -4;
}
queuePut(scroll_byte);
/*prev_byte1 = mouse_byte1;
prev_byte2 = Xmove;
prev_byte3 = Ymove;*/
}
prev_byte1 = mouse_byte1;
prev_byte2 = Xmove;
prev_byte3 = Ymove;
// reset state variables for this loop
}
}
}