/* ------------------------------------------------------------------------------------------------ */
/* FILE :		Demo_6_LPC1766STK_ATOLLIC.c															*/
/*																									*/
/* CONTENTS :																						*/
/*				Demo for the Olimex LPC1766-STK evaluation board									*/
/*				The ADC converts the value set by the trimmer										*/
/*				The value read is displayed on the serial port and LCD								*/
/*				Both UARTs (RS232_0 & RS232_1) ports are used										*/
/*				Serial port settings:																*/
/*							Baud Rate: 115200														*/
/*							Data bits:      8														*/
/*							Stop bits:		1														*/
/*							Parity:      none														*/
/*							Flow Ctrl:   none														*/
/*																									*/
/*																									*/
/* Copyright (c) 2012-2014, Code-Time Technologies Inc. All rights reserved.						*/
/*																									*/
/* Code-Time Technologies retains all right, title, and interest in and to this work				*/
/*																									*/
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS							*/
/* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF										*/
/* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL							*/
/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR								*/
/* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,							*/
/* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR							*/
/* OTHER DEALINGS IN THE SOFTWARE.																	*/
/*																									*/
/*																									*/
/*	$Revision: 1.2 $																				*/
/*	$Date: 2012/06/17 18:41:36 $																	*/
/*																									*/
/* ------------------------------------------------------------------------------------------------ */

#if OS_DEMO != 6
	#error "Wrong OS_DEMO value" 
#endif

#include <stdio.h>
#include <ctype.h>
#include <Abassi.h>

/* ------------------------------------------------ */

#include "lpc17xx_adc.h"
#include "lpc17xx_gpio.h"
#include "lpc17xx_libcfg.h"
#include "lpc17xx_pinsel.h"
#include "lpc17xx_uart.h"

#include "drv_glcd_cnfg.h"
#include "drv_glcd.h"
#include "glcd_ll.h"

#define BAUDRATE	   115200						/* Serial port baud rate						*/
#define SYS_FREQ	100000000						/* Processor clock frequency					*/

#define BG_COLOR	0x00000FFF						/* Background RGB color							*/
#define FG_COLOR	0x00000000						/* Foreground RGB color							*/

#define ADC3_DR_ADDRESS	((unsigned int)0x4001224C)

#define _ADC_INT		ADC_ADINTEN5
#define _ADC_CHANNEL	ADC_CHANNEL_5

extern FontType_t Terminal_9_12_6;

PINSEL_CFG_Type			PinCfg;
UART_CFG_Type			UARTConfigStruct;

void ADChandler(void);
void ADC3_CH10_DMA_Config(void);
void DrawBar(int);

#define LCD_LINE(x, txt) do {																		\
							int ISRstate;															\
							ISRstate = OSdint();													\
							GLCD_SetWindow(0, ((x)*12)+3, GLCD_HORIZONTAL_SIZE-1, (((x)+1)*12)+3);	\
							GLCD_TextSetPos(0,0);													\
							GLCD_print("\f %s\r", txt);												\
							OSeint(ISRstate);														\
						} while(0)

/* ------------------------------------------------ */

MBX_t *MbxADC;										/* Mailbox the ISR put thre ADC value in		*/
MBX_t *MbxTime;										/* Mailbox the ISR put the RTC valeu in			*/

TSK_t *A_E;

/* ------------------------------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------------------------------ */

int main(void)
{
unsigned int ADCval;								/* ADC value received from the mailbox			*/
int          ii;									/* General purpose								*/
intptr_t     Msg;									/* Message received from a mailbox				*/
int          Prio = 0;								/* SysTick interrupt priority					*/
unsigned int Time;									/* Running time value, received from ISR		*/
int          Tdigits[4];							/* To print the RTC								*/
int         *TimerBase;								/* SysTick register base address				*/

static char  Str[64];								/* String to print the update on serial port	*/

/* ------------------------------------------------ */
/* 	Processor clock set-up							*/

	SystemInit();

/* ------------------------------------------------ */
/* 	RTOS set-up										*/

	OSstart();

	A_E = TSKmyID();

/* ------------------------------------------------ */
/* UART0 set-up										*/

	PinCfg.Funcnum   = 1;
	PinCfg.OpenDrain = 0;
	PinCfg.Pinmode   = 0;
	PinCfg.Pinnum    = 2;
	PinCfg.Portnum   = 0;
	PINSEL_ConfigPin(&PinCfg);
	PinCfg.Pinnum    = 3;
	PINSEL_ConfigPin(&PinCfg);

	UART_ConfigStructInit(&UARTConfigStruct);
	UARTConfigStruct.Baud_rate = BAUDRATE;
	UART_Init((LPC_UART_TypeDef *)LPC_UART0, &UARTConfigStruct);
	UART_TxCmd((LPC_UART_TypeDef *)LPC_UART0, ENABLE);


/* ------------------------------------------------ */
/* UART1 set-up										*/

	PinCfg.Funcnum   = 1;
	PinCfg.OpenDrain = 0;
	PinCfg.Pinmode   = 0;
	PinCfg.Pinnum    = 15;
	PinCfg.Portnum   = 0;
	PINSEL_ConfigPin(&PinCfg);
	PinCfg.Pinnum    = 16;
	PINSEL_ConfigPin(&PinCfg);

	UART_ConfigStructInit(&UARTConfigStruct);
	UARTConfigStruct.Baud_rate = BAUDRATE;
	UART_Init((LPC_UART_TypeDef *)LPC_UART1, &UARTConfigStruct);
	UART_TxCmd((LPC_UART_TypeDef *)LPC_UART1, ENABLE);

	setvbuf(stdin,  NULL, _IONBF, 0);
	setvbuf(stdout, NULL, _IONBF, 0);

/* ------------------------------------------------ */
/* LCD set-up										*/

	GLCD_PowerUpInit(NULL);
	GLCD_Backlight(BACKLIGHT_ON);
	Dly100us((void*)3000);

	GLCD_SetFont(&Terminal_9_12_6, FG_COLOR, BG_COLOR);
	for (ii=0 ; ii<10 ; ii++) {
		LCD_LINE(ii, " ");
	}
	GLCD_SetWindow(0,0,GLCD_HORIZONTAL_SIZE-1, GLCD_VERTICAL_SIZE-1);
	GLCD_TextSetPos(0,0);
	GLCD_SetWindow(0, 120, GLCD_HORIZONTAL_SIZE-1, 131);
	GLCD_TextSetPos(0,0);
	GLCD_print("\f \r");
	GLCD_SetWindow(0, 0, GLCD_HORIZONTAL_SIZE-1, 12);
	GLCD_TextSetPos(0,0);
	GLCD_print("\f \r");

/* ------------------------------------------------ */
/* SysTick Set-up									*/

	TimerBase = (int *)0xE000E000;
	((volatile int *)0xE000Ed20)[0] = (((volatile int *)0xE000Ed20)[0] & 0x1FFFFFFF)
	                                |   ((Prio & 7) << 29);
	OSisrInstall(-1, TIMtick);						/* Install the OS timer tick function			*/
	TimerBase[5] = ((((SYS_FREQ)/100000) * OS_TIMER_US)/10)-1;
	TimerBase[4] = 0x7;								/* internal clock / int & enable				*/

/* ------------------------------------------------ */
/* ADC set-up										*/

	PinCfg.Funcnum   = 3;
	PinCfg.OpenDrain = 0;
	PinCfg.Pinmode   = 0;
	PinCfg.Pinnum    = 31;
	PinCfg.Portnum   = 1;
	PINSEL_ConfigPin(&PinCfg);

	ADC_Init(LPC_ADC, 1000);
	ADC_IntConfig(LPC_ADC,_ADC_INT,ENABLE);
	ADC_ChannelCmd(LPC_ADC,_ADC_CHANNEL,ENABLE);

	OSisrInstall(22, ADChandler);					/* Install the ADC interrupt					*/

/* ------------------------------------------------ */
/* Application set-up								*/

	MbxADC  = MBXopen("ADC", 5);
	MbxTime = MBXopen("Time", 5);

	ADC_StartCmd(LPC_ADC, ADC_START_NOW);

/* ------------------------------------------------ */
/* Interrupts ON, the application runs				*/

	NVIC_EnableIRQ(ADC_IRQn);

	OSeint(1);

	puts("\n\n");									/* Welcome banner								*/
	puts("\n       Abassi Demo 6\n");
	puts("\n    Olimex LPC1766-STK\n");
	puts("\n      Use the trimmer\n\n");

	LCD_LINE(1, "    Abassi Demo 6");
	LCD_LINE(3, "   Use the trimmer");

	ADCval = 0;

	Tdigits[0] = 0;
	Tdigits[1] = 0;
	Tdigits[2] = 0;
	Tdigits[3] = 0;

	Str[0]     = ' ';
	Str[1]     = ' ';
	Str[2]     = ' ';

	for (;;) {
		EVTwait(0x0000, 0xFFFF, -1);				/* A&E Waiting for a new time or ADC value		*/
		while (0 == MBXget(MbxTime, &Msg, 0)) {		/* Empty the mailbox with the running time		*/
			Time = (unsigned int)Msg;				/* The ISR limits the time to < 3600			*/
			Tdigits[0] = Time       / 600;			/* Minutes MS digit								*/
			Time      -= Tdigits[0] * 600; 
			Tdigits[1] = Time       / 60;			/* Minutes LS digit								*/
			Time      -= Tdigits[1] * 60; 
			Tdigits[2] = Time       / 10;			/* Seconds MS digit								*/
			Time      -= Tdigits[2] * 10; 
			Tdigits[3] = Time;						/* Seconds LS digit								*/
		}
			
		while(0 == MBXget(MbxADC, &Msg, 0)) {		/* Always completely mpty the mailbox			*/
			ADCval = (unsigned int)Msg;				/* Memo the ADC value 							*/
		}
		ii = (int)((double)ADCval/5.12);

		sprintf(&Str[3], "[%d%d:%d%d] ADC:%u%%       ", Tdigits[0], Tdigits[1], Tdigits[2], Tdigits[3],
		        ii);
		printf("%s\r", &Str[3]);

		LCD_LINE(6, &Str[0]);

		DrawBar(ii);
	}
}

/* ------------------------------------------------------------------------------------------------ */
/*																									*/
/* Idle Task																						*/
/*																									*/
/* ------------------------------------------------------------------------------------------------ */

void IdleTask(void)
{
	for(;;);										/* Idle is a do nothing task					*/
}

/* ------------------------------------------------------------------------------------------------ */
/*																									*/
/* RTOS Timer call back function																	*/
/*																									*/
/* Here we use the macro OS_TICK_PER_SEC to get the XXX led to toggle once every second				*/
/* The LED is not toggle here; instead FctHI gets awaken by posting SemRed							*/
/*																									*/
/* ------------------------------------------------------------------------------------------------ */

void TIMcallBack(void)
{
static int SecCnt  = 0;								/* Conter to incrm Seconds once per second		*/
static int Seconds = 0;								/* RTC cumulative seconds						*/

	NVIC_EnableIRQ(ADC_IRQn);

	SecCnt++;
	if (SecCnt >= OS_TICK_PER_SEC) {				/* Time to add one more second					*/
		Seconds++;
		if (Seconds >= 3600) {						/* The maximum display value is 59:59			*/
			Seconds = 0;
		}
		SecCnt = 0;
		MBXput(MbxTime, (intptr_t)Seconds, 0);		/* Send to the ADC task the new time in seconds	*/
		EVTset(A_E, 0x1);
	}

	return;
}

/* ------------------------------------------------------------------------------------------------ */
/*																									*/
/* ADC interrupt handler																			*/
/*																									*/
/* ------------------------------------------------------------------------------------------------ */


void ADChandler(void)
{
static unsigned int  ADCavg = 0;
static int           ADCcnt = 0;

	if (ADC_ChannelGetStatus(LPC_ADC,ADC_CHANNEL_5, ADC_DATA_DONE)) {
		ADCavg =  (unsigned int)ADC_ChannelGetData(LPC_ADC, ADC_CHANNEL_5);
		NVIC_DisableIRQ(ADC_IRQn);
		ADCcnt++;
		if (ADCcnt >= 8) {							/* Averaging 8 times							*/
			ADCavg = (ADCavg+4) >> 3;				/* Rounding and /8								*/
			MBXput(MbxADC, (intptr_t)ADCavg, 0);	/* Send ADC value to the A&E thriugh a mailbox	*/
			EVTset(A_E, 0x1);						/* Inform A&E there is soemting in one mailbox	*/
			ADCavg = 0;								/* Restart the averaging						*/
			ADCcnt = 0;
		}
	}

	return;
}

/* ------------------------------------------------------------------------------------------------ */
/*																									*/
/* Draw a sliding bar to show ADC value																*/
/*																									*/
/* ------------------------------------------------------------------------------------------------ */

void DrawBar(int PerCent)
{
int ii;
int jj;
int zz;

const unsigned int Colors[2] = {FG_COLOR, BG_COLOR};

static int PrevBar = 0;

	PerCent = (PerCent*GLCD_HORIZONTAL_SIZE)/100;
	
	if (PrevBar < PerCent) {
		for (ii=PrevBar ; ii<PerCent ; ii++) {
			for (zz=100 ; zz<125 ; zz++) {
				GLCD_SendCmd(CASET, (unsigned char *)&ii, 0);
				GLCD_SendCmd(RASET, (unsigned char *)&zz, 0);
				for (jj=0 ; jj<2 ; jj++) {
			        GLCD_SendCmd(RAMWR,(unsigned char *)&Colors[0],2);
				}
			}
		}
	}
	if (PrevBar > PerCent) {
		for (ii=PerCent ; ii<PrevBar ; ii++) {
			for (zz=100 ; zz<125 ; zz++) {
				GLCD_SendCmd(CASET, (unsigned char *)&ii, 0);
				GLCD_SendCmd(RASET, (unsigned char *)&zz, 0);
				for (jj=0 ; jj<2 ; jj++) {
			        GLCD_SendCmd(RAMWR,(unsigned char *)&Colors[1],2);
				}
			}
		}
	}

	PrevBar = PerCent;

	return;
}

/* ------------------------------------------------------------------------------------------------ */
/*																									*/
/* UART functions needed by the Peripheral library to access the UART								*/
/*																									*/
/* ------------------------------------------------------------------------------------------------ */

#if !defined(_write_r)
_ssize_t _write_r (struct _reent *rreenn, int fd, const void *vbuf, size_t len)
{
const char *buf;
int   size;

	size = len;
	buf  = vbuf;
	while (size > 0) {
		if (*buf == '\n') {
			while (!(LPC_UART0->LSR & UART_LSR_THRE));
			UART_SendByte((LPC_UART_TypeDef *)LPC_UART0, '\r');
			while (!(LPC_UART1->LSR & UART_LSR_THRE));
			UART_SendByte((LPC_UART_TypeDef *)LPC_UART1, '\r');
		}
		while (!(LPC_UART0->LSR & UART_LSR_THRE));
		UART_SendByte((LPC_UART_TypeDef *)LPC_UART0, *buf);
		while (!(LPC_UART1->LSR & UART_LSR_THRE));
		UART_SendByte((LPC_UART_TypeDef *)LPC_UART1, *buf);
		buf++;
		size--;
	}

	return(len);
}
#endif

/* ------------------------------------------------------------------------------------------------ */

#if !defined(_read_r)
_ssize_t  _read_r(struct _reent *rreenn, int fd, void *vbuf, size_t size)
{
int   len;
char *buf;

	buf = vbuf;
	len = 1;
	while ((!(LPC_UART0->LSR & UART_LSR_RDR))
	&&     (!(LPC_UART1->LSR & UART_LSR_RDR)));
	if (LPC_UART0->LSR & UART_LSR_RDR) {
		*buf = UART_ReceiveByte((LPC_UART_TypeDef *)LPC_UART0);
	}
	else {
		*buf = UART_ReceiveByte((LPC_UART_TypeDef *)LPC_UART1);
	}

	return(len);
}
#endif

/* ------------------------------------------------------------------------------------------------ */

int __putchar(int ccc)
{

	if (ccc == '\n') {
		while (!(LPC_UART0->LSR & UART_LSR_THRE));
		UART_SendByte((LPC_UART_TypeDef *)LPC_UART0, '\r');
		while (!(LPC_UART1->LSR & UART_LSR_THRE));
		UART_SendByte((LPC_UART_TypeDef *)LPC_UART1, '\r');
	}
	while (!(LPC_UART0->LSR & UART_LSR_THRE));
	UART_SendByte((LPC_UART_TypeDef *)LPC_UART0, ccc);
	while (!(LPC_UART1->LSR & UART_LSR_THRE));
	UART_SendByte((LPC_UART_TypeDef *)LPC_UART1, ccc);

	return(ccc);
}


/* ------------------------------------------------------------------------------------------------ */

int GetKey(void)
{
int RetVal;

	RetVal = 0;
	if ((LPC_UART0->LSR & UART_LSR_RDR)) {
		RetVal = UART_ReceiveByte((LPC_UART_TypeDef *)LPC_UART0);
	}
	else if ((LPC_UART1->LSR & UART_LSR_RDR)) {
		RetVal = UART_ReceiveByte((LPC_UART_TypeDef *)LPC_UART1);
	}

	return(RetVal);
	
}

/* EOF */
