/*
   DDS Signal generator
   --------
   v 1.00 2018/06/10
   Programmed 2018 By gijin77@gmail.com
*/

#include <Arduino.h>
#include <SPI.h>

#include <Elegoo_GFX.h>    // Core graphics library
#include <Elegoo_TFTLCD.h> // Hardware-specific library
#include <TouchScreen.h>

//   D0 connects to digital pin 8  (Notice these are
//   D1 connects to digital pin 9   NOT in order!)
//   D2 connects to digital pin 2
//   D3 connects to digital pin 3
//   D4 connects to digital pin 4
//   D5 connects to digital pin 5
//   D6 connects to digital pin 6
//   D7 connects to digital pin 7

#define LCD_RESET A4 // Can alternately just connect to Arduino's reset pin
#define LCD_CS A3 // Chip Select goes to Analog 3
#define LCD_CD A2 // Command/Data goes to Analog 2
#define LCD_WR A1 // LCD Write goes to Analog 1
#define LCD_RD A0 // LCD Read goes to Analog 0

#define SCLK_SG 13 //SCLK
#define MOSI_SG 11 //MOSI (Master Output Slave Input)
#define Fsync_PIN A5 //CS (Chip Select)

const int SINE = 0b0010000000000000; //0x2000
const int TRIANGLE = 0b0010000000000010; //0x2002
const int SQUARE = 0b0010000000100000; //0x2020
const int SQUARE_half = 0b0010000000101000; //0x2028
const float refFreq = 25000000.0;
int wave=SINE;;

// Color definitions
#define BLACK       0x0000      /*   0,   0,   0 */
#define NAVY        0x000F      /*   0,   0, 128 */
#define DARKGREEN   0x03E0      /*   0, 128,   0 */
#define DARKCYAN    0x03EF      /*   0, 128, 128 */
#define MAROON      0x7800      /* 128,   0,   0 */
#define PURPLE      0x780F      /* 128,   0, 128 */
#define OLIVE       0x7BE0      /* 128, 128,   0 */
#define LIGHTGREY   0xC618      /* 192, 192, 192 */
#define DARKGREY    0x7BEF      /* 128, 128, 128 */
#define BLUE        0x001F      /*   0,   0, 255 */
#define GREEN       0x07E0      /*   0, 255,   0 */
#define CYAN        0x07FF      /*   0, 255, 255 */
#define RED         0xF800      /* 255,   0,   0 */
#define MAGENTA     0xF81F      /* 255,   0, 255 */
#define YELLOW      0xFFE0      /* 255, 255,   0 */
#define WHITE       0xFFFF      /* 255, 255, 255 */
#define ORANGE      0xFD20      /* 255, 165,   0 */
#define GREENYELLOW 0xAFE5      /* 173, 255,  47 */
#define PINK        0xF81F

//******************* UI details
#define BTN_X 100
#define BTN_Y 188
#define BTN_W 20
#define BTN_H 30
#define BTN_SP_X 4
#define BTN_SP_Y 4
#define BTN_TEXTSIZE 3

// 波形 box 定数 
#define H_X 60
#define H_Y 45
#define H_W 200
#define H_H 36
#define H_TSIZE 4
#define H_TCOLOR MAGENTA

//*******************Touch For New ILI9341 TP
#define YP A2  // must be an analog pin, use "An" notation!
#define XM A3  // must be an analog pin, use "An" notation!
#define YM 8   // can be a digital pin
#define XP 9   // can be a digital pin
#define TS_MINX 120
#define TS_MAXX 900
#define TS_MINY 70
#define TS_MAXY 920

Elegoo_TFTLCD tft(LCD_CS, LCD_CD, LCD_WR, LCD_RD, LCD_RESET);
TouchScreen ts = TouchScreen(XP, YP, XM, YM, 300);

//釦関連パラメータ設定********************************************************
Elegoo_GFX_Button n_btn[8];
char frq[8][2] = {"0", "0", "0", "0", "1", "0", "0", "0" };

Elegoo_GFX_Button p_btn[8];
Elegoo_GFX_Button m_btn[8];
char p_m[2][2] = {"+","-"};

Elegoo_GFX_Button sel[6];
uint16_t sel_cl[3] = {LIGHTGREY,0x001C, RED};
char sel_txt[6][7] = {"DEMO","OUTPUT","RESET","","",""};

//全体画面描画*****************************************************************
void initbuttons(){
  tft.fillScreen(DARKGREY);
  dispString(20,2,GREEN,2," <DDS Signal generator>");
  // create buttons
  //サイン、三角波、方形波
  for (uint8_t col=0; col<3; col++) {
      sel[col+3].initButton(&tft, 45,150+col*35,
                  80,30,GREEN,DARKGREEN,BLUE,
                  sel_txt[col+3], 2); 
      sel[col+3].drawButton();
  }
  //DEMO/OUTPUT/RESET
  for (uint8_t col=0; col<3; col++) {
      sel[col].initButton(&tft, 60+col*100,110,
                  90, 35,GREEN,sel_cl[col],WHITE,
                  sel_txt[col], 2); 
      sel[col].drawButton();
  }
  for (uint8_t col=0; col<8; col++) {
      n_btn[col].initButton(&tft, BTN_X+col*(BTN_W+BTN_SP_X), 
                 BTN_Y,BTN_W, BTN_H,WHITE,BLUE,WHITE,
                  frq[col], BTN_TEXTSIZE); 
      n_btn[col].drawButton();

      p_btn[col].initButton(&tft, BTN_X+col*(BTN_W+BTN_SP_X),BTN_Y - BTN_H + 4,
                  BTN_W, BTN_H-5,GREEN,LIGHTGREY,GREEN,
                  p_m[0], 2); 
      p_btn[col].drawButton();

      m_btn[col].initButton(&tft, BTN_X+col*(BTN_W+BTN_SP_X),BTN_Y + BTN_H-4,
                  BTN_W, BTN_H-5,GREEN,LIGHTGREY,GREEN,
                  p_m[1], 2); 
      m_btn[col].drawButton();
   }
  dispString(BTN_X,230,YELLOW,1,"Programmed 2018 By gijin77@gmail.com");
  dispString(BTN_X+8*(BTN_W+BTN_SP_X)-10,BTN_Y,YELLOW,2,"kHz");
  tft.fillCircle(BTN_X+5*(BTN_W+BTN_SP_X)-13,BTN_Y+12,3,YELLOW);
  tft.fillCircle(BTN_X+2*(BTN_W+BTN_SP_X)-12,BTN_Y+12,2,YELLOW);
  tft.fillCircle(BTN_X+2*(BTN_W+BTN_SP_X)-15,BTN_Y+16,2,YELLOW);
  tft.drawRect(0,0,320,240,WHITE);
  tft.drawRect(1,1,319,239,WHITE);
  tft.drawRect(H_X-10,H_Y-24,H_W+20,H_Y+20,YELLOW);
  tft.drawRect(H_X-9,H_Y-23,H_W+19,H_Y+19,YELLOW);
  waveset(3);

}
//個別画面描画**********************************************************************
void dispStringBK(int x,int y,int tc,int bc,int ts,String msg) {
  int th,tl;
  tl=msg.length()*(ts*6);
  th=ts*8;
  tft.fillRect(x,y,tl,th,bc);
  tft.setTextSize(ts);
  tft.setTextColor(tc);
  tft.setCursor(x,y);
  tft.print(msg); 
}
void dispString(int x,int y,int tc,int ts,String msg) {
  tft.setTextSize(ts);
  tft.setTextColor(tc);
  tft.setCursor(x,y);
  tft.print(msg); 
}
void d_sine(uint16_t cl){
  static unsigned char t=0;
  int y;
  for(t=0;t<80;t++){
    y=(int)(sin((float)(t++)*2.0*3.14/32.0)*14.0);
    if (y>200) {
       y=y-251;
    }
    tft.drawPixel(t+6,y+149,cl);
    tft.drawPixel(t+6,y+150,cl);
    tft.drawPixel(t+6,y+151,cl);
  }
}
void d_triangle(uint16_t cl){
  for (int16_t i=0; i<80; i+=20) {
    tft.drawLine(i+6,198,i+16,172,cl);
    tft.drawLine(i+16,172,i+26,198,cl);
  }  
}
void d_square(uint16_t cl){
  for (int16_t i=5; i<80; i+=20) {
    tft.drawFastVLine(i+6,208,24,cl);
    tft.drawFastHLine(i+6,208,10,cl);
    tft.drawFastVLine(i+16,208,24,cl);
    tft.drawFastHLine(i+16,232,10,cl);    
  }  
}

void dsine(){
  tft.fillRect(H_X,H_Y,H_W,H_H,BLACK);
  tft.drawRect(H_X,H_Y,H_W,H_H,WHITE); 
  static unsigned char t=0;
  int y;
  for(t=0;t<H_W;t++){
    y=(int)(sin((float)(t++)*2.0*3.14/32.0)*16.0);
    if (y>200) {
       y=y-251;
    }
    tft.drawPixel(t+H_X, y+H_Y+H_H/2-1,YELLOW);
    tft.drawPixel(t+H_X, y+H_Y+H_H/2,YELLOW);
    tft.drawPixel(t+H_X, y+H_Y+H_H/2+1,YELLOW);
  }
  
}
 
void dtriangle(){
  tft.fillRect(H_X,H_Y,H_W,H_H,BLACK);
  tft.drawRect(H_X,H_Y,H_W,H_H,WHITE); 
  for (int16_t i=0; i<H_W; i+=40) {
    tft.drawLine(H_X+i,H_Y+30,H_X+i+20,H_Y+4,YELLOW);
    tft.drawLine(H_X+i+20,H_Y+4,H_X+i+40,H_Y+30,YELLOW);
  }
}
   
void dsquare(){
  tft.fillRect(H_X,H_Y,H_W,H_H,BLACK);
  tft.drawRect(H_X,H_Y,H_W,H_H,WHITE); 
  tft.drawFastHLine(H_X,H_Y+30, 20,YELLOW);
  for (int16_t i=20; i<(H_W-20); i+=40) {
    tft.drawFastVLine(H_X+i,H_Y+4,28,YELLOW);
    tft.drawFastHLine(H_X+i, H_Y+4, 20,YELLOW);
    tft.drawFastVLine(H_X+i+20,H_Y+4,28,YELLOW);
    tft.drawFastHLine(H_X+i+20, H_Y+30, 20,YELLOW);    
  }  
}

void dsquare_half(){
  tft.fillRect(H_X,H_Y,H_W,H_H,BLACK);
  tft.drawRect(H_X,H_Y,H_W,H_H,WHITE); 
  tft.drawFastHLine(H_X,H_Y+60, 10,YELLOW);
  for (int16_t i=10; i<(H_W-10); i+=20) {
    tft.drawFastVLine(H_X+i,H_Y+4,28,YELLOW);
    tft.drawFastHLine(H_X+i, H_Y+4, 10,YELLOW);
    tft.drawFastVLine(H_X+i+10,H_Y+4,28,YELLOW);
    tft.drawFastHLine(H_X+i+10, H_Y+30, 10,YELLOW);    
  }  
}

//SPI出力**********************************************************************
void Control_Resister_Write(uint16_t b){
  digitalWrite(Fsync_PIN, LOW);
  SPI.transfer((b>>8)&0xff); //上位8bit
  SPI.transfer(b&0xff);      //下位8bit
  digitalWrite(Fsync_PIN, HIGH);
}
//DDS出力**********************************************************************
void AD9833_SetFrequency(uint32_t frequency, int Waveform) {
      dispStringBK(H_X,25,WHITE,DARKGREY,2,"                 ");
      if (frequency > (uint32_t)12500000) {
      frequency=(uint32_t)12500000;
      dispStringBK(H_X,25,RED,DARKGREY,2,"Error:max 12.5MHz");
    } else if (frequency < (uint32_t)1000) {
      String msg = String("Frq:"+String(frequency)+"Hz");
      dispStringBK(H_X,25,WHITE,DARKGREY,2,msg);
    } else {
      String msg = String("Frq:"+String(float(float(frequency)/float(1000)),3)+"kHz");
      dispStringBK(H_X,25,WHITE,DARKGREY,2,msg);
    }
    if (Waveform==0x2000){ //SINE
       dsine();
    } else if (Waveform==0x2002){ //TRIANGLE
       dtriangle();
    } else if (Waveform==0x2020){ //M:SQUARE
       dsquare();
    } else if (Waveform==0x2028){ //SQUARE_half
       dsquare_half();
    }

  uint32_t FreqWord = (frequency * pow(2, 28)) / refFreq;
  uint16_t MSB = (uint16_t)((FreqWord & 0xFFFC000) >> 14);
  uint16_t LSB = (uint16_t)(FreqWord & 0x3FFF);
 
  LSB |= 0b0100000000000000; //=0x4000
  MSB |= 0b0100000000000000; //=0x4000
 
  Control_Resister_Write(0b0010000000000000); //制御ワード書き込み
  Control_Resister_Write(LSB);
  Control_Resister_Write(MSB);
 
  Control_Resister_Write(0b1100000000000000); //位相シフトはゼロ
  Control_Resister_Write(Waveform);
}


//LCDテスト**********************************************************************
void disptest() {
  for (int x=0,y=0;y<120;x++,y++){
    tft.drawRect(x,y,320-x*2,240-y*2,RED);
  }
  delay(500);
  for (int x=0,y=0;y<120;x++,y++){
    tft.drawRect(x,y,320-x*2,240-y*2,GREEN);
  }
  delay(500);
  for (int x=0,y=0;y<120;x++,y++){
    tft.drawRect(x,y,320-x*2,240-y*2,BLUE);
  }
  delay(500);
  for (int x=0,y=0;y<120;x++,y++){
    tft.drawRect(x,y,320-x*2,240-y*2,BLACK);
  } 
  tft.drawRect(0,0,320,240,WHITE);
  tft.drawRect(1,1,319,239,WHITE);
  tft.setTextSize(5);
  tft.setTextColor(GREEN);
  tft.setCursor(0,20);
  tft.println("    DDS");
  tft.println("   Signal"); 
  tft.println(" Generater");
  tft.setTextSize(2);
  tft.println();
  tft.println("     Programmed 2018");
  tft.println("   By gijin77@gmail.com");
  delay(2000);
  for (int x=0,y=0;y<120;x++,y++){
    tft.drawRect(x,y,320-x*2,240-y*2,GREEN);
  }
  
}
//デモ出力*************************************************************************
void demo(){
  if (wave==SINE) demo1();
  else if(wave==TRIANGLE) demo2();
  else demo3();
}

void demo1() {
  AD9833_SetFrequency(1000, SINE);
  Serial.println("1KHz サイン波");
  delay(5000);
  AD9833_SetFrequency(2000, TRIANGLE);
  Serial.println("2KHz 三角波");
  delay(5000);
  AD9833_SetFrequency(3000, SINE);
  Serial.println("3KHz サイン波");
  delay(5000);
  AD9833_SetFrequency(4000, TRIANGLE);
  Serial.println("4KHz 三角波");
  delay(5000);
  AD9833_SetFrequency(3000, SQUARE_half);
  Serial.println("3KHz 方形波");
  delay(5000);
  AD9833_SetFrequency(2000, SQUARE_half);
  Serial.println("2KHz 方形波");
  delay(5000);
  AD9833_SetFrequency(1000, SQUARE_half);
  Serial.println("1KHz 方形波");
  delay(5000);
}

void demo2() {
int f[8] ={262,294,330,349,392,440,494,523};  

  for (int i=0;i<8;i++) {
      AD9833_SetFrequency(f[i], SINE);
      String msg = String(String(f[i])+"Hz サイン波");
      Serial.println(msg);
      if (i==0) delay(3000); else delay(500);
  }
  delay(2000);
  for (int i=6;i>=0;i--) {
      AD9833_SetFrequency(f[i], SINE);
      String msg = String(String(f[i])+"Hz サイン波");
      Serial.println(msg);
      delay(500);
  }
}

void demo3() {
int f;
  for (f=1000;f<13000;f+=1000) {
      AD9833_SetFrequency(f, SINE);
      String msg = String(String(f)+"Hz サイン波");
      Serial.println(msg);
      delay(2000);
  }
  for (f=11000;f>=1000;f-=1000) {
      AD9833_SetFrequency(f, SINE);
      String msg = String(String(f)+"Hz サイン波");
      Serial.println(msg);
      delay(2000);
  }
  for (f=900;f>=100;f-=100) {
      AD9833_SetFrequency(f, SINE);
      String msg = String(String(f)+"Hz サイン波");
      Serial.println(msg);
      delay(2000);
  }
  for (f=90;f>=10;f-=10) {
      AD9833_SetFrequency(f, SINE);
      String msg = String(String(f)+"Hz サイン波");
      Serial.println(msg);
      delay(2000);
  }

}
//設定出力****************************************************************************
void outfrq() {
   char f[]="00001000";
   for(int i=0;i<8;i++) {
     f[i]=frq[i][0];
   }
   uint32_t frq =(uint32_t)(f[0]-0x30)*(uint32_t)10000000+(uint32_t)(f[1]-0x30)*(uint32_t)1000000+(uint32_t)(f[2]-0x30)*(uint32_t)100000+(uint32_t)(f[3]-0x30)*(uint32_t)10000+(uint32_t)(f[4]-0x30)*(uint32_t)1000+(uint32_t)(f[5]-0x30)*(uint32_t)100+(uint32_t)(f[6]-0x30)*(uint32_t)10+(uint32_t)(f[7]-0x30);
   AD9833_SetFrequency(frq, wave);
   Serial.println("++++++++++++++++");
   Serial.println(f); 
   digitalWrite(2, HIGH);
   Serial.println("----------------");
}
//出力波形設定***************************************************************************
void waveset(int b){
  sel[3].drawButton();
  sel[4].drawButton();
  sel[5].drawButton();
  d_sine(YELLOW);
  d_triangle(YELLOW);
  d_square(YELLOW); 
  if (b==3) {
    wave=SINE;
    sel[3].drawButton(true);
    d_sine(WHITE);
  } else if (b==4) {
    wave=TRIANGLE;
    sel[4].drawButton(true);
    d_triangle(WHITE);
  } else if (b==5) {
    wave=SQUARE_half;
    sel[5].drawButton(true);
    d_square(WHITE); 
  } 
}

//初期設定************************************************************************
void setup(void) {
  Serial.begin(115200);
  Serial.println(F("DDS Signal generator"));

#ifdef USE_Elegoo_SHIELD_PINOUT
  Serial.println(F("Using Elegoo 2.8\" TFT Arduino Shield Pinout"));
#else
  Serial.println(F("Using Elegoo 2.8\" TFT Breakout Board Pinout"));
#endif

  Serial.print("TFT size is ");
  Serial.print(tft.width()); Serial.print("x"); Serial.println(tft.height());

  tft.reset();

  uint16_t identifier = tft.readID();
  if(identifier == 0x9341) {
    Serial.println(F("Found ILI9341 LCD driver"));
  } else if(identifier==0x0101) {     
    identifier=0x9341;
    Serial.println(F("Found 0x9341 LCD driver"));
  }else {
    Serial.print(F("Unknown LCD driver chip: "));
    identifier=0x9341;
  }

  SPI.setBitOrder(MSBFIRST);  //最上位ビット(MSB)から送信
  SPI.setClockDivider(SPI_CLOCK_DIV2); //通信速度 16/2=8Mhz
  SPI.setDataMode(SPI_MODE2); //CPOL(クロック極性):0 CPHA(クロックフェーズ):0
  SPI.begin();
  pinMode(Fsync_PIN, OUTPUT);
  digitalWrite(Fsync_PIN, HIGH);
  Control_Resister_Write(0b0000000100000000); //Reset


  tft.begin(identifier);
  tft.setRotation(3);
  disptest();
  initbuttons(); //画面表示
}

//メインループ***************************************************************************
void loop(void) {

  TSPoint p = ts.getPoint();
  // アナログ入力と、LCD出力とピンを共有する場合は、タッチ入力後出力設定
  pinMode(XM, OUTPUT);
  pinMode(YP, OUTPUT);

  // タッチされた時
 if (p.z > 30) {
    Serial.print("["); Serial.print(p.x); Serial.print(", "); 
    Serial.print(p.y); Serial.print(", "); 
    Serial.print(p.z); Serial.println("] ");

//   tft.setRotation(1)の時
//    p.x = map(p.x, TS_MINX, TS_MAXX, 10, tft.width());
//    p.y = map(p.y, TS_MINY, TS_MAXY, 0, tft.height());

//   tft.setRotation(3)の時
    p.x = map(p.x, TS_MINX, TS_MAXX, tft.width(),10);
    p.y = map(p.y, TS_MINY, TS_MAXY, tft.height(),0);

    
    Serial.print("("); Serial.print(p.x); Serial.print(", "); 
    Serial.print(p.y); Serial.print(", "); 
    Serial.print(p.z); Serial.println(") ");
 }
  // すべてのボタンを検索して、押されたかどうかを確認する
  for (uint8_t b=0; b<6; b++) {
    if (sel[b].contains(p.x, p.y)) {
      Serial.print("Pressing: SEL"); Serial.println(b);
      sel[b].press(true);  // ボタンが押されたことを伝える
    } else {
      sel[b].press(false);  // ボタンは、押されていない
    }
  }
  for (uint8_t b=0; b<8; b++) {
    if (p_btn[b].contains(p.x, p.y)) {
      Serial.print("Pressing: +"); Serial.println(b);
      p_btn[b].press(true);  // ボタンが押されたことを伝える
    } else {
      p_btn[b].press(false);  // ボタンは、押されていない
    }
  }
  for (uint8_t b=0; b<8; b++) {
    if (m_btn[b].contains(p.x, p.y)) {
      Serial.print("Pressing: -"); Serial.println(b);
      m_btn[b].press(true);  // ボタンが押されたことを伝える
    } else {
      m_btn[b].press(false);  // ボタンは、押されていない
    }
  }


  // ボタンの状態が変更されたかどうかを確認する
  for (uint8_t b=0; b<6; b++) {
    if (sel[b].justReleased()) {
      Serial.print("Released: SEL"); Serial.println(b);
      if (b<3) { 
        sel[b].drawButton();  // draw normal         
      }
    }
    if (sel[b].justPressed()) {
      if (b>=3) { 
        waveset(b); //3=サイン波 4=三角波 5=方形波
      } else {
         sel[b].drawButton(true);  // draw invert!     
      }
        if (b == 0) { //DEMO
          demo();
        }
        if (b == 1) { //OUTPUT
          outfrq();
        }
        if (b == 2) { //RESET
          Control_Resister_Write(0b0000000100000000); //Reset
          for (int i=0;i<8;i++) {
             if (i==4) {frq[i][0]=0x31;} else {frq[i][0]=0x30;}
         }
         initbuttons(); //釦表示
        }
    }
  }
  for (uint8_t b=0; b<8; b++) {
    if (p_btn[b].justReleased()) {
      Serial.print("Released: +"); Serial.println(b);
      p_btn[b].drawButton();  // draw normal
    }
    
    if (p_btn[b].justPressed()) {
        p_btn[b].drawButton(true);  // draw invert!
        char dt=char(frq[b][0]);
        if (dt==0x39) {
          dt=0x30;
        } else {
          dt+=1;
        }
        frq[b][0]=char(dt);
        n_btn[b].initButton(&tft, BTN_X+b*(BTN_W+BTN_SP_X), 
                 BTN_Y,BTN_W, BTN_H,WHITE,BLUE,WHITE,
                  frq[b], BTN_TEXTSIZE); 
        n_btn[b].drawButton();
      }
  }
  for (uint8_t b=0; b<8; b++) {
    if (m_btn[b].justReleased()) {
      Serial.print("Released: -"); Serial.println(b);
      m_btn[b].drawButton();  // draw normal
    }
    
    if (m_btn[b].justPressed()) {
        m_btn[b].drawButton(true);  // draw invert!
        char dt=char(frq[b][0]);
        if (dt==0x30) {
          dt=0x39;
        } else {
          dt-=1;
        }
        frq[b][0]=char(dt);
        n_btn[b].initButton(&tft, BTN_X+b*(BTN_W+BTN_SP_X), 
                 BTN_Y,BTN_W, BTN_H,WHITE,BLUE,WHITE,
                  frq[b], BTN_TEXTSIZE); 
        n_btn[b].drawButton();
     }
  }
  delay(10);
 
}