1094 lines
28 KiB
C
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***************************************************/
|
|
|