
#include <hidef.h>      /* common defines and macros */
#include <mc9s12dg256.h>     /* derivative information */
#pragma LINK_INFO DERIVATIVE "mc9s12dg256b"

#include "main_asm.h" /* interface to the assembly module */

/*

EGR280 TETRIS PROJECT
M. Bowers, N. Griffith, I. Lubinski, G. Setter

This program contains a basic Tetris game controlled via accelerometer and a button for rotate. It sends out delta-encoded commands concerning the state of a 20x10 Tetris array to an FPGA over a 57600bps RS-232 link. The FPGA then outputs the game in 640x480 with 3-bit color via VGA signals.

Portions of this code based off of examples in:
"Learning by Example Using C: Programming the Dragon12-Plus using CodeWarrior"
by Richard Haskell and Darrin Hanna

Aside from use of code present in the course textbook, the code below is entirely original and was arrived at by observing the real Tetris in gameplay.

*/

// MUSIC VARIABLES
# define  AAf     3612   // A flat
# define  AA      3409
# define  BB      3038      
# define  c       2867
# define  d       2554
# define  e       2276
# define  f       2148
# define  g       1914
# define  a       1705
# define  af      1806   // A flat
# define  b       1519
# define  C       1434
# define  D       1277
# define  E       1138
# define  F       1074
# define  G       947
# define  A       853

/*
   NOTES
   -----

                          -O-  A
                         O   G
-----------------------O---F
                     O   E
-------------------O---D---
                 O   C
---------------O---b-------            | TREBLE |
             O   a     (af) = A flat   | CLEF   |
-----------O---g-----------
         O   f
-------O---e---------------
     O   d
  -O-  c
  
                     O   BB
-------------------O---AA---   (AAf) = A flat
                 O
---------------O------------         
             O                        |  BASS  |
-----------O----------------          |  CLEF  |
         O
-------O--------------------
     O
---O------------------------  
 O
 
 Note: 0 (zero) indicates a rest.


 */


int dtime; // delay time
int ix;    // index into states
int pitch;
int tempo = 10; // smaller is faster!
const int numstates = 186; // length of the song

// "Mary had a Little Lamb" - Test Song
//const int notes[50] = {0, b, a, g, a, b, b, b, 0, a, a, a, 0, b, b, b, 0, b, a, g, a, b, b, b, 0, a, a, b, a, g};
//const int times[50] = {1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4};

// "Korobeiniki" - Russian Folk Song and Tetris music on original Game Boy
const int notes[200] = {E, b, C, D, E, D, C, b, a, a, C, E, D, C, b, C, D, E, /*line2*/ C, a, a, 0, D, D, F, A, G, F, E, C, E, D, C, /*line3*/ b, b, C, D, E, C, a, a, 0, E, b, C, D, E, D, C, b, /*line4*/ a, a, C, E, D, C, b, C, D, E, C, a, a, /*line5*/ 0, D, D, F, A, G, F, E, C, E, D, C, b, b, C, D, E, /*line6*/ C, a, a, 0, e, c, d, BB, c, BB, /*line7*/ AAf, e, c, d, AAf, BB, 0, c, e, a, /*line8*/ af, 0, E, b, C, D, E, D, C, b, a, a, C, E, D, C, /*line9*/ b, C, D, E, C, a, a, 0, D, D, F, A, G, F, E, C, E, D, C, /*line10*/ b, b, C, D, E, C, a, a, 0, E, b, C, D, E, D, C, b, /*line11*/ a, a, C, E, D, C, b, C, D, E, C, a, a, /*line12*/ D, D, F, A, G, F, E, C, E, D, C, b, b, C, D, E, /*line13*/ C, a, a, 0};
const int times[200] = {4, 2, 2, 2, 1, 1, 2, 2, 4, 2, 2, 4, 2, 2, 6, 4, 4, 4, /*line2*/ 4, 4, 8, 2, 4, 2, 2, 4, 2, 2, 6, 4, 4, 2, 2, /*line3*/ 4, 2, 2, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 1, 1, 2, 2, /*line4*/ 4, 2, 2, 4, 2, 2, 6, 4, 4, 4, 4, 4, 8, /*line5*/ 2, 4, 2, 2, 4, 2, 2, 6, 4, 4, 2, 2, 4, 2, 2, 4, 4, /*line6*/ 4, 4, 4, 4, 8, 8, 8, 8, 8, 8,   /*line7*/   8, 8, 8, 8, 8,   4 , 4, 4, 4, 8, /*line8*/ 8, 8, 4, 2, 2, 2, 1, 1, 2, 2, 4, 2, 2, 4, 2, 2, /*line9*/ 6, 4, 4, 4, 4, 4, 4, 2, 4, 2, 2, 4, 2, 2, 4, 4, 4, 2, 2, /*line10*/ 4, 2, 2, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 1, 1, 2, 2, /*line11*/4, 2, 2, 4, 2, 2, 6, 4, 4, 4, 4, 4, 4, /*line12*/ 4, 2, 2, 4, 2, 2, 6, 4, 4, 2, 2, 4, 2, 2, 4, 4, /*line134,*/4, 4, 4, 4};



// Some GAME STUFF
int score=0;
int newscore=0; 

char flipstate=0;

char drawflag=0;  //  DRAW FLAG IS RAISED ONLY IF THERE IS A CHANGE THAT NEEDS WRITING!



// VARIOUS COUNTERS
int i=0;
int j=0;
int k=0;

int row=0;
int column=0;

int srcrow=0;
int dstrow=0;

int removeline;

int input=0;
int index=0;

// SHAPES




char cshape[4][4]=       // stores current shape
                       {{0, 0, 0, 0}, // 0
                        {0, 0, 0, 0}, // 1
                        {0, 0, 0, 0}, // 2
                        {0, 0, 0, 0}}; // 3

char src_shape[4][4]=       // temp
                       {{0, 0, 0, 0}, // 0
                        {0, 0, 0, 0}, // 1
                        {0, 0, 0, 0}, // 2
                        {0, 0, 0, 0}}; // 3
                        
char dst_shape[4][4]=       // temp
                       {{0, 0, 0, 0}, // 0
                        {0, 0, 0, 0}, // 1
                        {0, 0, 0, 0}, // 2
                        {0, 0, 0, 0}}; // 3
                                                
                                                                       
char shapetemp_v[4][4]=   // stores temp shape data (before rotation)
                       {{0, 0, 0, 0}, // 0
                        {0, 0, 0, 0}, // 1
                        {0, 0, 0, 0}, // 2
                        {0, 0, 0, 0}}; // 3
                        
char shapetemp_r[4][4]=   // stores temp shape data (after rotation)
                       {{0, 0, 0, 0}, // 0
                        {0, 0, 0, 0}, // 1
                        {0, 0, 0, 0}, // 2
                        {0, 0, 0, 0}}; // 3                        
                        
char s0[4][4]=                        //  (test shape)
                       {{1, 1, 1, 1}, //    [][][][] 
                        {1, 1, 0, 1}, //    [][]  [] 
                        {1, 0, 1, 1}, //    []  [][]
                        {1, 0, 0, 1}}; //   [][][][]
                        
char s1[4][4]=                          
                       {{1, 0, 0, 0}, //    []    [][][][]
                        {1, 0, 0, 0}, //    []
                        {1, 0, 0, 0}, //    []
                        {1, 0, 0, 0}};//    []
                        
char s2[4][4]=                          
                       {{0, 0, 0, 0}, //
                        {0, 0, 0, 0}, //          []
                        {0, 1, 1, 0}, //   [][]   [][]
                        {1, 1, 0, 0}};// [][]       []
                        
char s3[4][4]=                          
                       {{0, 0, 0, 0}, //
                        {0, 0, 0, 0}, //            []
                        {1, 1, 0, 0}, // [][]     [][]
                        {0, 1, 1, 0}};//   [][]   []
                        
char s4[4][4]=                          
                       {{0, 0, 0, 0}, //
                        {0, 1, 0, 0}, //   []             []
                        {1, 1, 0, 0}, // [][]      []     [][]    [][][]
                        {0, 1, 0, 0}}; //  []    [][][]   []        []             

char s5[4][4]=                          
                       {{0, 0, 0, 0}, //
                        {0, 0, 0, 0}, // 
                        {1, 1, 0, 0}, // [][]
                        {1, 1, 0, 0}};// [][]        

char s6[4][4]=                          
                       {{0, 0, 0, 0}, //
                        {0, 0, 0, 0}, //           [][]               []
                        {1, 0, 0, 0}, //  []       []      [][][]     []
                        {1, 1, 1, 0}};//  [][][]   []          []   [][]
                        
char s7[4][4]=                          
                       {{0, 0, 0, 0}, //
                        {0, 0, 0, 0}, //           []               [][]
                        {0, 0, 1, 0}, //      []   []      [][][]     []
                        {1, 1, 1, 0}};//  [][][]   [][]    []         []                        
                        

void moveshape(char src_shape[4][4], char dst_shape[4][4]){

for(i=0;i<=3;i++){
  for(j=0;j<=3;j++){
    dst_shape[i][j] = src_shape[i][j];
  }
}


}


// VIDEOBUFF - keeps a copy of what's stored in the video controller
char videobuff[20][10]=
                       {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 0
                        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 1
                        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 2
                        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 3
                        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 4
                        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 5
                        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 6
                        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 7
                        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 8
                        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 9
                        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 10
                        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 11
                        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 12
                        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 13
                        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 14
                        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 15
                        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 16
                        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 17
                        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 18
                        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}};// 19 
                        

void clearvideobuff(void){

  for(row = 0; row<=19; row++){
    for (column = 0; column<=9; column++){
         videobuff[row][column] = 0;
       }
    }
  }  


                        
// DRAWBUFF - buffer to write changes to                      
char drawbuff[20][10]=
                       {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 0
                        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 1
                        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 2
                        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 3
                        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 4
                        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 5
                        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 6
                        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 7
                        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 8
                        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 9
                        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 10
                        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 11
                        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 12
                        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 13
                        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 14
                        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 15
                        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 16
                        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 17
                        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 18
                        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}};// 19

void cleardrawbuff(void){

  for(row = 0; row<=19; row++){
    for (column = 0; column<=9; column++){
         drawbuff[row][column] = 0;
       }
    }
  }  
                                        
char blockbuff[23][13]= // Note: Columns is set to 13 for blocks that may run over the side.

/*Array for the active (i.e. moving) block.*/

                       {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9}, // 0
                        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9}, // 1
                        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9}, // 2
                        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9}, // 3
                        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9}, // 4
                        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9}, // 5
                        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9}, // 6
                        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9}, // 7
                        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9}, // 8
                        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9}, // 9
                        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9}, // 10
                        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9}, // 11
                        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9}, // 12
                        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9}, // 13
                        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9}, // 14
                        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9}, // 15
                        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9}, // 16
                        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9}, // 17
                        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9}, // 18
                        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9}, // 19
                        {9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9}, // 20
                        {9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9}, // 21 
                        {9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9}}; // 22

char stuckbuff[23][13]= 

/*Array for block that are "stuck".*/

                       {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9}, // 0
                        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9}, // 1
                        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9}, // 2
                        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9}, // 3
                        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9}, // 4
                        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9}, // 5
                        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9}, // 6
                        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9}, // 7
                        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9}, // 8
                        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9}, // 9
                        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9}, // 10
                        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9}, // 11
                        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9}, // 12
                        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9}, // 13
                        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9}, // 14
                        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9}, // 15
                        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9}, // 16
                        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9}, // 17
                        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9}, // 18
                        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9}, // 19
                        {9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9}, // 20
                        {9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9}, // 21 
                        {9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9}}; // 22
                                                

void clearblockbuff(void){

/*This function goes through and clears the BLOCK array*/

  for(row = 0; row<=19; row++){
    for (column = 0; column<=9; column++){
         blockbuff[row][column] = 0;
       }
    }
  }
  
void stickblock(void){

/*This function takes a block in the BLOCK array and moves it into the STUCK array.
  
  Called when a piece needs to "stick" to the bottom of the screen.*/

  for(row = 0; row<=19; row++){
    for (column = 0; column<=9; column++){
         stuckbuff[row][column] = stuckbuff[row][column] | blockbuff[row][column];
       }
    }
  }    
                        
void drawblock(char shape[4][4], int row, int column){

/*This function reads from a shape array, then
copies it's contents into the block buffer.

"ROW" and "COLUMN" refer to the coords of the upper right corner of the block you want to draw.*/

  clearblockbuff(); // get rid of anything else in the block buffer  
  
  blockbuff[row+3][column+3] = shape[3][3];
  blockbuff[row+3][column+2] = shape[3][2];
  blockbuff[row+3][column+1] = shape[3][1];  
  blockbuff[row+3][column+0] = shape[3][0];
  
  blockbuff[row+2][column+3] = shape[2][3];
  blockbuff[row+2][column+2] = shape[2][2];
  blockbuff[row+2][column+1] = shape[2][1];  
  blockbuff[row+2][column+0] = shape[2][0];
  
  blockbuff[row+1][column+3] = shape[1][3];
  blockbuff[row+1][column+2] = shape[1][2];
  blockbuff[row+1][column+1] = shape[1][1];  
  blockbuff[row+1][column+0] = shape[1][0];  
  
  blockbuff[row+0][column+3] = shape[0][3];
  blockbuff[row+0][column+2] = shape[0][2];
  blockbuff[row+0][column+1] = shape[0][1];  
  blockbuff[row+0][column+0] = shape[0][0]; 
}
                       

char checkdrawblock(char shape[4][4], int row, int column){
/*
This function checks to see if it's "legit" to write a shape at some particular coordinates.

"ROW" and "COLUMN" refer to the coords of the upper right corner of the block you want to draw.
*/

 if(
 (stuckbuff[row+3][column+3] && shape[3][3]) ||
 (stuckbuff[row+3][column+2] && shape[3][2]) ||
 (stuckbuff[row+3][column+1] && shape[3][1]) || 
 (stuckbuff[row+3][column+0] && shape[3][0]) ||
 
 (stuckbuff[row+2][column+3] && shape[2][3]) ||
 (stuckbuff[row+2][column+2] && shape[2][2]) ||
 (stuckbuff[row+2][column+1] && shape[2][1]) ||  
 (stuckbuff[row+2][column+0] && shape[2][0]) ||
  
 (stuckbuff[row+1][column+3] && shape[1][3]) ||
 (stuckbuff[row+1][column+2] && shape[1][2]) ||
 (stuckbuff[row+1][column+1] && shape[1][1]) || 
 (stuckbuff[row+1][column+0] && shape[1][0]) ||
   
 (stuckbuff[row+0][column+3] && shape[0][3]) ||
 (stuckbuff[row+0][column+2] && shape[0][2]) ||
 (stuckbuff[row+0][column+1] && shape[0][1]) || 
 (stuckbuff[row+0][column+0] && shape[0][0])
 ) {
 return 0x00; // 0 = NO don't draw a shape there
 } 
 // else if(row > 16) { // 20 - 4 = 16
 //   return 0x00; // 0 = NO can't draw a shape this low
 // }
 
 else 
 {return 0x01;} // 1 = YES you can have a shape here
}

// Drop counters
int droptime=20;
int droptempo = 100;   // the current "drop tempo"
int droptempo_n = 100; // the normal drop tempo


char checkaline(int row){
  
         if ((stuckbuff[row][0] == 1) &&   // IF THE ROW IS FILLED
            (stuckbuff[row][1] == 1) &&
            (stuckbuff[row][2] == 1) &&                        
            (stuckbuff[row][3] == 1) &&
            (stuckbuff[row][4] == 1) &&
            (stuckbuff[row][5] == 1) &&
            (stuckbuff[row][6] == 1) &&
            (stuckbuff[row][7] == 1) &&
            (stuckbuff[row][8] == 1) &&
            (stuckbuff[row][9] == 1)) {

            newscore++;                    // increment the score
            
            if (score>50){                 // if score is greater than 50
              if (droptempo_n > 40){droptempo_n--;}} // make the drop tempo slightly faster with each line
                                                     // for a maximum speed of 40
                          
            return 0x01;                // RETURN 0x01 (YES)
            }
            
            else {
            return 0x00;               // OTHERWISE 0x00 (N0)
            }
              
            
       }
       
       
void killaline(int row){             // This function wipes out a particular row with zeros.
          stuckbuff[row][0] = 0;
          stuckbuff[row][1] = 0;
          stuckbuff[row][2] = 0;
          stuckbuff[row][3] = 0;
          stuckbuff[row][4] = 0;
          stuckbuff[row][5] = 0;
          stuckbuff[row][6] = 0;
          stuckbuff[row][7] = 0;
          stuckbuff[row][8] = 0;
          stuckbuff[row][9] = 0;
}
       
       
void movealine(int srcrow, int dstrow){     // This function moves Tetris lines around
 
 
       for (column = 0; column<=9; column++){
         stuckbuff[dstrow][column] = stuckbuff[srcrow][column];
         stuckbuff[srcrow][column] = 0;
       }
  
  
  
}


void checklines(void){    // This function goes through and checks for completed lines.

    for (j=0;j<=19;j++){   // Starts at top (0), work to bottom (19)
  
  if (checkaline(j)){      // If a line is complete

      killaline(j);        // Wipe out that line
      for (k=j;k>=1;k--){  // Start at that line, moving upwards
       movealine(k-1, k);  // Moving each line down
      }

  }
 }
}  
                     
void clearscreen (void){

/*This function sends over serial 0xF8, which is hardcoded to set all 200 blocks to zero.*/

 outchar1(0xF8); // send 0xF8, which clears video on the FPGA
 clearvideobuff(); // also clear Dragon12's copy of the buffer
}
                      
                      
void updatescreen(void){
                     
/*This function compares the contents of the drawbuff and videobuff arrays
and sends the difference over the RS-232 connection.*/
  
  for(row = 0; row<=19; row++){                               // go through the rows
    for (column = 0; column<=9; column++){                    // go through the columns
      if (drawbuff[row][column] != videobuff[row][column]){   // if block on DRAW is different from VIDEO
            if (((row*10) + (column))<=199){                  // check to make sure we're only sending commands for the 200 blocks        
            outchar1(0x30 + (row*10) + (column));             // send out serial bitmap toggle 
            // leds_on(0x30 + (row*10) + (column));              // also put it to the LEDs just for the hell of it
            }
           videobuff[row][column] = drawbuff[row][column];    // update the VIDEO array to reflect these changes

       }
    }
  }  
}

void videotest(void){

/*This function clears the screen, then tests all the blocks.*/

   clearscreen();
   
   for(i=0;i<=200;i++){
    outchar1(0x30+i);
    ms_delay(5);
   }
   
   clearscreen();
}
  

void updatedraw(void){

/*This function ORs the BLOCK and STUCK buffers together and puts the result in DRAW.*/

      for(row = 0; row<=19; row++){
    for (column = 0; column<=9; column++){
        if((blockbuff[row][column] == 1) | (stuckbuff[row][column] == 1)){  // If either BLOCK or STUCK are 1
           drawbuff[row][column] = 1;                                       // Make that pixel 1 on the DRAW
        }else{
           drawbuff[row][column] = 0;                                       // Otherwise, make it a zero
          }
       }
    }
}

char timeindex;



// Starts the music over from the beginning.
void music_reset(void){
    ix = 0;     
    dtime = 1; 
}

// Updates the player's score
void updatescore(void){
 if (newscore != score){   // if the score has changed
  
  score = newscore;         // update the score

  set_lcd_addr(0x44);
  write_int_lcd(score);
  set_lcd_addr(0x40);  
  type_lcd("Score:"); 
  
    }
}
    
    

// Music Function
void music(void){

    dtime--;
  
  if (dtime==0){

   //if (1){sound_on();}     // if the 4th dip switch is down, enable music
   
   pitch = notes[ix];
   
   dtime = times[ix] * tempo;
   ix++;
   

   
   if(ix == numstates){
      music_reset();
   }
   } 
   
   else if (dtime==1){
    pitch = 0;
   }
}

// New Block Function
void newblock(void){
 
switch(timeindex & 0b00000111){
  case 0x00:
     moveshape(s1,cshape);
     break;
  case 0x01:
     moveshape(s2,cshape);
     break;
  case 0x02:
     moveshape(s3,cshape);
     break;
  case 0x03:
     moveshape(s4,cshape);
     break;
  case 0x04:
     moveshape(s5,cshape);  
     break;
  case 0x05:
     moveshape(s6,cshape);  
     break;
  case 0x06:
     moveshape(s7,cshape);  
     break;
  case 0x07:
     moveshape(s1,cshape);
     break;
}
}

void checklose(void){
    for (column = 0; column<9; column++){
         if (stuckbuff[0][column] != 0){
          outchar1(0xFA);
          outchar1(0xFB);
          RTI_disable();
          sound_off();          
         }
       }
  
}


// Block Rotation Functions

void rotate(void){

// store shape[][] in shapetemp_v[][]
for(i=0;i<=3;i++){
  for(j=0;j<=3;j++){
    shapetemp_v[i][j] = cshape[i][j];
  }
}

// zero out shapetemp_r[][]
for(i=0;i<=3;i++){
  for(j=0;j<=3;j++){
    shapetemp_r[i][j] = 0;   
  }
}

// special case: if (s5) box
if (shapetemp_v[2][0] && shapetemp_v[2][1] && shapetemp_v[3][0] && shapetemp_v[3][1]){
   shapetemp_r[2][0] = 1;
   shapetemp_r[2][1] = 1;
   shapetemp_r[3][0] = 1;
   shapetemp_r[3][1] = 1;
}

// special case: if (s1) long vertical
else if (shapetemp_v[0][0] && shapetemp_v[1][0] && shapetemp_v[2][0] && shapetemp_v[3][0]){
   shapetemp_r[3][0] = 1;
   shapetemp_r[3][1] = 1;
   shapetemp_r[3][2] = 1;
   shapetemp_r[3][3] = 1;
}

// special case: if (s1) long horizontal
else if (shapetemp_v[3][0] && shapetemp_v[3][1] && shapetemp_v[3][2] && shapetemp_v[3][3]){
   shapetemp_r[0][0] = 1;
   shapetemp_r[1][0] = 1;
   shapetemp_r[2][0] = 1;
   shapetemp_r[3][0] = 1;
}



// check to see if 3x3 type (s2, s3, s4, s6, s7)
else if (shapetemp_v[0][0]==0 && shapetemp_v[0][1]==0 && shapetemp_v[0][2]==0 && shapetemp_v[0][3]==0 && shapetemp_v[1][3]==0 && shapetemp_v[2][3]==0 && shapetemp_v[3][3]==0){
   shapetemp_r[1][0] = shapetemp_v[3][0];
   shapetemp_r[2][0] = shapetemp_v[3][1];
   shapetemp_r[3][0] = shapetemp_v[3][2];
   
   shapetemp_r[1][1] = shapetemp_v[2][0];
   shapetemp_r[2][1] = shapetemp_v[2][1];
   shapetemp_r[3][1] = shapetemp_v[2][2];
   
   shapetemp_r[1][2] = shapetemp_v[1][0];
   shapetemp_r[2][2] = shapetemp_v[1][1];
   shapetemp_r[3][2] = shapetemp_v[1][2];
   
   if(shapetemp_r[1][0]==0 && shapetemp_r[2][0]==0 && shapetemp_r[3][0]==0){ // if there is whitespace at the left
      shapetemp_r[1][0] = shapetemp_r[1][1];                                 // shift it over
      shapetemp_r[2][0] = shapetemp_r[2][1];   
      shapetemp_r[3][0] = shapetemp_r[3][1];   
      shapetemp_r[1][1] = shapetemp_r[1][2];
      shapetemp_r[2][1] = shapetemp_r[2][2];   
      shapetemp_r[3][1] = shapetemp_r[3][2];     
      shapetemp_r[1][2] = 0;
      shapetemp_r[2][2] = 0;   
      shapetemp_r[3][2] = 0;
   } 
   
   else if(shapetemp_r[3][0]==0 && shapetemp_r[3][1]==0 && shapetemp_r[3][2]==0){  // if there is whitespace at the bottom
      shapetemp_r[3][0] = shapetemp_r[2][0];                                       // shift it down
      shapetemp_r[3][1] = shapetemp_r[2][1];   
      shapetemp_r[3][2] = shapetemp_r[2][2];   
      shapetemp_r[2][0] = shapetemp_r[1][0];
      shapetemp_r[2][1] = shapetemp_r[1][1];   
      shapetemp_r[2][2] = shapetemp_r[1][2];     
      shapetemp_r[1][0] = 0;
      shapetemp_r[1][1] = 0;   
      shapetemp_r[1][2] = 0;
   

   }
   
}

/* Note: By the end of executing this function, we have
         stored shape[][] in shapetemp_v[][] and
         put the rotation in shapetemp_r[][].*/

}


// Sound Interrupt
void interrupt 13 handler13()
  {
 tone(pitch); 
  }

// Drawing Coordinates
int X=5;        // X coordinate
int Y=0;        // Y coordinate

// UI flags
char down_l = 0;    // L button down
char down_r = 0;    // R button down
char down_drop = 0; // drop button down
char down_rot = 0;  // rotate button down

char L_timer=10;
char R_timer=10;

// Accelerometer values
int ax;
int ay;
int az;

int ay_d;
int ax_d;


// REAL TIME INTERRUPT
// This is where everything happens
void interrupt 7 handler7(){
timeindex++;
leds_on(timeindex);

checklose();

  droptime--;
  if (droptime==0){                 // if it's time to drop the block
    droptime = droptempo;           // reset the counter
    
   if(checkdrawblock(cshape,Y,X) == 1){
              Y++;            // if it won't hit anything, then advance Y coordinate
              drawflag=1;}    // RAISE the drawflag
   
   if(checkdrawblock(cshape,Y,X) == 0){      // if it will hit something
              drawflag=0;                                
              stickblock();                  // stick the block
              clearblockbuff();              // clear the block buffer
              checklines();                  // check for completed lines
               Y=0; X=5;                     // move draw cursor to the top of the screen
               newblock();
               drawflag=1;}                  // RAISE the drawflag      
    }

 //collect a/d values
ax = ad1conv(0);
ay = ad1conv(1);

if (ay-245 < 0){ay=245;}  // filter out anything faster than g
if (ax-255 < 0){ax=245;}

ay_d = ay - 245; // ay - aymin 
ax_d = ax - 245; // ax - axmin


   //if player wants to move RIGHT                         
    if (ay_d < 45){                   // if tilting right
         R_timer--;                     // decrement R timer
          if (ay_d < 25){             // if tilting hard right
            R_timer--;                  // decrement R timer again
          }
    }
   
    if(R_timer<0){
      
                                          
    if(((X+1) < 10) && (checkdrawblock(cshape,Y,X+1)))    // see if it's legit
    X++;                                                  // then increase X coordinate
    drawflag=1;                                           // raise the drawflag
    down_l = 1;
   R_timer=20;
    }

  // if player wants to move LEFT

   if (ay_d > 135){                    // if tilting right
       L_timer--;                        // decrement L timer
          if (ay_d > 155){             // if tilting hard right
           L_timer--;                    // decrement L timer
          }
   }
   
   if(L_timer<0){
                                                         
    if(((X-1) >= 0) && (checkdrawblock(cshape,Y,X-1)))   // see if it's legit
    X--;                                                 // then decrease X coordinate
    drawflag=1;                                          // raise the drawflag
    down_r =1;
    
   L_timer=20; 
    }
   
   if ((ax_d < 30) && !(down_drop) && (ay_d < 135) && (ay_d > 45)){    // if player wants to drop block faster
    droptime = 5;
    droptempo = 5;
    down_drop = 1;                      
   }
   
   if (SW5_down() && !(down_rot)){          // if player wants to rotate block
     rotate();                              // produce shapetemp_r[][]
     if (checkdrawblock(shapetemp_r,Y,X)){  // if it's legit to rotate
       moveshape(shapetemp_r,cshape);       // replace cshape[][] with shapetemp_r[][]     
     }
    down_rot = 1;
    drawflag = 1;                             // raise the drawflag                
   }

if (ax_d > 30)      // if we're no longer trying to drop faster
{
down_drop = 0;            
droptempo = droptempo_n;  // reset tempo
}


if (SW5_up()){
  down_rot = 0;
}

// this draw code is processor-intensive, flag is to ensure it's executed minimally
if (drawflag) {             // if a change needs writing (aka if the drawflag is up)
drawblock(cshape,Y,X);      // draw the block
updatedraw();               // OR it with the stuck blocks
updatescreen();             // send it out
drawflag = 0;               // lower the drawflag
}

music();

clear_RTI_flag();  // clear flag, exit the RTI
}

float test_float=0;
int test_int=0;


void main(void) {

  PLL_init();        // set system clock frequency to 24 MHz 
  SCI1_init(57600);  // initialize second serial port
  lcd_init();        // initialize LCD
  led_enable();      // enable LED
  seg7_enable();
  sound_init();
  sound_on();
  music_reset(); // play from the top
  SW_enable();   // enable switches
  ad1_enable(); // enable a/d converter
   
  
videotest();
clearscreen();

 

outchar1(0xFA); // Left side blue
outchar1(0xFB); // Right side blue


newblock();      // prepare the first block

  set_lcd_addr(0x00);  
 // type_lcd("EGR280 TETRIS");
  set_lcd_addr(0x44);
  write_int_lcd(score);
  set_lcd_addr(0x40);  
  type_lcd("Score:"); 



  RTI_init();    // Go Go RTI!
             
while(1){
updatescore();
set_lcd_addr(0x00);
write_int_lcd(ax_d);

set_lcd_addr(0x06);
write_int_lcd(ay_d);

//set_lcd_addr(0x12);
//write_int_lcd(ay_deg);


}
   
   

  };

