/* LCD example code from Craig Hadady */

/*
 * Paul,
 * 
 * I thought that the attached code might be useful
 * to you.  You can do with it what you want, no strings
 * attached, etc etc.
 * 
 * What it does is copy whatever you type to the lcd.
 * Scrolling and backspace are supported.  I'm sure there
 * are still bugs, but I'm going to bed.
 * 
 * Regards,
 * 
 * Craig Hadady
*/

#include <paulmon2.h>
#include <8052.h>

xdata at 0xfe00 unsigned char lcd_command;
xdata at 0xfe01 unsigned char lcd_status;
xdata at 0xfe02 unsigned char lcd_write;
xdata at 0xfe03 unsigned char lcd_read;


void lcd_wait()
{
  volatile sbit at 0xe7 busy;

  do {
    ACC = lcd_status;
  } while (busy);
}

void main()
{

  data unsigned char x,y,i,c;
  data unsigned char b[40];

  // capture keystrokes and send them to the lcd

  // configure the lcd display
  lcd_wait();
  lcd_command = 0x38;  // 8 bit interface, two lines, 5x7 dots

  // clear the display
  lcd_wait();
  lcd_command = 1;

  // turn on the display, cursor off, no blink
  lcd_wait();
  lcd_command = 0x0c;

  // cursor home - also sets address to zero
  lcd_wait();
  lcd_command = 2;

  // get characters and display them - lcd stores 40 characters
  // per line, but the lines are 0x40 hex apart in address

  x=y=0;

  for (i=0;i<40;i++) b[i] = ' ';	// fill with spaces

  while ((c=pm2_cin())!='\033') {	// if escape, escape

    if (c == '\r') {		// carrage return
      pm2_cout('\r');
      pm2_cout('\n');
      i=0;
      // shift the display back to the left
      // also sets DDRAM address to zero
      lcd_wait();
      lcd_command = 2;
      // set the DDRAM address to line 1
      lcd_wait();
      lcd_command = 0xC0;
      // go to start of next line
      y++;
      x = 0;
      }

    if (c == '\b') {		// backspace
      // ignore if at start of line
      if (x==0) {
	continue;
	}
      x-=1;
      //set the DDRAM address
      lcd_wait();
      lcd_command = i = 0x80+y*64+x;
      // clear the character on the display
      lcd_wait();
      lcd_write = ' ';
      // set the DDRAM address
      lcd_wait();
      lcd_command = i;
      // shift the display left if needed
      if (x>15) {
	lcd_wait();
	lcd_command = 0x1c;
	}
      // clear the character in the buffer
      b[x] = ' ';
      // clear the character on the terminal
      pm2_cout(c);
      pm2_cout(' ');
      pm2_cout(c);
      continue;
      }

    if (y == 2) {		// scroll up the display
      // clear the display and home the cursor
      lcd_wait();
      lcd_command = 1;
      // shift the display back to the left
      // also sets DDRAM address to zero
      lcd_wait();
      lcd_command = 2;
      // copy line 1 to line 0
      for (i=0;i<40;i++) {
	lcd_wait();
	lcd_write = b[i];
	}
      // clear buffer memory
      for (i=0;i<40;i++) b[i] = ' ';
      //set the DDRAM address to line 1
      lcd_wait();
      lcd_command = 0xC0;
      // now on the second line
      y = 1;
      }

    if ((x<40)&(c!='\r')) {	// write the character
      lcd_wait();
      lcd_write = c;
      // left shift if necessary
      if (x>15) {
	lcd_wait();
	lcd_command = 0x18;
	}
      if (y==1) b[x] = c;	// save if on second line
      pm2_cout(c);
      x++;
      }

    }
    pm2_restart();		// return to monitor
}

