/* ------------------------------------------------------------------------------------------------ */
/* FILE :		Demo_0_STM32_P107_ATOLLIC.c															*/
/*																									*/
/* CONTENTS :																						*/
/*				Demo for the Olimex STM32-P107 evaluation board										*/
/*				Flashing rate control by the WKUP and TAMPER buttons								*/
/*				Flashing rate control also control through the serial port with '+' and '-'			*/
/*				Flashing info and control shown on the 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-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 != 0
	#error "Wrong OS_DEMO value" 
#endif

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

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

#include "stm32_eval.h"

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

EXTI_InitTypeDef  EXTI_InitStructure;
GPIO_InitTypeDef  GPIO_InitStructure;
NVIC_InitTypeDef  NVIC_InitStructure;
USART_InitTypeDef USART_InitStructure;

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

SEM_t *SemLed0;										/* Sempahore TaskLed0 blocks on					*/
SEM_t *SemLed1;										/* Sempahore TaskLed1 blocks on					*/
SEM_t *SemLed2;										/* Sempahore TaskLed2 blocks on					*/

TSK_t *TaskLed0;									/* Task toggling LED 0							*/
TSK_t *TaskLed1;									/* Task toggling LED 1							*/
TSK_t *TaskLed2;									/* Task toggling LED 2							*/

static volatile int g_Rate;							/* Controls the LEDs toggling rate				*/

const char Running[] = "|/-\\";

char Flashing[] = "[ ]  [ ]  [ ]";

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

void ButtonTamp(void);								/* Interrupt handler for Button TAMP			*/
void ButtonWkup(void);								/* Interrupt handler for Button WKUP			*/
void FctLed0(void);									/* Function attached to TaskLed0				*/
void FctLed1(void);									/* Function attached to TaskLed1				*/
void FctLed2(void);									/* Function attached to TaskLed2				*/
int  GetKey(void);

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

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

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

	SystemInit();

/* ------------------------------------------------ */
/* OS start-up										*/

	OSstart();

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

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

	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_OTG_FS | RCC_AHBPeriph_ETH_MAC |
	RCC_AHBPeriph_ETH_MAC_Tx | RCC_AHBPeriph_ETH_MAC_Rx , DISABLE);
	RCC_APB2PeriphClockCmd(~0xFFFF0002,DISABLE);
	RCC_APB1PeriphClockCmd(~(0xC10137C0 | RCC_APB1Periph_USART3),DISABLE);

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

/* ------------------------------------------------ */
/* LED & GPIO set-up								*/

	STM_EVAL_LEDInit(LED1);
	STM_EVAL_LEDInit(LED2);

	STM_EVAL_LEDOn(LED1);
	STM_EVAL_LEDOff(LED2);

/* ------------------------------------------------ */
/* Configure PA.00 in interrupt						*/

  /* Enable GPIOA clock */
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
  
  /* Configure PA.00 pin as input floating */
	GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_0;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_Init(GPIOA, &GPIO_InitStructure);

  /* Enable AFIO clock */
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);

  /* Connect EXTI0 Line to PA.00 pin */
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);

  /* Configure EXTI0 line */
	EXTI_InitStructure.EXTI_Line    = EXTI_Line0;
	EXTI_InitStructure.EXTI_Mode    = EXTI_Mode_Interrupt;
	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;  
	EXTI_InitStructure.EXTI_LineCmd = ENABLE;
	EXTI_Init(&EXTI_InitStructure);

  /* Enable and set EXTI0 Interrupt to the lowest priority */
	NVIC_InitStructure.NVIC_IRQChannel                   = EXTI0_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0F;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority        = 0x0F;
	NVIC_InitStructure.NVIC_IRQChannelCmd                = ENABLE;
	NVIC_Init(&NVIC_InitStructure);

	OSisrInstall(6, ButtonTamp);

/* ------------------------------------------------ */
/* Configure PC.13 in interrupt						*/

  /* Enable GPIOC clock */
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);

  /* Configure PC.13 pin as input floating */
	GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_13;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_Init(GPIOC, &GPIO_InitStructure);

  /* Enable AFIO clock */
 	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);

  /* Connect EXTI13 Line to PC.13 pin */
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOC, GPIO_PinSource13);

  /* Configure EXTI13 line */
	EXTI_InitStructure.EXTI_Line    = EXTI_Line13;
	EXTI_InitStructure.EXTI_Mode    = EXTI_Mode_Interrupt;
	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
	EXTI_InitStructure.EXTI_LineCmd = ENABLE;
	EXTI_Init(&EXTI_InitStructure);

  /* Enable and set EXTI15_10 Interrupt to the lowest priority */
	NVIC_InitStructure.NVIC_IRQChannel                   = EXTI15_10_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0F;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority        = 0x0F;
	NVIC_InitStructure.NVIC_IRQChannelCmd                = ENABLE;

	NVIC_Init(&NVIC_InitStructure);

	OSisrInstall(40, ButtonWkup);

/* ------------------------------------------------ */
/* 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");

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

	puts("\n\n");									/* Welcome banner								*/
	puts("\n         Abassi Demo 1");
	puts("\n       Olimex STM32-P107\n");
	puts("\n     Use + - on serial port\n");
	puts("\n             or\n");
	puts("\n   Use WKUP & TAMPER Buttons\n\n");

	g_Rate = 5;

	OSeint(1);

 	TSKsetPrio(TSKgetID(""), OS_PRIO_MIN);			/* No IdleTask created, Adam-Eve is 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;
		printf("%c  Current rate %d%s  %s\r", Running[jj++], ii, (ii<10)?" ":"", Flashing);

		jj &= 3;
	}
}

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

		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);
	}
}

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

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

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

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

void FctLed2(void)
{
	for ( ; ; ) {
		SEMwaitBin(SemLed2, -1);					/* Wait for ISR to post SemLed2					*/
		SEMpost(SemLed1);							/* Inform TaskLed1 to toggle LED 1				*/
		Flashing[11] = '*';							/* Show on serial port LED 2 on					*/
		STM_EVAL_LEDOn(LED2);

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

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

void TIMcallBack(void)
{
static int CntLed0 = 0;								/* Counter use to determine when LED 0 toggles	*/
static int CntLed2 = 0;								/* Counter use to determine when LED 2 toggles	*/


	if (++CntLed0 >= g_Rate*6*(OS_TICK_PER_SEC/10)) {/* Determine if it's time to toggle LED 0		*/
		SEMpost(SemLed0);							/* When it is, post the semaphore TaslLed0 is	*/
		CntLed0 = 0;								/* blocked on									*/
	}

	if (++CntLed2 >= g_Rate*6*((OS_TICK_PER_SEC/10)-(OS_TICK_PER_SEC/33))) {
		SEMpost(SemLed2);							/* Determine if it's time to toggle LED 2		*/
		CntLed2 = 0;								/* When it is, post the semaphore TaslLed2 is	*/
	}												/* blocked on									*/

	return;
}

/* ------------------------------------------------------------------------------------------------ */
/*																									*/
/* Tamper button interrupt handler																	*/
/* 																									*/
/* ------------------------------------------------------------------------------------------------ */

void ButtonTamp(void)
{

	if (g_Rate < 10) {								/* Slow down flashing rate						*/
		g_Rate++;									/* This means to increase the value of g_Rate 	*/
	}												/* But with ceiling at 10						*/

	EXTI_ClearITPendingBit(EXTI_Line0);				/* Acknowledge the TAMP interrupt				*/

	return;
}

/* ------------------------------------------------------------------------------------------------ */
/*																									*/
/* Wake-up Button interrupt handler																	*/
/* 																									*/
/* ------------------------------------------------------------------------------------------------ */

void ButtonWkup(void)
{

	if (g_Rate > 1) {								/* Speed up the flashing rate					*/
		g_Rate--;									/* This means to decrease the value of g_Rate 	*/
	}												/* But with flooring at 1						*/

	EXTI_ClearITPendingBit(EXTI_Line13);			/* Acknowledge the WKUP interrupt				*/

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