// NokiaLCD.c 
// 08/02/2005
#include "NokiaLCD.h"
#include <string.h>

/* This table defines the standard ASCII characters in a 5x7 dot format. */
//#pragma romdata ROOT_TABLE = 0x1000
#ifdef LINUX
#include "SimuLcd.h"
const UInt8 FontLookup [][5] =
#else
rom const UInt8 FontLookup [][5] =
#endif
{
  { 0x00, 0x00, 0x00, 0x00, 0x00 },  // sp
  //{ 0x00, 0x00, 0x2f, 0x00, 0x00 },   // !
  //{ 0x00, 0x07, 0x00, 0x07, 0x00 },   // "
  //{ 0x14, 0x7f, 0x14, 0x7f, 0x14 },   // #
  //{ 0x24, 0x2a, 0x7f, 0x2a, 0x12 },   // $
  //{ 0xc4, 0xc8, 0x10, 0x26, 0x46 },   // %
  //{ 0x36, 0x49, 0x55, 0x22, 0x50 },   // &
  //{ 0x00, 0x05, 0x03, 0x00, 0x00 },   // '
  // { 0x00, 0x1c, 0x22, 0x41, 0x00 },   // (

{ 0x7C, 0x76, 0x7F, 0x1E, 0x7C },   // ! => Home
{ 0x18, 0x1E, 0x7F, 0x1E, 0x18 },   // " => Tree
{ 0x00, 0x00, 0x11, 0x15, 0x1F },   // # => 3
{ 0x00, 0x00, 0x1D, 0x15, 0x17 },   // $ => 2
{ 0x00, 0x00, 0x02, 0x01, 0x1F },   // % => 1
{ 0x1F, 0x11, 0x1F, 0x00, 0x08 },   // & => 0
{ 0x10, 0x10, 0x02, 0x01, 0x1F },   // ' => -1
{ 0x00, 0x00, 0x00, 0x00, 0x08 },   // ( => . . . .

  { 0x00, 0x41, 0x22, 0x1c, 0x00 },   // )
  { 0x14, 0x08, 0x3E, 0x08, 0x14 },   // *
  { 0x08, 0x08, 0x3E, 0x08, 0x08 },   // +
  { 0x00, 0x00, 0x50, 0x30, 0x00 },   // ,
  { 0x08, 0x08, 0x08, 0x08, 0x08 },   // -
  { 0x00, 0x60, 0x60, 0x00, 0x00 },   // .
  { 0x20, 0x10, 0x08, 0x04, 0x02 },   // /
  { 0x3E, 0x51, 0x49, 0x45, 0x3E },   // 0
  { 0x00, 0x42, 0x7F, 0x40, 0x00 },   // 1
  { 0x42, 0x61, 0x51, 0x49, 0x46 },   // 2
  { 0x21, 0x41, 0x45, 0x4B, 0x31 },   // 3
  { 0x18, 0x14, 0x12, 0x7F, 0x10 },   // 4
  { 0x27, 0x45, 0x45, 0x45, 0x39 },   // 5
  { 0x3C, 0x4A, 0x49, 0x49, 0x30 },   // 6
  { 0x01, 0x71, 0x09, 0x05, 0x03 },   // 7
  { 0x36, 0x49, 0x49, 0x49, 0x36 },   // 8
  { 0x06, 0x49, 0x49, 0x29, 0x1E },   // 9
  { 0x00, 0x36, 0x36, 0x00, 0x00 },   // :
  { 0x00, 0x56, 0x36, 0x00, 0x00 },   // ;
  { 0x08, 0x14, 0x22, 0x41, 0x00 },   // <
  { 0x14, 0x14, 0x14, 0x14, 0x14 },   // =
  { 0x00, 0x41, 0x22, 0x14, 0x08 },   // >
  { 0x02, 0x01, 0x51, 0x09, 0x06 },   // ?
  { 0x32, 0x49, 0x59, 0x51, 0x3E },   // @
  { 0x7E, 0x11, 0x11, 0x11, 0x7E },   // A
  { 0x7F, 0x49, 0x49, 0x49, 0x36 },   // B
  { 0x3E, 0x41, 0x41, 0x41, 0x22 },   // C
  { 0x7F, 0x41, 0x41, 0x22, 0x1C },   // D
  { 0x7F, 0x49, 0x49, 0x49, 0x41 },   // E
  { 0x7F, 0x09, 0x09, 0x09, 0x01 },   // F
  { 0x3E, 0x41, 0x49, 0x49, 0x7A },   // G
  { 0x7F, 0x08, 0x08, 0x08, 0x7F },   // H
  { 0x00, 0x41, 0x7F, 0x41, 0x00 },   // I
  { 0x20, 0x40, 0x41, 0x3F, 0x01 },   // J
  { 0x7F, 0x08, 0x14, 0x22, 0x41 },   // K
  { 0x7F, 0x40, 0x40, 0x40, 0x40 },   // L
  { 0x7F, 0x02, 0x0C, 0x02, 0x7F },   // M
  { 0x7F, 0x04, 0x08, 0x10, 0x7F },   // N
  { 0x3E, 0x41, 0x41, 0x41, 0x3E },   // O
  { 0x7F, 0x09, 0x09, 0x09, 0x06 },   // P
  { 0x3E, 0x41, 0x51, 0x21, 0x5E },   // Q
  { 0x7F, 0x09, 0x19, 0x29, 0x46 },   // R
  { 0x46, 0x49, 0x49, 0x49, 0x31 },   // S
  { 0x01, 0x01, 0x7F, 0x01, 0x01 },   // T
  { 0x3F, 0x40, 0x40, 0x40, 0x3F },   // U
  { 0x1F, 0x20, 0x40, 0x20, 0x1F },   // V
  { 0x3F, 0x40, 0x38, 0x40, 0x3F },   // W
  { 0x63, 0x14, 0x08, 0x14, 0x63 },   // X
  { 0x07, 0x08, 0x70, 0x08, 0x07 },   // Y
  { 0x61, 0x51, 0x49, 0x45, 0x43 },   // Z
  { 0x00, 0x7F, 0x41, 0x41, 0x00 },   // [
  { 0x55, 0x2A, 0x55, 0x2A, 0x55 },   // 55
  { 0x00, 0x41, 0x41, 0x7F, 0x00 },   // ]
  { 0x04, 0x02, 0x01, 0x02, 0x04 },   // ^
  { 0x40, 0x40, 0x40, 0x40, 0x40 },   // _
  { 0x00, 0x01, 0x02, 0x04, 0x00 },   // '
  { 0x20, 0x54, 0x54, 0x54, 0x78 },   // a
  { 0x7F, 0x48, 0x44, 0x44, 0x38 },   // b
  { 0x38, 0x44, 0x44, 0x44, 0x20 },   // c
  { 0x38, 0x44, 0x44, 0x48, 0x7F },   // d
  { 0x38, 0x54, 0x54, 0x54, 0x18 },   // e
  { 0x08, 0x7E, 0x09, 0x01, 0x02 },   // f
  { 0x0C, 0x52, 0x52, 0x52, 0x3E },   // g
  { 0x7F, 0x08, 0x04, 0x04, 0x78 },   // h
  { 0x00, 0x44, 0x7D, 0x40, 0x00 },   // i
  { 0x20, 0x40, 0x44, 0x3D, 0x00 },   // j
  { 0x7F, 0x10, 0x28, 0x44, 0x00 },   // k
  { 0x00, 0x41, 0x7F, 0x40, 0x00 },   // l
  { 0x7C, 0x04, 0x18, 0x04, 0x78 },   // m
  { 0x7C, 0x08, 0x04, 0x04, 0x78 },   // n
  { 0x38, 0x44, 0x44, 0x44, 0x38 },   // o
  { 0x7C, 0x14, 0x14, 0x14, 0x08 },   // p
  { 0x08, 0x14, 0x14, 0x18, 0x7C },   // q
  { 0x7C, 0x08, 0x04, 0x04, 0x08 },   // r
  { 0x48, 0x54, 0x54, 0x54, 0x20 },   // s
  { 0x04, 0x3F, 0x44, 0x40, 0x20 },   // t
  { 0x3C, 0x40, 0x40, 0x20, 0x7C },   // u
  { 0x1C, 0x20, 0x40, 0x20, 0x1C },   // v
  { 0x3C, 0x40, 0x30, 0x40, 0x3C },   // w
  { 0x44, 0x28, 0x10, 0x28, 0x44 },   // x
  { 0x0C, 0x50, 0x50, 0x50, 0x3C },   // y
  { 0x44, 0x64, 0x54, 0x4C, 0x44 }    // z
};

UInt8 LcdCache [ 504 ]; //LCD_CACHE_SIZE
Int16 LcdCacheIdx;
Int16 LoWaterMark;
Int16 HiWaterMark;
UInt8 UpdateLcd;

void LcdInit ( void ) {
#ifndef LINUX
  // Ports configuration 
  LCD_SCE_PIN = 1; // Disable LCD first
  LCD_SCE_DIR = 0; // Output

  LCD_RES_PIN = 1; // No reset now
  LCD_RES_DIR = 0; // Output
  
  LCD_DC_DIR = 0;
  LCD_SDIN_DIR = 0;
  
  LCD_SCLK_PIN = 0; // To be sure the clk is 0
  LCD_SCLK_DIR = 0;

  // Here we go.
  LCD_SCE_PIN = 0; // Enable LCD
  LCD_SCE_DIR = 0; // Output
 
  // Reset
  LCD_RES_PIN = 0; // Reset LCD
  LCD_RES_PIN = 1; // End of Reset
  
  LcdSend( 0x21, LCD_CMD );  // LCD Extended Commands.
  LcdSend( 0xC8, LCD_CMD );  // Set LCD Vop (Contrast).
  LcdSend( 0x06, LCD_CMD );  // Set Temp coefficent.
  LcdSend( 0x13, LCD_CMD );  // LCD bias mode 1:48.
  LcdSend( 0x20, LCD_CMD );  // LCD Standard Commands, Horizontal addressing mode.
  LcdSend( 0x0C, LCD_CMD );  // LCD in normal mode.
#else
  SimuLcdInit ();
#endif
  //  Reset watermark pointers.
  LoWaterMark = LCD_CACHE_SIZE - 1;
  HiWaterMark = 0;
  LcdCacheIdx = 0;
  LcdClear();
  LcdUpdate();
}

void LcdContrast ( UInt8 contrast ) {
  LcdSend( 0x21, LCD_CMD );//  LCD Extended Commands.
  LcdSend( 0x80 | contrast, LCD_CMD ); // Set LCD Vop (Contrast).
  LcdSend( 0x20, LCD_CMD ); //  LCD Standard Commands, horizontal addressing mode.
}

void LcdClear ( void ) {
  UInt16 i;
  for ( i = 0; i < 504 ; i++ ){
    LcdCache[i] = 0x00;
  }
  
  //  Reset watermark pointers.
  LoWaterMark = 0;
  HiWaterMark = LCD_CACHE_SIZE - 1;
  UpdateLcd = 1;
}

/* 0 <= x <= 13, 0 <= y <= 5 */
void LcdGotoXY ( UInt8 x, UInt8 y ) {
  UInt16 xx, yy;
  xx = x;
  yy = y;
  LcdCacheIdx = (xx * 6) + (yy * 84);
}

// Same as LcdGotoXY but without computation
void LcdSetCacheIdx ( UInt16 anIndex) {
  if (anIndex < 504) LcdCacheIdx = anIndex;
}

void LcdChr ( LcdFontSize size, UInt8 ch ) {
  UInt8 i, c;
  UInt8 b1, b2;
  Int16  tmpIdx;

  if ( LcdCacheIdx < LoWaterMark ) {
    LoWaterMark = LcdCacheIdx; //  Update low marker.
  }

  if ( (ch < 0x20) || (ch > 0x7b) ) {
    ch = 92;//  Convert to a printable character.
  }

  if ( size == FONT_1X ) {
    for ( i = 0; i < 5; i++ ) {
      LcdCache[LcdCacheIdx++] = FontLookup[ch - 32][i] << 1;
    }
  }
  else if ( size == FONT_2X ) {
    tmpIdx = LcdCacheIdx - 84;

    if ( tmpIdx < LoWaterMark ) {
      LoWaterMark = tmpIdx;
    }

    if ( tmpIdx < 0 ) return;

    for ( i = 0; i < 5; i++ ) {
      c = FontLookup[ch - 32][i] << 1;
      b1 =  (c & 0x01) * 3;
      b1 |= (c & 0x02) * 6;
      b1 |= (c & 0x04) * 12;
      b1 |= (c & 0x08) * 24;

      c >>= 4;
      b2 =  (c & 0x01) * 3;
      b2 |= (c & 0x02) * 6;
      b2 |= (c & 0x04) * 12;
      b2 |= (c & 0x08) * 24;

      LcdCache[tmpIdx++] = b1;
      LcdCache[tmpIdx++] = b1;
      LcdCache[tmpIdx + 82] = b2;
      LcdCache[tmpIdx + 83] = b2;
    }
    LcdCacheIdx += 11; // Update x cursor position.
  }

  if ( LcdCacheIdx > HiWaterMark ){
    HiWaterMark = LcdCacheIdx; // Update high marker.
  }
  LcdCache[LcdCacheIdx++] = 0x00; // Horizontal gap between characters.
}

void LcdStr ( LcdFontSize size, UInt8 *dataPtr ) {
  while ( *dataPtr ) {
    LcdChr( size, *dataPtr++ );
  }
}

void LcdPixel ( UInt8 x, UInt8 y, LcdPixelMode mode ) {
  UInt16 index;
  UInt8 offset;
  UInt8 data;

  if ( x > LCD_X_RES ) return;
  if ( y > LCD_Y_RES ) return;

  index = ((y >> 3) * 84) + x;
  offset  = y - ((y >> 3) * 8);

  data = LcdCache[index];

  if ( mode == PIXEL_OFF ) {
    data &= (~(0x01 << offset));
  }
  else if ( mode == PIXEL_ON ) {
    data |= (0x01 << offset);
  }
  else if ( mode  == PIXEL_XOR ) {
    data ^= (0x01 << offset);
  }

  LcdCache[index] = data;

  if ( index < LoWaterMark ) {
    LoWaterMark = index; //  Update low marker.
  }

  if ( index > HiWaterMark ) {
    HiWaterMark = index; //  Update high marker.
  }
}

void LcdLine ( UInt8 x1, UInt8 y1, UInt8 x2, UInt8 y2, LcdPixelMode mode ) {
  Int16 dx, dy, stepx, stepy, fraction;

  dy = y2 - y1;
  dx = x2 - x1;

  if ( dy < 0 ) {
    dy    = -dy;
    stepy = -1;
  }
  else {
    stepy = 1;
  }

  if ( dx < 0 ) {
    dx    = -dx;
    stepx = -1;
  }
  else {
    stepx = 1;
  }

  dx <<= 1;
  dy <<= 1;

  LcdPixel( x1, y1, mode );

  if ( dx > dy ) {
    fraction = dy - (dx >> 1);
    while ( x1 != x2 ) {
      if ( fraction >= 0 ) {
	y1 += stepy;
	fraction -= dx;
      }
      x1 += stepx;
      fraction += dy;
      LcdPixel( x1, y1, mode );
    }
  }
  else {
    fraction = dx - (dy >> 1);
    while ( y1 != y2 ) {
      if ( fraction >= 0 ) {
	x1 += stepx;
	fraction -= dy;
      }
      y1 += stepy;
      fraction += dx;
      LcdPixel( x1, y1, mode );
    }
  }

  UpdateLcd =1;
}

void LcdUpdate ( void ) {
  Int16 i;

  if ( LoWaterMark < 0 )
    LoWaterMark = 0;
  else if ( LoWaterMark >= LCD_CACHE_SIZE )
    LoWaterMark = LCD_CACHE_SIZE - 1;

  if ( HiWaterMark < 0 )
    HiWaterMark = 0;
  else if ( HiWaterMark >= LCD_CACHE_SIZE )
    HiWaterMark = LCD_CACHE_SIZE - 1;

  //  Set base address according to LoWaterMark.
  LcdSend( 0x80 | (LoWaterMark % LCD_X_RES), LCD_CMD );
  LcdSend( 0x40 | (LoWaterMark / LCD_X_RES), LCD_CMD );

  //  Serialize the video buffer.
  for ( i = LoWaterMark; i <= HiWaterMark; i++ ) {
    LcdSend( LcdCache[i], LCD_DATA );
  }

  #ifdef LINUX
  SimuLcdUpdate ();
  #endif

  //  Reset watermark pointers.
  LoWaterMark = LCD_CACHE_SIZE - 1;
  HiWaterMark = 0;

  UpdateLcd =0;
}

void LcdSend ( UInt8 data, LcdCmdData cd ) {
#ifndef LINUX
  UInt8 i, temp;
  LCD_SCE_PIN = 0; // Enable display controller (active low).
  LCD_DC_PIN = cd; // 1:Data, 0:Cmde
 
  temp = data;
  for(i=0; i<8; i++) { // MSB first
    if (temp & 0x80) LCD_SDIN_PIN = 1;
    else LCD_SDIN_PIN = 0;

    LCD_SCLK_PIN = 1; // Rising clock
    LCD_SCLK_PIN = 0; // Falling clock
    temp = temp << 1;
  }

  LCD_SCE_PIN = 1; // Disable display controller.
#endif
}

// End of file





 

 
