User Tools

Site Tools


info:click_here

/* ECE 476 Final Project * Austin S. Lu & Albert Ren * asl45 awr8 */

#include <mega32.h> #include <stdio.h> #include <stdlib.h> for ltoa #include <delay.h> #asm .equ __lcd_port=0x15 #endasm #include <lcd.h> Bruce's definitions #define begin { #define end }

Define the states for the state machine #define Command 0 #define DecodeCommand 1 #define Send 2 #define button_release 3 #define hold 4 #define Receive 5 int state = 0; Define the commands we support MODE 2 iPod Remote Functions #define play 0x01 #define volup 0x02 #define voldown 0x04 #define skipfwd 0x08 #define skipback 0x10 #define menu 0x40 #define select 0x80 MODE 4 Advanced Remote #define type 0x12 #define name 0x14 #define current 0x1e #define title 0x20 #define artist 0x22 #define album 0x24

MODE 4 Send Commands #define Switch 0 #define GetTrack 1 #define UseTrack 2 #define SwitchtoMode2 3 #define SendPlay 4 Information on the Apple Accessory Protocol can be found at http://ipodlinux.org/Apple_Accessory_Protocol Here are some variables that we'll need char mstime = 0; char header1 = 0xff; char header2 = 0x55; char length; char mode=0x02; char command[2]; int checksum; int index = 0; int debouncecounter = 0; char lastpress = 0; char press = 0; int timeout = 0; unsigned long currentsong; int param_length = 0;

Here are the flags we're using char validcommand = 0; char commandtype = 0; char stopflag = 0; char releaseflag = 0; char transmitdone_flag = 0; char mode4flag = 0; unsigned char switchmode[16] = {0xff, 0x55, 0x03, 0x00, 0x01, 0x04, 0xF8, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; unsigned char switchback[16] = {0xff, 0x55, 0x03, 0x00, 0x01, 0x02, 0xFA, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; unsigned char currenttrackcommand[16] = {0xff, 0x55, 0x03, 0x04, 0x00, 0x1E, 0xDB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; int tempchecksum; unsigned char t_buffer_temp[16]; For LCD displays unsigned char lcdbuffer[50]; unsigned int lcdbufferlength = 16; unsigned int lcdstart = 0; int lcdtime = 0;

char hold_timer = 0; int timeoutcounter = 0; int failurecount = 0; int mode4sequence = 0;

variables we use for transmitting unsigned char t_index; current string index unsigned char t_buffer[16]; output string unsigned char t_ready; flag for transmit done unsigned char t_char; current character RXC ISR variables unsigned char r_index=0; current string index unsigned char r_buffer[128]; input string unsigned char r_ready; flag for receive done unsigned char r_char; current character unsigned char r_checksum; received checksum unsigned char prev_char = 0; unsigned char start_checksum = 0; unsigned char r_length = 0xF5; Functions we use void initialize(void); void puts_int(void); void buttons (void); void gets_int(void); void lcd_scroll(void);

timer 0 overflow ISR interrupt [TIM0_COMP] void timer0_overflow(void) begin mstime++; lcdtime ++; end UART xmit-empty ISR TRANSMITS LSB FIRST (Little Endian is stupid!) http://en.wikipedia.org/wiki/Serial_port interrupt [USART_DRE] void uart_send(void) {

t_index++;
  t_char = t_buffer[t_index];
  if(t_char == (char)checksum){//at this point, we know what the end is
      UDR = t_char;
      stopflag = 1;
      stopflag = 0;
      UCSRB.5=0; //kill isr
	t_ready=1; //transmit done
	checksum = 0;
  }
  else	{UDR = t_char;}     //send the char

}

UART character-ready ISR interrupt [USART_RXC] void uart_rec(void) begin r_char=UDR; get a char

	//build the input string
	//iPod takes the form of 0xFF 0x55 Data Checksum
	//We are assuming idle high, so we should check for 0x55 instead
if((r_char == (char)(r_checksum & 0xff)) && ((r_index-3)==r_length)) {
	r_ready=1;				   	//signal cmd processor
	UCSRB.7=0;   				//stop rec ISR
      start_checksum = 0;
  }
  if(start_checksum == 1) {
  	r_checksum = r_checksum - r_char;
  }
  if(r_char == 0x55 && prev_char == 0xff) {
  	start_checksum = 1;
      r_checksum = 0x100;
  }
  r_buffer[r_index]=r_char;
  if(r_index == 2) //Make the length so!
  	r_length = r_buffer[r_index];
  r_index++;
prev_char = r_char;

end

void main(void) begin

  int k, temp, ReturnToSender;
  unsigned char songnumber;

State machine updates every ms for now initialize(); while(1) begin if(lcdtime >= 300) { lcdtime = 0; lcd_scroll(); } if(mstime) begin buttons(); mstime = 0; switch (state) begin case(Command): check if there's a command. If so, we will decode it

              mode4sequence = Switch;
              timeoutcounter = 0;
              failurecount = 0;
              if(validcommand == 1)
              begin
                  validcommand = 0;
                  state = DecodeCommand;
              end
              if((releaseflag == 1) && (validcommand == 0) && (mode == 0x02)) //the button was released
              begin
              	releaseflag = 0;
                  state = button_release;
              end
              break;
              case(DecodeCommand):
                //We must decode the command! If statements galore!
                t_buffer[0] = header1; //0xff
                t_buffer[1] = header2; //0x55
                  if((mode == 0x02) || (commandtype == current))
                  {
                     length = 0x03;
                  }
                  else
                  begin
                      length = 7; //Otherwise length is 7 bytes, cause it's a mode 4 command
                  end
                t_buffer[2] = length;
                t_buffer[3] = mode;
                  if(mode == 0x04)
                  {
                     mode4flag = 1;
                  }
                t_buffer[4] = 0x00; //Beginning of command
                if(commandtype == play)
                    t_buffer[5] = play;
                if(commandtype == volup)
                    t_buffer[5] = volup;
                if(commandtype == voldown)
                    t_buffer[5] = voldown;
                if(commandtype == skipfwd)
                    t_buffer[5] = skipfwd;
                if(commandtype == skipback)
                    t_buffer[5] = skipback;
                if(commandtype == album)
                   t_buffer[5] = album;
                if(commandtype == title)
                   t_buffer[5] = title;
                  if (commandtype == artist)
                   t_buffer[5] = artist;
               if((mode == 0x04) && (commandtype != current)) //We need to send ipod the current song
               begin
                   t_buffer[6] = (currentsong >> 24) & 0xff ; //& with 0xFF cause we're cautious people!
                   t_buffer[7] = (currentsong >> 16) & 0xff;
                   t_buffer[8] = (currentsong >> 8) & 0xff;
                   t_buffer[9] = currentsong & 0xff;
                   param_length = 4; //Mode 4 and Mode 2 have different lengths
               end
                for (index = 2; index < 6 + param_length; index ++) { //for checksum
                    checksum = checksum + t_buffer[index];
                }
                checksum = (0x100 - checksum & 0xff);
                t_buffer[6+param_length] = (char) checksum & 0xff; //as a char */
                param_length = 0; //We always reset to Mode 2 commands
                state = Send;
              break;
              case(Send):
                stopflag = 0;
                timeoutcounter = 0;
                if (mode == 0x02)
                begin
					puts_int();
					commandtype = 0;
					state = Command;
                end
                  //Otherwise, the command is going to depend on
                  //switching the iPod into Mode 4 zone
                  //So, first we switch
                  else
                  begin
                  	//Switch to Mode 4
                      if((mode4sequence == Switch))
                      begin
                         for(k=0; k<16; k++)
                         begin
                              //t_buffer_temp holds original mode4 command
                              t_buffer_temp[k] = t_buffer[k];
                              t_buffer[k] = switchmode[k];
                         end
                         tempchecksum = checksum;
                         checksum = 0xF8; //Mode switching checksum
                         //Now send the sucker
                         stopflag = 0;
                         puts_int();
                         state = Receive; //Now we receive a response
                      end
                      //Now we gotta get the current song
                      if(mode4sequence == GetTrack)
                      begin
                         for(k = 0; k<16; k++)
                         begin
                             //Put in the current command!
                             t_buffer[k] = currenttrackcommand[k];
                         end
                         checksum = 0xDB; //Current track checksum
                         stopflag = 0;
                         puts_int();
                         state = Receive; //Now we receive a response
                      end
                      //Now we send the command we wanted to send!
                      if(mode4sequence == UseTrack)
                      begin
                         for (k=0; k<16; k++)
                         begin
                             t_buffer[k] = t_buffer_temp[k];
                             //Bring back the real command
                         end
                         //Placing the current song into the command
                         //& with 0xFF cause we're SCARED!
                         t_buffer[6] = (currentsong >> 24) & 0xff;
                         t_buffer[7] = (currentsong >> 16) & 0xff;
                         t_buffer[8] = (currentsong >> 8) & 0xff;
                         t_buffer[9] = currentsong & 0xff;
                         //recreating the checksum
                         for (index = 2; index < 10; index ++)
                         begin
                             checksum = checksum + t_buffer[index];
                         end
                         checksum = (0x100-checksum)&0xFF;
                         t_buffer[10] = (char)checksum;
                         //Now we transmit the command we wanted!
                         stopflag = 0;
                         puts_int();
                         state = Receive;
                      end
                      //Switch back to mode 2
                      if(mode4sequence == SwitchtoMode2)
                      begin
                         for(k=0; k<16; k++)
                         begin
                             t_buffer[k] = switchback[k];
                         end
                         checksum = 0xFA; //This is the checksum
                         stopflag = 0;
                         puts_int();
                         state = Receive;
                      end
                  end
              break;
              case(Receive):
                  //Before we can receive, we need to wait for transmission to complete
                  while(!t_ready){};
				if(mode4sequence == SwitchtoMode2)
                  begin
                      //Success!
                      failurecount = 0;
                      mode4sequence = Switch; //Originally Switch
                      state = Command;
                  end
                  if(mode4sequence == Switch)
                  begin
                      if(timeoutcounter >= 1000) {
                      	mode4sequence = GetTrack;
                      	state = Send;
                          timeoutcounter = 0;
                    	}
                  end
                  timeoutcounter ++;
                  //Base case: timeoutcounter = 1000 or we failed 5x
                  if(timeoutcounter >= 2000 || failurecount >= 5)
                  begin
                      failurecount = 0;
                      timeoutcounter = 0;
                      if(mode4sequence != SwitchtoMode2)
                      begin
                          //Try to bring it back to initial conditions
                          mode4sequence = SwitchtoMode2;
                          state = Send;
                      end
                      else
                      begin
                          //Looks like all hope is lost.
                          mode4sequence = Switch;
                          state = Command;
                      end
                  end
                  //Otherwise, we're still waiting to receive stuff
                  if(r_ready)
                  begin
                      //r_index holds the last thing
                      //What did we receive? Depends on the sequence
                      if(mode4sequence == UseTrack)
                      begin
                          //Check for success
                          if((r_buffer[4] == 0x00) && ((r_buffer[5] != 0) || (r_buffer[5] != 1)))
                          begin
                              failurecount = 0;
                              //the string is null terminated and starts at r_buffer[6]
                              lcd_clear();
                              lcd_gotoxy(0,0);
                              lcd_putsf("Num ");
                              ltoa(currentsong+1,&songnumber);
                              lcd_puts(&songnumber);
                              lcd_putsf(" - ");
                              //Declare artist, album, or title
                              if(r_buffer[5] == 0x21)
                                  lcd_putsf("Title ");
                              if(r_buffer[5] == 0x23)
                                  lcd_putsf("Artist");
                              if(r_buffer[5] ==0x25)
                                  lcd_putsf("Album ");
                              lcdbufferlength = r_index - 8;
                              lcdstart = 0;
                              for(k=6; k< 6+lcdbufferlength; k++)
                              {
                                  lcdbuffer[k-6] = r_buffer[k];
                              }
                              lcdbufferlength = lcdbufferlength+1;
                              lcdbuffer[lcdbufferlength-1] = ' ';
                              lcdbuffer[lcdbufferlength] = ' ';
                              lcdbufferlength = lcdbufferlength + 1;
                              state = Send;
                              mode4sequence = SwitchtoMode2;
                          end
                          else
                          begin
                          //Failure!
                              failurecount ++;
                              state = Send;
                          end
                      end
                      if(mode4sequence == GetTrack)
                      begin
                          if((r_buffer[3] == 0x04) && (r_buffer[4]==0x00) && (r_buffer[5] == 0x1f))
                          begin
                              failurecount = 0;
                              currentsong = r_buffer[6];
                              currentsong = (currentsong << 8) | r_buffer[7];
                              currentsong = (currentsong << 8) | r_buffer[8];
                              currentsong = (currentsong << 8) | r_buffer[9];
                              state = Send;
                              mode4sequence = UseTrack;
                          end
                          else //FAILURE!
                          begin
                              failurecount++;
                              state = Send;
                          end
                      end
                      gets_int(); //Start listening for the Serial TX again!
                  end
              break;
              case(button_release): //Send a button release;
				t_buffer[0] = header1; //0xff
                t_buffer[1] = header2; //0x55
                t_buffer[2] = length;  //0x03 at the moment (not always true)
                t_buffer[3] = 0x02; //This is the mode we support right now. TWO
                t_buffer[4] = 0x00; //Beginning of command
                  t_buffer[5] = 0x00; //button release command
                  checksum = 0xFB;
                t_buffer[6] = 0xFB; //as a char, should be 0xfb here
                  state= Send;
              break;
          end
      end
  end

end

void buttons(void) {

  press = ~PINA;
  if((press != lastpress) && (lastpress == 0)) { // Start debouncing
      debouncecounter++;
      lastpress = press;
  }
  if((press == lastpress) && (lastpress != 0)) //Held button
      debouncecounter ++;
  if ((press != lastpress) && (lastpress != 0)) { //Released button
  	releaseflag = 1;
      validcommand = 0;
      debouncecounter = 0;
      lastpress = 0;
      press = 0;
  }
  if((debouncecounter >= 40) && (lastpress != 0)) { //40ms
      //we have a solid press
      validcommand = 1;
      debouncecounter = -460; //To account for a .5 second holding time, Vol+
      switch(press) {
          case(0x01):
              //Play
              commandtype = play;
              mode = 0x02;
          break;
          case(0x02):
              commandtype = volup;
              mode = 0x02;
          break;
          case(0x04):
              commandtype = voldown;
              mode = 0x02;
          break;
          case(0x08):
              commandtype = skipfwd;
              mode = 0x02;
          break;
          case(0x10):
              commandtype = skipback;
              mode = 0x02;
          break;
          case(0x20):
              commandtype = album;
              mode = 0x04;
          break;
          case(0x40):
              commandtype = title;
              mode = 0x04;
          break;
          case(0x80):
              commandtype = artist;
              mode = 0x04;
          break;
          default:
          	commandtype = 0;
          break;
      }
  }

}

Set it all up void initialize(void) begin DDRA = 0x00; PORT A is an input - button switches for now

  DDRB = 0xff; //PORTB LED output
  PORTB = 0xff; //LEDs off for our sanity
  //serial setup for debugging using printf, etc.
  UCSRB = 0x18 ;
  UBRRL = 51 ; //set the oscillator, we need 19200 baud for iPod comm.
  //set up timer 0
  OCR0=249;	   			//1 mSec
  TIMSK=2;	   			//turn on timer 0 cmp-match ISR
  TCCR0=0b00001011;		//prescalar to 64  and Clr-on-match
  lcd_init(16);      	//initialize the display
  lcd_clear();
  lcd_gotoxy(0,0);
  lcd_putsf("start");
  //crank up the ISRs
  #asm
    sei
  #endasm
  gets_int();   //Start listening on the serial port

end

void puts_int(void) {

t_ready=0;
t_index=0;
stopflag =0;
if (t_buffer[0]>0)
begin
	putchar(t_buffer[0]);
	UCSRB.5=1;
end

}

void gets_int(void) {

  r_ready = 0;
  r_index = 0;
  r_length = 0xF5;
  UCSRB.7 = 1;

}

void lcd_scroll(void){

  unsigned char displaybuffer[16];
  int lcd_index;
  lcd_gotoxy(0,1);
  lcd_putsf("                "); //We clear it for scrolling
  lcd_gotoxy(0,1);
  lcd_index=0;
  while(lcd_index<15)
  {
  	displaybuffer[lcd_index] = lcdbuffer[((lcdstart + lcd_index)%lcdbufferlength)];
      if(lcd_index>=lcdbufferlength) //Prevents repeating of small strings
      {
      	displaybuffer[lcd_index] = ' ';
      }
      lcd_index++;
  }
  displaybuffer[15] = 0x00;
  lcd_puts(&displaybuffer[0]);
  if(lcdbufferlength>16) //Prevents scrolling of small strings
    lcdstart = (lcdstart+1);

}

info/click_here.txt · Last modified: 2008/11/26 19:08 by tomgee