/* System	: 二足歩行ロボット(walk)
* File		: serial.c
* function	: 通信制御
* Version	: 1.0
* Date		: 2019/5/7
* CPU		: RL78/G12 ROM:16KB RAM:1.5KB fCLK:24MHz
* IDE		: CS+ for CC V6.01.00 [01 Dec 2017]
* Programmer	: Hajime Sugiyama
* Note		: */

/* データ長		8ビット	 */
/* データ転送順序	LSB first*/
/* パリティ	奇数		 */
/* ストップ・ビット	1ビット	 */
/* 超小型USB-シリアル変換モジュール(MPL2303SA) */
/* 論理反転回路経由(SE9) */

/* 特殊機能レジスタ（SFR）へのアクセス記述を使用する(RL78/R5F1026A) */
#include "iodefine.h"
/* ユニット0のチャネル0とチャネル1のそれぞれに送・受信割込み関数を設定します */
#pragma interrupt uart0_interrupt_send(vect = INTST0)	/* 送信完了割込み：チャネル0 */
#pragma interrupt uart0_interrupt_receive(vect = INTSR0)/* 受信完了割込み：チャネル1 */

#include "sequence_data.h"
#include "serial.h"

#define NET_DATA_SIZE	8				/* 付加データ長 */
#define RX_STARTCODE	0xAA				/* 受信パケットのスタートコード */
#define TX_STARTCODE	0xAA				/* 送信パケットのスタートコード */
#define ACK		0x06				/* 肯定応答（accept） */
#define NAK		0x15				/* 否定応答（busy） */

/* 公開変数 */
struct _F_SERIAL f_serial = {1,0,0,0};			/* 通信フラグ */
enum MODE_EV e_mode_event = NO_EVM;			/* 動作モード指示イベント */
enum WALK_EV e_walk_event = NO_EVW;			/* 歩行動作指示イベント */
/* 内部変数 */
/* 送信パケットバッファ（通常返信用） */
static unsigned char uart0_tx[PACKET_SIZE] = {TX_STARTCODE,0,0,0,0,0,0,0,0,0,0,0};
/* 送信パケットバッファ（動作モード完了時肯定応答用） */
static unsigned char uart0_tx_fix[PACKET_SIZE] = {TX_STARTCODE,0,0,0,0,0,0,0,0,0,0,0};
/* 付加データ格納バッファ */
static unsigned char u8_rx_buff[NET_DATA_SIZE]
	= {0,0,0,0,0,0,0,0};
/* 受信データ種類
　　0x01:動作モード変更指示
　　0x04:歩行動作指示
　　0x08:歩行動作順序データ */
static unsigned char u8_rx_datatype = 0x01U;		/* 受信データ種類 */
static unsigned char u8_rx_packetno = 0U;		/* 受信パケット番号 */
/* 送信バッファポインタ：関数の引数で必ず初期化されるため初期値を設定しない */
static unsigned char * u8p_uart0_tx_address;
static unsigned char u8_uart0_tx_count = 0U;		/* 送信カウンタ */
static unsigned char u8_rec_sequence_number = 0U;	/* 受信歩行動作順序データの数 */

union SEQUENCE{	/* シーケンスデータ構造体　⇔　パケット配列　変換 */
	unsigned char u8_dummy[2 * SQ_NO_MAX];		/* 共用体初期化のための代用配列 */
	struct SEQDATA u8_seqpair[SQ_NO_MAX];		/* 歩行動作順序データ参照用 */
	unsigned char u8_seq[SQ_NO_MAX / 4][NET_DATA_SIZE];/* 通信データ格納用 */
};
/* 受信歩行動作順序データ一時記憶配列 */
static union SEQUENCE sequence_buf = {
	0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U,
	0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U,
	0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U,
	0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U,
	0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U,
	0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U,
	0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U,
	0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U
};

/* 内部関数 */
static void uart0_send(unsigned char * tx_buf);		/* 送信開始処理 */
static void uart0_receiveend(void);			/* 受信完了処理 */

/* シリアル送受信回路初期化処理ユニット	UART00：送信	UART01：受信 */
void uart0_initialize(void){
	/* 送受信ポートの設定 (SE8) */
	PIOR |= 0x02U;					/* TxD0,RxD0をP60,P61へ割付 */
	PM6 |= 0x02U;					/* RxD0(PM61:bit1)を入力モードに */
	P6 |= 0x01U;					/* ポートP60の出力ラッチの値を”１”に */
	PM6 &= 0xFEU;					/* RxD0(PM60:bit0)を出力モードに */

	/* シリアル・アレイ・ユニット０へクロック供給 (SE8) */
	SAU0EN = 1U;	/* シリアル・アレイ・ユニット０へクロック供給許可 */
	__nop();
	__nop();
	__nop();
	__nop();
	SPS0 = 0x0044U;	/* CK00、CK01ともに1.5MHzに設定(シリアル・クロック選択レジスタ０) */

	/* 送受信ユニットの設定初期化	UART00：送信	UART01：受信 (SE5,8) */
	ST0 |= 0x0003U;					/* 送受信を停止(チャネル0･1)(シリアル･チャネル停止レジスタ0) */
	STMK0 = 1U;					/* UART0送信の転送完了割込みを禁止 */
	STIF0 = 0U;					/* UART0送信の割込み要求フラグをクリア */
	SRMK0 = 1U;					/* UART0受信の転送完了割込みを禁止 */
	SRIF0 = 0U;					/* UART0送信の割込み要求フラグをクリア */
	SREMK0 = 1U;					/* 通信エラー割込みを禁止(フレーミング／パリティ／オーバラン・エラー) */
	SREIF0 = 0U;					/* 通信エラー割込み要求フラグをクリア */

	STPR10 = 1U;					/* UART0送信割込を低優先順位に設定 */
	STPR00 = 1U;

	SRPR10 = 1U;					/* UART0送信割込を低優先順位に設定 */
	SRPR00 = 1U;

	SMR00 = 0x0022U;				/* CK00選択,UARTモード,転送完了割込 */
	SCR00 = 0x8397U;				/* 送信のみ,データ長8,LSB first,奇数パリティ,ストップ・ビット1,エラー割込み禁止 */
	SDR00 = 0x9A00U;				/* 分周設定9615bps(← fMCK:1.5MHz ← fCLK:24MHz) (SE6,7) */
	NFEN0 |= 0x01U;					/* RxD0端子のﾉｲｽﾞ･ﾌｨﾙﾀ使用 */
	SIR01 = 0x0007U;				/* フレーミング／パリティ／オーバラン・エラー・フラグのクリア */
	SMR01 = 0x0162U;				/* CK00選択,ビット反転,UARTモード,転送完了割込み (SE9) */
	SCR01 = 0x4397U;				/* 受信のみ,データ長8,LSB first,奇数パリティ,ストップ・ビット1,エラー割込み禁止 */
	SDR01 = 0x9A00U;				/* 分周設定9615bps(← fMCK:1.5MHz ← fCLK:24MHz) (SE6,7) */
	SO0 &= ~0x0001U;				/* シリアル･データ出力値“0” */
	SOL0 |= 0x0001U;				/* 通信データのレベルは、反転出力(0:high、1:low) (SE9) */
	SOE0 |= 0x0001U;				/* シリアル通信動作による出力許可 */
}

/* シリアル通信開始処理ユニット */
void uart0_start(void){
	SOE0 |= 0x0001U;				/* シリアル通信動作による出力許可 */
	SS0 |= 0x0003U;					/* UART0の受・送信を許可 */
	STIF0 = 0U;					/* 送信割込み要求フラグクリア */
	SRIF0 = 0U;					/* 受信割込み要求フラグクリア */
	STMK0 = 0U;					/* 送信割込みを許可 */
	SRMK0 = 0U;					/* 受信割込みを許可 */
}

/* 受信完了割込処理ユニット */
static void uart0_interrupt_receive(void){
	/* 受信状態 */
	/* スタートコード取得,データ種類取得,パケット番号取得,付加データ取得,BCC取得,受信エラー */
	enum RX_STATE {START,CAT,PACNO,PACDAT,BCC,RXERR};
	static enum RX_STATE e_rx_state = START;	/* 受信状態 */
	static unsigned char u8_rx_data = 0U;		/* 受信データバッファ(1byte) */
	static unsigned char u8_rx_datano = 0U;		/* 付加データカウンタ */
	static unsigned int u16_err_type = 0U;		/* 受信エラー種別 */
	static unsigned char u8_rx_checkcode = 0U;	/* 受信BCC判定用バッファ */

	u16_err_type = (unsigned char)(SSR01 & 0x0007U);/* UART01受信エラーの検出 */
	SIR01 = (unsigned int)u16_err_type;		/* 受信エラー･フラグのクリア */
	if(u16_err_type != 0U){				/* 受信エラー発生時は受信エラー状態にする */
		e_rx_state = RXERR;
	}

	u8_rx_data = (unsigned char)RXD0;		/* 受信データの取得 */
	switch(e_rx_state){				/* パケットの解析 */
		case START:				/* スタートコード取得待ち */
			if(u8_rx_data == RX_STARTCODE){	/* スタートコード取得 */
				u8_rx_checkcode = u8_rx_data;/* 受信BCC算出 */
				e_rx_state = CAT;	/* データ種類取得へ */
			}
			break;
		case CAT:				/* データ種類取得 */
			u8_rx_datatype = u8_rx_data;	/* データ種類記憶 */
			u8_rx_checkcode ^= u8_rx_data;	/* 受信BCC算出 */
			e_rx_state = PACNO;		/* パケット番号取得へ */
			break;
		case PACNO:				/* パケット番号取得 */
			u8_rx_checkcode ^= u8_rx_data;	/* 受信BCC算出 */
			u8_rx_packetno = u8_rx_data;	/* パケット番号記憶 */
			u8_rx_datano = 0;		/* 付加データカウンタ初期化 */
			e_rx_state = PACDAT;		/* 付加データ取得へ */
			break;
		case PACDAT:				/* 付加データ取得(8byte) */
			u8_rx_checkcode ^= u8_rx_data;	/* 受信BCC算出 */
			u8_rx_buff[u8_rx_datano] = u8_rx_data;/* 付加データ記憶 */
			if(++u8_rx_datano >= NET_DATA_SIZE){/* 付加データ取得完了？ */
				e_rx_state = BCC;	/* BCC取得へ */
			}
			break;
		case BCC:				/* BCC取得 */
			/* ブロックチェックコード(BCC:垂直パリティ(XOR))の取得〜送信開始 */
			if(u8_rx_data == u8_rx_checkcode){/* 受信BCC一致 (SE1) */
				uart0_receiveend();	/* 受信完了処理 */
			}
			e_rx_state = START;		/* スタートコード取得待ちへ */
			break;
		case RXERR:				/* 受信エラー */
			e_rx_state = START;		/* スタートコード取得待ちへ */
			break;
		default:
			e_rx_state = START;		/* スタートコード取得待ちへ */
			break;
	}
}

/* 受信完了処理ユニット（パケット解析・イベント発行・歩行動作順序データ記憶・送信データ作成） */
static void uart0_receiveend(void){
	auto unsigned char u8_counter = 0U;		/* カウント用変数 */
	static unsigned char u8_rx_packetno_next = 0U;	/* 次回受信を期待するパケット番号 */
	/* 送信バッファ */
	auto unsigned char u8_tx_checkcode = 0U;	/* 送信BCC判定用バッファ */
	auto unsigned char f_tx = 1U;			/* 送信フラグ */
	uart0_tx[1] = u8_rx_datatype;			/* データ種類設定 */
	uart0_tx[2] = u8_rx_packetno;			/* パケット番号設定 */
	/* データ種別ごとの処理 */
	switch(u8_rx_datatype){
		case 0x01U:				/* 動作モード変更指示 */
			/* 動作モード変更指示イベントの発行 */
			switch(u8_rx_buff[0]){		/* 動作モード */
				case 0x01U:		/* 内蔵プログラム動作モード */
					e_mode_event = BUILTIN_EVM;
					break;
				case 0x04U:		/* 受信プログラム動作モード */
					e_mode_event = RX_EVM;
					break;
				case 0x10U:		/* パソコン操作モード */
					e_mode_event = PC_EVM;
					break;
				default:		/* その他 */
					f_tx = 0U;	/* 送信しない */
					break;
			}
			if(f_serial.mode_changeable == 1U){/* 動作モード変更可 */
				f_serial.mode_changeable = 0U;
				/* 送信データの作成 */
				uart0_tx[3] = u8_rx_buff[0];/* 動作モード */
			}else{				/* 動作モード変更否 */
				uart0_tx[3] = NAK;	/* 否定応答 */
				u8_tx_checkcode = 0;
				/* 動作モード変更完了時の肯定応答パケットの事前作成 */
				for(u8_counter = 0;u8_counter < (PACKET_SIZE - 1);u8_counter++){
					if(u8_counter != 3){
						uart0_tx_fix[u8_counter] = uart0_tx[u8_counter];
					}else{
						/* 動作モード記憶 */
						uart0_tx_fix[u8_counter] = u8_rx_buff[0];
					}
					u8_tx_checkcode ^= uart0_tx_fix[u8_counter];
				}
				uart0_tx_fix[PACKET_SIZE - 1] = u8_tx_checkcode;
				f_serial.respose_pending = 1U;	/* 肯定応答未送信 */
			}
			break;
		case 0x04U:				/* 歩行動作指示 */
			if(f_serial.walking_motion_changeable == 1U){
				/* 歩行動作指示の発行 */
				switch(u8_rx_buff[0]){	/* 動作種類 */
					case 0x0FU:	/* 停止 */
						e_walk_event = STOP_EVW;
						break;
					case 0x01U:	/* 前進 */
						e_walk_event = FORWARD_EVW;
						break;
					case 0x02U:	/* 右回転 */
						e_walk_event = RIGHT_EVW;
						break;
					case 0x04U:	/* 後退 */
						e_walk_event = BACKWARD_EVW;
						break;
					case 0x08U:	/* 左回転 */
						e_walk_event = LEFT_EVW;
						break;
					case 0x06U:	/* ダンス */
						e_walk_event = DANCE_EVW;
						break;
					default:	/* その他 */
						f_tx = 0U;/* 送信しない */
						break;
				}
				/* 送信データの作成 */
				uart0_tx[3] = u8_rx_buff[0];/* 動作種類 */
			}else{
				uart0_tx[3] = NAK;	/* 否定応答 */
			}
			break;
		case 0x08U: 				/* 歩行動作順序データ受信 */
			/* パケット欠落の検査・送信データの作成 */ 
			if(u8_rx_packetno >= (2 * SQ_NO_MAX / NET_DATA_SIZE)){	/* パケット番号が範囲外 */
				f_tx = 0U;		/* 送信しない */
			}else if((u8_rx_packetno == 0) || (u8_rx_packetno == u8_rx_packetno_next)){
				/* 正常受信（パケット番号：0〜7） */
				/* 歩行動作順序データの格納 */
				for(u8_counter = 0;u8_counter < NET_DATA_SIZE;u8_counter++){
					sequence_buf.u8_seq[u8_rx_packetno][u8_counter] = u8_rx_buff[u8_counter];
				}
				u8_rec_sequence_number = 4 * (u8_rx_packetno + 1);	/* 受信歩行動作順序データ数 */
				if(u8_rx_packetno < (2 * SQ_NO_MAX / NET_DATA_SIZE - 1)){
					u8_rx_packetno_next = u8_rx_packetno + 1;/* 次回受信を期待するパケット番号 */
				}else{
					u8_rx_packetno_next = 0;
				}
				uart0_tx[3] = ACK;	/* 正常受信 */
			}else{	/* ﾊﾟｹｯﾄ欠落 */
				uart0_tx[2] = u8_rx_packetno_next;/* パケット番号 */
				uart0_tx[3] = NAK;	/* パケット欠落 */
			}
			break;
		default:
			f_tx = 0U;			/* 送信しない */
			break;
	}
	/* 送信 */
	if(f_tx == 1U){					/* 受信パケット異常なし */
		/* 送信BCCの算出 (SE2) */
		u8_tx_checkcode = 0;
		for(u8_counter = 0;u8_counter < (PACKET_SIZE -1);u8_counter++){
			u8_tx_checkcode ^= uart0_tx[u8_counter];
		}
		uart0_tx[PACKET_SIZE -1] = u8_tx_checkcode;
		uart0_send(uart0_tx);			/* 送信開始 */
	}
}

/* 送信開始処理ユニット */
static void uart0_send(unsigned char * tx_buf){
	u8p_uart0_tx_address = tx_buf;			/* 送信バッファの先頭アドレスを設定 */
	u8_uart0_tx_count = 0U;				/* 送信カウンタをクリア */
	STMK0 = 1U;					/* 送信割込みを禁止 */
	/* パケットの先頭を送信用シリアル・データレジスタに設定 → 送信開始 */
	TXD0 = u8p_uart0_tx_address[u8_uart0_tx_count];
	u8_uart0_tx_count++;				/* 送信カウンタを増加 */
	STMK0 = 0U;					/* 送信割込み(INTST0)を許可 */
}

/* 送信開始処理（モード変更完了時） */
void uart0_send_mode_changed(void){
	uart0_send(uart0_tx_fix);
}

/* 送信完了割込処理ユニット */
static void uart0_interrupt_send(void){
	if (u8_uart0_tx_count < PACKET_SIZE){		/* 送信データあり */
		/* パケットの1 byte を送信用シリアル・データ・レジスタに設定 → 送信開始 */
		TXD0 = u8p_uart0_tx_address[u8_uart0_tx_count];
		u8_uart0_tx_count++;			/* 送信カウンタを増加 */
	}else{
		STMK0 = 1U;				/* 送信割込みを禁止 */
	}
}

/* 受信順序データ確定処理ユニット（歩行動作順序データを使用する前に呼出す） */
/* 受信したパケット番号 */
void get_sequence_data(void){
	auto unsigned char u8_counter = 0U;		/* カウント用変数 */
	__DI();						/* 割込み禁止 */
	/* 受信歩行動作順序データ数以下 かつ 歩行動作順序データ数上限以下 */
	for(u8_counter = 0;(u8_counter < u8_rec_sequence_number)
		&& (u8_counter < SQ_NO_MAX);u8_counter++){
		sequence_data[u8_counter].category = sequence_buf.u8_seqpair[u8_counter].category;
		sequence_data[u8_counter].count = sequence_buf.u8_seqpair[u8_counter].count;
	}
	__EI();						/* 割込み許可 */
}
