#include "M10PWM.h"
#include "M10SevenSeg.h"
 
#define LCD_CSR_CMD  0
#define LCD_CSR_DAT  1
#define LCD_CSR_RST  2
 
static void lcd_write_cmd (uint8_t data) __reentrant
{ 
    LCD_CSR = LCD_CSR_CMD;
    LCD_DATA = data;
    nop_delay (5);
    while(LCD_CSR == 0);
}
 
static void lcd_write_dat (uint8_t data) __reentrant
{
    LCD_CSR = LCD_CSR_DAT;
    LCD_DATA = data;
    nop_delay (5);
    while(LCD_CSR == 0);
}
 
static void lcd_reset () __reentrant
{
    LCD_CSR = LCD_CSR_RST;
    delay(50);
    LCD_CSR = 0;
    delay(50);
 
}
 
static void lcd_init() __reentrant
{
   lcd_reset();
 
    lcd_write_cmd (0x11);
    delay(50);
 
    lcd_write_cmd(0xB1);
    lcd_write_dat(0x05); 
    lcd_write_dat(0x3C); 
    lcd_write_dat(0x3C); 
 
    lcd_write_cmd(0xB2); 
    lcd_write_dat(0x05); 
    lcd_write_dat(0x3C); 
    lcd_write_dat(0x3C); 
 
    lcd_write_cmd(0xB3); 
    lcd_write_dat(0x05); 
    lcd_write_dat(0x3C); 
    lcd_write_dat(0x3C); 
    lcd_write_dat(0x05); 
    lcd_write_dat(0x3C); 
    lcd_write_dat(0x3C); 
 
    lcd_write_cmd(0xB4); //Column inversion 
    lcd_write_dat(0x03); 
 
    lcd_write_cmd(0xC0); 
    lcd_write_dat(0x28); 
    lcd_write_dat(0x08); 
    lcd_write_dat(0x04); 
 
    lcd_write_cmd(0xC1); 
    lcd_write_dat(0xC0); 
 
    lcd_write_cmd(0xC2); 
    lcd_write_dat(0x0D); 
    lcd_write_dat(0x00); 
 
    lcd_write_cmd(0xC3); 
    lcd_write_dat(0x8D); 
    lcd_write_dat(0x2A); 
 
    lcd_write_cmd(0xC4); 
    lcd_write_dat(0x8D); 
    lcd_write_dat(0xEE); 
 
    lcd_write_cmd(0xC5); //VCOM 
    lcd_write_dat(0x1A); 
 
    lcd_write_cmd(0x36); //MX, MY, RGB mode 
    lcd_write_dat(0xC0); 
 
    lcd_write_cmd(0xe0); 
    lcd_write_dat(0x04); 
    lcd_write_dat(0x22); 
    lcd_write_dat(0x07); 
    lcd_write_dat(0x0a); 
    lcd_write_dat(0x2e); 
    lcd_write_dat(0x30); 
    lcd_write_dat(0x25); 
    lcd_write_dat(0x2a); 
    lcd_write_dat(0x28); 
    lcd_write_dat(0x26); 
    lcd_write_dat(0x2e); 
    lcd_write_dat(0x3a); 
    lcd_write_dat(0x00);     
    lcd_write_dat(0x01); 
    lcd_write_dat(0x03); 
    lcd_write_dat(0x13); 
 
    lcd_write_cmd(0xe1); 
    lcd_write_dat(0x04); 
    lcd_write_dat(0x16); 
    lcd_write_dat(0x06); 
    lcd_write_dat(0x0d); 
    lcd_write_dat(0x2d); 
    lcd_write_dat(0x26); 
    lcd_write_dat(0x23); 
    lcd_write_dat(0x27); 
    lcd_write_dat(0x27); 
    lcd_write_dat(0x25); 
    lcd_write_dat(0x2d); 
    lcd_write_dat(0x3b); 
    lcd_write_dat(0x00); 
    lcd_write_dat(0x01); 
    lcd_write_dat(0x04); 
    lcd_write_dat(0x13);  
 
    lcd_write_cmd(0x3a);
    lcd_write_dat(0x06);
    lcd_write_cmd(0x29);
 
}
 
void lcd_SetRegion(uint8_t x_start,uint8_t y_start,uint8_t x_end,uint8_t y_end) __reentrant
{    
    lcd_write_cmd(0x2a);
    lcd_write_dat(0x0);
    lcd_write_dat(x_start);
    lcd_write_dat(0x0);
    lcd_write_dat(x_end);
 
    lcd_write_cmd(0x2b);
    lcd_write_dat(0x0);
    lcd_write_dat(y_start);
    lcd_write_dat(0x0);
    lcd_write_dat(y_end);
 
    lcd_write_cmd(0x2c);
}
 
void  lcd_write_16bit(uint16_t  Data) __reentrant
{
    uint8_t t;
 
    t = (Data>>8) & 0xff;
    lcd_write_dat(t);
 
    t = Data & 0xff;
    lcd_write_dat(t);        
 
}
 
uint8_t flash_byte_read (uint32_t addr)
{
  uint8_t t;
 
  t = (addr >> 24) & 0xff;
  FLASH_READ_DATA = t;
 
  t = (addr >> 16) & 0xff;
  FLASH_READ_DATA = t;
 
  t = (addr >> 8) & 0xff;
  FLASH_READ_DATA = t;
 
  t = addr & 0xff;
  FLASH_READ_DATA = t;
 
  nop_delay (10);
 
  FLASH_READ_CSR = 0;
  nop_delay (10);
 
  while(FLASH_READ_CSR == 0);
  t = FLASH_READ_DATA;
 
  return t;
 
}
 
static void single_color()
{
     uint8_t i,j,k,t;
     const uint8_t x = 128, y = 154;
     const uint8_t x_total = 132, y_total = 162;
     uint32_t addr = 0x8000;
 
 
    lcd_SetRegion(0,0,x_total-1,y_total-1);
 
    for (i = 0; i < x_total; ++i) {
      for (j = 0; j < y_total; ++j) {
        for (k = 0; k < 3; ++k) {
           lcd_write_dat(0xff);
        }
      }
    }
 
     lcd_SetRegion((x_total - x) >> 1, (y_total- y) >> 1,x-1 +((x_total - x) >> 1),y-1 + ((y_total- y) >> 1));
 
     for (i=0;i<x;i++) {
        for (j=0;j<y;j++) {
           // lcd_write_16bit(0x00ff);
           // lcd_write_dat (0);
 
            for (k = 0; k < 3; ++k) {
              t = flash_byte_read (addr++);
              lcd_write_dat(t);
             // Serial.print (addr, HEX);
             // Serial.write ("   ");
             // Serial.println(t, HEX);
            }
        }
     }
 
}
 
uint8_t old_count = 0;
uint8_t count = 0;
uint32_t big_count = 0;
 
 
typedef struct {
    void (*init) () __reentrant;
    uint8_t (*dataAvailable)() __reentrant;
    uint8_t (*read) () __reentrant;
} PS2_STRUCT;
 
extern const PS2_STRUCT PS2;
 
//----------------------------------------------------------------------------
// ps2_init()
//
// Parameters:
//      None
//     
// Return Value:
//      None
//
// Remarks:
//      call this function to init the PS2 module
//----------------------------------------------------------------------------
 
static void ps2_init() __reentrant
{
    PS2_CSR = 0;
    PS2_DATA = 0;
 
} // End of ps2_init()
 
 
//----------------------------------------------------------------------------
// ps2_data_available()
//
// Parameters:
//      None
//     
// Return Value:
//      1 when there is data in the FIFO
//      0 when FIFO is empty
//
// Remarks:
//      call this function to see if there is data in the receiving FIFO
//----------------------------------------------------------------------------
 
static uint8_t ps2_data_available() __reentrant
{    
    if (PS2_CSR) {
        return 1;
    } else {
        return 0;
    }
} // End of ps2_data_available() 
 
 
static uint8_t ps2_read() __reentrant
{
    uint8_t t;
 
    t = PS2_DATA;
    PS2_CSR = 0;
 
    return t;
 
} // End of ps2_read()
 
 
const PS2_STRUCT PS2 = {
    .init = ps2_init,
    .dataAvailable = ps2_data_available,
    .read = ps2_read
};
 
 
typedef struct {
    void (*reset) () __reentrant;
    void (*writeCMD)(uint8_t) __reentrant;
    void (*writeDAT) (uint8_t) __reentrant;
} LCD_STRUCT;
 
 
const LCD_STRUCT LCD = {
    .reset = lcd_reset,
    .writeCMD = lcd_write_cmd,
    .writeDAT = lcd_write_dat
};
 
void setup() {
 
  uint8_t t, i;
  Serial.begin (115200);
 
  SEVEN_SEG.init();
 
  ROTARY_ENCODER = 0x0;
 
  P3_DIRECTION = 0xFF;
 
  PS2.init();
  PWM.resolution (0, 938);
 
  lcd_init();
  single_color();
 
  PWM.dutyCycle (0, 255, 0);
 
  Serial.write ("Hello world!");
}
void loop() {
 
  uint8_t t;
 
//  Serial.println (big_count++);
 
  old_count = count;
  count = ROTARY_ENCODER;
  SEVEN_SEG.byteHex (count);
 
  if (old_count != count) {
     PWM.dutyCycle (0, count, 255-count);
  }
 
  P3 = (1 << (count >> 5)) - 1;
 
  if (PS2.dataAvailable()) {
    t = PS2.read();
 
    if (t == 0xF0) {
      Serial.print(t, HEX);
    } else {
      Serial.println(t, HEX);
    }
  }
}