0

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

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

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);

}
4

2 回答 2

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您感兴趣的信号的处理程序中调用。

于 2015-07-15T09:36:39.363 回答
0

以下是您可以执行的操作:

1.枚举所有信号(以及信号状态)并列出它们的名称:

 variables
 {
   enum signalName {
    signal1,
    signal2,
    ...
    signal639,
    ...
    signal70,
    signalMax
  };
  char signalName[signalMax][64] {
    "name_of_signal1",
    "name_of_signal2",
    ...
    "MIL", // name of the signal from message x639
    ...
    "name_of_signal70"
  };
  enum signalState {
    SIG_OFF,
    SIG_ON
  };
}

2.将计算延迟的代码放入函数中。我基本上采用了您的代码并概括了mil_stateandmil_start_time变量。

void CalculateHoldTime(enum signalId id, signal s) {
  int signal_state[signalMax];
  dword signal_start_time[signalMax];
  dword stop_time;
  dword retval;

   switch(signal_state[id])
    {
      case SIG_OFF:
          if(s == 1) {
              signal_start_time[id] = (timeNow()/100000);
              signal_state[id] = SIG_ON;
          }
          else signal_state[id] = SIG_OFF;
          break;
      case SIG_ON:
          if(s == 0) {
            stop_time = (timeNow()/100000);
            retval = writeCreate("SIG_STATUS"); // or signalName[id] if you need one tab per signal
            writeLineEx(retval,1," Signal %s turned ON at %ld  seconds for a duration of %ld seconds ", signalName[id], signal_start_time[id], stop_time - signal_start_time[id]);
            signal_start_time[id] =0;
            signal_state[id] = SIG_OFF;
          }
          else signal_state[id] = SIG_ON;
          break;
      default:
          break;     
    }
}

3.从您的消息处理程序中调用此函数。您必须为收到的每条消息重复此代码,但它要小得多。

on message x639
{
  message x639 mil_obj;
  mil_obj = this;
  CalculateHoldTime(signal639, mil_obj.iHwEcm_MILInput_flg);
  output(mil_obj);
}
于 2015-07-15T10:29:35.677 回答