

// PIN ASSIGNMENT //
sbit DATA_INT = P3^0;
sbit KB_DATA = P3^2;
sbit EN = P3^4;
sbit RS = P3^5;

// PROTOTYPES //
// LCD functions //
void lcd_delay(bit length);
void write_char(char character);
void write_message(char * message);
void clear_disp();
void lcd_initialize();
void monitor_lcd_line(signed char amt);

// Keyboard functions //
//bit calc_parity(char tmp);
void kb_machine(char * kb_arr);
char conv_to_ascii(char scan_code);

// Output functions //
char conv_to_send_protocol(char ascii_code);
void output_data(char scode);

// General functions //
char pow(char num, char pow);
int strlen(char * string);
void sec_delay(int sec);

// GLOBAL VARIABLES //
char output_buffer[49],output_buffer_counter=0,char_count=0;

#include <intrins.h>

/* LCD functions */
void lcd_delay(bit length)
{
// length = 1 -> 1.64ms
// length = 0 -> 40us
  int count_size = (length == 1) ? 3280 : 80;
/////////////////////////////////////////////////
  TR0=0;
/////////////////////////////////////////////////
  TH0 = ~(count_size/256);
  TL0 = -(count_size%256);

  TR0 = 1;
  while(!TF0);
  TF0 = 0;
  TR0 = 0;
}


void monitor_lcd_line(signed char amt)
{
// break line automatically
  if(char_count<24 && (char_count+amt)>=24)
  {
    RS = 0;
    P1 = 0xc0;
    EN = 1;
    EN = 0;
    lcd_delay(0);
    char_count+=amt;
  }
  else
  {
    char_count+=amt;
  }
}


void write_char(char character)
{
  RS = 1;
  P1 = character;
  EN = 1;
  EN = 0;
  lcd_delay(0);
  monitor_lcd_line(+1);
}


void write_message(char * message)
{
  char i;

  clear_disp();
  for(i=0; i<strlen(message); i++)
  write_char(message);
}


void clear_disp()
{
  RS = 0;
  P1 = 0x01;
  EN = 1;
  EN = 0;
  lcd_delay(1);
  char_count=0;
}


void lcd_initialize()
{
// function set
  RS = 0;
  P1 = 0x38;
  EN = 1;
  EN = 0;
  lcd_delay(0);
// entry mode set
  RS = 0;
  P1 = 0x06;
  EN = 1;
  EN = 0;
  lcd_delay(0);
// display control
  RS = 0;
  P1 = 0x0e;
  EN = 1;
  EN = 0;
  lcd_delay(0);
// clear display
  RS = 0;
  P1 = 0x01;
  EN = 1;
  EN = 0;
  lcd_delay(1);
}


/* KB functions */

void INT1_ISR() interrupt 2
{
  static char i=0;
  static char in_data[33];

  in_data = KB_DATA;
  i++;
  if(i==33)
  {
    kb_machine(in_data);
    i=0;
  }
}

// /*bit calc_parity(char tmp)
// {
// calculate odd parity = NOT(XOR(D0...D7))
//   char i;
//   bit xor;
//   for(i=0; i<8; i++)
//   {
//     tmp = tmp>>i;
//     xor = xor^tmp&0x01;
//   }
//   return ~xor;
// }*/

void kb_machine(char * kb_arr)
{
  char scan_code=0, ascii_code, i=0;
  static bit del_start_msg=0;
 
  if(!del_start_msg) 
  {
    clear_disp(); del_start_msg=1;
  }
 
  for(i=1; i<9; i++)
    scan_code = scan_code + kb_arr*pow(2,i-1);

  if(scan_code == 0x5a) // user pressed on ENTER, send out!
  {
    output_buffer[output_buffer_counter] = 0xff;
    EA = 0; // disable KB
    write_message("KB will not be available during transmission.");
    for(i=0; i<=output_buffer_counter; i++)
      output_data(output_buffer);
       
    clear_disp();
    write_message("Success. You can type a new message if you like.");
    sec_delay(10);
    clear_disp();
    EA = 1; // enable KB
    output_buffer_counter=0;
  }
// /* else if(is_effect(scan_code))
//   {
//     output_data(conv_to_send_protocol(scan_code));
// }*/
  else if(scan_code == 0x66) // delete last char
  {
    if(char_count!=24)
    {
      output_buffer[--output_buffer_counter] = 0;
// move cursor one char back
      RS = 0;
      P1 = 0x10;
      EN = 1;
      EN = 0;
      lcd_delay(0);
// write space (delete effect)
      RS = 1;
      P1 = ' ';
      EN = 1;
      EN = 0;
      lcd_delay(0);
// move cursor back to its place.
      RS = 0;
      P1 = 0x10;
      EN = 1;
      EN = 0;
      lcd_delay(0);
      monitor_lcd_line(-1);
    }
    else
    {
      output_buffer[--output_buffer_counter] = 0;
// go back to end of second line
      RS = 0;
      P1 = 0x97;
      EN = 1;
      EN = 0;
      lcd_delay(0);
// write space (delete effect)
      RS = 1;
      P1 = ' ';
      EN = 1;
      EN = 0;
      lcd_delay(0);
// move cursor back to its place.
      RS = 0;
      P1 = 0x10;
      EN = 1;
      EN = 0;
      lcd_delay(0);
/*RS = 0;
      P1 = 0x10;
      EN = 1;
      EN = 0;
      lcd_delay(0);*/
      monitor_lcd_line(-1);
    }
  }
  else
  {
    ascii_code = conv_to_ascii(scan_code);
    if(ascii_code!=0 && char_count<48)
    {
      write_char(ascii_code); // write to lcd
      output_buffer[output_buffer_counter++] = conv_to_send_protocol(ascii_code);
    }
  }
}

char conv_to_ascii(char scan_code)
{
  switch(scan_code)
  {
    case 0x1c: return 'A';
    case 0x32: return 'B';
    case 0x21: return 'C';
    case 0x23: return 'D';
    case 0x24: return 'E';
    case 0x2b: return 'F';
    case 0x34: return 'G';
    case 0x33: return 'H';
    case 0x43: return 'I';
    case 0x3b: return 'J';
    case 0x42: return 'K';
    case 0x4b: return 'L';
    case 0x3a: return 'M';
    case 0x31: return 'N';
    case 0x44: return 'O';
    case 0x4d: return 'P';
    case 0x15: return 'Q';
    case 0x2d: return 'R';
    case 0x1b: return 'S';
    case 0x2c: return 'T';
    case 0x3c: return 'U';
    case 0x2a: return 'V';
    case 0x1d: return 'W';
    case 0x22: return 'X';
    case 0x35: return 'Y';
    case 0x1a: return 'Z';
    case 0x29: return ' ';
    case 0x16: return '1';
    case 0x1e: return '2';
    case 0x26: return '3';
    case 0x25: return '4';
    case 0x2e: return '5';
    case 0x36: return '6';
    case 0x3d: return '7';
    case 0x3e: return '8';
    case 0x46: return '9';
    case 0x45: return '0';
    case 0x4e: return '-';
    default: return 0;
  }
}

/* Output functions */
void output_data(char scode)
{
  DATA_INT = 0;
/////////////////////////////////////
  while(!TI)       //////////////////
    ;              //////////////////
  TI=0;            //////////////////
/////////////////////////////////////
  SBUF = scode;
  while(!TI); // wait till end of transmission
  TI = 0;
  DATA_INT = 1;
}

char conv_to_send_protocol(char ascii_code)
{
  switch(ascii_code)
  {
    case 'A': return 0;
    case 'B': return 1;
    case 'C': return 2;
    case 'D': return 3;
    case 'E': return 4;
    case 'F': return 5;
    case 'G': return 6;
    case 'H': return 7;
    case 'I': return 8;
    case 'J': return 9;
    case 'K': return 10;
    case 'L': return 11;
    case 'M': return 12;
    case 'N': return 13;
    case 'O': return 14;
    case 'P': return 15;
    case 'Q': return 16;
    case 'R': return 17;
    case 'S': return 18;
    case 'T': return 19;
    case 'U': return 20;
    case 'V': return 21;
    case 'W': return 22;
    case 'X': return 23;
    case 'Y': return 24;
    case 'Z': return 25;
    case ' ': return 26;
    case '0': return 27;
    case '1': return 28;
    case '2': return 29;
    case '3': return 30;
    case '4': return 31;
    case '5': return 32;
    case '6': return 33;
    case '7': return 34;
    case '8': return 35;
    case '9': return 36;
    case '-': return 37;
    case 0x05: return 0xe0;
    case 0x06: return 0xe1;
    case 0x04: return 0xe2;
    case 0x0c: return 0xe3;
  }
}

/* General functions */

char pow(char num, char pow)
{
  char tmp=1,i;
  for(i=0; i<pow; i++)
  tmp *= num;
  return tmp;
}


int strlen(char * string)
{
  char i=0;
  while(1)
  {
    if(string!=0) i++;
    else break;
  }
}


void sec_delay(int sec)
{
  int i;

//////////  TMOD = 0x09; // timer 0 mode 1         
////////// this breaks TMOD configuration replace with
  TMOD &= 0xF0; ///////////////////////
  TMOD |= 0x09; ///////////////////////
///////////////////////////////////////
  for(i=0; i<20*sec; i++)
  {
    TH0 = ~(50000/256);
    TL0 = -(50000%256);
    
    TR0 = 1;
    while(!TF0);
    TF0 = 0;                             /////////////// Not Needed //////////////
    TR0 = 0;
  }
}


// main
void main()
{
  lcd_initialize(); // lcd initialization
  write_message("Welcome, please type in your message.");

  IE = 0x84; // enable INT1
  IT1 = 1;

// output options //
  SCON = 0x40; // Mode 1, No Parity  /////////////// REN=0 receive=disabled ///////////////
  TMOD = 0x21; // T1 Mode 2 (auto reload - baud gen). T0 Mode 1 (general use).
  TH1 = -26;
  TR1 = 1;

//T2CON = 0x34;
//PCON=PCON|0x80; // smod = 1
//RCAP2H = ~(40000/256); // 2400 baud rate
//RCAP2H = -(40000%256);
//TR2 = 1;

  DATA_INT = 1; // idle

  while(1);
}	


