/************************(abc899-18325.c)*******************
 *	I2C接続EEPROM(24FC1025)読み書きテスト
 ***********************************************************/
#define DEVICE	0x50                    // Blk0=0x50,Blk1=0x54
#define MBFSIZE	78                      // メモリ操作用バッファーサイズ
#include "mcc_generated_files/mcc.h"
#include "mcc_generated_files/examples/i2c1_master_example.h"
#include "i2cLCD_ST7032i.h"
#include "ctype.h"                      // isxdigit()
#include "stdio.h"                      // puts(),..
#include "stdlib.h"                     // atoi()...
#include "string.h"                     // strtok()...
//#include 
//=== グローバル変数 ============
char     Dlm[] = ",";                   // 文字列区切りデリミタ
//--- シリアル通信用
char     RBuf[BFSIZE];                  // シリアル受信用
                                        // BFSIZEはeusart.hで宣言
uint8_t  SFlg;                          // シリアル受信フラグ
char     SBuf[20];                      // 文字列処理用バッファー
//--- I2Cメモリー用
uint8_t  BlkNum = 0;                    // メモリブロック番号
uint16_t CrtAdr = 0;                    // カレントアドレス
uint8_t  DBuf[MBFSIZE];                 // ページメモリ用バッファー
uint8_t  SqMode;                        // シーケンスモードフラグ
/*************************************
 *  I2C EEPROM function
 **************************************/
//-----  アドレスadrから、1バイトを読み出す
uint8_t I2C_Mem_Read(uint16_t adr){
    uint8_t bf[2];
    bf[0] = adr >> 8;
    bf[1] = (uint8_t)adr;
    I2C1_WriteNBytes(DEVICE + BlkNum,bf,2);
    I2C1_ReadNBytes(DEVICE + BlkNum,bf,1);
    return bf[0];
}
//-----  アドレスadrに、1バイトdtを書き込む
void I2C_Mem_Write(uint16_t adr, uint8_t dt){
    uint8_t bf[3];
    bf[0] = adr >> 8;
    bf[1] = (uint8_t)adr;               // アドレスセット
    bf[2] = dt;                         // データセット
    I2C1_WriteNBytes(DEVICE + BlkNum,bf,3);  //書き込む
    __delay_ms(5);
}
//-----  アドレスadrからnバイトをary[]に読み出す
void I2C_Mem_NRead(uint16_t adr, uint8_t *ary, uint8_t n){
    uint8_t bf[2];
    bf[0] = adr >> 8;
    bf[1] = (uint8_t) adr;
    if(n > MBFSIZE) n = MBFSIZE;        // 配列要素数以内
    I2C1_WriteNBytes(DEVICE+BlkNum,bf,2);  // アドレス送信
    I2C1_ReadNBytes(DEVICE+BlkNum,ary,n);  // データ読込
}
//-----  アドレスadrからary[]のnバイトを書き込む
void I2C_Mem_NWrite(uint16_t adr, uint8_t  *ary, uint8_t n){
    uint8_t bf[MBFSIZE + 2];
    bf[0] = adr >> 8;                   // アドレスセット
    bf[1] = (uint8_t) adr;              // ページ境界に注意!
    if(n > MBFSIZE) n = MBFSIZE;
    memcpy(bf+2,ary,n);                 // ary[]をbf[]にコピー
    I2C1_WriteNBytes(DEVICE+BlkNum,bf,n+2);
    __delay_ms(5);
}
//---- ターミナルにプロンプト文字表示
void prtPrompt(uint8_t m){
    if(m)  printf("# ");                // 連続書込モード中
    else   printf("$ ");                // 通常書込モード
}
//---- 16進文字列を10進数に変換
int16_t my_xtoi(char *str){
    uint32_t dec;
    dec = strtoul(str,NULL,16);
    if(errno == ERANGE) return -1;      // 文字列変換エラー
    return (int16_t)dec;
}
/************************************
 * 	コマンドアクション
 ************************************/
//----- Wコマンド   W[aaaa][,[d0,・・[,]]]
uint16_t cmd_W(char *str){
    char     *pt;                       // 文字列操作用ポインタ
    uint8_t  last;                      // 文字列の最後の位置
    int16_t  res = 0;                   // Hex文字数値変換結果
    uint8_t  dt = 0;                    // 書き込むバイトデータ
    uint16_t cnt = 0;                   // 実際に書き込んだバイト数
    if(strlen(str)==1){                 // 'W'のみなら
        SqMode = 1;                     // 連続書込モードにセット
        puts("SqMode ON\n\r");
        return 0;                       // データは書き込まない
    }
    last = (uint8_t)strlen(str)-1;      // 文字列の行末位置を取得
    if(str[last] == ','){               // 行末がコンマなら
        SqMode = 1;                     // 連続書込モードにセット
        puts("SqMode ON\n\r");
        str[last]='\0';                 // 行末のコンマを消す
    }
    if(str[1]!=','){                    // 第2文字がコンマか?
        pt = strtok(str+1,Dlm);         // コマンドの次文字から
        if(pt != NULL){                 // アドレスデータがある
            res = my_xtoi(pt);
            if(res < 0) return cnt;     // 文字変換エラー
            CrtAdr = (uint16_t)res;
        }
        pt = strtok(NULL,Dlm);          // 次文字列取込
    }else{
        pt= strtok(str+1,Dlm);          // 文字列取込
    }
    do{
        if(pt != NULL){                 // データがあるか?
            res = my_xtoi(pt);
            if(res < 0) return cnt;
            dt = (uint8_t)res;
            I2C_Mem_Write(CrtAdr,dt);   // データを書き込む
            sprintf(SBuf,"%d:%04X < %02X",BlkNum,CrtAdr,dt);
            printf("%s\n\r",SBuf);
            LCD_cursor(1,1); LCD_str(SBuf);
            CrtAdr++; cnt++;
            pt = strtok(NULL,Dlm);      // 次文字へ
        }
    }while(pt != NULL);                 // データがあるだけ繰り返す
    return cnt;                         // 書き込んだ文字数を返す
}
//---- Rコマンド  R[aaaa][,n]
uint16_t cmd_R(char *str){
    char *pt;                           // 文字列操作用ポインタ
    uint16_t n = 1;                     // 指定された読込バイト数
    int16_t  res = 0;                   // Hex文字数値変換結果
    uint8_t  dt;                        // 読み込んだバイトデータ
    uint16_t cnt = 0;                   // 実際に読み出されたバイト数
    uint8_t  i;                         // ループ変数
    if(strlen(str) > 1){
        if(str[1]==','){
            pt = strtok(str+2,Dlm);
            if(pt != NULL){             // データ無し?
                res = my_xtoi(pt);
                if(res < 0) return cnt;
                n = (uint16_t)res;
            }
        }else{
            pt = strtok(str+1,Dlm);
            if(pt != NULL){             // addressがある?
                res = my_xtoi(pt);
                if(res < 0) return cnt; // 文字列変換エラー
                CrtAdr = (uint16_t)res;
            }
            pt = strtok(NULL,Dlm);      // 次文字へ
            if(pt != NULL){             // データ無し?
                res = my_xtoi(pt);
                if(res < 0) return cnt;
                n = (uint16_t)res;
            }
        }
    }
    for(i = 0; i < n;i++ ){
        dt = I2C_Mem_Read(CrtAdr);      // データを読み出す
        sprintf(SBuf,"%d:%04X > %02X",BlkNum,CrtAdr,dt);
        printf("%s\n\r",SBuf);
        LCD_cursor(1,1); LCD_str(SBuf);
        CrtAdr++; cnt++;
    }
    SqMode = 0;
//    puts("SqMode OFF");
    return cnt;                         // 読み込んだデータ数を返す
}
//---- WSQ (連続書込モード)
uint16_t cmd_WSQ(char *str){
    char     *pt;                       // 文字列操作用ポインタ
    uint8_t  dt;                        // 書き込むバイトデータ
    int16_t  res;                       // Hex文字数値変換結果
    uint16_t cnt = 0;                   // 実際に読み出されたバイト数
    pt = strtok(str,Dlm);
    while(pt != NULL){                  // データがあるだけ繰り返す
        res = my_xtoi(pt);
        if(res < 0) return cnt;         // 文字列変換エラー
        dt = (uint8_t)res;
        I2C_Mem_Write(CrtAdr,dt);       // データを書き込む
        printf("%d:%04X < %02X\n\r",BlkNum,CrtAdr,dt);
        CrtAdr++; cnt++;
        pt = strtok(NULL,Dlm);          // 次文字列へ
    }
    return cnt;                         // 書き込んだデータ数を返す
}
//---- MBコマンド  MBn
int cmd_M(char *str){
    char     *pt;                       // 文字列操作用ポインタ
    uint8_t  b;                         // メモリバンク番号
    if(str[1] != 'B') return -1;        // 第2文字がBか?
    pt = strtok(str+2,Dlm);
    if(pt==NULL) return -1;             // 文字列変換エラー
    b = atoi(pt) & 0x01;
    printf("Bank %d selected\n\r",b);
    BlkNum = b * 4;                     // Blk = bit2
    CrtAdr = 0;                         // 現在アドレスは0に
    SqMode = 0;
//    puts("SqMode OFF\r");
    return b;
}
//---- Qコマンド(連続書込モードの解除)   Q
void cmd_Q(char *str){
	SqMode = 0;
	puts("SqMode OFF\r");
}
//---- U(dump)コマンド    U[aaaa]
//         (64バイトのデータをDBuf[]に読み出す)
int cmd_U(char *str){
    char    *pt;                        // 文字列操作用ポインタ
    int16_t  res;                       // Hex文字数値変換結果
    uint16_t ad;                        // 指定アドレス
    uint8_t  i;                         // ループ処理用
    pt = strtok(str+1,Dlm);
    if(pt != NULL){                     // アドレス有り?
        res = my_xtoi(pt);
        if(res < 0) return -1;          // 文字列変換エラー
        CrtAdr = (uint16_t)res;
    }
    ad = CrtAdr & 0xFFC0;               // 64バイト単位に 
    I2C_Mem_NRead(ad,DBuf,64);          // 64バイトをDBuf[]に読出し
    printf("%d:%04X - %04X",BlkNum,ad,ad+63);
    for(i = 0; i < 64; i++){            // 16x4文字表示
        if(i % 16 == 0) printf("\n\r");
        printf(" %02X",DBuf[i]);
    }
    puts("\r");
    SqMode = 0;
    return 0;
            
}
//---- P(Page)コマンド    PW[aaaa]
//          (DBuf[]の64バイトをメモリに書き込む)
int cmd_P(char *str){
    char     *pt;                       // 文字列操作用ポインタ
    int16_t  res;                       // Hex文字数値変換結果
    uint16_t ad;                        // 指定アドレス
    uint8_t  i;                         // ループ処理用
    if(str[1] != 'W') return -1;        // 第2文字がW?
    pt = strtok(str+2,Dlm);
    if(pt != NULL){                     // アドレス有り?
        res = my_xtoi(pt);
        if(res < 0) return -1;          // 文字列変換エラー
        CrtAdr = (uint16_t)res;
    }
    ad = CrtAdr & 0xFFC0;               // 64バイト単位に
    I2C_Mem_NWrite(ad,DBuf,64);         // DBuf[]の64バイト書込
    printf("Page Write %d:%04X - %04X\n\r",BlkNum,ad,ad+63);
    SqMode = 0;    
    return 0;
}
/********************************
 *  main apprication 
 ********************************/
void main(){
    char cmd;                           // コマンド文字
    SYSTEM_Initialize();
    LCD_init();                         // LCD初期化
    INTERRUPT_GlobalInterruptEnable();
    INTERRUPT_PeripheralInterruptEnable();
    puts("ready\r");
    LCD_str("ready");                   // コマンド処理準備完了
    prtPrompt(SqMode);
    while(1){
        if(SFlg){                       // シリアル入力有り?
            LCD_clr(); LCD_str(RBuf);   // LCDにコマンド表示
            cmd = RBuf[0];              // コマンドは第1文字
            printf("\n\r");
            switch(cmd) {               // 各コマンドの実行
                case 'W':  cmd_W(RBuf);  break;
                case 'R':  cmd_R(RBuf);  break;
                case 'Q':  cmd_Q(RBuf);  break;
                case 'M':  cmd_M(RBuf);  break;
                case 'U':  cmd_U(RBuf);  break;
                case 'P':  cmd_P(RBuf);  break;
                                        // 有効なコマンドがなく
                default:   if(SqMode) cmd_WSQ(RBuf);
                                        // 連続書込モード中なら
                           break;       // 書込シーケンスを実行
            }
            SFlg = 0;
            prtPrompt(SqMode);
        }
    }
}
 
 |