/* ------------------------------------------------------------------------------------------------ */
/* FILE :		Demo_4_STM32_P407_ATOLLIC.c															*/
/*																									*/
/* CONTENTS :																						*/
/*				Demo for the Olimex STM32-P407 evaluation board (RS232_1 port)						*/
/*				Operation of the joystick shown on the LCD and serial port							*/
/*				Serial port settings:																*/
/*							Baud Rate: 115200														*/
/*							Data bits:      8														*/
/*							Stop bits:		1														*/
/*							Parity:      none														*/
/*							Flow Ctrl:   none														*/
/*																									*/
/*																									*/
/* Copyright (c) 2012, 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.4 $																				*/
/*	$Date: 2012/06/16 18:49:00 $																	*/
/*																									*/
/* ------------------------------------------------------------------------------------------------ */

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

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

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

#include "stm32_p407.h"

#include "drv_glcd_cnfg.h"
#include "drv_glcd.h"
#include "glcd_ll_st.h"

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

#define BG_COLOR	0x00000FFF
#define FG_COLOR	0x00000000

extern FontType_t Terminal_9_12_6;

USART_InitTypeDef USART_InitStructure;

#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)


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

int Debounce[5];									/* Used to debounce the joystick				*/
MBX_t *MbxUpDown;									/* Mailbox for the UP/DOWN task					*/
SEM_t *SemCenter;									/* Semaphore for CENTER task					*/
TSK_t *TaskCenter;									/* Task handling the joystick center activated	*/
TSK_t *TaskLeftRight;								/* Task handling the joystick R/L activated		*/
TSK_t *TaskTick;									/* Task operated one every RTOS tick			*/
TSK_t *TaskUpDown;									/* Task handling the joystick UP/DOWN activated	*/

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

void FctCenter(void);								/* Functon attached to TaskCenter				*/
void FctLeftRight(void);							/* Functon attached to TaskLeftRight			*/
void FctTick(void);									/* Functon attached to TaskTick					*/
void FctUpDown(void);								/* Functon attached to TaskUpDOwn				*/
void JoyStickHandler(void);							/* Joystick interrupt handler					*/

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

int main(void)
{
int  Prio = 0;										/* SysTick interrupt priority					*/
int *TimerBase;										/* Systick Timer register base adddress			*/


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

	SystemInit();

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

	OSstart();

/* ------------------------------------------------ */
/* UART set-up										*/

	USART_InitStructure.USART_BaudRate            = BAUDRATE;
	USART_InitStructure.USART_WordLength          = USART_WordLength_8b;
	USART_InitStructure.USART_StopBits            = USART_StopBits_1;
	USART_InitStructure.USART_Parity              = USART_Parity_No;
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
	USART_InitStructure.USART_Mode                = USART_Mode_Rx | USART_Mode_Tx;

	STM_EVAL_COMInit(COM1, &USART_InitStructure);

	setvbuf(stdin,  NULL, _IONBF, 0);				/* By default, Atollic library flush the I/O	*/
	setvbuf(stdout, NULL, _IONBF, 0);				/* buffer when full or when new-line			*/

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

	GLCD_PowerUpInit(NULL);
	GLCD_Backlight(BACKLIGHT_ON);
	DelayResolution100us(3000U);

	GLCD_SetFont(&Terminal_9_12_6, FG_COLOR, BG_COLOR);

	GLCD_SetWindow(0,0, GLCD_HORIZONTAL_SIZE-1, GLCD_VERTICAL_SIZE-1);
	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			*/


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

	TaskCenter    = TSKcreate("Center", 1, TC_TSK_STACK, &FctCenter,    1);
	TaskUpDown    = TSKcreate("UpDown", 1, TC_TSK_STACK, &FctUpDown,    1);
	TaskLeftRight = TSKcreate("LftRgh", 1, TC_TSK_STACK, &FctLeftRight, 1);
	TaskTick      = TSKcreate("Tick  ", 1, TC_TSK_STACK, &FctTick,      1);

	MbxUpDown     = MBXopen("UpDown", 3);			/* Create the mailbox used by FctUpDown()		*/

	SemCenter     = SEMopen("Center");				/* Create the semaphore used by FctCenter()		*/


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

	puts("\n\n");
	puts("\n      Abassi Demo 4");					/* Welcome banner								*/
	puts("\n    Olimex STM32-P407\n");
	puts("\n    Use the joystick\n\n");


	LCD_LINE(1, "    Abassi Demo 4");
	LCD_LINE(3, "  Use the joystick");


/* ------------------------------------------------ */
/* GPIO (Joystick) set-up							*/

	STM_EVAL_PBInit(BUTTON_UP,    BUTTON_MODE_EXTI);
	STM_EVAL_PBInit(BUTTON_DOWN,  BUTTON_MODE_EXTI);
	STM_EVAL_PBInit(BUTTON_RIGHT, BUTTON_MODE_EXTI);
	STM_EVAL_PBInit(BUTTON_LEFT,  BUTTON_MODE_EXTI);
	STM_EVAL_PBInit(BUTTON_SEL,   BUTTON_MODE_EXTI);

	memset(&Debounce[0], sizeof(Debounce),0);

	OSisrInstall(23, &JoyStickHandler);					/* Install the joystick interrupt handler		*/
	OSisrInstall(40, &JoyStickHandler);					/* The 5 switch are mapped to 2 interrupts		*/

	LCD_LINE(1, "    Abassi Demo 4");
	LCD_LINE(3, "  Use the joy stick");

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

	OSeint(1);

	for (;;) {
		TSKselfSusp();								/* And Adam & Eve is done, it self suspends		*/
	}
}

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

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

/* ------------------------------------------------------------------------------------------------ */
/*																									*/
/* Task functions																					*/
/*																									*/
/* ------------------------------------------------------------------------------------------------ */

void FctCenter(void)
{
 #if defined(OS_NEWLIB_REENT)						/* In case the reentrance is set on per task	*/
  #if ((OS_NEWLIB_REENT) > 0)
	setvbuf(stdin,  NULL, _IONBF, 0);
	setvbuf(stdout, NULL, _IONBF, 0);
  #endif
 #endif

	for (;;) {
		SEMwaitBin(SemCenter, -1);					/* Get blocked waiting for the joystick center	*/
													/* to be activated								*/
		printf("    Center\r");
		LCD_LINE(7, "      Center    ");
	}
}


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

void FctLeftRight(void)
{
int events;

 #if defined(OS_NEWLIB_REENT)						/* In case the reentrance is set on per task	*/
  #if ((OS_NEWLIB_REENT) > 0)
	setvbuf(stdin,  NULL, _IONBF, 0);
	setvbuf(stdout, NULL, _IONBF, 0);
  #endif
 #endif

	for (;;) {
		EVTwait(0xFFFF, 0xFFFF, -1);				/* Wait for the event flags to be set by ISR	*/
		events = EVTget();
		if ((0x01 & events) != 0) {					/* Flag bit #0 is for right position			*/
			printf("    Right \r");
			LCD_LINE(7, "       Right    ");
		}

		if ((0x10 & events) != 0) {					/* Flag bit #4 is for right position			*/
			printf("    Left  \r");
			LCD_LINE(7, "       Left    ");
		}
	}
}

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

void FctUpDown(void)
{
intptr_t Msg;

 #if defined(OS_NEWLIB_REENT)						/* In case the reentrance is set on per task	*/
  #if ((OS_NEWLIB_REENT) > 0)
	setvbuf(stdin,  NULL, _IONBF, 0);
	setvbuf(stdout, NULL, _IONBF, 0);
  #endif
 #endif

	for (;;) {
		MBXget(MbxUpDown, &Msg, -1);

		if ((int)Msg == 1) {						/* Message #1 is for up position				*/
			printf("    Up    \r");
			LCD_LINE(7, "        Up    ");
		}
		if ((int)Msg == 2) {						/* Message #2 is for down position				*/
			printf("    Down  \r");
			LCD_LINE(7, "       Down    ");
		}
	}
}

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

void FctTick(void)
{
int   ii;
const char Running[] = "|/-\\";

 #if defined(OS_NEWLIB_REENT)						/* In case the reentrance is set on per task	*/
  #if ((OS_NEWLIB_REENT) > 0)
	setvbuf(stdin,  NULL, _IONBF, 0);
	setvbuf(stdout, NULL, _IONBF, 0);
  #endif
 #endif

	ii = 0;
	for (;;) {
		EVTwait(0xFFFF, 0xFFFF, -1);				/* Wait for any event flag to be set by the		*/
													/* RTOS tierm callback							*/
		putchar(Running[ii++]);
		putchar('\r');
		ii &= 3;
	}
}

/* ------------------------------------------------------------------------------------------------ */
/*																									*/
/* Joystick interrupt handler function																*/
/* 																									*/
/* ------------------------------------------------------------------------------------------------ */

void JoyStickHandler(void)
{
int ii;

	if (RESET != EXTI_GetITStatus(DOWN_BUTTON_EXTI_LINE)) {
		ii = 0;
	}
	else if (RESET != EXTI_GetITStatus(UP_BUTTON_EXTI_LINE)) {
		ii = 1;
	}
	else if (RESET != EXTI_GetITStatus(SEL_BUTTON_EXTI_LINE)) {
		ii = 2;
	}
	else if (RESET != EXTI_GetITStatus(RIGHT_BUTTON_EXTI_LINE)) {
		ii = 3;
	}
	else {
		ii = 4;
	}

	if (Debounce[ii] == 0) {						/* Is this pin currently being debounced		*/
		Debounce[ii] = OS_TICK_PER_SEC/50;			/* 20 ms debounce time							*/
		switch(ii) {								/* Trigger the corresponding task unless the	*/
		case 0:										/* pin is currrently in debounce				*/
			MBXput(MbxUpDown, 2, 0);				/* Down position								*/
			break;
		case 1:										/* Up position									*/
			MBXput(MbxUpDown, 1, 0);
			break;
		case 2:										/* Center position								*/
			SEMpost(SemCenter);
			break;
		case 3:										/* Right position								*/
			EVTset(TaskLeftRight, 0x01);
			break;
		case 4:										/* Left position								*/
			EVTset(TaskLeftRight, 0x10);
			break;
		default:
			break;
		}
	}
													/* Acknowledge all joystick interrupts			*/
	EXTI_ClearITPendingBit( DOWN_BUTTON_EXTI_LINE);
	EXTI_ClearITPendingBit(   UP_BUTTON_EXTI_LINE);
	EXTI_ClearITPendingBit(  SEL_BUTTON_EXTI_LINE);
	EXTI_ClearITPendingBit(RIGHT_BUTTON_EXTI_LINE);
	EXTI_ClearITPendingBit( LEFT_BUTTON_EXTI_LINE);

	return;
}

/* ------------------------------------------------------------------------------------------------ */
/*																									*/
/* Timer call back function																			*/
/* 																									*/
/* ------------------------------------------------------------------------------------------------ */

void TIMcallBack(void)
{
int ii;
static int CBcnt=0;


	if (++CBcnt > (OS_TICK_PER_SEC/10)) {			/* Trigger FctTick()once every 0.1 s			*/
		CBcnt=0;
		EVTset(TaskTick, 1);
	}


	for (ii=0 ; ii<5 ; ii++) {						/* Debouncing: Need to wait for the pin to go	*/
		if (Debounce[ii] != 0) {					/* back to a low level for long enough			*/
			switch(ii) {
			case 0:
				if (!(Bit_SET == STM_EVAL_PBGetState(BUTTON_DOWN))) {
					Debounce[ii]--;
				}
				break;
			case 1:
				if (!(Bit_SET == STM_EVAL_PBGetState(BUTTON_UP))) {
					Debounce[ii]--;
				}
				break;
			case 2:
				if (!(Bit_SET == STM_EVAL_PBGetState(BUTTON_SEL))) {
					Debounce[ii]--;
				}
				break;
			case 3:
				if (!(Bit_SET == STM_EVAL_PBGetState(BUTTON_LEFT))) {
					Debounce[ii]--;
				}
				break;
			default:
				if (!(Bit_SET == STM_EVAL_PBGetState(BUTTON_RIGHT))) {
					Debounce[ii]--;
				}
				break;
			}
		}
	}

	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 (USART_GetFlagStatus(EVAL_COM1, USART_FLAG_TXE) == RESET);
			USART_SendData(EVAL_COM1, '\r');
		}
		while (USART_GetFlagStatus(EVAL_COM1, USART_FLAG_TXE) == RESET);
		USART_SendData(EVAL_COM1, *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(USART_GetFlagStatus(EVAL_COM1, USART_FLAG_RXNE) == RESET);
	*buf = USART_ReceiveData(EVAL_COM1) & 0xFF;
	if(EVAL_COM1->SR & (USART_FLAG_ORE | USART_FLAG_PE | USART_FLAG_FE) ) {
		len = 0;
	}
	return(len);
}
#endif

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

int GetKey(void)
{
int RetVal;

	RetVal = 0;
	if (EVAL_COM1->SR & USART_FLAG_RXNE) {
		RetVal = 0xFF & USART_ReceiveData(EVAL_COM1);
	}

	return(RetVal);
}

/* EOF */
