#include <kernel.h>
#include <t_syslog.h>
#include <t_stdlib.h>
#include "kernel_cfg.h"
#include "app.h"
#include <lpc17xx_pinsel.h>
#include "lpc17xx_gpio.h"
#include "lpc17xx_adc.h"
#include "lpc17xx_clkpwr.h"

/*
 *  サービスコールのエラーのログ出力
 */
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);
	}
}

#define	SVC_PERROR(expr)	svc_perror(__FILE__, __LINE__, #expr, (expr))

	/* LPCXpresso 1768/1769では、GPIO0のbit22がLEDに接続されている */
#define LPCX_LEDMASK	(1<<22)

/*
 *  メインタスク
 */
void main_task(intptr_t exinf)
{

	syslog(LOG_NOTICE, "Sample program starts (exinf = %d).", (int_t) exinf);

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

	while(1)
	{
			/* 500m秒待つ */
		tslp_tsk(500);
			/* LED制御ピンをLにする */
		GPIO_ClearValue(
				0,			// GPIOポート番号
				LPCX_LEDMASK	// 操作するビットマスク
				);
			/* 500m秒待つ */
		tslp_tsk(500);
			/* LED制御ピンをHにする */
		GPIO_SetValue(
				0,			// GPIOポート番号
				LPCX_LEDMASK	// 操作するビットマスク
				);
	}


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


/* KIRISHIMAでは、GPIO2のbit4-7がLEDに接続されている */
#define KIRISIHMA_LEDMASK_OFST (4)
#define KIRISHIMA_LEDMASK	(0x0F<<KIRISIHMA_LEDMASK_OFST)

/* KIRISHIMAでは、GPIO2のbit10-13がLEDに接続されている */
#define KIRISHIMA_SW_OFST	(10)
#define KIRISHIMA_SW			(0x0F<<KIRISHIMA_SW_OFST)

/*
 *  LEDテストタスク
 *  SW1-4の状態を読み取り、LED1-4に反映する。
 */
void led_task(intptr_t exinf)
{
	unsigned int value;

	syslog(LOG_NOTICE, "LED test starts ");

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

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

	while(1)
	{
			/* 50m秒待つ */
		tslp_tsk(50);

		value = GPIO_ReadValue(2);
			/* LED制御ピンをLにする */
		GPIO_ClearValue(
				2,			// GPIOポート番号
				KIRISHIMA_LEDMASK	// 操作するビットマスク
				);
			/* LED制御ピンをHにする */
		GPIO_SetValue(
				2,			// GPIOポート番号
				value >> (KIRISHIMA_SW_OFST - KIRISIHMA_LEDMASK_OFST)// 操作するビットマスク
				);
	}


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


/*
 *  ADCテストタスク
 *  ADC0-3の値を読み取り、コンソール出力する
 */
void adc_task(intptr_t exinf)
{
	PINSEL_CFG_Type pincfg;
	unsigned int values[4];
	int i;

	syslog(LOG_NOTICE, "ADC test starts ");

	CLKPWR_ConfigPPWR( CLKPWR_PCONP_PCAD, ENABLE);

	ADC_Init(LPC_ADC, 200000);

	pincfg.Portnum = 0; 	/* ADC0は port0 */
	pincfg.Pinnum = 23;	/* ADC0.0は pin 23 */
	pincfg.Pinmode = PINSEL_PINMODE_TRISTATE;
	pincfg.OpenDrain = PINSEL_PINMODE_NORMAL;
	pincfg.Funcnum = 1;	/* set to ADC assign */

	PINSEL_ConfigPin(&pincfg);

	pincfg.Pinnum = 24;	/* ADC0.1は pin 24 */
	PINSEL_ConfigPin(&pincfg);

	pincfg.Pinnum = 25;	/* ADC0.2は pin 25 */
	PINSEL_ConfigPin(&pincfg);

	pincfg.Pinnum = 26;	/* ADC0.3は pin 26 */
	PINSEL_ConfigPin(&pincfg);

	while (1)
	{
			/* ソフトウェアによる変換開始の場合、一度に変換できるのは1チャンネルだけである
			 * したがって、全部のチャンネルをソフトウェアでスキャンする */
		for ( i=0; i<4; i++)
		{
				/* チャンネル選択 */
			ADC_ChannelCmd(LPC_ADC,i,ENABLE);
				/* ワンショットの変換開始　*/
			ADC_StartCmd(LPC_ADC, ADC_START_NOW);
				/* 50m秒待つ */
			tslp_tsk(50);
			values[i] = ADC_ChannelGetData(LPC_ADC, i);
				/* チャンネル選択解除 */
			ADC_ChannelCmd(LPC_ADC,i,DISABLE);

		}

		syslog(LOG_NOTICE, "ch0:%4d, ch1:%4d, ch2:%4d, ch3:%4d. ",
					values[0], values[1], values[2], values[3]
				);

	}


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


