zoukankan      html  css  js  c++  java
  • 用于小型嵌入式的定时控制服务

          在物联网中,定时控制服务可能是非常非常重要的一种服务,而服务器如何将控制信息,发送给设备,让设备在某时某分周几,每周的星期几,每月的几号开关或者进行其他的控制。下面详细的定义了控制命令的格式:

    定时器1;    定时器2;    定时器3;    定时器4;    定时器5;…
    每个定时器的格式如下:
    秒 分 小时 日 月 周 年 执行命令
    序号 说明 范围 允许的通配符 备注
    10-59 , - * / 20-59 , - * / 3 小时 0-23 , - * / 41-31 , - * ? / 51-12 , - * / 60-6 , - * ? / 0表示星期日 72000-2099 , - * / 8 执行命令 SwitchOn SwitchOff LeakTest 通配符说明: *表示所有值。 例如:在分的字段上设置 "*",表示每一分钟都会触发。 ? 表示不指定值。 使用的场景为不需要关心当前设置这个字段的值。例如:要在每月的10号触发一个操作,但不关心是周几,所以需要周位置的那个字段设置为"?" ,后面代码会根据周几和每月几号中的一个去判断是否到达某分时刻 - 表示区间。例如 在小时上设置 "10-12",表示 10,11,12点都会触发。 , 表示指定多个值。 例如在周字段上设置 "1,3,5" 表示周一,周三和周五触发 /用于递增触发。 例如在秒上面设置"5/15" 表示从5秒开始,每增15秒触发(5,20,35,50)。 常用示例: 0 0 8 * * ? * SwitchOn 每天8点开启 0 0 17 * * ? * SwitchOff 每天17点关闭 0 0 8 ? * 1-5 * SwitchOn 周一至周五8点开启 0 0 17 ? * 1-5 * SwitchOff 周一至周五17点关闭 0 0 84-10 1-5 * SwitchOn 4至10月份周一至周五8点开启 0 0 174-10 1-5 * SwitchOff 4至10月份周一至周五17点关闭 0 0 0 1 * ?* LeakTest 每月1号00:00:00进行自测

    我们实现以上方法就根据控制信息解析成时间结构体,然后填充,填充后将本地或者网络时间转换成同样的时间结构体,然后去对每一位进行对比(每一位代表一天或者一分,如60分就用8个字节存储,当月日时分秒都是置1时就认为到达了时间结构体),然后响应动作

    具体查看已下代码:

      注意几点写在前面:

    1.   提供给上层用户的API其实就是几个,具体怎么使用请查看每个函数的作用
    •   TimerTask()                                                                   需在绝对定时器1s调用一次
    •   UpdateTimeConfigIinfo()                                                 需在开机配置信息初始化和服务器下达命令时自主调用

    __weak bool GetRealTime (struct tm *ptOutTime);                    需要自己根据实际情况填充,如RTC或者实时网络获取等等
    __weak bool pTimerOverAction(ETimerActionType eAction);  这两个是虚函数,必须由调用定时模块的用户重新定义,

      2.    可用于一个设备设置多个定时,当多个设备设置索格定时时,需要修改此代码

      3. 全部存储方式位小端方式,大神写的大端的存储,算法由于本人实在太菜看不懂,就自己写的一个非常简单的处理方式,实现方法很简单,已下代码已测试,可直接使用

     1 #ifndef __TIMER_MODULE_H
     2 #define __TIMER_MODULE_H
     3 #include <stdio.h>
     4 #include <stdbool.h>
     5 #include <time.h>
     6 #include "tool.h"
     7 #include "ModuleLibOpt.h"
     8 
     9 
    10 #if   (TIME_MODULE == 1)
    11 #define TIMERS_CONFIG_STR_MAX_LEN     200
    12 #define TIME_STR_FRAME_LEN_MIN         8
    13 #define TIMER_CONTROL_MOUDLE_MAX       4
    14 #define TIMERS_CONIFG_STR_ONCE_LEN     40     /* 逗号字符数量 */
    15 
    16 
    17 
    18 #define TIMER_BITS_NUM_DOW    7
    19 #define TIMER_BITS_NUM_MONS   12
    20 #define TIMER_BITS_NUM_HOURS  24
    21 #define TIMER_BITS_NUM_DAYS   32
    22 #define TIMER_BITS_NUM_MINS   60
    23 #define TIMER_BITS_NUM_SECS   60
    24 #define TIMER_BITS_NUM_YEARS  100
    25 
    26 typedef enum {
    27     TIMER_ACTION_TYPE_UNKNOWN = 0,
    28     TIMER_ACTION_TYPE_SWITCHON = 1,   /* 开启断路器 */
    29     TIMER_ACTION_TYPE_SWITCHOFF = 2,  /* 关闭断路器 */
    30     TIMER_ACTION_TYPE_LEAKTEST = 3,   /* 漏保自检 */
    31     TIMER_ACTION_TYPE_MAX
    32 }ETimerActionType;
    33 
    34 typedef struct TTimerCtl
    35 {
    36     ETimerActionType m_eAction;
    37     
    38     /* orderd by bit */
    39     uint8_t m_byDow;                    /* 0-6 bit, beginning sunday */
    40     uint8_t m_abyMons[2];               /* 0-11 bit */
    41     uint8_t m_abyHrs[3];                /* 0-23 bit */
    42     uint8_t m_abyDays[4];               /* 1-31 bit */
    43     uint8_t m_abyMins[8];               /* 0-59 bit */
    44   uint8_t m_abySecs[8];               /* 0-59 bit */
    45 #if 0 /* Not Support Now */
    46   uint8_t m_abyYears[13];             /* 0-99 bit, beginning 2000, */
    47 #endif
    48 }TTimerCtl;
    49 
    50 
    51 
    52 typedef struct TIMER_Handle_t
    53 {
    54     bool             m_TimeStatsus;
    55     uint8_t   m_byTimersCount;                               /* 定时控制数量 */
    56     uint8_t   m_abyTimerControl[TIMERS_CONFIG_STR_MAX_LEN];  /* 定时控制 */
    57     TTimerCtl m_atTimers[TIMER_CONTROL_MOUDLE_MAX];        /* 定时控制,TimerControl配置解析得到 */
    58 }TIMER_Handle;
    59 
    60 
    61 TIMER_Handle *TimerRegister(void);
    62 bool PerseTimers(char * pbyTimerCtrl,TTimerCtl *ptTimers,uint8_t *pbycnt);
    63 bool PerseField(char *arry,int dwlen,uint8_t bybitCnt,char *pbyBuff);
    64 bool UpdateTimeConfigIinfo(const char *pbydata);
    65 void TimerTask(void);
    66  
    67 __weak bool GetRealTime (struct tm *ptOutTime);
    68 __weak bool pTimerOverAction(ETimerActionType eAction);
    69 
    70 
    71 #endif
    72 
    73 #endif
      1 TIMER_Handle g_tTimer = { 
      2         false,
      3         TIMER_CONTROL_MOUDLE_MAX,
      4         {0},
      5         {0}
      6 };
      7 /*====================================================================
      8   函数名:TimerRegister
      9   功  能:获取定时模块操作句柄
     10   输入参数说明:
     11   输出参数说明:
     12   返回值说明 :当前任务操作句柄
     13   ====================================================================*/
     14 
     15 TIMER_Handle *TimerRegister(void)
     16 {
     17         return &g_tTimer;
     18 }
     19 /*====================================================================
     20   函数名:GetRealTime
     21   功  能:获取当前真实时间 
     22   输入参数说明:
     23     pbydata     :控制命令 
     24   输出参数说明:
     25   返回值说明 :
     26     备        注:需要用户在初始化的时候自己注册
     27   ====================================================================*/
     28 __weak bool GetRealTime (struct tm *ptOutTime)    
     29 {    
     30         return true;
     31 }
     32 /*====================================================================
     33   函数名:UpdateTimeConfigIinfo
     34   功  能:更新一下定时的命令,服务器下载的时候和从flash读取配置用  
     35   输入参数说明:
     36     pbydata     :控制命令 
     37   输出参数说明:
     38   返回值说明 :
     39   ====================================================================*/
     40 bool UpdateTimeConfigIinfo(const char *pbydata)
     41 {    
     42         u16 wRecvLen = 0;
     43         u8 byTimerCnt = 0;
     44         bool bRet = false;
     45         wRecvLen  = strlen((pbydata));
     46         if( wRecvLen >= TIME_STR_FRAME_LEN_MIN && wRecvLen <= TIMERS_CONFIG_STR_MAX_LEN)
     47         {    
     48                 memset(g_tTimer.m_abyTimerControl,0,sizeof(g_tTimer.m_abyTimerControl));
     49                 memset(g_tTimer.m_atTimers,0,sizeof(g_tTimer.m_atTimers));
     50                 memcpy(g_tTimer.m_abyTimerControl,pbydata,wRecvLen);
     51                 byTimerCnt = TIMER_CONTROL_MOUDLE_MAX;
     52                 bRet = PerseTimers((char *)(g_tTimer.m_abyTimerControl),g_tTimer.m_atTimers, &byTimerCnt);
     53                 if(bRet)
     54                 {
     55                             g_tTimer.m_TimeStatsus = true;
     56                             g_tTimer.m_byTimersCount = byTimerCnt;
     57                 }
     58         }    
     59         else
     60         {
     61                 g_tTimer.m_TimeStatsus = false;
     62                 memset(g_tTimer.m_abyTimerControl,0,sizeof(g_tTimer.m_abyTimerControl));
     63                 memset(g_tTimer.m_atTimers,0,sizeof(g_tTimer.m_atTimers));
     64         }
     65 }
     66 
     67 /*====================================================================
     68   函数名:pTimerOverAction
     69   功能:  到达延时,操作响应函数
     70   输入参数说明:
     71     ETimerActionType: 操作类型 开/关/自检
     72   输出参数说明:
     73   返回值说明 :
     74     备        注:需要用户在初始化的时候自己注册
     75   ====================================================================*/
     76 __weak  bool pTimerOverAction(ETimerActionType eAction)
     77 {
     78         return true;
     79 }
     80 
     81 /*====================================================================
     82   函数名:TimerTask
     83   功能:  定时调用函数,绝对定时器中1s调用一次
     84   输入参数说明:
     85   输出参数说明:
     86   返回值说明:
     87   ====================================================================*/
     88 void TimerTask(void)
     89 {
     90     u8 byAddr = 0,  byTimerIndex = 0;
     91     TTimerCtl *ptTimer = NULL;
     92     struct tm ptm = {0};
     93     if(false == g_tTimer.m_TimeStatsus)
     94         return ;
     95     
     96     GetRealTime(&ptm);
     97 
     98     if(g_tTimer.m_TimeStatsus)
     99     {
    100             for(byTimerIndex = 0; byTimerIndex < g_tTimer.m_byTimersCount; byTimerIndex++)
    101             {
    102                 ptTimer = &(g_tTimer.m_atTimers[byTimerIndex]);
    103                 if(TestBit(ptTimer->m_abyMins, sizeof(ptTimer->m_abyMins), ptm.tm_min) == true &&
    104                  TestBit(ptTimer->m_abyHrs, sizeof(ptTimer->m_abyHrs), ptm.tm_hour) == true &&
    105                  (TestBit(ptTimer->m_abyDays, sizeof(ptTimer->m_abyDays), ptm.tm_mday) == true || TestBit(&(ptTimer->m_byDow), sizeof(ptTimer->m_byDow), ptm.tm_wday) == true) &&
    106                  TestBit(ptTimer->m_abyMons, sizeof(ptTimer->m_abyMons), ptm.tm_mon) == true)
    107                 {
    108                         pTimerOverAction(ptTimer->m_eAction);
    109                 }
    110             }
    111         }
    112 }
    113 
    114 /*====================================================================
    115   函数名:FixDayDow
    116   功  能:根据周/日调整,判断使用的是什么定时
    117   输入参数说明:
    118     ptTimer     :时间控制结构体
    119   输出参数说明:
    120 
    121   返回值说明: 
    122   ====================================================================*/
    123 static void FixDayDow(TTimerCtl *ptTimer)
    124 {
    125     unsigned i;
    126     int weekUsed = 0;
    127     int daysUsed = 0;
    128 
    129     for (i = 0; i < TIMER_BITS_NUM_DOW; ++i) 
    130     {
    131         if (TestBit(&(ptTimer->m_byDow), sizeof(ptTimer->m_byDow), i) == false) 
    132         {
    133             weekUsed = 1;
    134             break;
    135         }
    136     }
    137     for (i = 0; i < TIMER_BITS_NUM_DAYS; ++i)
    138     {
    139         if (TestBit(ptTimer->m_abyDays, sizeof(ptTimer->m_abyDays), i) == false) 
    140         {
    141             daysUsed = 1;
    142             break;
    143         }
    144     }
    145     if (weekUsed != daysUsed) 
    146     {
    147         if (weekUsed)
    148             memset(ptTimer->m_abyDays, 0, sizeof(ptTimer->m_abyDays));
    149         else /* daysUsed */
    150             memset(&(ptTimer->m_byDow), 0, sizeof(ptTimer->m_byDow));
    151     }
    152 }
    153 
    154 /*====================================================================
    155   函数名:PerseField
    156   功  能:解析字段
    157   输入参数说明:
    158     dwlen   :需要保存的数组的长度
    159     bybitCnt:一共有多少位
    160     pbyBuff :待解析字段
    161   输出参数说明:
    162         arry :需要保存的数组
    163   返回值说明:     解析成功/失败
    164   ====================================================================*/
    165 bool PerseField(char *arry,int dwlen,uint8_t bybitCnt,char *pbyBuff)
    166 {
    167         if(NULL == arry || NULL == pbyBuff || dwlen == 0 || bybitCnt == 0 || (bybitCnt / 8 > dwlen))
    168                 return false;
    169         
    170         uint8_t i;
    171         int sta,end;
    172         char *pBase = pbyBuff;
    173         const char *delim_t = ",";
    174         char *token_t = NULL,*saveptr_t = NULL;
    175         char  byTemp[TIMERS_CONIFG_STR_ONCE_LEN] = {0};
    176         uint8_t bydiv = bybitCnt / 8; 
    177         uint8_t byred = bybitCnt % 8 - 1;
    178         
    179         if(*pBase == '*' || *pBase == '?')
    180         {
    181                 for(i =0; i < bybitCnt; i ++ )
    182                         SetBit(arry,dwlen,i);
    183         }
    184         else if(isdigit(*pBase))
    185         {
    186                 if(NULL != strstr(pBase,"-"))
    187                 {
    188                     sscanf(pBase,"%d-%d",&sta,&end);
    189                     for(i =sta; i <= end; i ++ )
    190                         SetBit(arry,dwlen,i);    
    191                 }
    192                 else if(NULL != strstr(pBase,","))
    193                 {
    194                      i = 0;
    195                      memcpy(byTemp,pBase,strlen(pBase));
    196                       pBase = byTemp;
    197                      while(NULL != (token_t = strtok_r(pBase,delim_t,&saveptr_t)))
    198                      {
    199                             SetBit(arry,dwlen,atoi(token_t));
    200                           pBase = NULL;
    201                      }
    202                 }
    203                 else if(NULL != strstr(pBase,"/"))
    204                 {
    205                     sscanf(pBase,"%d/%d",&sta,&end);
    206                     for(i =sta; i <= bybitCnt; i += (end - 1))
    207                         SetBit(arry,dwlen,i);    
    208                 }
    209                 else
    210                 {
    211                         sscanf(pBase,"%d",&sta);
    212                         SetBit(arry,dwlen,sta);
    213                 }
    214 
    215         }
    216         else 
    217                 return false;
    218     
    219         return  true;
    220         
    221 }
    222 
    223 /*====================================================================
    224   函数名:PerseTimers
    225   功  能:将服务器控制命令解析
    226   输入参数说明:
    227         pbyTimerCtrl :服务下达的控制命令
    228   输出参数说明:
    229         TTimerCtl    :解析成控制命令结构体
    230         pbycnt       :解析成的第几个定时器
    231   返回值说明:     解析成功/失败
    232   ====================================================================*/
    233 bool PerseTimers(char * pbyTimerCtrl,TTimerCtl *ptTimers,uint8_t *pbycnt)
    234 {
    235             char  strbuf[TIMERS_CONFIG_STR_MAX_LEN];
    236             char *pbyPos = strbuf;
    237             char *token_t = NULL, *saveptr_t =NULL;
    238             char *token_f = NULL, *saveptr_f =NULL;
    239             char *delim_t = ";" , *delim_f = " ";
    240             char *savefield[8];
    241             uint8_t  byFieldCnt = 0;
    242             uint8_t  byTimeCnt  = 0;
    243             uint16_t dwLen = strlen(pbyTimerCtrl);
    244             TTimerCtl *timer = NULL;
    245     
    246             if(NULL == pbyTimerCtrl || NULL == ptTimers || NULL == pbycnt || dwLen > TIMERS_CONFIG_STR_MAX_LEN)
    247                     return false;
    248             
    249             memset(ptTimers,0,sizeof(TTimerCtl));
    250             memcpy(strbuf,pbyTimerCtrl,strlen(pbyTimerCtrl));
    251             printf("strbuf:%s
    ",strbuf);
    252             while(NULL != (token_t = strtok_r(pbyPos,delim_t,&saveptr_t)))
    253             {
    254                 while(*token_t == ' ')
    255                 {
    256                     token_t++;
    257                 }
    258                 printf("token_t:%s
    ",token_t);
    259                 memset(savefield,0,sizeof(savefield));
    260                 
    261                 while(NULL != (token_f = strtok_r(token_t,delim_f,&saveptr_f)))
    262                 {
    263                         while(*token_f == ' ')
    264                         {
    265                             token_t++;
    266                         }
    267                         savefield[byFieldCnt] = token_f;
    268                         printf("field[%d]:%s
    ",byFieldCnt,savefield[byFieldCnt]);
    269                         
    270                         byFieldCnt++;
    271                         token_t = NULL;
    272                 }
    273                 
    274                 if(byFieldCnt >= 8)
    275                 {
    276                         timer = &ptTimers[byTimeCnt];
    277                         
    278                         PerseField((char *)timer->m_abySecs,sizeof(timer->m_abySecs),TIMER_BITS_NUM_SECS,savefield[0]);
    279                         PerseField((char *)timer->m_abyMins,sizeof(timer->m_abyMins),TIMER_BITS_NUM_MINS,savefield[1]);
    280                         PerseField((char *)timer->m_abyHrs, sizeof(timer->m_abyHrs),TIMER_BITS_NUM_HOURS,savefield[2]);
    281                         PerseField((char *)timer->m_abyDays,sizeof(timer->m_abyDays),TIMER_BITS_NUM_DAYS,savefield[3]);
    282                         PerseField((char *)timer->m_abyMons,sizeof(timer->m_abyMons),TIMER_BITS_NUM_MONS,savefield[4]);
    283                         PerseField((char *)&(timer->m_byDow),sizeof(timer->m_byDow),  TIMER_BITS_NUM_DOW,savefield[5]);
    284                         /* year not surport now */
    285                 }
    286                 
    287                 FixDayDow(timer);
    288                 
    289                 if(strcmp(savefield[7], "SwitchOn") == 0)
    290                 {
    291                     timer->m_eAction = TIMER_ACTION_TYPE_SWITCHON;
    292                 }
    293                 else if(strcmp(savefield[7], "SwitchOff") == 0)
    294                 {
    295                     timer->m_eAction = TIMER_ACTION_TYPE_SWITCHOFF;
    296                 }
    297                 else if(strcmp(savefield[7], "LeakTest") == 0)
    298                 {
    299                     timer->m_eAction = TIMER_ACTION_TYPE_LEAKTEST;
    300                 }
    301                 else
    302                 {
    303                     continue;
    304                 }
    305                 
    306                 byTimeCnt++;
    307                 byFieldCnt = 0;
    308                 pbyPos = NULL;
    309             }
    310             *pbycnt = byTimeCnt;
    311             return true;
    312     
    313 }
     1 /*====================================================================
     2   函数名:SetBit
     3   功  能:将字符串的某一位置1
     4   输入参数说明:
     5              date :传入的字符串
     6                 byCnt:传入字节数
     7                 byBit:第几位
     8   输出参数说明:
     9     
    10   返回值说明:   
    11   ====================================================================*/
    12 void SetBit(char *date,uint8_t byCnt,uint8_t byBit)
    13 {    
    14             if(byBit / 8 >= byCnt) return ;
    15             uint8_t bydiv = byBit / 8; 
    16             uint8_t byred = byBit % 8;
    17             
    18             *(date + bydiv) |= 1 << byred;
    19              printf("byBit:%d date:%02x
    ",byBit,*(date + bydiv));
    20 }
    21 
    22 
    23 
    24 /*====================================================================
    25   函数名:TestBit
    26   功  能:判断某位是否置1
    27   输入参数说明:
    28     pbydata   :传入数组
    29     byCnt     :传入数组长度
    30     byBit     :待判断的位
    31   输出参数说明:
    32 
    33   返回值说明: 置1/置0
    34   ====================================================================*/
    35 bool TestBit(uint8_t *pbydata,uint8_t byCnt,uint8_t byBit)
    36 {
    37         if(byBit / 8 >= byCnt) return false;
    38     
    39         uint8_t *pBytePos  = NULL;
    40         uint8_t  pBitPos  =  byBit % 8;
    41     
    42         pBytePos  = pbydata + byBit / 8;
    43     
    44         if(*pBytePos & (1 << pBitPos))
    45         {
    46                 return true;
    47         }
    48         else
    49         {
    50                 return false;
    51         }
    52 }
     1 /*====================================================================
     2   函数名:SetBit
     3   功  能:将字符串的某一位置1
     4   输入参数说明:
     5              date :传入的字符串
     6                 byCnt:传入字节数
     7                 byBit:第几位
     8   输出参数说明:
     9     
    10   返回值说明:   
    11   ====================================================================*/
    12 void SetBit(char *date,uint8_t byCnt,uint8_t byBit)
    13 {    
    14             if(byBit / 8 >= byCnt) return ;
    15             uint8_t bydiv = byBit / 8; 
    16             uint8_t byred = byBit % 8;
    17             
    18             *(date + bydiv) |= 1 << byred;
    19              printf("byBit:%d date:%02x
    ",byBit,*(date + bydiv));
    20 }
    21 
    22 
    23 
    24 /*====================================================================
    25   函数名:TestBit
    26   功  能:判断某位是否置1
    27   输入参数说明:
    28     pbydata   :传入数组
    29     byCnt     :传入数组长度
    30     byBit     :待判断的位
    31   输出参数说明:
    32 
    33   返回值说明: 置1/置0
    34   ====================================================================*/
    35 bool TestBit(uint8_t *pbydata,uint8_t byCnt,uint8_t byBit)
    36 {
    37         if(byBit / 8 >= byCnt) return false;
    38     
    39         uint8_t *pBytePos  = NULL;
    40         uint8_t  pBitPos  =  byBit % 8;
    41     
    42         pBytePos  = pbydata + byBit / 8;
    43     
    44         if(*pBytePos & (1 << pBitPos))
    45         {
    46                 return true;
    47         }
    48         else
    49         {
    50                 return false;
    51         }
    52 }
  • 相关阅读:
    python3 pyinstaller
    python3 random
    python3 turtle
    产生一个序列的所有排列组合
    蒙特卡洛算法
    lightoj 1014
    UVA11426
    nginx 配置本地https(免费证书)
    ElementUI
    Airbnb 代码规范
  • 原文地址:https://www.cnblogs.com/st-home/p/12527269.html
Copyright © 2011-2022 走看看