/**
 * \file i2c_max518.c
 * \brief I2Cサブシステムのサンプルプログラム
 * \details
 * subsystems ディレクトリ中のライブラリを使うためのサンプルプログラム。
 */

/**
 * \mainpage
 * \author Takemasa Nakamura
 * \date 2011/May/6
 * \details
 * subsystems ディレクトリ中のI2Cライブラリを使うデモプログラム。
 *
 * 以下の開発環境を使用して検証した
 *　\li LPCXpresso IDE 3.8.2 [build 129]
 *　\li ubuntu 10.04
 *
 * 起動すると、I2Cバスに接続しているMAX518への読み書きを行う。
 * MAX518の出力は位相が180度違うふたつの三角波になる。
 *
 * 同じworkspaceに、cmsisアーカイブプロジェクトとsubsystemsアーカイブプロジェクトが
 * 必要である。
 */
#include <kernel.h>
#include <t_syslog.h>
#include <t_stdlib.h>
#include "kernel_cfg.h"
#include "app.h"

/**
 * \brief I2C0, I2C1, I2C2のどのポートを使うか指定する
 * \details
 * 0から2のいずれかを選ぶ。このマクロは main() 関数のなかで使用され、I2Cに割り当てる
 * ピンを決定するために使う。
 */
#define I2CPORT	0

/**
 * \brief サービスコールのエラーのログ出力
 * \details
 * TOPPERS/ASPのsample 1からそのまま流用している。エラーコードが非0のとき、
 * ファイル名、行番号、式とエラーコードを出力する便利なプログラム。 SVC_PERROR マクロで
 * くるんで使う。
 */
Inline void
svc_perror(const char *file, int_t line, const char *expr, ER ercd)
{
	if (ercd < 0) {
		t_perror(LOG_ERROR, file, line, expr, ercd);
	}
}

/**
 * \brief サービスコールのエラーのログ出力
 * \details
 * TOPPERS/ASPのsample 1からそのまま流用している。エラーコードが非0のとき、
 * ファイル名、行番号、式とエラーコードを出力する便利なプログラム。
 */
#define	SVC_PERROR(expr)	svc_perror(__FILE__, __LINE__, #expr, (expr))

	/**
	 * \brief LPCXpresso 1768の基板上のLEDを指定するビットマスク
	 * \details
	 *  LPCXpresso 1768/1769では、GPIO0のbit22がLEDに接続されている
	 */
#define LEDMASK	(1<<22)
	/**
	 * \brief MAX518の I2C スレーブアドレス
	 * \details
	 * 7bitで表したMX518のスレーブアドレス。アドレスはストラップ・ピンの状態により
	 * 変更できるが、このサンプルでは、A0, A1, A2ピンはGNDに続されていると仮定している。
	 * */
#define MAX518	0x2C	/* 7bit address */

/**
 * \brief 送信バッファのうち、CH0データの位置
 */
#define MAX518_CH0 1
/**
 * \brief 送信バッファのうち、CH1データの位置
 */
#define MAX518_CH1 3

/**
 * \brie 3Vに対応する設定値
 * \details
 * 5V電源時に3Vに相当する出力となる値。
 */
#define HIGH_V  153
/**
 * \brie 0.65Vに対応する設定値
 * \details
 * 5V電源時に0.65Vに相当する出力となる値。
 */
#define LOW_V		33

/**
 * \brief i2c_master_write() 関数に渡す送信データバッファ
 * \details
 * i2c ポートから MAX518に送信されるデータを格納しておくバッファ。
 * 最初の1バイトはMAX518の要請により、チャンネル選択バイトであり、
 * 続く1バイトはデータになる。あとはこの繰り返しである。
 */
unsigned char dac_data[4] = {0,0,1,255};		// 0 and 2 is register address. 1 and 3 is data

/**
 * \brief メインタスク
 */
void main_task(intptr_t exinf)
{
	PINSEL_CFG_Type PinCfg;
	int i = 0;

	/* I2C0 ポートにピンを割り当てる */
#if ( I2CPORT == 0 )
		// I2C0 出力ピンの設定
	PinCfg.OpenDrain = PINSEL_PINMODE_NORMAL;
	PinCfg.Pinmode = PINSEL_PINMODE_PULLUP;
	PinCfg.Funcnum = PINSEL_FUNC_1;
		// ポート0
	PinCfg.Portnum = 0;
		// ピン27と28
	PinCfg.Pinnum = 27;
	PINSEL_ConfigPin(&PinCfg);
	PinCfg.Pinnum = 28;
	PINSEL_ConfigPin(&PinCfg);
#elif  ( I2CPORT == 1 )
		// I2C1 出力ピンの設定
	PinCfg.OpenDrain = PINSEL_PINMODE_OPENDRAIN; // OpenDrain
	PinCfg.Pinmode = PINSEL_PINMODE_TRISTATE;	// neither pull up nor pull down
	PinCfg.Funcnum = PINSEL_FUNC_3;
		// ポート0
	PinCfg.Portnum = 0;
		// ピン0と1
	PinCfg.Pinnum = 0;
	PINSEL_ConfigPin(&PinCfg);
	PinCfg.Pinnum = 1;
	PINSEL_ConfigPin(&PinCfg);
#elif  ( I2CPORT == 2 )
	// I2C2 出力ピンの設定
	PinCfg.OpenDrain = PINSEL_PINMODE_OPENDRAIN; // OpenDrain
	PinCfg.Pinmode = PINSEL_PINMODE_TRISTATE;	// neither pull up nor pull down
	PinCfg.Funcnum = PINSEL_FUNC_2;
	// ポート0
	PinCfg.Portnum = 0;
	// ピン10と11
	PinCfg.Pinnum = 10;
	PINSEL_ConfigPin(&PinCfg);
	PinCfg.Pinnum = 11;
	PINSEL_ConfigPin(&PinCfg);
#else
#error "Wrong Configuration of I2C"
#endif


	syslog(LOG_NOTICE, "I2C test program with PCF8570 starts." );
	syslog(LOG_NOTICE, "Try to write incremental value and compare with read value.");



		/* GPIO0のLED制御ピンを出力にする */
	GPIO_SetDir(
			0,			// GPIOポート番号
			LEDMASK,	// 操作するビットマスク
			1			// 設定する値
			);

		/* 1秒周期で LPCXpressoのLEDを点滅させつつ、I2C SRAMに読み書きを行う */
	while(1)
	{
		for ( i=LOW_V; i<HIGH_V ; i++ ){
				/* 30m秒待つ */
			tslp_tsk(30);
			dac_data[MAX518_CH0] = i;
			dac_data[MAX518_CH1] = HIGH_V + LOW_V - i;
			i2c_master_write(
						I2CPORT,	// i2c peripheral #. I2C0 is 0
						MAX518,	// Slave address by 7bits
						dac_data,	// transmit data
						sizeof(dac_data)	// number of bytes to transmit
						);
		}
			/* LED制御ピンをLにする */
		GPIO_ClearValue(
				0,			// GPIOポート番号
				LEDMASK	// 操作するビットマスク
				);
		syslog(LOG_NOTICE, "Flip" );

		for ( i=HIGH_V; i>LOW_V ; i-- ){
				/* 30m秒待つ */
			tslp_tsk(30);
			dac_data[MAX518_CH0] = i;
			dac_data[MAX518_CH1] = HIGH_V + LOW_V - i;
			i2c_master_write(
						I2CPORT,	// i2c peripheral #. I2C0 is 0
						MAX518,	// Slave address by 7bits
						dac_data,	// transmit data
						sizeof(dac_data)	// number of bytes to transmit
						);
		}
			/* LED制御ピンをHにする */
		GPIO_SetValue(
				0,			// GPIOポート番号
				LEDMASK	// 操作するビットマスク
				);
		syslog(LOG_NOTICE, "Flop" );

	}


	syslog(LOG_NOTICE, "Sample program ends.");
	SVC_PERROR(ext_ker());
	assert(0);
}
