軟件定時器(一)

之前偶爾瞭解到軟件定時器,也在網上找了許多網友寫的各種版本,知道讀到嵌入式TCP/IP協議棧中的軟件定時器的寫法時,歎爲觀止,故將其修改移植到裸機stm32上使用,並向大家做一分享。

首先得感謝那些兢兢業業從事着自己的工作,並毫不吝嗇的向別人公佈自己源代碼的前輩們,正因爲他們慷慨無私,我們才能閱讀到各種精巧的代碼,並從中汲取養分,從而培養了許多熱愛技術,真誠無私的人。

/**@brief:1、該文件參考LWIP協議中的times.c編寫
  *       2、該超時定時器按鏈表的形式進行組織,按時間長短進行排序,時間最短的永遠排在最前面
  *       3、移植時應該注意的幾點:
  *              a.週期性的調用函數。b.需要外部定時器實現時基。c.注意動態內存分配mallco的使用。
  *@author: LT
  *@date: 2016/12/3
  */
#ifndef __SOFT_TIME_H
#define __SOFT_TIME_H

#include "typedef.h"
#include <string.h>
#include <stdlib.h>

/* 定時器超時處理函數指針 */
typedef void (* soft_timeout_handler)(void *arg);

/* 超時定時器 */
struct soft_timeo {
  struct soft_timeo *next;
  u32 time;
  soft_timeout_handler h;
  void *arg;
};

#define MEMP_soft_TIMEOUT (sizeof(struct soft_timeo))

void soft_timeouts_init(u32 msecs, soft_timeout_handler handler, void *arg);
void soft_timeout(u32 msecs, soft_timeout_handler handler, void *arg);
void soft_untimeout(soft_timeout_handler handler, void *arg);
void soft_check_timeouts(void);
void soft_restart_timeouts(void);
void soft_run_timeout(soft_timeout_handler handler, void *arg);
u32 time_to_sec(char *RTC_set);
u32 RTC_set(char* RTC_set);

#endif
#include "soft_time.h"
#include "bsp.h"
#include "malloc.h"

extern volatile u32 g_soft_timer_count;

static u32 timeouts_last_time; 
static struct soft_timeo *next_timeout;


/*從字符串的左邊截取n個字符*/
char * str_left(char *dst,const char *src, int n)
{
    const char *p = src;
    char *q = dst;
    int len = strlen(src);
    if(n>len) n = len;
    while(n--) *(q++) = *(p++);
    *(q++)='\0'; /*有必要嗎?很有必要*/
    return dst;
}

u32 soft_time_now(void)
{
    return RTC_GetCounter();
}

/** @brief  計算預定時間距現在的時間(單位:s)
  * @param  預定時間轉成的字符串(例如:2016 12 03 18 30 00 錯誤)
  *                              (      2016 12 3 18 30 0   正確)
  * @retval 
  * @tips   注意strtol函數的使用
  */
u32 time_to_sec(char *RTC_set)
{
    u32 set_sec;
//  u32 now_sec;
    u8 n;
    char *pEnd;

    n = accumulationdayfrom1970((int*)&set_sec, RTC_set);
    set_sec = set_sec * 3600 * 24 + (int)strtol(RTC_set + n,&pEnd,0) * 3600 ;
    set_sec = set_sec + (int)strtol(pEnd, &pEnd, 0) * 60;
    set_sec = set_sec + (int)strtol(pEnd, NULL, 0);
/*  
    RTC_Get_str(RTC_now);
    n = accumulationdayfrom1970((int*)&now_sec, RTC_now);
    now_sec = now_sec * 3600 * 24 + (int)strtol(RTC_now + n,&pEnd_,0) * 3600 ;
    now_sec = now_sec + (int)strtol(pEnd_, &pEnd_, 0) * 60;
    now_sec = now_sec + (int)strtol(pEnd_, NULL, 0);
    printf("%d   \n",set_sec - now_sec);
*/
    return (set_sec - RTC_GetCounter());

}

/** @brief  計算預定時間距1970\1\1的時間(單位:s)
  * @param  預定時間轉成的字符串(例如:2016 12 03 18 30 00 錯誤)
  *                              (      2016 12 3 18 30 0   正確)
  * @retval 時間 單位 S
  * @tips   注意strtol函數的使用
  */
u32 RTC_set(char* RTC_set)
{
    u32 set_sec;
    char* pEnd;
    u8 n;
    n = accumulationdayfrom1970((int*)&set_sec, RTC_set);
    set_sec = set_sec * 3600 * 24 + (int)strtol(RTC_set + n,&pEnd,0) * 3600 ;
    set_sec = set_sec + (int)strtol(pEnd, &pEnd, 0) * 60;
    set_sec = set_sec + (int)strtol(pEnd, NULL, 0);
    return set_sec;
}


/** Initialize this module */
void soft_timeouts_init(u32 msecs, soft_timeout_handler handler, void *arg)
{
  soft_timeout(msecs, handler, arg);
  timeouts_last_time = soft_time_now();
}

/*
 * Must be called periodically from your main loop.
 * 檢查是否有某個定時器的時間到了,以作出進一步的處理
 */
void
soft_check_timeouts(void)
{
    if (next_timeout) {
        struct soft_timeo *tmptimeout;
        u32 diff;
        soft_timeout_handler handler;
        void *arg;
        u8 had_one;
        u32 now;

        now = soft_time_now();
        /* this cares for wraparounds */
        diff = now - timeouts_last_time;
        do
        {
            had_one = 0;
            tmptimeout = next_timeout;
            if (tmptimeout && (tmptimeout->time <= diff)) {
                /* timeout has expired */
                had_one = 1;
                timeouts_last_time = now;
                diff -= tmptimeout->time;
                next_timeout = tmptimeout->next;
                handler = tmptimeout->h;
                arg = tmptimeout->arg;
                myfree(SRAMIN, tmptimeout);
                if (handler != NULL) {
                    handler(arg);
                }
            }
            /* repeat until all expired timers have been called */
        }while(had_one);
    }
} 

/*
 *      功能:添加超時定時器
 *      
 */
void
soft_timeout(u32 msecs, soft_timeout_handler handler, void *arg)
{
    struct soft_timeo *timeout, *t;

    timeout = (struct soft_timeo *)mymalloc(SRAMIN, MEMP_soft_TIMEOUT);
    if (timeout == NULL) {
        printf("soft_timeout: timeout != NULL, pool MEMP_soft_TIMEOUT is empty");
        return;
    }

    timeout->next = NULL;
    timeout->h = handler;
    timeout->arg = arg;
    timeout->time = msecs;
    if (next_timeout == NULL) {
        next_timeout = timeout;
        return;
    }
/* 實現對定時器鏈表的插入,排列順序按照定時時間的長短確定 */
    if (next_timeout->time > msecs) {
        next_timeout->time -= msecs;
        timeout->next = next_timeout;
        next_timeout = timeout;
    } else {
        for(t = next_timeout; t != NULL; t = t->next) {
            timeout->time -= t->time;
            if (t->next == NULL || t->next->time > timeout->time) {
                if (t->next != NULL) {
                    t->next->time -= timeout->time;
                }
                timeout->next = t->next;
                t->next = timeout;
                break;
            }
        }
    }
}
/* 
 *      功能:刪除與所指定的回調函數及參數相同的第一個定時器
 */
void
soft_untimeout(soft_timeout_handler handler, void *arg)
{
  struct soft_timeo *prev_t, *t;

  if (next_timeout == NULL) {
    return;
  }

  for (t = next_timeout, prev_t = NULL; t != NULL; prev_t = t, t = t->next) {
    if ((t->h == handler) && (t->arg == arg)) {
      /* We have a match */
      /* Unlink from previous in list */
      if (prev_t == NULL) {
        next_timeout = t->next;
      } else {
        prev_t->next = t->next;
      }
      /* If not the last one, add time of this one back to next */
      if (t->next != NULL) {
        t->next->time += t->time;
      }
      myfree(MEMP_soft_TIMEOUT, t);
      return;
    }
  }
  return;
}

/*
 *      功能:如果定時器回調函數在很久沒有被調用,可以使用該函數更新
 *               計數值,使之前的函數被調用。
 */
void
soft_restart_timeouts(void)
{
  timeouts_last_time = soft_time_now();
}

/*
 *      功能:直接指定相應的定時器執行
 */

void
soft_run_timeout(soft_timeout_handler handler, void *arg)
{
        soft_untimeout(handler,arg);
        soft_timeout(0, handler, arg);
}


















發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章