Files

1094 lines
28 KiB
C

/*
@NOT_ACT_USED
*/
/*******************************************************************
RTOS操作系统接口函数,用于对系统底层的部分函数进行重新封装,以方便使用
**********************************************************************/
//#include "stm32f4x7_eth.h"
//#include "stm32f4xx_wwdg.h"
#include "stm32f4xx_hal.h"
#include <string.h>
#include "type.h"
#include "os_task.h"
#include "task.h"
#include "FreeRTOS.h"
#include "semphr.h"
#include "stm32f407xx.h"
#include "core_cm4.h"
#include "gps.h"
#include "rtc.h"
SYS_TASK sys_task = {0,};
S_RUN_TIME run_time = {0xff,0xff,0xff}; //记录系统运行时间 时分秒 最大单位,小时
static TIME_MSG_Q time_msg_queue;
const static MSG sec_msg = {MSG_SEC,MSG_NO_NEED_FREE};
const static MSG min_msg = {MSG_MINUTE,MSG_NO_NEED_FREE};
static S_SYS_TIME date_time;
static S_MSG_STATE msg_state;
extern __IO uint32 sys_ready;
static uint32 os_int_nesting = 0; //中断嵌套层级
static TIMER tick_timer[MAX_TIMER_NUM];
#if USE_MEM_DEBUG
static S_MEM_STATE mem_state;
#endif
void sys_para_init(void)
{
#if USE_MEM_DEBUG //内存统计必须打开开关才有效
extern uint32 __heap_base; //堆首地址
extern uint32 __heap_limit; //堆地址 也是中断栈的首地址
memset((void*)&mem_state,0,sizeof(mem_state));
mem_state.total =(uint32)&__heap_limit- (uint32)&__heap_base;
mem_state.used = 0;
#endif
memset((void*)&msg_state,0,sizeof(msg_state));
}
#if 0
//判断当前是否处于中断模式
//根据局部变量地址进行判断, UCOS中是在所有的中断函数中置一个变量,表示当前为中断模式,退出时清楚标志
//也可以搞一个系统全局变量,所有中断函数入口置位,返回时清除.这样速度快,但编写中断函数时需要额外操作
static uint32 __inline func_is_in_isr(void)
{
//extern uint32 __heap_base; //堆首地址
extern uint32 __heap_limit; //堆末地址 也是中断栈的首地址
//extern uint32 __initial_sp; //中断栈末地址
//#define OS_ISR_TASK_SIZE (0X400) //当前系统栈地址为0x400(1kbyte)
//#define OS_ISR_TASK_SIZE (__initial_sp - __heap_limit) //当前系统保留栈大小,具体配置在startup*.s中
uint32 temp = 0;
if(((uint32)&temp)>((uint32)&__heap_limit))
return 1;
else
return 0;
}
#endif
/*****************************************************************************
函 数 名 : create_task
功能描述 : 创建任务API函数
输入参数 : void (*fun)(void*) 任务函数主体
char* pcname 任务名称
uint32 task_id 任务ID,全局唯一
uint32 task_pro 任务优先级
uint32 stacksize 堆栈大小,若无特殊需要,使用默认值即可 注意单位为4字节(机器字长)
uint32 queuesize 消息队列大小,大小需是8(MSG大小)的整倍数 注意单位为4字节
输出参数 :
返 回 值 : 0 成功 其他:异常
调用函数 :
被调函数 :
修改历史 :
1.日 期 : 2012年12月24日
作 者 : 郭金涛
修改内容 : 新生成函数
*****************************************************************************/
uint32 create_task(void (*fun)(void*),char* pcname,uint32 task_id,uint32 task_pro,uint32 stacksize,uint32 queuesize)
{
uint32 ret_value = 0;
pSYS_TASK ptask = &sys_task; //为输出参数,
uint32 task_tcb = 0;
if(task_id>MAX_TASK)
return ERR_TASKID_TOO_LARGE;
ret_value = xTaskCreate(fun,(const char*)pcname,stacksize,NULL,task_pro,(void*)&task_tcb);
if(ret_value!=pdPASS)
return ERR_CREATE_TASK_FAILED;
vTaskSetTaskNumber((void*)task_tcb,task_id);
if(queuesize)
{
ptask->queue[task_id] = (void*)xQueueGenericCreate( queuesize/sizeof(void*), sizeof(void*), queueQUEUE_TYPE_BASE);
if(ptask->queue==NULL)
return ERR_CREATE_QUEUE_FAILED;
}
ptask->created[task_id] = 1;
ptask->num++;
return 0;
}
#if 1//_USE_RVL_
//将task_id的任务配置为进制任务状态检查
uint32 task_set_ignore_chk(uint32 task_id)
{
if(task_id>MAX_TASK)
return ERR_TASKID_TOO_LARGE;
sys_task.ignore_chk[task_id] = 1;
return 0;
}
/*****************************************************************************
函 数 名 : send_msg
功能描述 : 向对应id的任务发送消息 RTOS函数封装,是否需要判断当前是否处于中断状态
输入参数 : uint32 task_id 目的任务ID(内部仅用到高16位)
pMSG pmsg 消息体指针
输出参数 : 无
返 回 值 :uint32 0 成功, 其他 异常
调用函数 :
被调函数 :
修改历史 :
1.日 期 : 2012年12月24日
作 者 : 郭金涛
修改内容 : 新生成函数
signed portBASE_TYPE xQueueGenericSend( xQueueHandle pxQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition )
signed portBASE_TYPE xQueueGenericSendFromISR( xQueueHandle pxQueue, const void * const pvItemToQueue, signed portBASE_TYPE *pxHigherPriorityTaskWoken, portBASE_TYPE xCopyPosition )
实现对上述两个函数的封装 且采用FIFO模式
*****************************************************************************/
uint32 send_msg(uint32 task_id,pMSG pmsg)
{
uint32 ret = 0;
#if USE_MSG_DEBUG
MSG_DEBUG *pdebug_msg = (MSG_DEBUG *)pmsg;
pdebug_msg->rec_id = task_id;
#endif
if(task_id>MAX_TASK)
return ERR_SEND_MSG_FAILED;
if(!sys_task.queue[task_id])
return ERR_SEND_MSG_FAILED;
//if(func_is_in_isr()) //是否处于中断处理函数中 可以定义个全局变量.
if(os_int_nesting)
{
int32 need_sched = pdFALSE;
ret = xQueueGenericSendFromISR(sys_task.queue[task_id],(const void*)&pmsg,(BaseType_t *)&need_sched,queueSEND_TO_BACK);
if(ret!=pdPASS)
return ERR_SEND_MSG_FAILED;
if(need_sched) //若需要任务立即调度,调度此函数,以配置pendsv中断
taskYIELD();
taskENTER_CRITICAL();
msg_state.isr_send_num++;
taskEXIT_CRITICAL();
}
else
{
ret = xQueueGenericSend(sys_task.queue[task_id],(const void*)&pmsg,0,queueSEND_TO_BACK);
if(ret != pdPASS)
return ERR_SEND_MSG_FAILED;
taskENTER_CRITICAL();
msg_state.task_send_num++;
taskEXIT_CRITICAL();
}
return 0;
}
/*****************************************************************************
函 数 名 : get_msg
功能描述 : 接收该任务收到的消息 RTOS底层函数封装,接收消息由于当前结构原因,不需要在中断中接收消息,不需考虑
输入参数 : uint32 wait_ticks 等待的tick值,若为(-1),则为一直等待
输出参数 : 无
返 回 值 :
调用函数 :
被调函数 :
修改历史 :
1.日 期 : 2012年12月24日
作 者 : 郭金涛
修改内容 : 新生成函数
signed portBASE_TYPE xQueueGenericReceive( xQueueHandle pxQueue, void * const pvBuffer, portTickType xTicksToWait, portBASE_TYPE xJustPeeking )
对上述函数的封装
*****************************************************************************/
pMSG get_msg(uint32 wait_ticks)
{
MSG *pmsg = NULL;
uint32 task_id;
get_current_task_id(&task_id);
if(task_id>=MAX_TASK)
return NULL;
if(sys_task.queue[task_id]==NULL)
return NULL;
//xQueueGenericReceive(sys_task.queue[task_id],(void*)&pmsg,wait_ticks,pdFALSE);
xQueueReceive(sys_task.queue[task_id],(void*)&pmsg,wait_ticks);//_USE_RVL_
//Protype:BaseType_t xQueueReceive( QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait )
return pmsg;
}
//可考虑增加一些调试信息
//最好不要再中断函数中调用,
void *alloc_mem(uint32 size)
{
MEM_PTR *pmem = NULL;
//申请内存4字节对齐. 若未对齐,增加填充字节
if(size&3)
{
size += 4-(size&3);
}
#if USE_MEM_DEBUG
pmem = pvPortMalloc(size+sizeof(MEM_DEBUG_HEADER));
#else
pmem = pvPortMalloc(size);
#endif
if(!pmem)
{
return NULL;
}
#if USE_MEM_DEBUG
pmem->header.size = size;
pmem->header.tick = get_sys_tick();
taskENTER_CRITICAL();
mem_state.used+=size;
taskEXIT_CRITICAL();
#endif
return (void*)&pmem->mem[0];
}
void free_mem(void* p)
{
MEM_PTR *pmem = (MEM_PTR *)p;
if(!pmem)
return;
#if USE_MEM_DEBUG
pmem = (MEM_PTR *)((uint32)pmem-sizeof(MEM_DEBUG_HEADER));
taskENTER_CRITICAL();
mem_state.used-=pmem->header.size;
taskEXIT_CRITICAL();
#endif
vPortFree(pmem);
}
/*****************************************************************************
函 数 名 : alloc_msg
功能描述 : 申请消息函数,FREERTOS不同于UCOS,实际上消息只是个内存区,也可以调用alloc_mem来自由实现,甚至申请一块很大的内存发送消息
输入参数 : void
输出参数 : 无
返 回 值 :
调用函数 :
被调函数 :
修改历史 :
1.日 期 : 2013年5月3日
作 者 : 郭金涛
修改内容 : 新生成函数
调用此函数申请的消息,是一个MSG类型的结构体指针
*****************************************************************************/
MSG* alloc_msg(void)
{
#if USE_MSG_DEBUG//打开后,需要改下代码
MSG_DEBUG *pdebug_msg = NULL;
pdebug_msg = alloc_mem(sizeof(MSG_DEBUG));
if(pdebug_msg==NULL)
return NULL;
if(os_int_nesting)
{
pdebug_msg->alloc_id = OS_MSG_ISR_TASK_ID;
taskENTER_CRITICAL();
msg_state.isr_alloc_num++;
taskEXIT_CRITICAL();
}
else
{
pdebug_msg->alloc_id = uxTaskPriorityGet(NULL);
taskENTER_CRITICAL();
msg_state.task_alloc_num++;
taskEXIT_CRITICAL();
}
pdebug_msg->magci_word = OS_MSG_MAGIC_WORD;
//pdebug_msg->need_free = MSG_NEED_FREE;
return &pdebug_msg->msg;
#else
pMSG pmsg = NULL;
pmsg = alloc_mem(sizeof(MSG));
if(pmsg==NULL)
return NULL;
pmsg->type = 0;
pmsg->wPara = 0;
pmsg->rPara = 0;
pmsg->need_free = MSG_NEED_FREE;
pmsg->lPara = 0;
if(os_int_nesting)
{
taskENTER_CRITICAL();
msg_state.isr_alloc_num++;
taskEXIT_CRITICAL();
}
else
{
taskENTER_CRITICAL();
msg_state.task_alloc_num++;
taskEXIT_CRITICAL();
}
return pmsg;
#endif
}
/*****************************************************************************
函 数 名 : free_msg
功能描述 : 释放消息函数,理论上该函数要与alloc_msg配对使用. 处理后的消息,是否需要释放,要有用户判断
//当前不需要释放的有sec,min,timer和key消息
输入参数 : pMSG p
输出参数 : 无
返 回 值 :
调用函数 :
被调函数 :
修改历史 :
1.日 期 : 2013年5月3日
作 者 : 郭金涛
修改内容 : 新生成函数
*****************************************************************************/
void free_msg(MSG *p)
{
#if USE_MSG_DEBUG
MSG_DEBUG *pdebug_msg = (MSG_DEBUG *)p;
if(pdebug_msg->magci_word!= OS_MSG_MAGIC_WORD)
{
; //内存使用可能存在异常
}
free_mem(pdebug_msg);
#else
free_mem(p);
#endif
taskENTER_CRITICAL();
msg_state.free_num++;
taskEXIT_CRITICAL();
}
SEM_HANDLE create_sem(uint32 max_count,uint32 init_count)
{
return xQueueCreateCountingSemaphore(max_count,init_count);
}
//等待信号量 会挂起任务
uint32 pend_sem(SEM_HANDLE sem_hd,uint32 wait_ticks)
{
uint32 ret = 0;
if(NULL== sem_hd)
return ERR_SEM_PTR_INVALID;
ret = xSemaphoreTake(sem_hd,wait_ticks);
if(ret!=pdPASS)
return ERR_PEND_SEM_FAILED;
return 0;
}
//发送信号量
uint32 post_sem(SEM_HANDLE sem_hd)
{
uint32 ret = 0;
if(sem_hd==NULL)
return ERR_SEM_PTR_INVALID;
//if(func_is_in_isr()) //是否处于中断处理函数中
if(os_int_nesting)
{
int32 task_sched = pdFALSE;
ret = xSemaphoreGiveFromISR(sem_hd,(BaseType_t *)&task_sched);
if(ret!=pdPASS)
return ERR_POST_SEM_FAILED;
if(task_sched)
taskYIELD();
return 0;
}
else
{
ret = xSemaphoreGive(sem_hd);
if(ret!=pdPASS)
return ERR_POST_SEM_FAILED;
else
return 0;
}
}
MUTEX_HANDLE create_mutex(void)
{
return xSemaphoreCreateMutex();
}
uint32 take_mutex(MUTEX_HANDLE mtx_hd)
{
uint32 ret = 0;
if(sys_ready)
{
if(NULL==mtx_hd)
return ERR_MUTEX_PTR_INVALID;
ret = xSemaphoreTake(mtx_hd,OS_WAIT_FOREVER);
if(ret!=pdPASS)
return ERR_TAKE_MUTEX_FAILED;
}
return 0;
}
uint32 give_mutex(MUTEX_HANDLE mtx_hd)
{
uint32 ret = 0;
if(sys_ready)
{
if(NULL==mtx_hd)
return ERR_MUTEX_PTR_INVALID;
ret = xSemaphoreGive(mtx_hd);
if(ret!=pdPASS)
return ERR_GIVE_MUTEX_FAILED;
else
return 0;
}
return 0;
}
/*
void task_stop_sec_msg(void)
{
uint32 task_id = 0;
if(!sys_ready)
return;
get_current_task_id(&task_id);
if(task_id>=MAX_TASK)
{
return;
}
sys_task.pause[task_id] = 0XFF;
}
void task_resume_sec_msg(void)
{
uint32 task_id = 0;
if(!sys_ready)
return;
get_current_task_id(&task_id);
if(task_id>=MAX_TASK)
{
return;
}
sys_task.pause[task_id] = 0;
}*/
#endif//_USE_RVL_
/***********计算CPU利用率相关函数***********************/
#if 1//_USE_RVL_
#define AVERAGE_NUM 4
#define AVERAGE() \
do { \
uint32 i,j; \
for(i=0,j=0;i<AVERAGE_NUM;i++) \
{ \
j+=aCpu[i]; \
} \
cpu_useage = (j/AVERAGE_NUM); \
}while(0)
static uint32 cpu_useage = 0;
/*
void sys_state(void * pvParameters) //可以由最高任务的秒消息驱动进行计算
{
static const uint32 sec_run_time = 5418758/100; //经验数值
uint32 index = 0;
for(;;)
{
set_idle_run_time(0);
task_delay(configTICK_RATE_HZ);
aCpu[index] = 100-get_idle_run_time()/sec_run_time;
if(aCpu[index]>100)
aCpu[index] = 0;
AVERAGE();
index++;
if(index >= AVERAGE_NUM)
{
index = 0;
}
}
}*/
void calc_cpu_usage(void)
{
#if configUSE_CALC_CPU_USAGE
static const uint32 sec_run_time = 5418758/100; //经验数值
uint32 index = 0;
static uint8 aCpu[AVERAGE_NUM] = {0,};
aCpu[index] = 100-get_idle_run_time()/sec_run_time;
if(aCpu[index]>100)
aCpu[index] = 0;
AVERAGE();
index++;
if(index >= AVERAGE_NUM)
{
index = 0;
}
set_idle_run_time(0);
#endif
}
uint32 get_cpu_useage(void)
{
return cpu_useage;
}
static void check_sec_tick(void)
{
static uint32 sec_tick = 0;
if(!sys_ready)
{
return; //启动完成后再发,否则main_task会堆积过多的秒消息
}
sec_tick++;
if(sec_tick>=OS_TICKS_PER_SEC)
{
sec_tick = 0;
send_msg(MAIN_TASK_ID,(pMSG)&sec_msg);
}
}
static void send_min_msg(void)
{
uint32 i = 0;;
while(i<time_msg_queue.min_num)
{
send_msg(time_msg_queue.min_msg_q[i],(pMSG)&min_msg);
i++;
}
}
static void send_sec_msg(void)
{
uint32 i = 0;
uint32 task_id = 0;
while(i<time_msg_queue.sec_num)
{
task_id = time_msg_queue.sec_msg_q[i];
if(sys_task.pause[task_id]==0)
send_msg(task_id,(pMSG)&sec_msg);
i++;
}
}
void send_clk_msg(void)
{
if(run_time.sec == 0xff)
{
run_time.sec = 0;
run_time.min = 0;
run_time.hour= 0;
return;
}
send_sec_msg();
if(++run_time.sec>=60)
{
run_time.sec = 0;
send_min_msg();
if(++run_time.min>=60)
{
run_time.min = 0;
run_time.hour++;
}
}
}
uint32 get_current_task_id(uint32 *pid)
{
if(os_int_nesting)
{
*pid = (uint32)-1;
return 1;
}
else
{
*pid = uxTaskGetTaskNumber(xTaskGetCurrentTaskHandle());
return 0;
}
}
uint32 get_task_id(uint32 *pid,void *ptcb)
{
if(os_int_nesting)
{
*pid = (uint32)-1;
return 1;
}
else
{
*pid = uxTaskGetTaskNumber(ptcb);
return 0;
}
}
//配置当前任务能收到的时间消息,秒消息主任务不需要配置
uint32 config_time_msg(uint32 type)
{
uint32 task_id = 0;
get_current_task_id(&task_id);
if(task_id>=MAX_TASK)
{
return 2;
}
switch(type)
{
case MSG_SEC:
time_msg_queue.sec_msg_q[time_msg_queue.sec_num++] = task_id;
break;
case MSG_MINUTE:
time_msg_queue.min_msg_q[time_msg_queue.min_num++] = task_id;
break;
default:
break;
}
return 0;
}
get_sys_time
/*
void get_sys_time(S_SYS_TIME *ptime)
{
if(!ptime)
return;
ptime->hour = date_time.hour;
ptime->min = date_time.min;
ptime->sec = date_time.sec;
ptime->date = date_time.date;
ptime->month= date_time.month;
ptime->year = date_time.year;
return;
}
*/
S_SYS_TIME *os_get_sys_time_ptr(void)
{
return &date_time;
}
typedef struct
{
uint8_t WeekDay; /*!< Specifies the RTC Date WeekDay.
This parameter can be a value of @ref RTC_WeekDay_Definitions */
uint8_t Month; /*!< Specifies the RTC Date Month (in BCD format).
This parameter can be a value of @ref RTC_Month_Date_Definitions */
uint8_t Date; /*!< Specifies the RTC Date.
This parameter must be a number between Min_Data = 1 and Max_Data = 31 */
uint8_t Year; /*!< Specifies the RTC Date Year.
This parameter must be a number between Min_Data = 0 and Max_Data = 99 */
}usr_PKT_RTC_DateTypeDef;
typedef struct
{
uint8_t Hours; /*!< Specifies the RTC Time Hour.
This parameter must be a number between Min_Data = 0 and Max_Data = 12 if the RTC_HourFormat_12 is selected.
This parameter must be a number between Min_Data = 0 and Max_Data = 23 if the RTC_HourFormat_24 is selected */
uint8_t Minutes; /*!< Specifies the RTC Time Minutes.
This parameter must be a number between Min_Data = 0 and Max_Data = 59 */
uint8_t Seconds; /*!< Specifies the RTC Time Seconds.
This parameter must be a number between Min_Data = 0 and Max_Data = 59 */
uint8_t TimeFormat; /*!< Specifies the RTC AM/PM Time.
This parameter can be a value of @ref RTC_AM_PM_Definitions */
uint32_t SubSeconds; /*!< Specifies the RTC_SSR RTC Sub Second register content.
This parameter corresponds to a time unit range between [0-1] Second
with [1 Sec / SecondFraction +1] granularity */
uint32_t SecondFraction; /*!< Specifies the range or granularity of Sub Second register content
corresponding to Synchronous pre-scaler factor value (PREDIV_S)
This parameter corresponds to a time unit range between [0-1] Second
with [1 Sec / SecondFraction +1] granularity.
This field will be used only by HAL_RTC_GetTime function */
uint32_t DayLightSaving; /*!< Specifies DayLight Save Operation.
This parameter can be a value of @ref RTC_DayLightSaving_Definitions */
uint32_t StoreOperation; /*!< Specifies RTC_StoreOperation value to be written in the BCK bit
in CR register to store the operation.
This parameter can be a value of @ref RTC_StoreOperation_Definitions */
}usr_PKT_RTC_TimeTypeDef;
//设置系统时钟,更新本地,同时更改RTC时钟
void set_sys_time(S_SYS_TIME *p)
{
RTC_DateTypeDef date;
RTC_TimeTypeDef time;
S_SYS_TIME tmptime={0};
if(!p)
{
return;
}
date.RTC_Year = p->year-2000;
date.RTC_Date = p->date;
date.RTC_Month= p->month;
time.RTC_Hours = p->hour;
time.RTC_Minutes= p->min;
time.RTC_Seconds= p->sec;
rtc_set_date_time(&date,&time);
tmptime.year = date.RTC_Year;
tmptime.month = date.RTC_Month;
tmptime.date = date.RTC_Date;
tmptime.hour = time.RTC_Hours;
tmptime.min = time.RTC_Minutes;
tmptime.sec = time.RTC_Seconds;
usr_set_sys_rtc_time(&tmptime);
}
void update_sys_time_by_rtc(void)
{
RTC_DateTypeDef date;
RTC_TimeTypeDef time;
//printf("%s ..\n",__FUNCTION__);
rtc_get_date_time(&date,&time);
portENTER_CRITICAL();
date_time.year = date.RTC_Year+2000;
date_time.date = date.RTC_Date;
date_time.month= date.RTC_Month;
date_time.hour = time.RTC_Hours; //默认为24小时模式
date_time.min = time.RTC_Minutes;
date_time.sec = time.RTC_Seconds;
portEXIT_CRITICAL();
//printf("System time:%04d-%02d-%02d %02d:%02d:%02d.\n",
// date_time.year,date_time.month,date_time.date,date_time.hour,date_time.min,date_time.sec);
//printf("%s success.\n",__FUNCTION__);
}
void rtc_update_by_gps(GPRMC_T *p)
{
portENTER_CRITICAL();
date_time.year = p->year;
date_time.date = p->day;
date_time.month= p->month;
date_time.hour = p->hour; //默认为24小时模式
date_time.min = p->min;
date_time.sec = p->sec;
date_time.valid = 1;
portEXIT_CRITICAL();
set_sys_time(&date_time);
}
void get_msg_state(S_MSG_STATE *pstate)
{
if(!pstate)
{
return;
}
taskENTER_CRITICAL();
memcpy(pstate,&msg_state,sizeof(msg_state));
taskEXIT_CRITICAL();
}
void get_mem_state(S_MEM_STATE *pstate)
{
if(!pstate)
return;
#if USE_MEM_DEBUG
taskENTER_CRITICAL();
memcpy(pstate,&mem_state,sizeof(mem_state));
taskEXIT_CRITICAL();
#else
pstate->total = (uint32)-1;
pstate->used = (uint32)-1;
#endif
}
uint32 os_get_free_heap_size(void)
{
return xPortGetFreeHeapSize();
}
HANDLE create_timer(void)
{
uint32 i;
uint32 task_id = 0;
for(i=0;i<MAX_TIMER_NUM;i++)
{
if(tick_timer[i].state == TMR_IDLE)
{
get_current_task_id(&task_id);
if(task_id>=MAX_TASK)
return (HANDLE)-1;
tick_timer[i].task_id = task_id;
tick_timer[i].state = TMR_STOP;
tick_timer[i].msg.type = MSG_TIMER;
tick_timer[i].msg.lPara = (HANDLE)i;
return i;
}
}
return (HANDLE)-1;
}
/*
hdl:
定时器句柄,创建时获取
interval:
定时器间隔,单位tick
type:
TMR_TYPE_ONE 单次定时器
TMR_TYPE_CYCLE 周期性定时器
*/
void start_timer(HANDLE hdl,uint32 interval_ticks,uint32 type)
{
if(tick_timer[hdl].state == TMR_IDLE)
return;
tick_timer[hdl].ticks = interval_ticks;
tick_timer[hdl].count = tick_timer[hdl].ticks;
tick_timer[hdl].state = TMR_RUN;
tick_timer[hdl].type = type;
}
void stop_timer(HANDLE hdl)
{
tick_timer[hdl].state = TMR_STOP;
}
void delete_timer(HANDLE hdl)
{
tick_timer[hdl].state = TMR_IDLE;
}
//由tick中断调用
static void timer_check(void)
{
uint32 i;
TIMER *p = &tick_timer[0];
if(!sys_ready)
return;
for(i=0;i<MAX_TIMER_NUM;i++,p++)
{
if(p->state == TMR_RUN)
{
if(!--p->count)
{
send_msg(p->task_id,&p->msg); //处于暂停状态的是否发送?
if(p->type == TMR_TYPE_CYCLE)
p->count = p->ticks; //周期性定时器,需再次载入周期值
else
p->state = TMR_STOP;
}
}
}
}
//由系统tick中断维护时钟变化,1分钟与RTC同步一次
static void update_sys_time(void)
{
static uint32 sec_tick = 0;
if(!sys_ready)
return;
sec_tick++;
if(sec_tick<OS_TICKS_PER_SEC)
return;
//1秒钟
sec_tick = 0;
portENTER_CRITICAL();
if(date_time.sec+1<60)
{
date_time.sec++;
goto EXIT;
}
date_time.sec = date_time.sec+1-60;
if(date_time.min+1<60)
{
date_time.min++;
goto EXIT;
}
date_time.min = date_time.min+1-60;
inc_hour((GPRMC_T*)&date_time,1);
EXIT:
portEXIT_CRITICAL();
}
extern WWDG_HandleTypeDef hwwdg;
void feed_watchdog(void)
{
#if WATCHDOG_ENABLE
if(sys_ready)
{
static uint32 i = 0;
//第一次进来不喂狗,防止初始化好到喂狗时间小于5ms引起复位,以后10ms喂一次
if(i)
{
#if 1//_USE_RVL_
//WWDG_SetCounter(0x7f);
HAL_WWDG_Refresh(&hwwdg);
#endif
}
else
{
i=1;
}
}
#endif
}
void os_task_suspend_all(void)
{
if(!sys_ready)
return;
vTaskSuspendAll();
}
void os_task_resume_all(void)
{
if(!sys_ready)
return;
if(xTaskResumeAll() == pdFALSE )
{
//portYIELD_WITHIN_API();
}
}
//应用层需要用到的tick级别调用,可写在该函数中
void vApplicationTickHook(void)
{
os_int_enter();
//feed_watchdog(); 放在中断最开始处调用,不经过rtos内核处理
check_sec_tick();
timer_check();
update_sys_time();
os_int_exit();
}
//主要提供特殊函数使用,用来判断当前是否处于中断模式下,在发送发送消息或使用系统API时要用
void os_int_enter(void)
{
os_int_nesting++;
}
void os_int_exit(void)
{
if(os_int_nesting)
{
os_int_nesting--;
}
}
//用户层面任务均调用,由秒消息驱动
void task_is_ok(void)
{
#if TASK_CHK_ENABLE
uint32 task_id;
if(!sys_ready)
return;
get_current_task_id(&task_id);
if(task_id<MAX_TASK)
{
sys_task.status[task_id] = OS_TASK_OK;
}
#endif
}
void os_sys_info_printf(void)
{
printf("%s start..\n",__FUNCTION__);
printf(" sys free mem size:%dKB\n",xPortGetFreeHeapSize()/1024);
printf(" msg alloc isr:%d,task:%d, free total:%d\n",msg_state.isr_alloc_num,msg_state.task_alloc_num,msg_state.free_num);
printf("%s End!\n",__FUNCTION__);
}
//检查是否有异常任务,由main_task调用
uint32 task_chk_status(void)
{
uint32 i;
for(i=0;i<sys_task.num;i++)
{
if(!sys_task.created[i])
{
continue;
}
if(sys_task.ignore_chk[i])
{
continue;
}
if(sys_task.pause[i])
{
sys_task.pause[i]--;
continue;
}
if(++sys_task.status[i]>OS_TASK_MAX_ABNORMAL_TIME)
{
return i;
}
}
return 0; //主任务id为0
}
//检测到异常任务,可写日志信息等.具体待扩展
void os_dead_task_abnormal(uint32 task_id)
{
#if USE_DEBUG_UART
char buf[32];
#endif
printf(buf,"Abnormal task id:%d!",task_id);
}
//WWDG看门狗中断触发,可以保存临终遗言,日志等信息
void os_dead_wwdg(void)
{
#if USE_DEBUG_UART
char buf[32];
#endif
printf(buf,"Abnormal wwdg!");
}
#endif//_USE_RVL_
/**********************************************END***************************************************/