/* ------------------------------------------------------------------------------------------------ */
/* FILE :		Demo_4_STM3220G_ATOLLIC.c															*/
/*																									*/
/* CONTENTS :																						*/
/*				Demo for the ST microelectronics STM3220G evaluation board							*/
/*				Operation of the joystick shown on the LCD Display & Serial port					*/
/*				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.4 $																				*/
/*	$Date: 2013/06/14 18:11:54 $																	*/
/*																									*/
/* ------------------------------------------------------------------------------------------------ */

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

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

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

#include "stm32f2xx.h"
#include "stm32_eval.h"
#include "stm322xg_eval_lcd.h"
#include "stm322xg_eval_ioe.h"

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

#if 0											/* Setting != 0, looks like old plasma display	*/
  #define BG_COLOR	LCD_COLOR_BLACK
  #define FG_COLOR	(((0xFC>>3)<<11)|((0x39>>2)<<5)|(0x02>>3))
#else
  #define BG_COLOR	(((0xFC>>3)<<11)|((0x39>>2)<<5)|(0x02>>3))
  #define FG_COLOR	LCD_COLOR_BLACK
#endif

USART_InitTypeDef USART_InitStructure;

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

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 register base address				*/

/* ------------------------------------------------ */
/* 	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);
	setvbuf(stdout, NULL, _IONBF, 0);

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

	STM322xG_LCD_Init();

	LCD_Clear(LCD_COLOR_BLACK);

	LCD_SetColors(FG_COLOR, BG_COLOR);

/* ------------------------------------------------ */
/* 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");									/* Welcome banner								*/
	puts("\n      Abassi Demo 4");
	puts("\n     ST STM3220G-EVAL\n");
	puts("\n     Use the joystick\n\n");

	LCD_DisplayStringLine(LINE(0), (uint8_t *)"                    ");
	LCD_DisplayStringLine(LINE(1), (uint8_t *)"   Abassi Demo 4    ");
	LCD_DisplayStringLine(LINE(2), (uint8_t *)"                    ");
	LCD_DisplayStringLine(LINE(3), (uint8_t *)"  Use the joystick  ");
	LCD_DisplayStringLine(LINE(4), (uint8_t *)"                    ");
	LCD_DisplayStringLine(LINE(5), (uint8_t *)"                    ");
	LCD_DisplayStringLine(LINE(6), (uint8_t *)"                    ");
	LCD_DisplayStringLine(LINE(7), (uint8_t *)"                    ");
	LCD_DisplayStringLine(LINE(8), (uint8_t *)"                    ");
	LCD_DisplayStringLine(LINE(9), (uint8_t *)"                    ");


/* ------------------------------------------------ */
/* Configure IO expander for the joystick			*/

	if (IOE_Config() != IOE_OK) {
		LCD_DisplayStringLine(Line4, (uint8_t *)"IO Expander FAILED ");
		LCD_DisplayStringLine(Line5, (uint8_t *)" Please Reset the  ");
		LCD_DisplayStringLine(Line6, (uint8_t *)"   board and start ");
		LCD_DisplayStringLine(Line7, (uint8_t *)"    again          ");
		while(1);
	}

	IOE_ITConfig(IOE_ITSRC_JOYSTICK); 

	OSisrInstall(8, &JoyStickHandler);				/* Install the joystick interrupt handler		*/

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

	OSeint(1);										/* And here we go								*/

	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_DisplayStringLine(LINE(7), (uint8_t *)"      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_DisplayStringLine(LINE(7), (uint8_t *)"       Right        ");
		}
		if ((0x10 & events) != 0) {					/* Flag bit #4 is for right position			*/
			printf("    Left  \r");

			LCD_DisplayStringLine(LINE(7), (uint8_t *)"       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_DisplayStringLine(LINE(7), (uint8_t *)"        Up          ");
		}
		if ((int)Msg == 2) {						/* Message #2 is for down position				*/
			printf("    Down  \r");

			LCD_DisplayStringLine(LINE(7), (uint8_t *)"       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)
{
JOY_State_TypeDef JoyState;

	if (EXTI_GetITStatus(IOE_IT_EXTI_LINE) != RESET) {
		if (IOE_GetGITStatus(IOE_2_ADDR, IOE_GIT_GPIO)) {
			JoyState = IOE_JoyStickGetState();
			switch (JoyState) {
			case JOY_UP:
				MBXput(MbxUpDown, 1, 0);
				break;
			case JOY_DOWN:
				MBXput(MbxUpDown, 2, 0);
				break;
			case JOY_LEFT:
				EVTset(TaskLeftRight, 0x10);
				break;
			case JOY_RIGHT:
				EVTset(TaskLeftRight, 0x01);
				break;
			case JOY_CENTER:
				SEMpost(SemCenter);
				break;
			default:
				break;
			}
		}
		IOE_ClearGITPending(IOE_2_ADDR,  IOE_GIT_GPIO);
		IOE_ClearIOITPending(IOE_2_ADDR, IOE_JOY_IT);     
	}

	IOE_ClearGITPending(IOE_1_ADDR, ALL_IT);
	IOE_ClearGITPending(IOE_2_ADDR, ALL_IT);
    
    EXTI_ClearITPendingBit(IOE_IT_EXTI_LINE);  

	return;
}


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

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


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

	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

