/**
 * @file   CUnet.c
 * @author StepTechnica
 * @date   May 22, 2023
 *
 * @brief Evaluation Board 用ソースファイル「CUnet 処理」
 *
 * @copyright (C) 2022- StepTechnica Co.,Ltd.
 *
 * このソフトウェアは、コピー利用、配布、変更の追加、変更を加えたもの再配布、商用利用、有料販売など、どなたも自由にお使いいただくことができます。
 * このソフトウェアには保証はついていません。
 * このソフトウェアを利用したことで問題が起きた際に、ソフトウェアの製作者は一切の責任を負いません。
 *
 */

/* -----------------------------------------------------------------------------
 * #include
 */
#include <stdbool.h>
#include "CUnet.h"
#include "IB43config.h"
#include "ctrlUART4.h"
#include "Utility.h"

/* -----------------------------------------------------------------------------
 * enumタグ定義 (typedefを同時に行う)
 */
typedef enum _CUStatus
{
    st_STOP = 0,	// STOP phase
	st_CALL,      	// CALL phase
	st_BREAK,       // BREAK phase
	st_RUN,	        // RUN phase
	st_GMM,	        // GMM phase
}CUStatus;


/* -----------------------------------------------------------------------------
 * 変数定義
 */
CUStatus        	gCUState = st_STOP;

/* -----------------------------------------------------------------------------
 * 関数プロトタイプ宣言
 */
void CUnet_main(void);
void CUnet_initialize(void);


/**
 *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 * @brief： CUnet 処理
 * 
 * @note： main() から呼ばれるメインルーチン
 * 
 * @param  none
 * @retval none
 * 
 */
void CUnet_main(void)
{
	unsigned scr;
	unsigned cctr;

	scr = MKY_Read16(OFS_regSCR);
	switch (gCUState) {
	case st_STOP:
		if ( scr & (1<<BIT_regSCR_RUN) )
		{
			print_string("CUnet state=<RUN>.\n");
			gCUState = st_RUN;
		}
		else
		{
			if ( scr & (1<<BIT_regSCR_CALL) )
			{
				//ビット10（CALL）が“1”になった。
				print_string("CUnet state=<CALL>.\n");
				gCUState = st_CALL;
			}
			if ( scr & (1<<BIT_regSCR_BRK) )
			{
				//ビット11（BRK）が“1”になった。
				print_string("CUnet state=<BREAK>.\n");
				gCUState = st_BREAK;
			}
			if ( scr & (1<<BIT_regSCR_GMM) )
			{
				//ビット15（GMM）が“1”になった。
				print_string("CUnet state=<GMM>.\n");
				gCUState = st_GMM;
			}
		}
		break;
	case st_CALL:
		if ( scr & (1<<BIT_regSCR_RUN) )
		{
			print_string("CUnet state=<RUN>.\n");
			gCUState = st_RUN;
		}
		else
		{
			if ( !( scr & (1<<BIT_regSCR_START) ) )
			{
				//ビット8（START）が“0”になった。
				print_string("CUnet state=<STOP>.\n");
				gCUState = st_STOP;
			}
		}
		break;
	case st_BREAK:
		if ( scr & (1<<BIT_regSCR_RUN) )
		{
			print_string("CUnet state=<RUN>.\n");
			gCUState = st_RUN;
		}
		else
		{
			if ( !( scr & (1<<BIT_regSCR_START) ) )
			{
				//ビット8（START）が“0”になった。
				print_string("CUnet state=<STOP>.\n");
				gCUState = st_STOP;
			}
		}
		break;
	case st_RUN:
		if ( !( scr & (1<<BIT_regSCR_START) ) )
		{
			//ビット8（START）が“0”になった。
			print_string("CUnet state=<STOP>.\n");
			gCUState = st_STOP;
		}
		else
		{
			cctr = MKY_Read16(OFS_regCCTR);
			if ((cctr & 0xFF00) != 0 )
			{
				print_string("\nCUnet MCARE Detected.\n");
				MKY_Write16(OFS_regCCTR, 0x0100);
			}
			if ((cctr & 0x00FF) != 0 )
			{
				print_string("\nCUnet LCARE Detected.\n");
				MKY_Write16(OFS_regCCTR, 0x0001);
			}
		}
		break;
	case st_GMM:
		if ( !( scr & (1<<BIT_regSCR_GMM) ) )
		{
			//ビット15（GMM）が“0”になった。
			print_string("CUnet state=<STOP>.\n");
			gCUState = st_STOP;
		}

		break;
	}

}


/**
 *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 * @brief： CUnet 初期化
 * 
 * @note： メインループの前に実施する初期化
 * 
 * @param  none
 * @retval none
 * 
 */
void CUnet_initialize(void)
{
	unsigned short scr, bcr, ccr;
	bool	ret, matchCCR;
	int		loop;

	gCUState = st_STOP;
	// Device Initialize
	ret = MKY_Initialize();
	if (ret == false) {
		// 初期化失敗
		print_string("Device initialize failed.\n");
		return;
	}

	loop = 0;
	do {
		delay_us(100);
		matchCCR = true;
		ccr = MKY_Read16(OFS_regCCR);
		if (ccr != VAL_CCR10)	matchCCR = false;
		ccr = MKY_Read16(OFS_regCCR+2);
		if (ccr != VAL_CCR32)	matchCCR = false;
		ccr = MKY_Read16(OFS_regCCR+4);
		if (ccr != VAL_CCR54)	matchCCR = false;
		ccr = MKY_Read16(OFS_regCCR+6);
		if (ccr != VAL_CCR76)	matchCCR = false;
		loop++;
		if (loop == 10000) {
			// CCR 確認失敗
			print_string("CCR is not correct.\n");
			return;
		}
	} while (matchCCR == false);

	//① 内部のメモリ（GM、MSB、MRB0、MRB1）へ“00H” のデータをライトし、ゼロクリアします。
	//前半
	MKY_FillMemory(MKY_OFS_MEMORY, 0, MKY_LEN_MEMORY);

#if defined(MKY_OFS_MEMORY_1) && (MKY_LEN_MEMORY_1 > 0)
	//後半
	MKY_FillMemory(MKY_OFS_MEMORY_1, 0, MKY_LEN_MEMORY_1);
#endif

	// SW5-8 is ON -> Start automatically
	if (readSW5_8() == true)
	{
		// SW5-1 is ON -> auto Start
		//② 通信設定を行ないます。
		//BCR（Basic Control Register）にステーションアドレス（SA）、占有幅（OWN）、転送レート（BPS）を設定します。
		//(1) SCR（System Control Register） のビット8（START） が“0”であることを確認します。
		scr = MKY_Read16(OFS_regSCR);
		if( scr & (1<<BIT_regSCR_START) )
		{
			//STARTビットが0でない。
			print_string("CUnet already Running.\n");
			return;
		}

		//(2) SCR のビット15（GMM）へ“1” をライトします。
		scr |= (1<<BIT_regSCR_GMM);
		MKY_Write16(OFS_regSCR, scr);
		scr = MKY_Read16(OFS_regSCR);

		//(3) BCR（Basic Control Register）のビット0 ～ 5（SA0 ～ 5）へステーションアドレス（SA）値を、
		//ビット6、7（BPS0、BPS1）へ転送レート選択を、ビット8 ～ 13（OWN0 ～ 5）へ占有幅（OWN）値を、
		//ビット15 のLFS（Long Frame Select）へライトします。
		bcr = (MKY_BCR_SA_VALUE << BIT_regBCR_SA) |		//Station Address
//			(MKY_BCR_BPS_VALUE << BIT_regBCR_BPS) |		//BPS (12Mbps)
			(MKY_BCR_OWN_VALUE << BIT_regBCR_OWN) |		//OWN width
			(MKY_BCR_LFS_VALUE << BIT_regBCR_LFS);		//Long Frame Select

		if (readSW5_6() == true)
		{
			bcr |= (0x02 << BIT_regBCR_BPS);
		}
		if (readSW5_5() == true)
		{
			bcr |= (0x01 << BIT_regBCR_BPS);
		}

		MKY_Write16(OFS_regBCR, bcr);
		bcr = MKY_Read16(OFS_regBCR);

		//(4) SCR のビット15（GMM）へ“0” をライトします。
		scr &= ~(1<<BIT_regSCR_GMM);
		MKY_Write16(OFS_regSCR, scr);
		scr = MKY_Read16(OFS_regSCR);

		//③ SCR（System Control Register）のビット8（START）へ“1” をライトします。
		scr |= (1<<BIT_regSCR_START);
		MKY_Write16(OFS_regSCR, scr);
		scr = MKY_Read16(OFS_regSCR);

		//④ SCR（System Control Register）をリードし、
		//ビット9（RUN）が“1”（ランフェーズに遷移した）であることを確認します。
		scr = MKY_Read16(OFS_regSCR);
		if( scr & (1<<BIT_regSCR_RUN) )
		{
			print_string("CUnet state=<RUN>.\n");
			gCUState = st_RUN;
		}
		else
		{
			if( scr & (1<<BIT_regSCR_CALL) )
			{
				//ビット10（CALL）が“1”になった。
				print_string("CUnet state=<CALL>.\n");
				gCUState = st_CALL;
			}
			if( scr & (1<<BIT_regSCR_BRK) )
			{
				//ビット11（BRK）が“1”になった。
				print_string("CUnet state=<BREAK>.\n");
				gCUState = st_BREAK;
			}
		}

		// Clear CARE Counter
		MKY_Write16(OFS_regCCTR, 0x0101);
	}
	else
	{
		print_string("CUnet state=<STOP>.\n");
		gCUState = st_STOP;
	}

}
