#include "iodefine.h"
#include "intI2C.h"
#include <stdio.h>

static int _scl_set;			//SCL設定 0/1
static int _sda_set;			//SDA設定 0/1

int _i2c_count;					//カウント(4カウント1クロック)
int _i2c_stop;					//通信停止(終了)
int _trans_now;					//通信中
int _trans_fin;					//通信完了
char _trans_buf[128];			//送信制御文字列
unsigned short _set_data[64];	//送信データ(コード＋数値)
volatile short* _recive_buf;	//格納先のアドレス
short _dummy_buf[10];			//ダミーの格納先
short _set_clock[64];			//送信に使用するクロック数
int _set_len;					//送信するデータ数(スタートコンデション等を含む)
int _recive_len_set;			//受信するデータ数
int _recive_len_now;			//受信したデータ数
int _trans_count;				//送信したデータ数
int _trans_clock;				//送信したクロック数

#define	strto0x(s)		strtol(s,0,16)	//16進数表記文字列を数字に変換

//送信内容判別コード
#define I2C_ST	0x0100	//開始
#define I2C_SP	0x0200	//終了
#define I2C_RS	0x0400	//リスタート
#define I2C_WX	0x0800	//待機
#define I2C_RD	0x1000	//受信
#define I2C_WD	0x2000	//送信

#define I2C_ST_CLK	1	//開始
#define I2C_SP_CLK	1	//終了
#define I2C_RS_CLK	1	//リスタート
#define I2C_WX_CLK	1	//待機
#define I2C_RD_CLK	9	//受信
#define I2C_WD_CLK	9	//送信

#define I2C_RECIVE_SET		0x0100
#define I2C_RECIVE_START	0x0200

//I2C初期化
void init_I2C(void){
    //ポートAの入出力を設定する
	PFC.PAIORL.BIT.B2 = 0;	//入力
	PFC.PAIORL.BIT.B5 = 0;	//入力

	//出力値を初期化する
	PA.DRL.BIT.B2=0;		//出力値は0
	PA.DRL.BIT.B5=0;		//出力値は0

	_scl_set=1;
	_sda_set=1;
	_i2c_count=0;
	_i2c_stop=1;
	_trans_now=0;
	_trans_fin=0;
	_trans_count=0;
	_trans_clock=0;
	_set_len=0;

	_recive_len_set=0;
	_recive_len_now=0;

	set_SCL(1);	//ポートを制御
	set_SDA(1);

	init_CMT1_I2C(8);	//1クロック:8×0.32×4μ秒→10.24μ秒→96.6kbps
}

//CMT1をI2Cに利用するための初期化
void init_CMT1_I2C(int T){
	long int LN;

	//	CMT1の割り込みレベル（優先順位）を設定
	INTC.IPRJ.BIT._CMT1 = 0x2;	// ※(0x0:最低〜0xF:最高)

	STB.CR4.BIT._CMT=0;			// CMTモジュールのスタンバイ解除

	//設定中なのでカウンター一時停止
	CMT.CMSTR.BIT.STR1=0;	// 0：カウント停止, 1：カウント開始

	CMT1.CMCSR.BIT.CMIE=1;	// コンペアマッチ割り込み許可　※1で割り込み許可
	CMT1.CMCSR.BIT.CKS=0;	// クロックセレクト[1,0]  00=>0：Pφ/8　0.32μ秒

	LN = T ;
	if(LN < 2) LN = 2;		//下限
	else if(LN > 0xffff) LN = 0xffff; //335msに相当

	CMT1.CMCNT = 0;			// カウンタリセット
	CMT1.CMCOR = (int)LN;	// カウント目標値セット
	//CMT.CMSTR.BIT.STR1=1;	// CMT1カウント開始
}


//SCL出力設定
void set_SCL(int value){
	_scl_set=value;
	PA.DRL.BIT.B2=0;		//出力値は0
	if(value){
		PFC.PAIORL.BIT.B2 = 0;	//入力
	}else{
		PFC.PAIORL.BIT.B2 = 1;	//出力
	}
}

//SDA出力設定
void set_SDA(int value){
	_sda_set=value;
	PA.DRL.BIT.B5=0;		//出力値は0
	if(value){
		PFC.PAIORL.BIT.B5 = 0;	//入力
	}else{
		PFC.PAIORL.BIT.B5 = 1;	//出力
	}
}

//SCL状態取得
int get_SCL(void){
	return PA.DRL.BIT.B2;
}

//SDA状態取得
int get_SDA(void){
	return PA.DRL.BIT.B5;
}

//I2C送信の設定
void write_i2c(short* buff_address,char* data){
	int i;
	char sub_buf[3];

	while(_trans_now);	//通信完了待ち

	CMT.CMSTR.BIT.STR1=0;	// CMT1カウント停止
	_trans_now=1;	//送信開始
	_trans_fin=0;	//送信完了
	_i2c_count=0;	//内部カウントリセット
	_trans_clock=0;	//送信ビット数リセット
	_trans_count=0;	//送信データ数リセット
	_i2c_stop=0;	//送信停止フラグ解除

	_recive_len_now=0;	//受信済みデータ数リセット
	_recive_len_set=0;	//受信予定数リセット

	sprintf(_trans_buf,"%s",data);	//送信命令をコピー
	_recive_buf=buff_address;		//格納先の先頭アドレスをコピー

	for(i=0;i<64;i++){	//1回の送信データ最大64(指令128字)
		strncpy(sub_buf, _trans_buf+i*2, 2 );	//2文字切り出し
		sub_buf[2]='\0';
		if(sub_buf[0]=='S'&&sub_buf[1]=='T'){		//スタート
			_set_data[i]=I2C_ST;
			_set_clock[i]=I2C_ST_CLK;
		}else if(sub_buf[0]=='S'&&sub_buf[1]=='P'){	//ストップ
			_set_data[i]=I2C_SP;
			_set_clock[i]=I2C_SP_CLK;
		}else if(sub_buf[0]=='R'&&sub_buf[1]=='S'){	//リスタート
			_set_data[i]=I2C_RS;
			_set_clock[i]=I2C_RS_CLK;
		}else if(sub_buf[0]=='W'){	//ウェイト
			sub_buf[0]==' ';
			_set_data[i]=I2C_WX|strto0x(sub_buf);
			_set_clock[i]=I2C_WX_CLK*strto0x(sub_buf);
		}else if(sub_buf[0]=='R'&&sub_buf[1]=='D'){	//リード
			if(buff_address==NULL){	//受信しない予定なのに受信制御が含まれている
				_recive_buf=_dummy_buf;
			}
			_recive_buf[_recive_len_set]=I2C_RECIVE_SET;	//受信待機
			_set_data[i]=I2C_RD;
			_set_clock[i]=I2C_RD_CLK;
			_recive_len_set++;
		}else{										//データ
			_set_data[i]=I2C_WD|strto0x(sub_buf);
			_set_clock[i]=I2C_WD_CLK;
		}
		if(_trans_buf[i*2+3]=='\0'){	//最後まで到達
			_set_len=i+1;
			_set_data[i+1]=0;			//エンドキャップ
			break;
		}
	} //end for
	CMT.CMSTR.BIT.STR1=1;	// CMT1カウント開始
}

//intprg.cのINT_CMT1_CMI1へ登録が必要
void CMT1_INT_CMI_I2C(void)
{
	CMT.CMSTR.BIT.STR1=0;		// 0：カウント停止, 1：カウント開始
	CMT1.CMCSR.BIT.CMF=0;		// CMT1割込みフラグクリア
	i2c_ctrl();					//I2Cポート制御
	if(!_i2c_stop){
		CMT.CMSTR.BIT.STR1=1;	// 0：カウント停止, 1：カウント開始
	}
}

//I2Cの制御(繰り返し実行させる)
void i2c_ctrl(void){
	int scl;
	int sda;
	int cycle;
	int ACK;
	unsigned short mode;
	unsigned short mode_next;
	short data;

	if(_i2c_stop)			//停止状態
		return;

	if( _scl_set && !get_SCL())	//クロックストレッチ
		return;

	_trans_clock=_i2c_count/4;
	cycle=_i2c_count%4;

	mode=_set_data[_trans_count]&0xFF00;	//現在のモード
	data=_set_data[_trans_count]&0x00FF;	//現在のデータ
	mode_next=_set_data[_trans_count+1]&0xFF00;	//次のモード

	ACK=(mode==I2C_RD&&mode_next==I2C_RD)?0:1;	//受信モードで、次も受信の場合はACK(0)を返す

	switch(mode){	//モード毎にSCL,SDAの制御を変える
		case I2C_ST:	//開始
			scl=(_i2c_count>=3)?0 :1;
			sda=(_i2c_count>=2)?0 :1;
			break;
		case I2C_SP:	//終了
			scl=(_i2c_count>=1)?1 :0;
			sda=(_i2c_count>=2)?1 :0;
			break;
		case I2C_RS:	//リスタート
			scl=(cycle==0||cycle==3)?0 :1;
			sda=(_i2c_count>=2)?0 :1;
			break;
		case I2C_WX:	//待機
			scl=1;
			sda=1;
			break;
		case I2C_RD:	//読出し
			scl=(cycle==0||cycle==3)?0 :1;
			sda=(_trans_clock>=8)?ACK :1;
			break;
		case I2C_WD:	//書込み/アドレス
			scl=(cycle==0||cycle==3)?0 :1;
			sda=(_trans_clock>=8)?1 :data&(0x80>>_trans_clock);
			break;
		default:
			break;
	} //end switch


	if(mode==I2C_RD){		//受信モード
		if( _i2c_count==0){	//受信開始
			_recive_buf[_recive_len_now]|=I2C_RECIVE_START;	//受信待機
		}
		if( cycle==2 && _trans_clock<8){		//受信したビットを格納
			_recive_buf[_recive_len_now]|=((get_SDA()*0x80)>>_trans_clock);
		}
	} // I2C_RD

	set_SCL(scl);	//ポートを制御
	set_SDA(sda);	//ポートを制御

	if( cycle==3 && (_trans_clock+1)>=_set_clock[_trans_count]){	//最後のサイクルを処理した
		_i2c_count=0;			//内部カウントリセット
		_trans_count++;			//送信データ数加算

		if(mode==I2C_RD){		//受信モードのとき
			_recive_buf[_recive_len_now]&=~(I2C_RECIVE_SET|I2C_RECIVE_START);	//受信完了状態
			_recive_len_now++;	//受信済みデータ数増加
		} // I2C_RD

		if(_trans_count>=_set_len){	//最後まで送信した
			_i2c_count=0;	//内部カウントリセット
			_i2c_stop=1;	//通信停止フラグ
			_trans_now=0;	//通信完了
			_trans_fin=1;	//送信完了
			_trans_count=0;	//送信データ数クリア
			_trans_clock=0;	//送信ビット数クリア
			_set_len=0;		//送信予定データ数クリア
		} //_set_len
	}else{
		_i2c_count++;		//内部カウント増加
	} //end cycle==3
} //end i2c_ctrl

//通信完了の確認
int check_i2c_fin(void){
	return _trans_fin;
}
//通信完了フラグのクリア
void clr_i2c_fin(void){
	_trans_fin=0;
}