|
#include <Mega32.h>
#include <stdio.h>
#include <delay.h>
#include <string.h>
#define LCDwidth 16
//port A
#asm
.equ __lcd_port = 0x1B
#endasm
#include <lcd.h>
#define button0 0x01
#define button1 0x02
#define button2 0x04
#define button3 0x08
#define button4 0x10
#define button5 0x20
#define button6 0x40
#define button7 0x80
#define CHOICE 0
#define PLAY 1
#define STOP 2
#define PAUSE 3
#define VOLUMEUP 4
#define VOLUMEDOWN 5
#define RWD 6
#define FFWD 7
#define TOGGLE_MODE 8
#define NO_PUSH 0
#define MAYBE_PUSH 1
#define PUSHED 2
#define MAYBE_NO_PUSHED 3
#define PLAY_STATUS 0
#define SONG_TITLE 1
#define TIME_STATUS 2
#define PRINT_STATUS 3
#define PLAYLIST_PRINT 4
#define PRINT_PL_0 5
#define PRINT_PL_1 6
#define BITRATE 7
#define DOWN 0
#define UP 1
#define NONE 2
//mode defines
#define NORMAL 0
#define PLAYLIST 1
void debounce(int);
void init(void);
void toggleLED(unsigned int, char);
void checkStatus(void);
char * format(char[]);
unsigned char multi_space(char[]);
unsigned int pit_count;
unsigned char debounce_state;
unsigned char push_flag;
char debounced;
char adjust_done_flag;
char button_state;
char wait_for_input;
char status;
char c;
char cmd_str[250];
char song_title_full_prev[250];
char song_title_full[250];
char song_title_print[17];
char cmd_ready;
int char_count;
char play_status_str[6];
char lcd_buffer0[17];
char repeat_flag;
char mode;
char song_time[7];
unsigned char song_pos=0;
char pl_line0[17], pl_line1[17];
char bit_rate[6];
char output[12];
unsigned char counter, song_pos_timer;
unsigned int pl_pos;
unsigned int time_out_counter;
unsigned char start_counter;
unsigned char scroll;
//receive interrupt service routine
interrupt[USART_RXC] void uartRx(void)
{
c = UDR; //copy character from UDR to global C
if(c!='\v') cmd_str[char_count++] = c;
else
{
cmd_str[char_count] = 0;
cmd_ready = 1;
UCSRB.7 = 0; //kill interrupt until software is ready
}
}
//init Rx interrupt servicing
void get_cmd_init(void)
{
char_count = 0;
cmd_ready = 0;
UCSRB.7 = 1; //enable Rx interrupt
time_out_counter=0;
start_counter=1;
}
//main function
void main(void)
{
int x;
//init variables
init();
while(1)
{
//poll for button presses
switch (button_state)
{
case CHOICE:
if (~PINB == 0x0) break; //no button pushed
else if(~PINB == button6)
{
toggleLED(button6, 'C');
button_state = PLAY;
}
else if(~PINB == button5 && mode==NORMAL)
{
toggleLED(button5, 'C');
button_state = PAUSE;
}
else if(~PINB == button4 && mode==NORMAL)
{
toggleLED(button4, 'C');
button_state = STOP;
}
else if(~PINB == button2)
{
toggleLED(button2, 'C');
button_state = VOLUMEUP;
}
else if(~PINB == button1)
{
toggleLED(button1, 'C');
button_state = VOLUMEDOWN;
}
else if(~PINB == button7 && mode==NORMAL)
{
toggleLED(button7, 'C');
button_state = RWD;
}
else if(~PINB == button3 && mode==NORMAL)
{
toggleLED(button3, 'C');
button_state = FFWD;
}
else if(~PINB == button0)
{
button_state = TOGGLE_MODE;
}
break;
case PLAY:
if (pit_count%30 == 0) debounce(button6);
if (mode==NORMAL)
{
if (debounced)
{
putchar('1');
button_state = CHOICE;
debounced = 0;
toggleLED(button6, 'C');
}
}
else if (mode==PLAYLIST)
{
//play the current song viewed on the playlist
if (debounced)
{
putchar('m');
button_state = CHOICE;
debounced = 0;
mode = NORMAL;
toggleLED(button6, 'C');
}
}
break;
case PAUSE:
if (pit_count%30 == 0) debounce(button5);
if (debounced)
{
putchar('3');
button_state = CHOICE;
debounced = 0;
toggleLED(button5, 'C');
}
break;
case STOP:
if (pit_count%30 == 0) debounce(button4);
if (debounced)
{
putchar('2');
button_state = CHOICE;
debounced = 0;
toggleLED(button4, 'C');
}
break;
//volume up and scroll up in playlist mode
case VOLUMEUP:
if (pit_count%30 == 0) debounce(button2);
if(mode==NORMAL)
{
if (push_flag)
{
if(pit_count%100 == 0)
{
putchar('4');
//delay to prevent putchar from occuring mutliple times on the same tick
delay_ms(1);
}
}
else if(debounced)
{
button_state = CHOICE;
debounced = 0;
toggleLED(button2, 'C');
}
}
else if (mode==PLAYLIST)
{
//scroll playlist up
if(debounced)
{
//scroll playlist up
scroll=UP;
button_state = CHOICE;
debounced = 0;
toggleLED(button2, 'C');
}
}
break;
//volume down and scroll down in playlist mode
case VOLUMEDOWN:
if (pit_count%30 == 0) debounce(button1);
if (mode==NORMAL)
{
if (push_flag)
{
if(pit_count%100 == 0)
{
putchar('5');
//delay to prevent putchar from occuring mutliple times on the same tick
delay_ms(1);
}
}
else if(debounced)
{
button_state = CHOICE;
debounced = 0;
toggleLED(button1, 'C');
}
}
else if(mode==PLAYLIST)
{
//scroll playlist down
if(debounced)
{
//scroll playlist down
scroll = DOWN;
button_state = CHOICE;
debounced = 0;
toggleLED(button1, 'C');
}
}
break;
//fast forward and skip to next song
case FFWD:
if (pit_count%30 == 0) debounce(button3);
if (push_flag)
{
if(pit_count%400 == 0)
{
putchar('d');
repeat_flag = 1;
//delay to prevent putchar from occuring mutliple times on the same tick
delay_ms(1);
}
}
else if(debounced)
{
if(repeat_flag == 0)
putchar('b');
else repeat_flag = 0;
button_state = CHOICE;
debounced = 0;
toggleLED(button3, 'C');
}
break;
//rewind and skip to prev song
case RWD:
if (pit_count%30 == 0) debounce(button7);
if (push_flag)
{
if(pit_count%400 == 0)
{
putchar('e');
repeat_flag = 1;
//delay to prevent putchar from occuring mutliple times on the same tick
delay_ms(1);
}
}
else if(debounced)
{
if(repeat_flag == 0)
putchar('c');
else repeat_flag = 0;
button_state = CHOICE;
debounced = 0;
toggleLED(button7, 'C');
}
break;
//change mode between playlist and normal mode
case TOGGLE_MODE:
if (pit_count%30 == 0) debounce(button0);
if (debounced)
{
if(mode==PLAYLIST)
{
mode = NORMAL;
//set the start state of print to the play status
status = PLAY_STATUS;
}
else
{
mode=PLAYLIST;
//set the start state of print to print the playlist
status = PLAYLIST_PRINT;
}
button_state = CHOICE;
debounced = 0;
toggleLED(button0, 'C');
}
break;
}
//call check status every 50ms
if(pit_count%50==0)
checkStatus();
}
}
//this function is the LCD routines.
//it retrieves the needed info fromt the plugin
//and spits it out to the LCD one piece at a time
void checkStatus()
{
unsigned char x;
switch(status)
{
case PLAY_STATUS:
//not waiting for any input
if(wait_for_input == 0)
{
get_cmd_init();
putchar('7'); //send status request
wait_for_input = 1;
}
//data is ready to be read
if(cmd_ready==1)
{
sprintf(play_status_str,"%-s", format(cmd_str));
play_status_str[5]=0;
lcd_gotoxy(0,1);
lcd_puts(play_status_str);
wait_for_input = 0;
status = SONG_TITLE;
start_counter = 0;
}
break;
case SONG_TITLE:
//not waiting for any input
if(wait_for_input == 0)
{
get_cmd_init();
putchar('h'); //send songtitle request
wait_for_input = 1;
}
//data is ready to be read
if(cmd_ready==1)
{
strcpy(song_title_full,cmd_str); //copy the input data to the song title
//if same song is still playing and the whol
//e or at least the end of the title didn't show last time
if(song_pos_timer==10)
{
counter++;
if(counter==2)
{
if(strcmp(song_title_full, song_title_full_prev)==0
&& strpos(song_title_full_prev,'\0')>16 && multi_space(song_title_print)==0)
{
//change index so the song will seem to scroll
song_pos++;
}
//reset index
else
{
song_pos=0;
song_pos_timer=0;
}
counter = 0;
}
}
else song_pos_timer++;
//copy the first 16 characters of the song title.
for(x=0;x<16;x++)
{
song_title_print[x]=song_title_full[x+song_pos];
}
song_title_print[16]=0; //null terminate the string
strcpy(song_title_full_prev,song_title_full);
sprintf(lcd_buffer0,"%-s", format(song_title_print));
lcd_buffer0[16]=0;
lcd_gotoxy(0,0);
lcd_puts(lcd_buffer0);
wait_for_input = 0;
status = TIME_STATUS;
start_counter = 0;
}
break;
case TIME_STATUS:
if(wait_for_input == 0)
{
get_cmd_init();
putchar('g'); //send songtitle request
wait_for_input = 1;
}
//data is ready to be read
if(cmd_ready==1)
{
sprintf(song_time, " %s",cmd_str);
wait_for_input=0;
status = BITRATE;
start_counter = 0;
}
break;
case BITRATE:
if(wait_for_input == 0)
{
get_cmd_init();
putchar('9'); //send bitrate request
wait_for_input = 1;
}
//data is ready to be read
if(cmd_ready==1)
{
sprintf(bit_rate, "%s",cmd_str);
bit_rate[5]=0;
sprintf(output, "%s %s",song_time,bit_rate);
lcd_gotoxy(5,1);
lcd_puts(output);
wait_for_input=0;
status = PRINT_STATUS;
start_counter = 0;
}
break;
case PLAYLIST_PRINT:
//if(pit_count%300==0){
if(wait_for_input == 0)
{
get_cmd_init();
if(scroll==NONE)
{
putchar('l');
}
else if(scroll==DOWN)
{
putchar('j');
}
else if(scroll==UP)
{
putchar('k');
}
scroll = NONE;
wait_for_input = 1;
}
//data is ready to be read
if(cmd_ready==1)
{
for(x=0;x<16;x++)
{
pl_line0[x]=cmd_str[x];
pl_line1[x]=cmd_str[x+16];
}
pl_line0[16]=0;
pl_line1[16]=0;
wait_for_input=0;
status = PRINT_PL_0;
start_counter = 0;
}
break;
//print first song of playlist
case PRINT_PL_0:
lcd_gotoxy(0,0);
lcd_puts(pl_line0);
status = PRINT_PL_1;
break;
//print second song of playlist
case PRINT_PL_1:
lcd_gotoxy(0,1);
lcd_puts(pl_line1);
status = PRINT_STATUS;
break;
//resest to beginning state
case PRINT_STATUS:
if(mode == PLAYLIST)
status = PLAYLIST_PRINT;
else status = PLAY_STATUS;
break;
}
}
//remove all null characters and replace with spaces
char * format(char string[])
{
char x=0;
char y;
while(string[x]!='\0')
x++;
for(y=x;y<16;y++)
string[y]=' ';
string[16]=0;
return string;
}
//count the num of consecutive empty spaces
//used for song scrolling
unsigned char multi_space(char string[])
{
unsigned char x, count=0;
for(x=13;x<16;x++)
{
if(string[x]==' ')
count ++;
}
if(count==3)
return 1;
else return 0;
}
//debounce button
//30ms ticks
void debounce(int button)
{
switch(debounce_state)
{
case NO_PUSH:
if(~PINB == button) debounce_state=MAYBE_PUSH;
break;
case MAYBE_PUSH:
if(~PINB == button)
{
debounce_state=PUSHED;
push_flag=1;
}
else debounce_state=NO_PUSH;
break;
case PUSHED:
if(~PINB == button){}
else debounce_state=MAYBE_NO_PUSHED;
break;
case MAYBE_NO_PUSHED:
if(~PINB == button) debounce_state=PUSHED;
else
{
push_flag=0;
debounce_state=NO_PUSH;
debounced = 1; //flag set when completely debounced
}
break;
}
}
//timer 0 interrupt service routine
interrupt [TIM0_COMP] void timer0_compare(void)
{
//1ms ticks
pit_count++; //counter for checking debounce state machine
//timeout counter
if(start_counter==1)
time_out_counter++;
//if timeout
if(time_out_counter==500)
{
//disable interrupt for now
UCSRB.7 = 0;
TIMSK=0;
//re-init
init();
}
}
//function to toggle leds.
//easy to use, takes out some complexity in
//writing code
void toggleLED(unsigned int led, char port)
{
if(port=='a' || port=='A')
PORTA = PORTA^led;
if(port=='b' || port=='B')
PORTB = PORTB^led;
if(port=='c' || port=='C')
PORTC = PORTC^led;
}
void init(void)
{
//set up the ports
DDRD=0x00; // PORT D is an input
DDRB=0x00; // PORT B is an input - buttons
PORTB=0xff; // PORT B off
DDRC=0xff; // PORT C is output - LEDs
PORTC=0xff; //port c is off
DDRA=0xff;
//USART
UCSRB = 0x18;
UBRRL = 103;
//set up timer 0
TIMSK=2;
OCR0 = 250; //set the compare re to 250 time ticks
TCCR0=0b00001011;
wait_for_input = 0;
status = PLAY_STATUS;
repeat_flag=0;
mode = NORMAL;
scroll = NONE;
pit_count=0;
counter = 0;
song_pos_timer=0;
start_counter = 0;
time_out_counter = 0;
debounced=0; //button is debounced
adjust_done_flag=0; //done making changes to freq
debounce_state = NO_PUSH;
button_state = CHOICE;
lcd_init(LCDwidth);
lcd_gotoxy(0,0);
lcd_putsf("WinAmp Cont v1.0");
lcd_gotoxy(0,1);
lcd_putsf(" no connection");
//crank up the ISRs
#asm
sei
#endasm
} |
|
|