在CAPL中重新使用状态机

时间:2015-07-13 23:53:05

标签: state-machine capl

我在CAPL中创建了一个非常简单的状态机,告诉我信号何时变高以及在关闭之前它保持打开的时间。 现在我有大约70个信号,我需要知道信号何时开始以及在进入OFF之前它保持多长时间。 我已经实现的代码在这里。

我的问题:有没有办法模板化这个状态机的功能,所以我不必在代码中的任何地方实现它。

on message x639
{
   message x639 mil_obj;
   mil_obj = this;

   switch(mil_state)
    {
      case MIL_OFF:
        {
          if(mil_obj.iHwEcm_MILInput_flg == 1)
            {
            mil_start_time = (timeNow()/100000);
            mil_state = MIL_ON;
            }
            else
            {
            mil_state = MIL_OFF;
            }

          break;
        }
      case MIL_ON:
        {
          if(mil_obj.iHwEcm_MILInput_flg == 0)
          {
            mil_stop_time = (timeNow()/100000);
            mil_retval = writeCreate("MIL_STATUS");
            writeLineEx(mil_retval,1," MIL turned ON at %ld  seconds for a duration of %ld seconds ", mil_start_time, mil_stop_time - mil_start_time);
            mil_stop_time =0;
            mil_start_time =0;
            mil_state = MIL_OFF;

          }
          else
          {
          mil_state = MIL_ON;

          }

          break;
        }
      default:

          break;     
    }

output(mil_obj);

}

1 个答案:

答案 0 :(得分:1)

有可能避免为每个信号复制粘贴代码。

您可以使用数组为您感兴趣的每个信号存储状态和start_time。访问这些数组有点棘手,因为您没有像std :: map中那样的构造

state["Signal1"] = STATE_ON;

因此,创建一个存储信号名称,状态和start_time的结构(在您的示例中不需要保存stop_time,因为在计算并输出它之后它不会被使用)。像:

  struct signal_state {
    char sig_name[100];
    int last_value;
    int start_time;
  };

然后制作大量这些状态(因此每个信号都适合)

每当您想要访问信号状态时,您必须遍历数组并strcmp()所有带有您要访问的信号的值都能获得正确的数组索引。对于非常大的阵列来说,这可能需要花费很多时间,但是对于你的70个信号,它几乎可以立即计算出来。

以下代码应该非常接近您的实际需求:

/*@!Encoding:1252*/
includes
{

}

variables
{
  const max_sig_name_len = 100;
  const max_num_states = 100;

  struct signal_state {
    char sig_name[max_sig_name_len];
    int last_value;
    int start_time;
  };

  int num_states = 0;
  struct signal_state states[max_num_states];

}

on start {
  register_signal("CAN1::net1::Message1::Signal1");
  register_signal("CAN1::net1::Message2::Signal2");
}

on signal Signal1 {
  handle_signal(this.name, this.raw);
  output(this);
}

on signal Signal2 {
  handle_signal(this.name, this.raw);
  output(this);
}

void register_signal(char foo[]) {
  strncpy(states[num_states].sig_name, foo, max_sig_name_len);
  num_states++;
}

void handle_signal(char sig_name[], int sig_value) {
  int i;
  for (i = 0; i < num_states; i++) {
    if (strncmp(sig_name, states[i].sig_name, max_sig_name_len) == 0) 
      break;
    //writeLineEx(0,1, "%s != %s", this.name, states[i].sig_name);
  }
  // i now contains the index of the state that represents the current signal
  if (i < num_states) {
    if ( sig_value == 0 && states[i].last_value > 0) {
      int stop_time;
      stop_time = timeNow()/100000;
      writeLineEx(0,1, "signal %s turned ON at %ld seconds for a duration of %ld seconds.", states[i].sig_name, states[i].start_time, stop_time - states[i].start_time );
    } else if (sig_value > 0 && states[i].last_value == 0) {
      states[i].start_time = timeNow()/100000;
    }
    states[i].last_value = sig_value;
  }
}

register_signal()只是填充数组的便捷方式。 必须在您感兴趣的信号的handle_signal()处理程序中调用on signal