/*
*********************************************************************************************************
*	                                  
*	模块名称 : uCOS-II
*	文件名称 : app.c
*	版    本 : V1.0
*	说    明 : 本实验主要实现消息队列
*              实验目的：
*                1. 学习uCOS-II中消息队列的使用。
*              实验内容：
*                1. 共创建了如下几个任务，通过按下按键K1可以通过串口打印任务堆栈使用情况
*                    Prio   Used   Free  Per     Taskname
*                     63     17    111   13%   uC/OS-II Idle
*                     62     23    105   17%   uC/OS-II Stat
*                     61     27    101   21%   uC/OS-II Tmr
*                      1     31    993   03%   Start Task
*                      3     65    959   06%   User Interface
*                     60     29    995   02%   LED
*                      4     29    995   02%   COM
*                      2     31    993   03%   KeyScan
*                    串口软件建议使用SecureCRT（V5光盘里面有此软件）查看打印信息。
*                    Start Task任务    ：主要是LED1的闪烁，500ms一次。
*                    User Interface任务：根据用户的按键消息，实现相应的操作。
*                    LED任务           ：实现LED的闪烁。
*                    KeyScan任务       ：主要是实现按键扫描。
*                    COM任务           ：等待消息队列中的数据。
*                 2. 按键K2向消息队列Post数据。
*                 3. 如果收到消息队列中的数据，在任务COM中通过串口打印出来。
*
*	修改记录 :
*		版本号  日期         作者            说明
*       v1.0    2014-03-23  Eric2013    ST固件库到V1.3.0版本
*                                       BSP驱动包V1.2
*                                       uCOS-II版本V2.92.07
*
*	Copyright (C), 2013-2014, 安富莱电子 www.armfly.com
*
*********************************************************************************************************
*/
#include "includes.h"

/*
*********************************************************************************************************
*                                       LOCAL GLOBAL VARIABLES
*********************************************************************************************************
*/
                                                               
static  OS_TCB   AppTaskStartTCB;
static  OS_TCB   AppTaskUserIFTCB;
static  OS_TCB   AppTaskKeyScanTCB;
/*
********************************************************************************************************
*                              任务堆栈
********************************************************************************************************
*/

/* 定义每个任务的堆栈空间，app_cfg.h文件中宏定义栈大小 */
static CPU_STK AppTaskStartStk[APP_TASK_START_STK_SIZE];
static CPU_STK AppTaskUserIFStk[APP_TASK_USER_IF_STK_SIZE];
static CPU_STK AppTaskKeyScanStk[APP_TASK_KeyScan_STK_SIZE];	
			
/*
*******************************************************************************************************
*                              函数声明
*******************************************************************************************************
*/

static void AppTaskCreate(void);
static void AppObjCreate(void);

static void AppTaskStart(void *p_arg);

static void AppTaskUserIF(void *p_arg);
static void AppTaskKeyScan(void *p_arg);

/*
*******************************************************************************************************
*                               变量
*******************************************************************************************************
*/

OS_Q RPM_Q;
OS_MEM MyPartition;
CPU_INT08U *MyDataBlkPtr;
CPU_INT08U MyPartitionStorage[12][100];
CPU_INT08U counter;

	CPU_INT08U ucKeyCode;	/* 按键代码 */
	CPU_INT08U ucTemp;
/*
*******************************************************************************************************
*	函 数 名: main
*	功能说明: 标准c程序入口。
*	形    参：无
*	返 回 值: 无
*******************************************************************************************************
*/
int main(void)
{
	 OS_ERR  err;
   BSP_IntDisAll();                                            /* Disable all interrupts.                                  */
   CPU_Init();                                                 /* Initialize uC/CPU services.                              */
   OSInit(&err);                                               /* Init OS.        */
 
 /*创建一个启动任务,启动任务会创建所有的应用程序任务*/
  OSTaskCreate((OS_TCB     *)&AppTaskStartTCB,                /* Create the start task                                    */
                 (CPU_CHAR   *)"App Task Start",
                 (OS_TASK_PTR ) AppTaskStart,
                 (void       *) 0,
                 (OS_PRIO     ) APP_TASK_START_PRIO,
                 (CPU_STK    *)&AppTaskStartStk[0],
                 (CPU_STK     )(APP_TASK_START_STK_SIZE / 10u),
                 (CPU_STK_SIZE) APP_TASK_START_STK_SIZE,
                 (OS_MSG_QTY  ) 0,
                 (OS_TICK     ) 0,
                 (void       *) 0,
                 (OS_OPT      )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
                 (OS_ERR     *)&err);
	 		AppObjCreate();		
					/*  定义如下：
						OS_TASK_OPT_STK_CHK      使能检测任务栈，统计任务栈已用的和未用的
						OS_TASK_OPT_STK_CLR      在创建任务时，清零任务栈
						OS_TASK_OPT_SAVE_FP      如果CPU有浮点寄存器，则在任务切换时保存浮点寄存器的内容
					*/                  
	
/* 启动多任务系统，控制权交给uC/OS-III */
	    OSStart(&err);
			    while (DEF_ON) {                                            /* Should Never Get Here                                    */
    };		 
}

/*
*********************************************************************************************************
*	函 数 名: AppTaskStart
*	功能说明: 这是一个启动任务，在多任务系统启动后，必须初始化滴答计数器(在BSP_Init中实现)
*	形    参：p_arg 是在创建该任务时传递的形参
*	返 回 值: 无
	优 先 级：1
*********************************************************************************************************
*/
static void AppTaskStart(void *p_arg)
{	
		OS_ERR err; 
	/* BSP 初始化。 BSP = Board Support Package 板级支持包，可以理解为底层驱动。*/
	 bsp_Init();
   CPU_Init();          
	 BSP_Tick_Init();
  Mem_Init();          

	/* 检测CPU能力，统计模块初始化。该函数将检测最低CPU占有率 */
	#if (OS_TASK_STAT_EN > 0)
		OSStatInit();
	#endif	
		
	/* 创建应用程序的任务 */
	AppTaskCreate();

	/* 任务主体，必须是一个死循环 */
	OSTaskDel((void *)0,&err);   
}

/*
*********************************************************************************************************
*	函 数 名: AppTaskKeyScan
*	功能说明: 按键扫描		
*	形    参：p_arg 是在创建该任务时传递的形参
*	返 回 值: 无
	优 先 级：2
*********************************************************************************************************
*/
static void AppTaskKeyScan(void *p_arg)
{
	OS_ERR err;

	(void)p_arg;
	//从目标分区中获得存储块，并返回指向分配的存储块的指针
		MyDataBlkPtr=(CPU_INT08U *)OSMemGet((OS_MEM *)&MyPartition,
										(OS_ERR *)&err); 
	while(1)
	{  

		bsp_KeyScan();        
		ucTemp = bsp_GetKey();
		if (ucTemp !=KEY_NONE)
		{	

			ucKeyCode = ucTemp;
			*MyDataBlkPtr++=ucKeyCode;
			/* 将按键代码发送到邮箱 */
			OSQPost((OS_Q *)&RPM_Q,
					 (void *)MyDataBlkPtr,
					 (OS_MSG_SIZE)10,
					 (OS_OPT)OS_OPT_POST_FIFO,
					 (OS_ERR *)&err);
		}		
		else
		{
						GPIO_ResetBits(GPIOE,GPIO_Pin_0);
		}
		/* 延迟10ms。必须释放CPU，否则低优先级任务会阻塞 */    	
		OSTimeDlyHMSM(0,0,0,10,OS_OPT_TIME_HMSM_NON_STRICT,&err);   //延时5ms		
	}   
}

/*
*********************************************************************************************************
*	函 数 名: AppTaskUserIF
*	功能说明: 此函数主要用于得到按键的键值。
*	形    参：p_arg 是在创建该任务时传递的形参
*	返 回 值: 无
	优 先 级：3
*********************************************************************************************************
*/
static void AppTaskUserIF(void *p_arg)
{
	OS_ERR err;
	CPU_INT08U   msg;
//	OS_MSG_SIZE size;
	CPU_TS ts;
    
	while (1) 
	{
		msg =(CPU_INT32U) OSQPend((OS_Q *)&RPM_Q,
															(OS_TICK ) 0,
															(OS_OPT)OS_OPT_PEND_BLOCKING,
															(OS_MSG_SIZE *)1,
															(CPU_TS *)&ts,
															(OS_ERR *)&err);
		if (err == OS_ERR_NONE)                             /* 无错表示成功接收到一个消息 */
		{
			if (msg == KEY_DOWN_K1)		
			{    
					counter++;
			}
			else if(msg == KEY_DOWN_K2)
			{
					counter--;
			} 
		}
			OSMemPut((OS_MEM *)&MyPartition,
					  (void *)MyDataBlkPtr,
					  (OS_ERR *)&err);
						
		OSTimeDlyHMSM(0,0,0,5,OS_OPT_TIME_HMSM_NON_STRICT,&err);   //延时5ms

	}

}		

/*
*********************************************************************************************************
*	函 数 名: AppTaskCreate
*	功能说明: 创建应用任务
*	形    参：p_arg 是在创建该任务时传递的形参
*	返 回 值: 无
*********************************************************************************************************
*/
static void AppTaskCreate (void)
{
	OS_ERR err;
	/* 创建按键发送任务 */
    OSTaskCreate((OS_TCB     *)&AppTaskKeyScanTCB,                /* Create the start task                                    */
                 (CPU_CHAR   *)"App Task KeyScan",
                 (OS_TASK_PTR ) AppTaskKeyScan,
                 (void       *) 0,
                 (OS_PRIO     ) APP_TASK_KeyScan_PRIO,
                 (CPU_STK    *)&AppTaskKeyScanStk[0],
                 (CPU_STK     )(APP_TASK_KeyScan_STK_SIZE / 10u),
                 (CPU_STK_SIZE) APP_TASK_KeyScan_STK_SIZE,
                 (OS_MSG_QTY  ) 0,
                 (OS_TICK     ) 0,
                 (void       *) 0,
                 (OS_OPT      )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
                 (OS_ERR     *)&err);
    
	/* 创建按键处理任务*/
    OSTaskCreate((OS_TCB     *)&AppTaskUserIFTCB,                /* Create the start task                                    */
                 (CPU_CHAR   *)"App Task UserIF",
                 (OS_TASK_PTR ) AppTaskUserIF,
                 (void       *) 0,
                 (OS_PRIO     ) APP_TASK_USER_IF_PRIO,
                 (CPU_STK    *)&AppTaskUserIFStk[0],
                 (CPU_STK     )(APP_TASK_USER_IF_STK_SIZE / 10u),
                 (CPU_STK_SIZE) APP_TASK_USER_IF_STK_SIZE,
                 (OS_MSG_QTY  ) 0,
                 (OS_TICK     ) 0,
                 (void       *) 0,
                 (OS_OPT      )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
                 (OS_ERR     *)&err);


}
static void AppObjCreate (void)
{
		OS_ERR err;
		OSQCreate((OS_Q *)&RPM_Q,
							(CPU_CHAR *)"My Queue",
							(OS_MSG_QTY)10,
							(OS_ERR *)&err);
		OSMemCreate((OS_MEM *)&MyPartition,
					(CPU_CHAR *)"My Partition",
					(void *)&MyPartitionStorage[0][0],
					(OS_MEM_QTY)12,
					(OS_MEM_SIZE)100,
					(OS_ERR *)&err);
			
							
}

