#include <intrinsics.h>
#include "lpc2388.h"

/****************************************************************************
    インターフェース2009年5月号基板
    CPUカード オンボードLED点灯制御
    main_puw090414.c
    2009/03/30  USBポート使用UART0 シリアル通信 追加
            31  数値を文字列に変換してタイマー割り込みでPCへ送信OK
                レジスタの参照方法を変更 インクルードファイル作成OK
         04/02  UART0受信してエコーバック OK リターンキーでバッファー文字列エコーOK
                atoi 文字列を引数->整数値を戻り値に返す関数追加
            03  拡張ボード配線TD62083 2個 PORT2[0-7]
            04  パルスモーター励磁パターン出力2相、1−2相出力OK ターミナルより速度変更OK
            05  X軸Y軸同時制御OK 速度は共通
            10  X,Y,Z軸同時書込みコマンド'm'追加
            11  レジスター書込みコマンド'w'追加OK
            12  レジスター読込みコマンド'r'追加OK
                CPUに割り込み禁止コマンド'd'追加OK
                CPUに割り込み許可コマンド'e'追加OK
            14  ADCコマンド a0-a7 0-7CHリードOK 注)クロックが遅いと読取値が減少する。Vref:3.3V->1023 OK 
                DACコマンド D****:(0-1023) 追加 OK DAC出力はADC3cHと同じPin

****************************************************************************/

#define TX_BUFSIZE    80
#define UART_BUFSIZE  80

static unsigned char  txbuf[TX_BUFSIZE];
static char  UART0Buffer[UART_BUFSIZE];
static char  buf[10];
static unsigned char  pat[8];

static unsigned char  RBRValue, LSRValue;
static unsigned char  txptr = 0;
static unsigned char  ptr = 0;
static unsigned int   UART0Count = 0;
static unsigned int   no = 0 ;
static unsigned int   Xpat_no = 0 ; // X軸パルスモーター励磁位置
static unsigned char  Xcw = 0 ;     // X軸パルスモーター回転方向
static int            Xcount;       // X軸パルスモーターパルス
static unsigned int   Ypat_no = 0 ; // Y軸パルスモーター励磁位置
static unsigned char  Ycw = 0 ;     // Y軸パルスモーター回転方向
static int            Ycount;       // Y軸パルスモーターパルス
static unsigned int   Zpat_no = 0 ; // Z軸パルスモーター励磁位置
static unsigned char  Zcw = 0 ;     // Z軸パルスモーター回転方向
static int            Zcount;       // Z軸パルスモーターパルス

void UART0_Init(void)
{
// Fpclk = 4.000.000 MHz
// DLM,DLH = Fpclk / (19200*16) = 13
 
  PCLKSEL0 = 0x00000040;        // PCLK_UART0 = CCLK
  GPIO_PINSEL0 = 0x00000050;  // Select UART0 RXD/TXD

  U0LCR = 0x83;   // 8N1, enable Divisor latch bit on
  U0DLM = 0;
  U0DLL = 13;           // baud rate fixed to 19200 @ PCLK = 4 Mhz
  U0FCR = 7;    // Enable and clear FIFO's
  U0LCR = 0x03;   // 8N1, enable Divisor latch bit off
}

// 文字列をバッファーにコピー
static void SendString(char *text)
{
    txptr = 0;                // previous message send ?
    while(*text)
    {
      txbuf[txptr++] = *text++;
      if(txptr >= TX_BUFSIZE) txptr = 0;
    }
}

// バッファーの文字列送信
static void Send(void)
{
ptr = 0;
    while (txptr != 0)
    { 
      while (!(U0LSR && 0x20));   // THRE status, contain valid data
        U0THR = txbuf[ptr];
        txptr--;
        ptr++;
    }
}

// UART0へ文字列送信
static void StrTX(char *text)
{
    while(*text)
    {
      while (!(U0LSR && 0x20));  // THRE status, contain valid data
      U0THR = *text++;
    }
}

// UART0へ1文字送信
static void TX(char ch)
{
    while (!(U0LSR && 0x20));  // THRE status, contain valid data
    U0THR = ch;
}

/* LEDを点灯する処理 */
void LED_ON() {
    FGPIO_FIO1PIN=0x00000000; /* P1[18] を'0'に(LEDを点ける) */
}

/* LEDを消灯する処理 */
void LED_OFF() {
    FGPIO_FIO1PIN=0x00040000; /* P1[18] を'1'に(LEDを消す)   */
}

/* LED1を点灯する処理 */
void LED1_ON() {
    FGPIO_FIO2PIN=0x00000080; /* P2[7] を'1'に(LEDを点ける) */
}

/* LED1を消灯する処理 */
void LED1_OFF() {
    FGPIO_FIO2PIN=0x00000000; /* P2[7] を'0'に(LEDを消す)   */
}

// カウンターの値をP2ポートへ出力
void COUNT_OUT() {
    FGPIO_FIO2PIN = no;
}

// 文字列を最後から先頭に並べ変える
char* strrevP(char *s)
{
char *ret = s;
char *t = s;
char c;

    while(*t != '\0')
      t++;
      t--;
    while(t > s){
      c = *s;
      *s = *t;
      *t = c;
      s++;
      t--;
    }
return ret;
}

//整数を文字に変換する。
void itoa(int value, char *buff)
{
char *p;
int mod;
      // 入力した値の正負を文字にする。
 if( 0 > value ) {
 *buff++ = '-';
 value = -value;
 }
 p = buff;

      // 入力した値を下位の桁から順に文字にする。
 do{
     mod = value % 10 + 48;
     *p++ = (char)mod;
     value /= 10;
 }while(value);
 *p = '\0';                  // 文字列の最後に '\0' を追加して締める。
 strrevP(buf);               // 文字列の上位の桁から始まるように並べ替える。
}

// 文字列送信
void mesTX()
{
        StrTX("Hello LPC2388 2009/04/09\r\n"); // UART0へ文字列送信

        no = Xcount;
        itoa(no,buf);               // 整数を文字に変換する
        StrTX(buf);                 // カウンター数値送信
        StrTX("\r\n");              // CR LF送信
}
       
// IRQ 割り込み処理
__irq __arm void IRQ_Handler()
{
static int led = 0;

  // IRQ Timer0
  if((TIMER0_InterruptRegister & 1) == 1){

    if( led == 0 ) {
        led = 1;
        LED_ON();
//        mesTX();                    // 文字列送信
    } else {
        led = 0;
        LED_OFF();
    }
    TIMER0_InterruptRegister = 1;   // MC0をクリア
  }

  // IRQ Timer1
  if((TIMER1_InterruptRegister & 1) == 1){

    if(Xcount >= 0){  // X軸
      if (Xcw == 0){
        if(Xpat_no == 7) Xpat_no = 0; else Xpat_no++;
      }
      else{
        if(Xpat_no == 0) Xpat_no = 7; else Xpat_no--;
      }

      Xcount--;
    }   

    if(Ycount >= 0){  // Y軸
      if (Ycw == 0){
        if(Ypat_no == 7) Ypat_no = 0; else Ypat_no++;
      }
      else{
        if(Ypat_no == 0) Ypat_no = 7; else Ypat_no--;
      }

      Ycount--;
    }   

    FGPIO_FIO2PIN = pat[Xpat_no];         // 励磁パターをポートへ出力
    FGPIO_FIO2PIN |= (pat[Ypat_no] << 4); // 励磁パターをポートへ出力

    TIMER1_InterruptRegister = 1;         // MC1をクリア
  }

}

// 文字列を引数->整数値を戻り値に返す
int a2i(char *str)
{
    int cnt;

    int num=0;

    for(cnt=0;(str[cnt]>='0')&&(str[cnt]<='9');cnt++){
      num = 10 * num + (str[cnt] - '0');
    }

    return num;
}

// 検索文字列の位置を戻り値に返す
int strstr(){
char s[] = "This is a pen. That is an apple.";
char str[] = "an";
int i,j,p;
i=j=p=0;

  while (s[i] !='\0' && str[j] != '\0'){
    if (s[i] == str[j]) {
      i++;
      j++;
      p=i-j;
    }else{
    i -= j - 1;
    j = 0;
    }
  }
  if(str[j]=='\0')
    return p;
  else
    return 0;
}

// 検索文字の位置を戻り値に返す 0:見つからない
int strchr(char*s,char ch){
int i=0;

    while (s[i] !='\0'){
    if(s[i] == ch) return i+1; else i++;
    }
    return 0;
}

// 文字列移動 前に詰める
void strmov(char*s,int no){
int i=0;

    while (s[no] !='\0'){
      s[i] = s[no];
      i++;
      no++;
    }
    s[no]='\0';
}

// 検索文字列の文字数を戻り値に返す
int strLEN(char *s){
int i=0;
    while (s[i] !='\0'){ i++; }
 //printf("LEN= %d\n\r",i);
    return i;
}

// 検索文字の位置を戻り値に返す
int strcha(char *s, char ch){
int i=0;

    while (s[i] !='\0'){
      if (s[i] == ch) return i; else i++;
    }
    return 0;
}

// 10進文字列を引数->INT値を戻り値に返す(符号付き)
int a2I(char *str)
{
int cnt;
int num=0;
char flg;

    if(str[0]=='-'){
        flg=1;
        str[0]='0';
    }
    for(cnt=0;(str[cnt]>='0')&&(str[cnt]<='9');cnt++){
        num = 10 * num + (str[cnt] - '0');
    }
    if(flg==1){
     num = 0 - num;
     return num;
    }else{
     return num;
    }
}

// 順序入れ替え用関数
char* func(char* data)
{
char dat;
int StrLength = strLEN(data);   /* 列長 */
int i,j;

      for(i = 0, j = StrLength - 1; i < StrLength / 2; i++,j--){
 dat = data[i];
 data[i] = data[j];
 data[j] = dat;
      }
      data[StrLength] = '\0';
      return(data);
}

// 整数を16進数文字列に変換する
void ItoA16(int value, char *buff)
{
char *p;
int mod;

    p = buff;
    // 入力した値を下位の桁から順に文字にする。
    do{
        mod = value % 16;
 if(mod > 9) mod += 7;
 *p++ = (char)(mod + 48);
 value /= 16;
    }while(value);

    *p = '\0';               // 文字列の最後に '\0' を追加
    func(buff);          // 順序入れ替え用関数 
}

// 16進文字列を引数->整数値
int a16toi(char *str)
{
int cnt;
int num=0;
    for(cnt=0; ((str[cnt]>='0')&&(str[cnt]<='9')||(str[cnt]>='A')&&(str[cnt]<='F')); cnt++){
 if((str[cnt]>='0')&&(str[cnt]<='9')) num = 16 * num + (str[cnt] - '0');
 if((str[cnt]>='A')&&(str[cnt]<='F')) num = 16 * num + (str[cnt] - '0'-7);
    }
    return num;
}

//-------------------------------------------------------------------------         
// main関数
int main(void)
{
    SYS_SCS = SYS_SCS | 1;      // FGPIO Select

    FGPIO_FIO1DIR =0x00040000; // P1[18] を出力端子にする
    FGPIO_FIO1MASK=0x00000000; // P1には一切マスクをかけない

//    FGPIO_FIO2DIR =0x0000000F;    // P2[0-3] を出力端子にする
    FGPIO_FIO2DIR =0x000000FF;    // P2[0-7] を出力端子にする
//    FGPIO_FIO2MASK=0x00000000; /* P2には一切マスクをかけない
//    FGPIO_FIO2MASK=0xFFFFFFF0; // P2にマスクをかける
    FGPIO_FIO2MASK=0xFFFFFF00;   // P2にマスクをかける

    // 割り込みがかかると初めて点灯するようにLEDを消しておく
    LED_OFF();

    // 割り込み種類選択 (全ての割り込みをFIQではなくIRQにする)
    VIC_IntSelect = 0;

    // Timer0のパラメータ設定
    TIMER0_PrescaleRegister     = 0x00000000;     // プリスケール無
//    TIMER0_MatchRegister0       = 500000;         // MC0 ≒ 0.5*1M 1S
    TIMER0_MatchRegister0       = 1000000;         // MC0 ≒ 1*1M 2S
//    TIMER0_MatchRegister0       = 0x00080000;     // MC0 ≒ 0.5*1M
    TIMER0_MatchControlRegister = 0x00000003;     // Match時にTCクリア & 割り込み
    VIC_IntEnable = TIMER0_INT_BIT;               // VICに割り込み許可

    // 1のパラメータ設定
    TIMER1_PrescaleRegister     = 0x00000000;     // プリスケール無
    TIMER1_MatchRegister0       = 0x00010000;     // MC1
    TIMER1_MatchControlRegister = 0x00000003;     // Match時にTCクリア & 割り込み
    VIC_IntEnable = TIMER1_INT_BIT;               // VICに割り込み許可

    __enable_interrupt();                         // CPUに割り込み許可を指示する

    // タイマスタート
    TIMER0_TimerControlRegister = 1;
    TIMER1_TimerControlRegister = 1;

//#define reiji
#ifdef reiji
    //2相励磁パターン
    pat[0] = 0x03;
    pat[1] = 0x06;
    pat[2] = 0x0c;
    pat[3] = 0x09;
    pat[4] = 0x03;
    pat[5] = 0x06;
    pat[6] = 0x0c;
    pat[7] = 0x09;
#else
    //1−2相励磁パターン
    pat[0] = 0x01;
    pat[1] = 0x03;
    pat[2] = 0x02;
    pat[3] = 0x06;
    pat[4] = 0x04;
    pat[5] = 0x0c;
    pat[6] = 0x08;
    pat[7] = 0x09;
#endif

    UART0_Init();
    no = 0;
    Xcw = 1;
    Xcount = 16;

    char str[256];
    char s[]="X12345Y67890";
    char ch;
    int  adr,data;

    StrTX("Hello LPC2388 2009/04/14\r\n");          // オープニングメッセージ送信
   
    // メインループ(文字のエコーバックとリターンキーで受信バッファー文字列エコー)
    for(;;){

      LSRValue = U0LSR;                             // 受信フラグ読出し
   
      if (LSRValue & LSR_RDR){              // 受信可   
        RBRValue = U0RBR;                           // 受信データ読出し
        UART0Buffer[UART0Count] = RBRValue;
 UART0Count++;
         
        if(RBRValue == '\r'){                       // リターンキー?
          UART0Buffer[UART0Count] = '\0';
          StrTX(">");                               // CR LF送信
          StrTX(UART0Buffer);                       // 受信バッファー文字列送信 
          StrTX("\r\n");                            // CR LF送信
          UART0Count = 0;


          if(UART0Buffer[0]=='F'){                  // 速度
            UART0Buffer[0]='0';
            no = a2i(UART0Buffer);                  // 文字列を引数->整数値
            TIMER1_TimerControlRegister = 2;        // Timer1 reset
            TIMER1_MatchRegister0 = no;             // Timerマッチレジスター変更
            TIMER1_TimerControlRegister = 1;        // Timer1 start
            goto LE;
          }
         
          if(UART0Buffer[0]=='X'){                  // X軸データ
            UART0Buffer[0]='0';
            if(UART0Buffer[1]=='-'){
              UART0Buffer[1]='0';
              Xcw = 1;
            }else{ Xcw = 0;}
            no = a2i(UART0Buffer);                  // 文字列を引数->整数値
            Xcount = no;
            goto LE;
          }

          if(UART0Buffer[0]=='Y'){                  // Y軸データ Y*****
            UART0Buffer[0]='0';
            if(UART0Buffer[1]=='-'){
              UART0Buffer[1]='0';
              Ycw = 1;
            }else{ Ycw = 0;}
            no = a2i(UART0Buffer);                  // 文字列を引数->整数値
            Ycount = no;
            goto LE;
          }

          if(UART0Buffer[0]=='s'){                  // 文字位置サーチ OK
            ch = UART0Buffer[1];
            no = strchr(&UART0Buffer[2],ch);        // ch文字位置検索

            itoa(no,buf);                           // 整数を文字に変換する
     //strrevP(buf);                           // 文字列の上位の桁から始まるように並べ替える。
            StrTX("no:");                           // 文字列送信
            StrTX(buf);                             // 文字列送信
            StrTX("\r\n");                          // CR LF送信

            goto LE;
          } 

          if(UART0Buffer[0]=='r'){                  // レジスター読込みコマンド?
            adr = a16toi(&UART0Buffer[1]);          // 読込みアドレス文字列を数値に変換
            no  = (*(volatile unsigned int *)(adr));// レジスター読込み

            ItoA16(no, buf);                        // 整数を16進数文字列に変換する
            StrTX(buf);                             // 文字列送信
            StrTX("\r\n");                          // CR LF送信

            goto LE;
          } 

          if(UART0Buffer[0]=='w'){                      // レジスター書込み
            adr = a16toi(&UART0Buffer[1]);              // 書込みアドレス文字列を数値に変換
     no = strcha(UART0Buffer,',');               // 文字位置サーチ
            if(no>0){
              data = a16toi(&UART0Buffer[no+1]);        // 書込みデータ文字列を数値に変換
              (*(volatile unsigned int *)(adr)) = data; // レジスター書込み
            }
            goto LE;
          } 

          if(UART0Buffer[0]=='d'){     
            __disable_interrupt();                      // CPUに割り込み禁止
            StrTX("disable\r\n");                       // 文字列送信
            goto LE;
          }         
         
          if(UART0Buffer[0]=='e'){
            __enable_interrupt();                       // CPUに割り込み許可
            StrTX("enable\r\n");                        // 文字列送信
            goto LE;
          }         
         
          if(UART0Buffer[0]=='m'){                      // X,Y,Z数値取出し

     no = strcha(UART0Buffer,'X');               // X文字位置サーチ
            if(no>0){
              UART0Buffer[no]='0';
              if(UART0Buffer[no+1]=='-'){               // 符号チェック
                UART0Buffer[no+1]='0';
                Xcw = 1;
              }else{ Xcw = 0;}
              no = a2i(&UART0Buffer[no+1]);             // 文字列を整数値に変換
              Xcount = no;
            }

     no = strcha(UART0Buffer,'Y');               // Y文字位置サーチ
            if(no>0){
              UART0Buffer[no]='0';
              if(UART0Buffer[no+1]=='-'){               // 符号チェック
                UART0Buffer[no+1]='0';
                Ycw = 1;
              }else{ Ycw = 0;}
              no = a2i(&UART0Buffer[no+1]);             // 文字列を整数値に変換
              Ycount = no;
            }

     no = strcha(UART0Buffer,'Z');               // Z文字位置サーチ
            if(no>0){
              UART0Buffer[no]='0';
              if(UART0Buffer[no+1]=='-'){               // 符号チェック
                UART0Buffer[no+1]='0';
                Zcw = 1;
              }else{ Zcw = 0;}
              no = a2i(&UART0Buffer[no+1]);             // 文字列を整数値に変換
              Zcount = no;
            }
            goto LE;
   }
         
          if(UART0Buffer[0]=='a'){        // ADCコマンド a0-a7
            PCONP   |= 1 << 12;           // A/Dコンバータの電源をONにする
            PCLKSEL0|= 1 << 24;           // A/DにCPUクロックを供給
            //AD0CR   |= 16 << 8;           // A/Dコンバータの周波数をCPUクロックの1/16
            AD0CR   |= 1 << 21;           // A/Dを有効にする

            ch =(UART0Buffer[1] -= '0');      // A/Dチャンネル
            switch(ch){
              case 0:             
                GPIO_PINSEL1 |= 1 << 14;   // P0[23]のピンAD0として使用
                break;
              case 1:             
                GPIO_PINSEL1 |= 1 << 16;   // P0[24]のピンAD1として使用
                break;
              case 2:             
                GPIO_PINSEL1 |= 1 << 18;   // P0[25]のピンAD2として使用
                break;
              case 3:             
                GPIO_PINSEL1 |= 1 << 20;   // P0[26]のピンAD3として使用
                break;
              case 4:             
                GPIO_PINSEL3 |= 3 << 28;   // P1[30]のピンAD4として使用
                break;
              case 5:             
                GPIO_PINSEL3 |= 3 << 30;   // P1[31]のピンAD5として使用
                break;
              case 6:             
                GPIO_PINSEL0 |= 3 << 24;   // P0[12]のピンAD6として使用
                break;
              case 7:             
                GPIO_PINSEL0 |= 3 << 26;   // P0[13]のピンAD7として使用
                break;
            }
            AD0CR = (AD0CR & 0xffffff00) | (0x01 << ch);    // チャンネル選択
            AD0CR |= 1 << 24;                               // ADC開始

            switch(ch){
              case 0:             
                while((AD0DR0 & 0x80000000) == 0x80000000) ;// ADC完了待ち
         no = AD0DR0 >> 6;                           // データ読込み
                break;
              case 1:             
                while((AD0DR1 & 0x80000000) == 0x80000000) ;
         no = AD0DR1 >> 6;
                break;
              case 2:             
                while((AD0DR2 & 0x80000000) == 0x80000000) ;
         no = AD0DR2 >> 6;
                break;
              case 3:             
                while((AD0DR3 & 0x80000000) == 0x80000000) ;
         no = AD0DR3 >> 6;
                break;
              case 4:             
                while((AD0DR4 & 0x80000000) == 0x80000000) ;
         no = AD0DR4 >> 6;
                break;
              case 5:             
                while((AD0DR5 & 0x80000000) == 0x80000000) ;
         no = AD0DR5 >> 6;
                break;
              case 6:             
                while((AD0DR6 & 0x80000000) == 0x80000000) ;
         no = AD0DR6 >> 6;
                break;
              case 7:             
                while((AD0DR7 & 0x80000000) == 0x80000000) ;
         no = AD0DR7 >> 6;
                break;
            }
              str[0] = ch+'0';
              str[1] = '\0';

              itoa(no,buf);                           // 10進文字に変換する
//              ItoA16(no,buf);                       // 16進文字に変換する
              StrTX("AD");                            // 文字列送信
              StrTX(str);                             // 文字列送信
              StrTX(":");                             // 文字列送信
              StrTX(buf);                             // 文字列送信
              StrTX("\r\n");                          // CR LF送信

            goto LE;
          }         
         
          if(UART0Buffer[0]=='D'){                    // DACコマンド D****:(0-1023)   
 
            no = a2i(&UART0Buffer[1]);                        // 文字列を整数値に変換
            PCLKSEL0 = (PCLKSEL0 & 0xff3fffff) | (1 << 22);   // D/AのクロックをCPUクロックと同じに
            GPIO_PINSEL1 = (GPIO_PINSEL1 & 0xffcfffff) | (0x02 << 20);  // P0[26]をD/Aとして使用
     DACR = (DACR & 0xffff003f) | (no << 6);           // DAC出力

            goto LE;
          }         
         
         
          // ここより上にif文でコマンドを追加する
          StrTX("Error\r\n");                           // コマンドError crlf送信
LE:     ;
        }else TX(RBRValue);                             // 1文字送信 エコーバック
                         
      if(UART0Count == UART_BUFSIZE) UART0Count = 0;    // buffer overflow
    }
  }
}

//-----------------------------------------------------------------------------