Реализация тайм-аута связи - PullRequest
1 голос
/ 29 сентября 2010

Я реализую класс, который общается с контроллером мотора через USB-устройство. У меня все работает, кроме способа указать, является ли параметр, выбранный по каналу связи, "свежим" или нет. Что у меня так далеко:

class MyCommClass
{
public:
  bool getSpeed( double *speed );

private:
  void rxThread();

  struct MsgBase 
  { /* .. */ };

  struct Msg1 : public MsgBase
  { /* .. */ };

  struct Msg2 : public MsgBase
  { /* .. */ };

  /* .. */

  struct MsgN : public MsgBase
  { /* .. */ };

  Msg1 msg1;
  Msg2 msg2;
  /* .. */
  MsgN msgn;

  std::map< unsigned long id, MsgBase *msg > messages;
};

rxThead() - это бесконечный цикл, выполняемый в отдельном потоке, проверяющем USB-устройство на наличие доступных сообщений. Каждое сообщение имеет уникальный идентификатор, который rxThread() использует, чтобы вставить его в правильный msgx объект. Что мне нужно, так это когда пользователь вызывает функцию getSpeed(), он должен иметь возможность определить, является ли текущее значение скорости «свежим» или «устаревшим», т.е. был ли объект msgx, который содержит значение скорости, обновлен в пределах указанного период ожидания Таким образом, каждый объект сообщения должен реализовать свое собственное время ожидания (так как они варьируются в зависимости от сообщения).

Все сообщения периодически передаются контроллером мотора, но есть также некоторые, которые передаются, как только их содержимое изменяется (но они также будут передаваться периодически, если содержимое не изменяется). Это означает, что получение сообщения с номинальной скоростью выше допустимого, но оно должно появляться как минимум один раз в течение максимального периода времени ожидания.

Устройство USB предоставляет метки времени вместе с сообщениями, поэтому у меня есть доступ к этой информации. Временная метка не отражает текущее время, это число unsigned long с микросекундным разрешением, которое устройство обновляет каждый раз при получении сообщения. Я подозреваю, что устройство только начинает увеличивать это значение с 0 со времени, когда я вызываю его функции инициализации. Я могу придумать несколько способов реализации этого:

  • Каждый объект сообщения запускает поток, который бесконечно работает (WaitForSingleObject) в течение периода ожидания. По истечении времени ожидания он проверяет, была ли увеличена переменная счетчика (которая была кэширована до ожидания). Если нет, он устанавливает флаг, помечающий сообщение как устаревшее. Счетчик будет увеличиваться каждый раз, когда rxThread() обновляет этот объект сообщения.

  • rxThread(), в дополнение к заполнению сообщений, также выполняет итерацию по списку сообщений и проверяет отметку времени последнего обновления. Если отметка времени превышает время ожидания, оно помечает сообщение как устаревшее. Этот метод может иметь проблемы с объемом обработки требуется. Вероятно, это не будет проблемой на большинстве машин, но этот код должен работать на очень медленном «промышленном компьютере».

Буду очень признателен за ваши мысли и предложения о том, как это реализовать. Я открыт для идей, кроме двух, которые я упомянул. Я использую Visual Studio 2005, и кросс-платформенная переносимость не представляет большой проблемы, поскольку драйверы USB-устройств предназначены только для Windows. В настоящее время я отслеживаю около 8 сообщений, но было бы неплохо, если бы решение было достаточно легким, чтобы я мог добавить еще несколько (может быть, еще 8) без ограничений по мощности.

Заранее спасибо, Ashish.

Ответы [ 2 ]

1 голос
/ 29 сентября 2010

Если вам не нужно делать что-то «сразу», когда сообщение становится устаревшим, я думаю, что вы можете пропустить использование таймеров, если вы сохраняете время компьютера и метку времени устройства для каждого сообщения:

#include <ctime>
#include <climits>

class TimeStamps {
public:
  std::time_t sys_time() const;   // in seconds
  unsigned long dev_time() const; // in ms
  /* .. */
};

class MyCommClass {
  /* .. */
private:
  struct MsgBase {
    TimeStamps time;
    /* .. */
  };

  TimeStamps most_recent_time;

  bool msg_stale(MsgBase const& msg, unsigned long ms_timeout) const {
    if (most_recent_time.sys_time() - msg.time.sys_time() > ULONG_MAX/1000)
      return true; // device timestamps have wrapped around
    // Note the subtraction may "wrap".
    return most_recent_time.dev_time() - msg.time.dev_time() >= ms_timeout;
  }
  /* .. */
};

Конечно, TimeStamps может быть другим вложенным классом в MyCommClass, если вы предпочитаете.

Наконец, rxThread () должен устанавливать объект TimeStamps соответствующего сообщения и элемент most_recent_time при каждом получении сообщения. Все это не обнаружит сообщение как устаревшее, если оно устарело после того, как было получено последнее сообщение любого другого типа, но у вашего второго возможного решения в вопросе будет та же проблема, так что, возможно, это не имеет значения. Если это имеет значение, что-то подобное может работать, если msg_stale () также сравнивает текущее время.

1 голос
/ 29 сентября 2010

Как насчет хранения метки времени в сообщении и getSpeed() проверки метки времени?

...