/* ------------------------------------------------------------------------------------------------ */
/* FILE :		Demo_0_STM32_P407_ATOLLIC.c															*/
/*																									*/
/* CONTENTS :																						*/
/*				Demo for the Olimex STM32-P407 evaluation board (RS232_1 port)						*/
/*				Flashing info and control shown on LEDs and the 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 != 0
	#error "Wrong OS_DEMO value" 
#endif

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

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

#include "stm32_p407.h"

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

USART_InitTypeDef USART_InitStructure;

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

SEM_t *SemLed0;										/* Semaphore used by TaskLed0					*/
SEM_t *SemLed1;										/* Semaphore used by TaskLed1					*/
SEM_t *SemLed2;										/* Semaphore used by TaskLed2					*/

TSK_t *TaskLed0;									/* Task used to control LED 0					*/
TSK_t *TaskLed1;									/* Task used to control LED 1					*/
TSK_t *TaskLed2;									/* Task used to control LED 2					*/

int    Debounce[2];									/* Used to debounce the 2 switches				*/

static volatile int g_Rate;							/* LED toggling rate control					*/

const char Running[] = "|/-\\";						/* To show on the serial port a running system	*/

char Flashing[] = "[ ]  [ ]  [ ]";					/* Template showing LED toggling on serial port	*/

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

void FctLed0(void);									/* Function attached to TaskLed0				*/
void FctLed1(void);									/* Function attached to TaskLed1				*/
void FctLed2(void);									/* Function attached to TaskLed2				*/

int  GetKey(void);									/* Non-blocking keyboard input read				*/
void SwitchISR(void);								/* Interrupt handler for the switches			*/

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

int main(void)
{
int  ii;											/* General purpose								*/
int  jj;											/* General purpose								*/
int  Prio = 0;										/* SysTicvk interrupt priority					*/
int *TimerBase;										/* SysTick register base address				*/


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

	SystemInit();

/* ------------------------------------------------ */
/* 	Start the RTOS									*/

	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			*/

/* ------------------------------------------------ */
/* 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/100000L) * OS_TIMER_US)/10)-1;
	TimerBase[4] = 0x7;								/* internal clock / int & enable			*/

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

	TaskLed0 = TSKcreate("LED 0", 1, TC_TSK_STACK, &FctLed0, 1);
	TaskLed1 = TSKcreate("LED 1", 1, TC_TSK_STACK, &FctLed1, 1);
	TaskLed2 = TSKcreate("LED 2", 1, TC_TSK_STACK, &FctLed2, 1);

	SemLed0  = SEMopen("LED 0");
	SemLed1  = SEMopen("LED 1");
	SemLed2  = SEMopen("LED 2");

/* ------------------------------------------------ */
/* Welcome banner									*/

	puts("\n\n");
	puts("\n           Abassi Demo 0");
	puts("\n         Olimex STM32-P407\n");
	puts("\n     Use the TAMPER & WKUP Buttons\n");
	puts("\n       or + - on serial port\n\n");

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

	STM_EVAL_PBInit(BUTTON_WAKEUP,  BUTTON_MODE_EXTI);
	STM_EVAL_PBInit(BUTTON_TAMPER,  BUTTON_MODE_EXTI);

	OSisrInstall( 6, &SwitchISR);					/* Install the switches interrupt handler		*/
	OSisrInstall(40, &SwitchISR);					/* Each swicth is on a different interrupt		*/

/* ------------------------------------------------ */
/* LED set-up										*/

	STM_EVAL_LEDInit(LED1);
	STM_EVAL_LEDInit(LED2);
	STM_EVAL_LEDInit(LED3);

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

	g_Rate = 5;										/* Start-up toggling rate						*/

	OSeint(1);

 	TSKsetPrio(TSKgetID(""), OS_PRIO_MIN);			/* Adam-Eve becomes the Idle Task				*/

	jj = 0;											/* From here on, the code is the Idle Task		*/
   	for(;;) {										/* Check key to be pressed to change the rate	*/
		switch(GetKey()) {
		case '+':									/* Key '+' pressed, increase the toggling rate	*/
			ii = g_Rate - 1;						/* which means to decrease the variable g_Rate	*/
			if (ii <= 0) {							/* Floor g_Rate at 0							*/
				ii = 1;
			}
			g_Rate = ii;
			break;
		case '-':									/* Key '-' pressed, decrease the toggling rate	*/
			ii = g_Rate + 1;						/* which means to increase the variable g_Rate	*/
			if (ii > 10) {							/* Ceiling g_Rate at 10							*/
				ii = 10;
			}
			g_Rate = ii;;
			break;
		default:									/* Any other key is ignored						*/
			break;
		}

		ii = g_Rate;								/* The switch ISR modifies g_Rate, so snapshot	*/
		printf("%c  Current rate %d%s  %s\r", Running[jj++], ii, (ii<10)?" ":"", Flashing);

		jj &= 3;									/* The running character span 4 types			*/
	}
}

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

void IdleTask(void)
{
	
	TSKselfSusp();									/* A&E is set to Idle priority so we can		*/
													/* disappear									*/
	for(;;);										
}

/* ------------------------------------------------------------------------------------------------ */
/* 																									*/
/* LED0 task																						*/
/* 																									*/
/* ------------------------------------------------------------------------------------------------ */

void FctLed0(void)
{

	for ( ; ; ) {
		SEMwaitBin(SemLed0, -1);					/* Wait for ISR to post SemLed0					*/
		SEMpost(SemLed1);							/* Inform TaskLed1 to toggle LED 1				*/
		Flashing[1] = '*';							/* Show on serial port LED 0 on					*/
		STM_EVAL_LEDOn(LED1);						/* We turn on LED 0								*/

		SEMwaitBin(SemLed0, -1);					/* Wait for ISR to post SemLed0					*/
		SEMpost(SemLed1);							/* Inform TaskLed1 to toggle LED 1				*/
		Flashing[1] = ' ';							/* Show on serial port LED 0 off				*/
		STM_EVAL_LEDOff(LED1);						/* We turn off LED 0							*/
	}
}

/* ------------------------------------------------------------------------------------------------ */
/* 																									*/
/* LED1 task																						*/
/* 																									*/
/* ------------------------------------------------------------------------------------------------ */

void FctLed1(void)
{

	for ( ; ; ) {
		SEMwaitBin(SemLed1, -1);					/* Each posting of SemLed1 toggle LED 1			*/
		Flashing[6] = '*';
		STM_EVAL_LEDOn(LED2);

		SEMwaitBin(SemLed1, -1);
		Flashing[6] = ' ';
		STM_EVAL_LEDOff(LED2);
	}
}

/* ------------------------------------------------------------------------------------------------ */
/* 																									*/
/* LED2 task																						*/
/* 																									*/
/* ------------------------------------------------------------------------------------------------ */

void FctLed2(void)
{

	for ( ; ; ) {
		SEMwaitBin(SemLed2, -1);					/* Wait for ISR to post SemLed0					*/
		SEMpost(SemLed1);							/* Inform TaskLed1 to toggle LED 1				*/
		Flashing[1] = '*';							/* Show on serial port LED 0 on					*/
		STM_EVAL_LEDOn(LED3);						/* We turn on LED 0								*/

		SEMwaitBin(SemLed2, -1);					/* Wait for ISR to post SemLed0					*/
		SEMpost(SemLed1);							/* Inform TaskLed1 to toggle LED 1				*/
		Flashing[1] = ' ';							/* Show on serial port LED 0 off				*/
		STM_EVAL_LEDOff(LED3);						/* We turn off LED 0							*/
	}
}

/* ------------------------------------------------------------------------------------------------ */
/* 																									*/
/* TAMPER & WKUP switch interrupt function															*/
/*																									*/
/* ------------------------------------------------------------------------------------------------ */

void SwitchISR(void)
{
													/* Check if WKUP is pressed						*/
	if ((RESET != EXTI_GetITStatus(WAKEUP_BUTTON_EXTI_LINE))
	&&  (Debounce[0] == 0)) {						/* WKUP is right one, increase toggle rate by	*/
		if (--g_Rate <= 0) {						/* decreassing g_Rate, with flooring at 0		*/
			g_Rate = 1;
		}
		Debounce[0] = OS_TICK_PER_SEC/50;
	}
	if ((RESET != EXTI_GetITStatus(TAMPER_BUTTON_EXTI_LINE))
	&&  (Debounce[1] == 0)) {						/* WKUP is left one, decrease toggle rate by	*/
		if (++g_Rate > 10) {						/* increassing g_Rate, with ceiling at 10		*/
			g_Rate = 10;
		}
		Debounce[1] = OS_TICK_PER_SEC/50;
	}

	EXTI_ClearITPendingBit(TAMPER_BUTTON_EXTI_LINE);/* Acknowledge both interrupts					*/
	EXTI_ClearITPendingBit(WAKEUP_BUTTON_EXTI_LINE);

	return;
}

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

void TIMcallBack(void)
{
static int Count0=0;								/* Counter to control when to toggle LED 0		*/
static int Count2=0;								/* Counter to control when to toggle LED 2		*/


	if (++Count0 >= g_Rate*(OS_TICK_PER_SEC/10)) {
		SEMpost(SemLed0);
		Count0 = 0;
	}
	if (++Count2 >= g_Rate*((81*OS_TICK_PER_SEC)/1000)) {
		SEMpost(SemLed2);
		Count2 = 0;
	}
													/* Switch debouncing							*/
	if ((!(Bit_SET == STM_EVAL_PBGetState(BUTTON_WAKEUP)))
	&&  (Debounce[0] != 0)) {
		Debounce[0]--;
	}
	if ((!(Bit_SET == STM_EVAL_PBGetState(BUTTON_TAMPER)))
	&&  (Debounce[1] != 0)) {
		Debounce[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

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

int GetKey(void)
{
int RetVal;

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

	return(RetVal);
}

/* EOF */
