状态机——protothreads

状态机——Protothreads

一、prothreads的优缺点

优点:

    1. 以纯C语言实现,无硬件依靠性;因此不存在移植的困难。

    2. 极少的资源需求,每个Protothread仅需要2个额外的字节;

3. 支持阻塞操纵且没有栈的切换。

缺点:

    1. 函数中不具备可重入型,不能使用局部变量;

    2. 按顺序判断各任务条件是否满足,因此无优先级抢占;

3. 任务中的各条件也是按顺序判断的,因此要求任务中的条件必须是依次出现的 protothread的阻塞机制:在每个条件判断前,先将当前地址保存到某个变量中,再判断条件是否成立,若条件成立,则往下运行;若条件不成立,则返回。

 

二、注意事项

注意:
(1)任务中使用的变量应为静态变量
(2)线程内不能使用纯 while(1)--即含 PT_WAIT_UNTIL()等宏的 while(1)是可以的。
不能在 switch(){case…}中调用任务 Protothreads API 带有 case 的语句(即只能单向嵌套)。
(3)线程内可以使用:
for(){…}
switch(){case…}-- case 与 case 之间必须是一个完整的语句或者语句段
if(){…}else{…}
含宏的 while(1){…}
(4)ProtothreadS 系统可以仍然还是个大 while(1)循环。但也可设计为根据定时器产生的恒定间隔的中断来触发和管理任务
--时间触发方式的嵌入式系统,此时可更改 pt 结构体为(见《时间触发模式下的 ProtothreadS 设计应用》):
struct pt

{

lc_t lc;

unsigned short count; // 每次中断都减 1

unsigned short load; // 初始计数值

char ready; // 任务就绪标志

}
(5)在 ProtothreadS 系统中延时:
1)如果 ProtothreadS 系统是基于时间触发,则延时可基于该触发--即基于系统时钟。
2)如果 ProtothreadS 系统中无系统时钟,
(6)Protothreads 虽然提供了在各自线程内的条件阻塞机制,但对于在该线程内调用的其它函数,则无法阻塞其运行。所以,
如果要在线程内调用占用时间较多的函数,为保证各个线程的实时性要求,需要将这类函数进一步划分为更小的函数,分步执
行。
(7) Protothread 的精华:当 Protothread 程序运行到 PT_WAIT_UNTIL 时,判断其运行条件是否满足,若不满足,则阻塞。
Protothread 的阻塞其实质就是函数返回。
Protothread 仅能在程序员指定位置阻塞。

 

三、protothreads各函数简要介绍

函数

说明

PT_INIT(pt)

初始化任务变量,只在初始化函数中执行一次

PT_BEGIN(pt)

启动任务处理,放在函数开始处

PT_END(pt)

结束任务,放在函数的最后

PT_WAIT_UNTIL(pt,condition)

条件成立,执行下面的;否则退出,下次直接跳到此处执行

PT_WAIT_WHILE(pt, condition)

类似PT_WAIT_UNTIL,只是条件取反了

PT_WAIT_THREAD(pt, thread)

等待一个子任务执行完成

PT_SPAWN(pt, child, thread)

新建一个子任务,并等待其执行完退出

PT_RESTART(pt)

重新启动某个任务执行

PT_EXIT(pt)

任务后面的部分不执行,直接退出重新执行

PT_YIELD(pt)

锁死任务

PT_YIELD_UNTIL(pt, condition)

锁死任务等待条件成立重新执行

 

四、protothreads代码

struct pt {
  lc_t lc;
};

#define PT_WAITING 0
#define PT_YIELDED 1
#define PT_EXITED 2
#define PT_ENDED  3

#define PT_INIT(pt)  LC_INIT((pt)->lc)

#define PT_THREAD(name_args) char name_args

#define PT_BEGIN(pt) { char PT_YIELD_FLAG = 1;LC_RESUME((pt)->lc)

#define PT_END(pt) LC_END((pt)->lc);PT_YIELD_FLAG = 0; \
                  PT_INIT(pt); return PT_ENDED; }

#define PT_WAIT_UNTIL(pt, condition)            \
  do {                                       \
   LC_SET((pt)->lc);                      \
   if(!(condition)) {                         \
      returnPT_WAITING;               \
    }                                        \
  } while(0)

#define PT_WAIT_WHILE(pt, cond)  PT_WAIT_UNTIL((pt), !(cond))

#define PT_WAIT_THREAD(pt, thread)PT_WAIT_WHILE((pt), PT_SCHEDULE(thread))

#define PT_SPAWN(pt, child, thread)   \
  do {            \
   PT_INIT((child));       \
   PT_WAIT_THREAD((pt), (thread));  \
  } while(0)

#define PT_RESTART(pt)        \
  do {            \
   PT_INIT(pt);        \
    returnPT_WAITING;      \
  } while(0)

#define PT_EXIT(pt)       \
  do {            \
   PT_INIT(pt);        \
    returnPT_EXITED;     \
  } while(0)

#define PT_SCHEDULE(f) ((f) < PT_EXITED)

#define PT_YIELD(pt)        \
  do {            \
   PT_YIELD_FLAG = 0;        \
    LC_SET((pt)->lc);       \
   if(PT_YIELD_FLAG == 0) {      \
      returnPT_YIELDED;      \
    }           \
  } while(0)

#define PT_YIELD_UNTIL(pt, cond)    \
  do {            \
   PT_YIELD_FLAG = 0;        \
   LC_SET((pt)->lc);       \
   if((PT_YIELD_FLAG == 0) || !(cond)) { \
      returnPT_YIELDED;      \
    }           \
  } while(0)

五、举例

//解码

static char
camera_rs485_rx_decode(struct pt *pt, uint8_t c)
{
 PT_BEGIN(pt);

 PT_WAIT_UNTIL(pt, 0x7E == c);

 camera_rs485.rx_count = 0;

  while(1)
  {
   PT_YIELD(pt);

    if (0x7E== c)
    {
     if(camera_rs485.rx_count)
      {
        camera_rs485_dispatch(camera_rs485.rx_buf,camera_rs485.rx_count);
       PT_EXIT(pt);
      }
      else
      {
       continue;
      }
    }

    if(0x1B ==c)
    {
     PT_YIELD(pt);

      if (0x00== c)
      {
        c =0x1B;
      }
      else if (0x65 == c)
      {
        c =0x7E;
      }
      else
      {
        //c ^=0x20;
      }
    }
    if(camera_rs485.rx_count < CAMERA_RS485_RX_BUF_SIZE)
    {
     camera_rs485.rx_buf[camera_rs485.rx_count++] = c;
    }
    else
    {
      PT_EXIT(pt);
    }
  }
  PT_END(pt);
}

// 模块类型识别——定时器
static char
gps_probe(struct pt *pt, uint32_t ms)
{
  staticuint32_t tmo = 0;
  static inti;
 
  const char*cmd;
 
  if (tmo >ms)
  {
    tmo -= ms;
  }
  else
  {
    tmo = 0;
  }
 
  PT_BEGIN(pt);
 
  tmo = 3000;
 PT_WAIT_UNTIL(pt, (0 == tmo));
 
  if(GPS_MODULE_TYPE_UNKNOWN == gps.module_type)
  {
    for(i =GPS_MODULE_TYPE_UNKNOWN + 1; i < GPS_MODULE_TYPE_COUNT; ++i)
    {
      if(gps_cmds[i].query_version)
      {
       debug("gps_probe type: %d cmd: %s", i,gps_cmds[i].query_version);
        // 发送两次,确保模块接收到正确的命令
        cmd =gps_cmds[i].query_version;
       UartSend(gps_uart, cmd, strlen(cmd));
       PT_YIELD(pt);
        cmd =gps_cmds[i].query_version;
       UartSend(gps_uart, cmd, strlen(cmd));
        // 等待模块输出版本信息
        tmo =3000;
       PT_WAIT_UNTIL(pt, (0 == tmo));
      }
      if(GPS_MODULE_TYPE_UNKNOWN != gps.module_type)
      {
        break;
      }
    }
  }
  // stop
 PT_WAIT_UNTIL(pt, FALSE);
 
  PT_END(pt);
}



你可能感兴趣的:(状态机,protothreads)